시작하는 중
웹팩 webpack 설정 알아보기 본문
webpack
웹팩은 무엇이고 왜 사용할까?
웹팩은 모듈 번들로로써 가장 많이 사용되는 모듈 번들러 중 하나이기도 하다. 모듈 번들링은 하나의 웹 어플리케이션을 구성하는 여러 자원들을 하나의 파일로 병합해주는 동작이다.
웹팩을 왜 써야할까?
- 성능
압축을 통해 크기를 줄이고, 이를 다운로드해야하는 클라이언트가 이를 더 빠르게 다운로드할 수 있기 때문이다. 즉, 성능적인 부분 때문에 사용해야한다고 볼 수 있다.
다운로드가 빠르다면, 페이지 로딩 속도가 빠르다는 것이고 UX적인 측면에서 더 많은 체감을 한다는 것이다.
- 동일 변수명의 오염
<script src="1.js" />
<script src="2.js" />
<script>
console.log(a);
</script>
1.js에서 a를 1로 정의하고 있고, 2.js에서 b를 2로 정의하고 있다면, 저 console.log(a)는 어떻게 될까?
2가 출력된다. 이렇듯 변수명이 겹쳐서 스코프 오염이 발생하게 되어, 각 js 파일마다 변수명을 겹치지 않게 조심해야했다.
- HTTP 요청의 수
위의 예시에서는 두개의 JavaScript 파일을 요청하게 된다. 하지만, 이를 합쳐서
<script scr="12.js" />
같이 요청한다면, 하나의 JS 파일만 다운로드하면 된다.
웹팩의 핵심 4가지
Entry, Output, Loaders, Plugins
1. Entry
엔트리 포인트는 웹 자원을 웹팩을 통해서 압축하기 위한 진입점이다. 그래서 엔트리 포인트(진입점)이다.
module.exports = {
entry: '.src/yourJSFile.js'
}
이렇게 한다면, src 디렉토리 안에 있는 js파일이 타겟이 되어 웹팩이 빌드를 수행한다. 해당 타겟을 기준으로 의존성 그래프를 그리고 필요한 모든 모듈 파일을 가져온다.
의존성 그래프를 그린다는 것은 쉽게 말해서 파일들간의 import를 추적하여 필요한 파일들을 구분한다는 것이다.
// 1.js
import init from './2.js'
import init from './3.js'
...
// 2.js
import init from './4.js'
...
이런 구조를 가진 파일 4개가 있다고 하고 1이 진입점이라면,

