github.com/doonguk/webpack-boilerplate
doonguk/webpack-boilerplate
Webpack, Babel 를 이용한 프론트엔드 개발환경 셋팅. Contribute to doonguk/webpack-boilerplate development by creating an account on GitHub.
github.com
그냥 위 사이트 따라 타이핑하면서 공부함.
1. 바벨
바벨이란? 최신 버전의 자바스크립트 문법을 이전 버전의 문법으로 변환시켜주는 트랜스 컴파일러임.
하지만 바벨을 사용한다고 해서 모든 최신 문법을 사용할 수 있는것은 아니다. Array.from, Object.assign() 등 기존에 없던 문법은 pollyfill 을 추가하야 지원하게 해 줘야한다.
바벨의 동작원리
파싱(소스코드를 읽어서 파싱 후 추상 구문트리를 생성) -> 변환 (추상구문트리를 각 브라우저에 맞게 변환, 여기서 바벨 설정에 추가한 플러그인들이 적용됨.) -> 코드생성(브라우저 환경에 맞는 실제 코드로 변환)
2. 웹팩
웹팩이란? 여러개의 파일을 하나로 합쳐주는 모듈 번들러이다.
웹팩에서의 Loader란?
웹팩은 모든 파일을 모듈로 관리함. js, 이미지, 폰트, 스타일시트 등등. 그러나 웹팩은 js밖에 모른다. js가 아닌 파일을 웹팩이 이해하게끔 변경하는게 로더의 역할이다. babel-loader, css-loader, sass-loader 등등이 있다.
웹팩을 쓰는 이유?
1. 모듈간 의존성 문제를 해결. -> 웹팩이 모듈간의 의존성을 계산해서 번들링 해줌.
2. 네트워크 병목을 줄여줌 -> <script> 태그를 여러개 쓰면 웹 페이지를 로드할 때 네트워크 병목 현상이 생길 수 있다. 이런 문제를 해결하기 위해 하나의 js파일로 로드하면 됨. 그러나 실제로 코드를 하나의 js파일에다가 작성하면 가독성이나 전역공간의 오염 문제가 발생하게 되므로 웹팩을 써서 여러개의 파일을 하나로 묶어주는 방법을 사용.
3. 모듈단위의 개발 가능 -> 가독성, 유지보수 효율 높임. 스코프에 신경스지 않아도 됨. 라이브러리간 종속 문제를 고민할 필요 없음.(웹팩이 이 계산하니까)
4. 코드 압축, 최적화.
5. es6+ 스크립트를 지원함 -> 바벨로더로 바벨사용.
웹팩의 동작원리?
1. entry 파일의 의존성을 분석
2. 다음 파일의 의존성을 분석
3. 모든 파일의 의존성을 분석할 때 까지 2번 과정 반복.
4. 종속성 그래프를 만들고 이 그래프를 사용해 모든 모듈을 하나의 번들 파일로 합친다.
3. 바벨 적용하기.
필요한 모듈 install
npm i @babel/core @babel/cli @babel/preset-env -D
- @babel/core : 바벨을 쓰기 위한 필수 패키지
- @babel/cli : 바벨을 터미널에서 커맨드를 입력해 사용하기 위한 패키지 (선택사항)
- @babel/preset-env : 바벨 공식 preset중 하나. browerlist 형식. .browerlistrc 파일을 만들어서 상세하게 설정 가능하다.
babel config 설정 (babel.config.js 파일)
module.exports = function (api) {
api.cache(true)
const presets = [
[
"@babel/preset-env",
{
targets: "> 0.25%, not dead",
useBuiltIns: "usage",
corejs: 3,
modules: false,
},
],
]
return {
presets,
}
}
- api.cache(true) : babel 설정 파일을 한번만 실행하겠다는 뜻. 다른옵션(babeljs.io/docs/en/config-files#apicache)
- targets : 지원하는 브라우저의 범위를 정함
pollyfill 추가
npm i core-js@3 -D
- useBuiltIns : pollyfill을 필요한 것만 import 할건지 설정. usage는 필요한 것만, entry는 전부.
- moudules : ES6 module syntax를 사용할건지 설정. true면 import, export를 require, module.exports로 대체하게 됨. 여기서 false로 설정한 이유는 웹팩의 트리 쉐이킹이 import, exports를 쓰므로 false로 설정했다고 함.
트리쉐이킹이란? 사용하지 않는 코드를 제거하는 방식. ui.toast.com/weekly-pick/ko_20180716 나중에 읽어보기
이후 npx babel index.js를 커맨드에 치면 바벨로 변환한 코드가 출력된다.
변환전 index.js
const foo = [1, 2, 3, [4, 5]];
console.log(foo.flat());
변환 후
import "core-js/modules/es.array.flat";
import "core-js/modules/es.array.unscopables.flat";
var foo = [1, 2, 3, [4, 5]];
console.log(foo.flat());
flat() 함수에 대한 polyfill이 적용되었다.
4. 웹팩 적용하기
필요 모듈 install
npm i webpack webpack-cli -D
webpack.config.js 작성
const path = require('path')
const config = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'build.js'
}
}
module.exports = config
- entry : webpack이 의존성 분석을 하는 시작점.
- output : 빌드한 결과물을 저장할 path와 filename설정
웹팩 실행
"scripts": {
"build": "webpack"
},
package.json 파일의 script에 build 커맨드 추가하고 npm run build.
const foo = [1, 2, 3, [4, 5]];
console.log(foo.flat());
이 index.js 파일이
console.log([1,2,3,[4,5]].flat());
이렇게 한줄로 나옴.
바벨 로더 적용.
위에선 단순히 웹팩으로만 빌드하여 적절히 트랜스파일링된 코드를 얻을 수 없다. babel을 웹팩에 적용해서 코드를 트랜스파일링 하자.
바벨로더 설치
npm i babel-loader -D
웹팩 설정 수정
const path = require('path')
const config = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'build.js'
},
module: {
rules: [
{
test: /\.js$/,
use: "babel-loader",
exclude: /node_modules/
}
]
}
}
module.exports = config
결과물

