이전 웹팩의 등장배경에 대하여 살펴보았다.
이번엔 웹팩을 어떻게 설정하고 실행하는지 알아보자. (node.js설치 필요)
설치 진행은 웹팩 공식 홈페이지의 Getting Started를 참고해서 webpack.config.js를 설정
// 터미널 명령어
npm init -y
npm i -D webpack webpack-cli --save-dev
💡 최신 npm은 --save가 기본으로 설정되어 있어서 따로 적어주지 않아도 된다
-dev
로 설치시 package.json에 dependencies가 아닌devDependencies
에 추가가 된 것을 확인할 수 있다.
// package.json
"devDependencies": {
"webpack": "^5.4.0",
"webpack-cli": "^4.2.0"
}
touch webpack.config.js
// path 모듈 불러오기
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
// 최종 번들링된 자바스크립트
filename: 'main.js',
// dist를 배포용 폴더로 사용
path: path.resolve(__dirname, 'dist')
}
}
src 폴더를 만들고 하위에 index.html
파일과 index.js
파일 생성
설치를 마쳤으면 아래 명령어를 참고해서 웹팩을 실행해보자.
실행 시 필요에 따라 --mode 옵션을 줄 수 있다. 'development', 'production', 'none' 세 가지 값을 정할 수 있다.
// 터미널 명령어
npx webpack --mode development
// 또는
node_modules/.bin/webpack --mode development
웹팩 설정에서 중요한 4가지가 Entry
, Output
, Loader
, Plugin
이다. 웹팩 공식홈페이지에서 Core Concepts
라고 소개한다.
webpack은 번들링 과정에서 디펜던시 그래프
(dependency graph)를 그린다.
특정 시작지점
부터 애플리케이션에 필요한 모든 모듈을 포함하는 그래프를 재귀적
으로 완성해 나간다. 그래프를 모두 그리고 나면 이 모든 모듈을 소수의 번들로 묶어서 (보통 하나의 번들로 묶는다) 브라우저에 로드될 준비를 마친다.
config파일에서 entry 속성
을 설정해서 웹팩이 어떤 모듈로부터 시작해서 디펜던시 그래프를 그려나갈지 명시해줄 수 있다. (여러 개도 지정 가능)
module.exports = {
entry: './src/index.js',
}
output 은 웹팩이 번들 후 결과물을 어디로 내보낼지 지정하는 속성이다. 기본값으로 메인 결과물인 main.js 파일은 ./dist/main.js에, 그 외 파일은 ./dist 폴더에 내보내 진다. 파일 이름(filename), 경로(path)를 별도로 지정할 수 있고, clean
을 true
로 설정하면 지정한 결과물이 내보내지는 디렉토리에 사용하지 않는 파일을 알아서 정리해준다.
module.exports = {
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
clean: true
}
}
사실 웹팩은 기본적으로 JavaScript
와 JSON 파일
만 이해할 수 있다. 이 때 필요한 것이 Loader
이다. 사용하려는 포맷에 대응하는 Loader를 설정해주면 다른 포맷의 리소스도 디펜던시 그래프에 추가할 수있게 된다.
Loader를 설정하려면 test
와 use
두 가지 필수 속성을 적어주어야 한다. test
는 어떤 파일을 변환할지
지정하는 속성으로, 보통 정규표현식으로 작성한다. use
는 파일을 변환할 때 어떤 로더를 사용
해야하는지 명시하는 속성이다.
디펜던시 그래프를 그리다
test
에 지정된 파일 형식 발견시 번들에 넣기 전use
에 지정한 로더로 변환
주의할 점은 config에 바로 rules 속성
을 쓰는게 아니라 반드시 module.rules
에 정의해 주어야 한다는 것이다. (웹팩이 알아서 경고)
1) 바벨 설정
💡 바벨(babel) 은 ES6+문법으로 작성된 js파일을 ES5문법으로 트랜스 파일링 해준다.
// 터미널 명령어
npm i -D babel-loader @babel/core @babel/preset-env
npm i core-js regenerator-runtime
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|pages)/,
use: {
loader: 'babel-loader',
},
},
],
},
}
2) CSS
// 터미널 명령어
npm i -D css-loader
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
options: { import: true },
},
],
},
],
},
};
3) 이미지 설정
module.exports = {
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
},
],
},
};
바닐라 자바스크립트 프로젝트에서 꼭 필요한 두 가지 Plugin
만 설정해보자. (주요 플러그인 리스트)
html-webpack-plugin
을 사용하면 dist의 main.js를 스크립트 파일로 포함하는 HTML 문서를 dist 디렉토리 내에 자동으로 생성해준다. template
에 원본으로 사용할 HTML문서 경로
를 넣어주면 된다. 이 플러그인을 사용하지 않고 빌드하면 dist 디렉토리에 .html 파일이 생성되지 않는다.
즉, dist 디렉토리 내의 빌드 결과물 만으로는 렌더할 수 없다.
mini-css-extract-plugin
를 사용하면 빌드 결과 JS파일에서 스타일시트를 분리해서 CSS 파일을 따로 만들어준다. 크기가 큰 하나의 파일을 받는 것보다 작은 여러 개의 파일을 다운로드 하는 것이 성능상 유리하기 때문에, 배포 시에는 분리하는 것이 좋다.
// 터미널 명령어
npm i -D html-webpack-plugin mini-css-extract-plugin
// webpack.config.js
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
module.exports = {
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
new MiniCssExtractPlugin()
],
};
저장시 hot reload가능 웹서버 dev-server
를 설정
// 터미널 명령어
npm i -D webpack-dev-server
module.exports = {
devServer: {
port: 3000,
hot: false,
compress: true,
historyApiFallback: true,
open: true,
},
};
설정을 마치면 package.json에 script를 추가해보자. 참고로 serve는 키워드는 webpack-dev-server와 같다. 참고링크
// package.json
"scripts": {
"start": "webpack serve --mode=production",
"start:dev": "webpack serve --mode=development",
"build": "webpack --mode=production",
"build:dev": "webpack --mode=production",
},
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|pages)/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
options: { import: true },
},
],
},
{
test: /\.png$/,
type: 'asset/resource',
},
],
},
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin()],
devServer: {
port: 3000,
hot: false,
compress: true,
historyApiFallback: true,
open: true,
},
};
// package.json
{
"name": "webpack",
"version": "1.0.0",
"description": "webpack-setting",
"main": "index.js",
"scripts": {
"start": "webpack serve --mode=production",
"start:dev": "webpack serve --mode=development",
"build": "webpack --mode=production",
"build:dev": "webpack --mode=production"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"babel-loader": "^8.2.2",
"css-loader": "^5.1.3",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.3.9",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}
}