이 타겟은 하나일 필요는 없다. 엔트리 포인트가 될 파일들을 여러개 지정해도 상관없다.
그렇다면 Entry 파일은 어떤 내용이어야 할까?
? Entry에 쓰인 파일의 내용
웹팩으로 빌드할 파일의 진입점인 만큼, 해당 웹 애플리케이션의 전반적인 내용을 설명하고 있어야한다.
리액트에서는 main.jsx라고 볼 수 있겠다.
위의 그림에서 엔트리 포인트를 1.js로 잡았다면, 1,2,3,4까지의 JavaScript 파일이 의존성 그래프로 연결되어 4개의 파일이 빌드되어 하나의 js파일로 묶인다.
여기서 2.js를 잡는다면, 2, 4만 묶인다. 즉, import를 통해서 순서를 묶을 수 있다고 생각할 수 있겠다.
? entry에 여러개의 엔트리 포인트 설정
module.exports = {
entry: {
main: './src/index.js',
blog: './src/blog.js'
}
}
main에 string을 할당하는 것은 main이라는 key에 value 하나만 있는 object를 할당하는 것과 같다.
이렇게 여러 엔트리 포인트를 설정하는 것은, SPA가 아니라 특정 페이지에 진입했을 경우에 페이지에 맞는 js파일을 보낼 때에 적합하다.
2. Output
entry가 빌드할 파일의 시작점을 나타내는 것이라면, output은 빌드한 후의 파일 경로를 의미한다.
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js'
}
}
entry는 string으로 할당하면 자동으로 main을 키로 가지는 object로 인식하지만, output은 직접 만들어줘야만 한다.
이렇게 하게 되면, bundle.js파일을 자동으로 dist 디렉토리에 생성한다.
? 여러개의 entry 설정시
module.exports = {
entry: {
main: './src/index.js',
blog: './src/blog.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
__dirname은 Node.js의 전역변수이다. 이렇게 하면 이 웹팩의 현재 디렉토리 경로를 읽고 /dist 디렉토리로 설정하는 것이다.
filename: '[name].js'는 entry에 할당된 obect의 key 이름들을 읽어와서 [name] 자리에 할당되어 해당 이름으로 저장할 수 있다.
위의 경우에는 main.js, blog.js
? filename에 사용할 수 있는 다른 변수들
1. [id]: 내부적으로 사용하는 모듈 ID
2. [hash]: 매 빌드시마다 생기는 고유 해시 값
3. [chunkhash]: 웹팩의 각 모듈 내용을 기준으로 생생된 해시 값을 붙이는 옵션
3. Loader
loader는 JavaScript 파일이 아닌 웹 자원들을 변환할 수 있게 지정하는 것이다.
module.exports = {
module: {
rules: [
...
],
},
};
module.rules에 배열 형태로 지정하는 것이다.이게 왜 필요할까?
? loader가 필요한 이유
다른 사람들의 예시를 보다보면,
import './index.css'
import './react.svg'
같이 JavaScript 내에서 정적 파일인 svg나 css파일들을 import하는 것을 볼 수 있다.
이렇게 하면, 웹팩은 빌드시에 이 구문을 이해할 수 없다. 왜냐하면 이 css를 해석하기 위한 loader가 없기 때문이다.
즉, loader는 JavaScript만 이해하는 웹팩을 위한 통역기라고 볼 수 있다.
이런 loader는 설치를 통해서 가져와야한다.
// in terminal
npm install --save-dev css-loader style-loader
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
],
},
};
이렇게 사용할 수 있다.
rules 배열안에 존재하는 Object의 key 의미
1. test
정규 표현식을 사용하여 어떤 파일들이 해당 로더를 적용할지를 지정하는 것
위의 경우에는 .css로 끝나는 모든 확장자에 대해서 use구문의 loader를 적용한다.
2. use
test에 해당하는 파일들에 대해서 어떤 loader를 사용할 것인지 알려주는 것이다.
만약 'css-loader'하나만 사용한다면 다음과 같이 사용할 수 있다.
...
{
test: /\.css$/,
use: 'css-loader'
}
...
즉, loader 외에 options라는 옵션이 추가되었기에 배열 요소에 Object로 할당해준 것이라서 loader로 따로 명시해준 것이다.
options의 modules:true는 css의 클래스 이름 고유 해시값과 결합하여 스타일 내의 충돌을 방지하는 것이다.
// before building
.Button {
color: red;
}
// after building
.Button_a1b2c3 {
color: red;
}
이렇게 된다는 것!
? 근데 use에 배열로 로더를 여러개 설정하면 어떤 순서로 될까
바로 오른쪽에서 왼쪽으로 index의 역순이다.
4. plugins
plugin은 웹팩이 할 수 없는 작업들을 수행할 목적으로 설정하는 것이다.
module.exports = {
plugins: [
...
]
}
이걸 어떻게 사용하냐 전에, 웹팩 공식 홈페이지에서 간단한 플러그인을 만드는 방법을 보여주고 있다.
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('The webpack build process is starting!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
중요한 것은 apply 메서드를 가지고 있어야만 하는 클래스이다.
이걸 어떻게 사용하냐면,
module.exports = {
// ...
plugins: [
new ConsoleLogOnBuildWebpackPlugin(),
],
};
이렇게 해주면 된다. 여러 플러그인들이 많아서 다 설명할 수는 없고, 공홈에서 소개하는 플러그인 두개만 살펴보려고 한다.
webpack.ProgressPlugin: 웹팩 빌드 진행 상황을 표시해주는 플러그인
HtmlWebpackPlugin: HTML 파일을 동적으로 생성하여 웹팩 번들 결과물을 자동으로 삽입하는 플러그인
node API를 사용한 빌드
const webpack = require('webpack'); //webpack 런타임에 접근하기 위함
const configuration = require('./webpack.config.js'); // webpack의 설정을 불러오기
let compiler = webpack(configuration); // webpack 컴파일러 생성
new webpack.ProgressPlugin().apply(compiler); // ProgressPlugin 플러그인 사용
// compiler 객체의 run 메서드를 호출하여 빌드 실행
compiler.run(function (err, stats) {
// ...
});
reference
https://joshua1988.github.io/webpack-guide/guide.html
'자바스크립트' 카테고리의 다른 글
Next.js에서 yarn start를 하면 일어나는 일 (0) | 2023.07.03 |
---|---|
JavaScript History API (0) | 2023.06.06 |
함수형 프로그래밍 (0) | 2023.05.15 |
모듈, 번들러, 모듈 번들러의 개념과 등장한 이유 (0) | 2023.05.06 |
자바스크립트 iterator와 iterable (0) | 2023.04.07 |