외계어가 된다. 아마 바벨 코어 안에있는 코드랑 합쳐진것 같다.
5.style 관련 로더 적용하기
1) css-loader
npm i css-loader -D
왜씀? 웹팩은 js 밖에 모른다. 그래서 css파일을 js파일로 변환해서 로딩해줘야함.
css-loader는 css파일을 import하게 해주고 번들과정에서 css코드를 js코드로 변환해준다.
적용
{
test: /\.css$/,
use: "css-loader"
}
webpack.config.js 의 modules -> rules 배열에 추가.
2) style-loader
npm i style-loader -D
쓰는 이유? css-loader에 의해 모듈로 변경된 스타일 시트는 돔에 추가되어야만 브라우저가 해석할 수 있다. style-loader는 자바스크립트로 변경된 스타일시트를 동적으로 head태그에 추가하는 로더임.
{
test: /\.css$/,
use: ["style-loader","css-loader"]
}
.css파일에 똑같이 적용하므로 css-loader와 같이쓴다.
use는 오른쪽에서 왼쪽순서로 적용되는데 css-loader가 적용된 후 style-loader를 적용시켜야 하므로 위의 순서로 배열에 넣어야함.
3) Mini-css-extract-plugin
style-loader는 파일의 수 만큼 head 태그에 style 태그가 생긴다. mini-css-extract-plugin은 css 파일을 따로 빼서 파일로 관리해주는 플러그인이다.
npm i mini-css-extract-plugin -D
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const path = require("path")
const config = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "build.js",
},
module: {
rules: [
{
test: /\.js$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "style.css",
}),
],
}
module.exports = config

