웹팩 입문
소개
번들러이다.
웹팩을 이용하면 수백 개의 파일을 몇 개의 정적 파일, 그것도 아주 작은 용량으로 압축할 수 있다.
웹팩은 어떻게 이런 마법 같은 작업을 해낼까?
파일 간에 얽혀있는 import와 export 관계를 추적해서 해낸다.
간단히 설명하자면 HTML 파일에서는 <script>
tag로 js 파일을 불러오고, 해당 js 파일은 다른 js 파일, css 파일, 이미지 파일 등을 import한다. import된 파일은 각기 또 다른 파일을 import해온다.
entry, output, loader, plugin, optimization 개념과 자주 쓰이는 라이브러리만 알면 어느 정도 혼자 공식 문서를 보고 따라할 수 있다.
(혼자 공부하면서 느낀 건데, webpack 5 이전과 이후는 많이 달랐다. 5 이전 버전 자료를 보고 공부하면 속터지는 경우가 많이 발생할 것이다...)
dev, prod 구별하기
어차피 개발을 하면 dev와 prod를 구별해야 하니깐 webpack-merge
부터 설치하자
그 다음 루트 경로에 webpack.common.js, webpack.dev.js, webpack.prod.js 파일을 각각 만든다.
셋 다 웹팩 config 파일인데 common에는 이름 그대로 dev와 prod에서 공통적으로 쓰이는 설정을 적는다.
// ./webpack.common.js
module.exports = {
entry: './src/index.js',
}
// ./webpack.dev.js
const common = require("./webpack.common")
const { merge } = require("webpack-merge")
module.exports = merge(common, {
mode: "development",
})
// ./webpack.prod.js
const common = require("./webpack.common")
const { merge } = require("webpack-merge")
module.exports = merge(commmon, {
mode: "production",
})
모드를 나눠놨으니 package.json의 scripts를 작성해보자.
webpack serve
코드를 수정할 때마다 빌드하는 과정이 귀찮으므로 dev mode일 때에는 webpack-dev-server
의 도움을 받자.
이 패키지는 실제로 파일을 산출하는 게 아니라 메모리상에서 동작한다.
--config
--config 뒤에는 파일 경로명이 온다. (웹팩 config 파일명의 default값은 webpack.config.js임)
// ./package.json
"scripts": {
"start": "webpack serve --config webpack.dev.js --open",
"build": "webpack --config webpack.prod.js"
},
entry, output
entry는 이름 그대로 진입점이다. 보통 HTML에서 script
tag로 불러올 파일을 적으면 된다.
dev 모드인지, prod 모드인지와 관계가 없기 때문에 common에 적는다.
진입점이 여러 개인 경우에는 객체로 만들고 key 자리에 이름을 적어주면 된다.
// 한 개인 경우
module.exports = {
entry: './src/index.js',
}
// 여러 개인 경우
module.exports = {
entry: {
main: "./src/index.js",
vendor: './src/vendor.js'
},
}
output도 이름 그대로 산출물이다. 빌드를 끝낸 결과물을 어떤 이름으로 할 것인지, 어떤 경로에 저장할 것인지 등을 설정한다.
dev 모드, prod 모드 다르게 설정할 것이다.
파일명에 템플릿(예: [contenthash])을 쓴 이유는 캐싱 버스팅(cache busting) 때문이다. 예를 들어 코드를 수정하고 파일을 새로 빌드해봤자 동일한 파일명을 계속 쓰면, 사용자의 브라우저는 캐시를 이용하기 때문에 웹페이지의 수정사항이 반영되지 않는다. 이를 방지하고자 빌드할 때마다 파일명을 바뀌도록 설정해준다.
문제는 “이렇게 하면 HTML의 script
tag의 src를 일일이 수정해줘야 하는 거 아닐까?”라는 의문이 든다. 다행히 이를 해결해주는 플러그인이 있다. html-webpack-plugin
을 사용하면 된다. 빌드 대상인 src 폴더내 HTML 파일에는 script
태그를 적지 않는다. 빌드하고 나면 산출물인 HTML 파일의 script
태그내 src 경로를 확인해보면 변동하는 파일명에 맞게 지정된다.
// ./webpack.dev.js
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "development",
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
}
// ./webpack.prod.js
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(common, {
mode: "production",
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "./imgs/[name].[hash].[ext]",
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/template.html",
})
],
}
loader
웹팩은 js 파일만 압축한다.
loader는 js가 아닌 다양한 정적 파일을 전처리하는 역할을 한다.
몇 가지 주의할 점이 있다.
- module: {rules: []} 형식으로 적는다.
- test에는 해당 파일의 확장자를 적는데 정규표현식으로 적는다.
- use에는 해당 loader를 적는다. 이때 적용순서는 “거꾸로”다.
prod 모드에서는 MiniCssExtractPlugin.loader를 사용했다. css를 별도 파일로 뽑아내야 html이 렌더링 속도가 빠르기 때문이다.
// ./webpack.common.js
module.exports = {
entry: {
main: "./src/index.js",
vendor: './src/vendor.js'
},
module: {
rules: [
{
test: /\.html$/,
use: ["html-loader"]
},
]
}
};
// ./webpack.dev.js
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(common, {
mode: "development",
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/template.html",
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", //3. styles를 DOM에 주입
"css-loader", //2. css를 commonjs로 변환
"sass-loader" //1. SASS를 css로 변환
]
},
]
}
});
// ./webpack.prod.js
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = merge(common, {
mode: "production",
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "./imgs/[name].[hash].[ext]",
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css"
}),
],
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader, //3. css를 별개 파일로 전환
"css-loader", //2. css를 commonjs로 변환
"sass-loader" //1. SASS를 css로 변환
]
},
]
}
});
optimization
말 그대로 최적화를 위한 설정이다. 보통 optimization 설정을 하게 되면 코드는 난독화가 되어 산출된다.
주의할 점: optimization은 덮어쓰기라고 생각해야 된다. css를 optimization하면, 기존의 난독화되어 빌드되던 HTML 파일이 더 이상 난독화가 되지 않는다. 따라서 optimization 설정에는 CSS, JS, HTML을 모두 다 적어줘야 한다.
// ./webpack.prod.js
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
... ,
optimization: {
minimizer: [
new OptimizeCssAssetsPlugin(), // css 최적화
new TerserPlugin(), // js 최적화
new HtmlWebpackPlugin({ // html 최적화
template: './src/template.html',
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
removeComments: true,
}
})
]
},
}
plugin
빌드를 몇 번만 해도 dist 폴더가 지저분해진다.
clean-webpack-plugin
은 이전 빌드 산출물을 알아서 지워준다.
이외에도 다양한 플러그인이 있다. 필요에 따라 찾아보기 바란다.
// ./webpack.prod.js
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
... ,
plugins: [
new CleanWebpackPlugin(),
],
}
Author And Source
이 문제에 관하여(웹팩 입문), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@bochodev/webpackintroduction저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)