For the complete documentation index, see llms.txt. This page is also available as Markdown.
Webpack 구성 파일
구성 파일
Webpack 구성 파일을 프로젝트 루트(root) 위치에 생성하고 진입, 진출 파일 경로, 모드 등을 설정합니다.
// Node.js 모듈 path 불러오기constpath=require('path')// CommonJS 방식의 모듈 내보내기module.exports={// 엔트리 파일 설정entry:'./src/index.js',// 아웃풋 파일 출력 설정output:{// 파일 이름filename:'main.js',// 경로path:path.resolve(__dirname,'./dist'),},// 번들링 모드 설정mode:'development',}
모듈 번들링
webpack 명령을 터미널에 입력해 모듈 번들링을 수행합니다.
만약 명령 실행 후, 다음과 같은 오류 메시지가 출력된다면? 출력 경로 설정이 잘못된 것입니다.
이 문제는 출력 경로 설정을 다음과 같이 절대 값으로 설정하면 손쉽게 해결할 수 있습니다.
NPM 스크립트
프로젝트 구성 파일의 scripts 항목에 bundle 명령을 추가 등록한 다음 값으로 webpack 명령을 추가합니다.
그러면 터미널에서 NPM 명령 bundle로 Webpack 모듈 번들링을 수행할 수 있습니다.
모드 별, 구성 파일
구성할 내용이 많아지고, 모드에 따라 조건 처리해야 할 경우 구성 파일은 상당히 복잡해집니다. 이런 경우 개발용, 배포용 구성 파일을 각각 만들어 효율적으로 관리할 수도 있습니다.
[webpack-cli]
# 잘못된 구성 객체입니다.
Invalid configuration object.
# Webpack API 스키마(Schema)와 일치하지 않는 구성 객체를 사용해 초기화 되었습니다.
Webpack has been initialized using a configuration object that does not match the API schema.
# 구성.출력.경로 설정인 './dist' 공급 값은 절대 경로가 아닙니다!
- configuration.output.path: The provided value "./dist" is not an absolute path!
# 출력 디렉토리 설정은 반드시 **절대 경로**로 처리해야 합니다.
-> The output directory as **absolute path** (required).
path: path.resolve(__dirname, './dist'),
"scripts": {
"bundle": "webpack"
}
npm run bundle
.
├── config/
│ ├── webpack.dev.js # 개발용 Webpack 구성 파일
│ └── webpack.prod.js # 배포용 Webpack 구성 파일
├── src/
├── package-lock.json
└── package.json
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
/* -------------------------------------------------------------------------- */
module.exports = {
// 입력 파일
entry: {
main: './src/index.js',
},
// 출력 파일
output: {
path: path.resolve(__dirname, '../dist'),
// 파일 이름 브라우저 캐싱 처리
filename: '[name].js',
},
// 감시 설정 (package.json 스크립트로 제어)
// watch: true,
// 모드 설정
mode: 'development',
// 소스맵 설정
devtool: 'inline-source-map',
// 모듈 설정
module: {
// 로더 규칙
rules: [
// 이미지 파일 로더
{
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
},
// 스타일 파일 로더
{
test: /\.(sa|sc|c)ss$/i,
exclude: /node_modules/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
// 스크립트 파일 로더
{
test: /\.js$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['@babel/plugin-proposal-class-properties'],
sourceMap: true,
},
},
},
],
},
// 플러그인 설정
plugins: [
// 환경 변수 등록
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
// 빌드 된 결과물 정리
new CleanWebpackPlugin(),
// 빌드 결과 HTML 문서 자동 주입
new HtmlWebpackPlugin({
// 템플릿 설정
template: './src/template/template.ejs',
// 자동 주입 해제
inject: false,
// 압축 설정
minify: true,
// 문서 메타
meta: {
'theme-color': '#4285f4',
'description': 'Webpack 러닝 가이드 실습을 진행합니다.',
},
// 사용자 정의 옵션
templateParameters: {
title: 'Webpack 러닝 가이드',
lang: 'ko-KR',
},
}),
],
}
const os = require('os')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const CSSMQPackerPlugin = require('css-mqpacker-webpack-plugin')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
// 개발 모드 구성 가져오기
const devConfig = require('./webpack.dev')
// 배포 모드 구성 설정
const prodConfig = {
entry: {
...devConfig.entry,
'polyfills': './src/polyfills/polyfills.js',
'detect.polyfills': './src/polyfills/detect.polyfills.js',
},
output: {
...devConfig.output,
filename: '[name].[contenthash].js',
publicPath: '',
},
module: {
rules: [
...devConfig.module.rules.filter((rule) => {
if (Array.isArray(rule.use)) {
return !rule.use.includes('css-loader')
}
return rule
}),
// MiniCssExtractPlugin.loader 설정 (대체)
{
test: /\.(sa|sc|c)ss$/i,
exclude: /node_modules/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
plugins: [
...devConfig.plugins,
// CSS 추출
new MiniCssExtractPlugin({
linkType: false,
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
}),
// PNG — 이미지 포멧 최적화
new ImageMinimizerPlugin({
minimizerOptions: {
plugins: ['pngquant'],
},
}),
// WEBP — 이미지 포멧 최적화
new ImageMinimizerPlugin({
deleteOriginalAssets: true,
filename: '[name].webp',
minimizerOptions: {
plugins: ['imagemin-webp'],
},
}),
// JPE?G — 이미지 포멧 최적화
new ImageMinimizerPlugin({
// 약 8kb 이상 파일만 최적화 적용
filter: (source) => (source.byteLength >= 8192 ? true : false),
minimizerOptions: {
plugins: [['jpegtran', { progressive: true }]],
},
}),
new ImageMinimizerPlugin({
// 약 8kb 미만 파일만 최적화 적용
filter: (source) => (source.byteLength < 8192 ? true : false),
minimizerOptions: {
plugins: [['jpegtran', { progressive: false }]],
},
}),
],
}
/* -------------------------------------------------------------------------- */
module.exports = {
entry: prodConfig.entry,
output: prodConfig.output,
mode: 'production',
devtool: 'source-map',
// 모듈 설정
module: prodConfig.module,
// 플러그인 설정
plugins: prodConfig.plugins,
// 최적화 설정
optimization: {
// 압축
minimize: true,
// 미니마이저
minimizer: [
// 플러그인 인스턴스 생성
new CssMinimizerPlugin({
// CPU 멀티 프로세서 병렬화 옵션 (기본 값: true)
// os.cpus() → CPU 코어 정보를 포함하는 배열 객체 반환
parallel: os.cpus().length - 1,
}),
// 미디어쿼리 그룹 병합
new CSSMQPackerPlugin({
sort: true,
}),
],
},
}
const os = require('os')
const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const CSSMQPackerPlugin = require('css-mqpacker-webpack-plugin')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
/* -------------------------------------------------------------------------- */
// 개발 모드 감지
const isDevMode = process.env.NODE_ENV.includes('dev')
/* -------------------------------------------------------------------------- */
// 개발,배포 모든 모드에서 사용되는 Webpack 플러그인 목록(배열)
const plugins = [
// 환경 변수 등록
new webpack.EnvironmentPlugin({
// process.env.NODE_ENV가 정의되지 않은 경우, 'development' 사용
NODE_ENV: 'development',
}),
// 빌드 된 결과물 정리
new CleanWebpackPlugin(),
// 빌드 결과 HTML 문서 자동 주입
new HtmlWebpackPlugin({
// 템플릿 설정
template: './src/template/template.ejs',
// 자동 주입 해제
inject: false,
// 압축 설정
minify: true,
// 문서 타이틀
// 문서 메타
meta: {
'theme-color': '#4285f4',
'description': 'Webpack 러닝 가이드 실습을 진행합니다.',
},
// 사용자 정의 옵션
templateParameters: {
title: 'Webpack 러닝 가이드',
lang: 'ko-KR',
},
}),
]
// 개발,배포 모든 모드에서 사용되는 엔트리 파일 설정
let entry = {
main: './src/index.js',
}
// 배포 모드 설정
if (!isDevMode) {
// 배포용 엔트리 파일(들) 추가
entry = {
...entry,
'polyfills': './src/polyfills/polyfills.js',
'detect.polyfills': './src/polyfills/detect.polyfills.js',
}
// 배포용 플러그인 추가
plugins.push(
// CSS 추출
new MiniCssExtractPlugin({
linkType: false,
filename: '[name].[contenthash].css', // 'style.css' 설정도 가능
chunkFilename: '[id].[contenthash].css',
}),
// PNG — 이미지 포멧 최적화
new ImageMinimizerPlugin({
minimizerOptions: {
plugins: ['pngquant'],
},
}),
// WEBP — 이미지 포멧 최적화
new ImageMinimizerPlugin({
deleteOriginalAssets: true,
filename: '[name].webp',
minimizerOptions: {
plugins: ['imagemin-webp'],
},
}),
// JPE?G — 이미지 포멧 최적화
new ImageMinimizerPlugin({
// 약 8kb 이상 파일만 최적화 적용
filter: (source) => {
if (source.byteLength >= 8192) {
return true
}
return false
},
minimizerOptions: {
plugins: [['jpegtran', { progressive: true }]],
},
}),
new ImageMinimizerPlugin({
// 약 8kb 미만 파일만 최적화 적용
filter: (source) => {
if (source.byteLength < 8192) {
return true
}
return false
},
minimizerOptions: {
plugins: [['jpegtran', { progressive: false }]],
},
})
)
}
/* -------------------------------------------------------------------------- */
module.exports = {
// 입력 파일
entry,
// 출력 파일
output: {
path: path.resolve(__dirname, './dist'),
// 파일 이름 브라우저 캐싱 처리
filename: '[name].[contenthash].js',
// publicPath: 'dist/',
},
// 감시 설정 (package.json 스크립트로 제어)
// watch: true,
// 모드 설정
mode: isDevMode ? 'development' : 'production',
// 소스맵 설정
devtool: isDevMode ? 'inline-source-map' : 'source-map',
// 플러그인 설정
plugins,
// 모듈 설정
module: {
// 로더 규칙
rules: [
// 이미지 파일 로더
{
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: {
loader: 'file-loader',
options: {
// name: '[name].[ext]',
name: '[name].[contenthash].[ext]',
},
},
},
// 스타일 파일 로더
{
test: /\.(sa|sc|c)ss$/i,
exclude: /node_modules/,
use: [
isDevMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
// 스크립트 파일 로더
{
test: /\.m?js$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['@babel/plugin-proposal-class-properties'],
sourceMap: true,
},
},
},
],
},
// 최적화 설정
optimization: {
// 압축
minimize: isDevMode ? false : true,
// 미니마이저
minimizer: [
// 플러그인 인스턴스 생성
new CssMinimizerPlugin({
// CPU 멀티 프로세서 병렬화 옵션 (기본 값: true)
// os.cpus() → CPU 코어 정보를 포함하는 배열 객체 반환
parallel: os.cpus().length - 1,
}),
// 미디어쿼리 그룹 병합
new CSSMQPackerPlugin({
sort: true,
}),
],
},
}