style.css가 분리되어 번들링된다. 이걸 쓰면 style-loader는 필요없음.
4) sass-loader
.scss, .sass파일을 import 할 수 있게 해준다.
npm i sass-loader -D
{
test: /\.(sa|sc|c)ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
sass-loader는 sass파일을 읽어서 css파일로 변환시켜줘야 하기 때문에 css-loader보다 우선순위가 높다.
추가적으로 node-sass모듈을 설치하면 아주 빠르게 css 파일로 컴파일 시켜준다고 한다.
6. file-loader, url-loader 적용하기
둘다 위 css-loader와 같은 이유로 쓴다. png, jpg, ico 등 이미지 파일에 주로 쓰는듯?
url-loader는 file-loader와 달리 작은 파일이나 글꼴을 파일로 복사하지 않고 toString('base64') 문자열로 변환하여 번들 파일에 넣는다고 한다.
적용방법은 css-loader와 유사하니 생략.
7. 모듈을 절대경로로 불러오기
npm i babel-plugin-module-resolver -D
바벨 플러그인을 설치한다. 이 플러그인으로 절대경로의 기준(ex. src폴더로)을 바꿔서 상대경로 대신 쓸 수 있다.
바벨 설정
module.exports = function (api) {
api.cache(true)
const presets = [
[
"@babel/preset-env",
{
targets: "> 0.25%, not dead",
useBuiltIns: "usage",
corejs: 3,
modules: false,
},
],
]
const plugins = [
[
"module-resolver",
{
root: ["./src"],
alias: {
imgs: "./public/images",
},
},
],
]
return {
presets,
plugins,
}
}
- root : 사용자 정의 프로젝트 루트 지정.
- alias : 여러개의 경로에 별칭을 줘서 파일을 쉽게 가져올 수 있도록 한다. 예를들어 /public/images 경로에 aa.png 이미지를 imgs/aa.png로 가져올 수 있다.
이런 코드를
import '../styles/index.css'
import '../styles/index2.css'
const foo = [1, 2, 3, [4, 5]];
console.log(foo.flat());
이렇게 쓸 수 있다.
import 'styles/index.css'
import 'styles/index2.css'
const foo = [1, 2, 3, [4, 5]];
console.log(foo.flat());
상대 경로로 위 코드보다 더 지저분하게 쓴적이 많았는데 엄청 유용하게 쓸 수 있을듯..
8. index.html 생성하기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>title</title>
</head>
<body>
<div id="App"></div>
</body>
</html>
static 한 파일을 번들링해서 하나의 js 파일로 만들고 이를 index.html 파일에서 불러오는 형식으로 개발하는데 HtmlWebpackPlugin을 사용한다.
npm i html-webpack-plugin -D
설치후 웹팩설정파일 플러그인에 추가.
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './src/index.html'),
inject: true,
filename: path.resolve(__dirname, './dist/index.html')
})
- template : 어떤 경로의 html을 참조할건지
- inject : 번들링한 파일을 자동으로 불러올지 여부
- filename : 파일이름.
빌드시 dist에 위에서 만든 build.js파일과 style.css를 참조하는 index.html이 생성된다.
9. webpack으로 개발서버 띄우기
npm i webpack-dev-server -D
webpack-dev-server 플러그인 설치
webpack.config.js 의 config에 추가
mode: "development",
devtool: "inline-source-map",
devServer: {
contentBase: "./dist",
port: 9000,
hot: true
},
- mode : webpack-dev-server에만 쓰이는 기능이 아님. development, production, none 3개 옵션으로 NODE 환경변수(process.env) 을 설정
- devtool : debug tool을 정해준다. source-map은 원본 소스와 난독화된 소스를 맵핑시켜주는 방법이라고 한다.(perfectacle.github.io/2016/11/14/Webpack-devtool-option-Performance/)
- contentBase : 서버를 띄울 때 서빙할 폴더
- port : 개발서버 포트
- hot : 코드가 수정되면 자동으로 re-bulid
- webpack-dev-server 빌드 결과물은 실제 파일로 빌드되진 않고, 메모리에 저장됨.
package.json의 스크립트에 추가
"dev" : "webpack-dev-server --open --config webpack.config.js"
npm run dev 하면 localhost:9000에 개발서버가 실행된다.
10. 개발서버, 실 서버 환경 분리하기
npm i webpack-merge -D
webpack-merge 모듈로 개발서버와 실서버의 config을 분리시켜주자.
기존 webpack.config.js는 webpack.common.js로 이름을 바꾸고 webpack-dev-server에 관한 코드는 삭제시킨다.
webpack.dev.js 생성
const commonConfig = require('./webpack.common')
const { merge } = require('webpack-merge')
module.exports = merge(commonConfig, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: "./dist",
port: 9000,
hot: true
}
})
commonConfig와 dev-server 코드를 머지시킴.
webpack.prod.js
const commonConfig = require("./webpack.common")
const { merge } = require("webpack-merge")
module.exports = merge(commonConfig, {
mode: "production",
})
package.json의 스크립트 수정
"dev": "webpack-dev-server --open --config webpack.dev.js",
"prod": "webpack ---config webpack.prod.js"
npm run dev -> 개발서버
npm run prod -> 프로덕션 빌드
11. 리액트 사용하기
npm i @babel/preset-react -D
react를 쓰기 위해서 @babel/preset-react 설치한다. 이 모듈에는 3가지 플러그인이 포함되는데 jsx를 사용하게 해주고, 번들링 과정에서 jsx를 createElement를 통한 바닐라js로 변환시켜준다.
바벨 설정에 프리셋을 추가한다.
module.exports = function (api) {
api.cache(true)
const presets = [
[
"@babel/preset-env",
{
targets: "> 0.25%, not dead",
useBuiltIns: "usage",
corejs: 3,
modules: false,
},
],
["@babel/preset-react"] // 여기
]
const plugins = [
[
"module-resolver",
{
root: ["./src"],
alias: {
imgs: "./public/images",
},
},
],
]
return {
presets,
plugins,
}
}
리액트 설치후 테스트
npm i react react-dom
App.js
import React from 'react'
export default function App() {
return ( <div>hello world</div>)
}
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "App.js";
import 'styles/index.css'
import 'styles/index2.css'
ReactDOM.render(<App />, document.querySelector("#App"));
결과

된다.
'공부' 카테고리의 다른 글
HTML (0) | 2020.11.28 |
---|---|
프론트엔드 지식 - 프론트엔드 전반 (0) | 2020.11.27 |
토익 문법 정리 - 접속사 (0) | 2020.09.01 |
토익 문법 정리 - 동명사 / to 부정사 / 분사 (0) | 2020.09.01 |
토익 문법 정리 - 동사 (0) | 2020.08.31 |