Webpack 치트시트
Webpack - Static Module Bundler
Webpack은 현대적인 JavaScript 애플리케이션을 위한 정적 모듈 번들러입니다. Webpack이 애플리케이션을 처리할 때, 내부적으로 하나 이상의 진입점에서 의존성 그래프를 빌드한 후 프로젝트에 필요한 모든 모듈을 하나 이상의 번들로 결합합니다.
[This section appears to be empty, so no translation is needed]목차
Would you like me to continue translating the rest of the document? If so, could you provide the specific text for sections 4-20?```bash
Install webpack globally
npm install -g webpack webpack-cli
Check version
webpack —version
### Local Installation (Recommended)
```bash
# Initialize npm project
npm init -y
# Install webpack locally
npm install --save-dev webpack webpack-cli
# Install webpack dev server
npm install --save-dev webpack-dev-server
# Install common loaders and plugins
npm install --save-dev html-webpack-plugin css-loader style-loader file-loader url-loader
Package.json Scripts
{
"scripts": {
"build": "webpack --mode production",
"dev": "webpack --mode development",
"start": "webpack serve --mode development",
"watch": "webpack --mode development --watch"
}
}
Basic Configuration
Minimal webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Complete Basic Configuration
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
TypeScript Configuration
const path = require('path');
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Entry Points
Single Entry Point
module.exports = {
entry: './src/index.js'
};
Multiple Entry Points
module.exports = {
entry: {
main: './src/index.js',
vendor: './src/vendor.js'
}
};
Dynamic Entry Points
module.exports = {
entry: () => {
return {
main: './src/index.js',
admin: './src/admin.js'
};
}
};
Entry with Dependencies
module.exports = {
entry: {
main: {
import: './src/index.js',
dependOn: 'shared'
},
admin: {
import: './src/admin.js',
dependOn: 'shared'
},
shared: 'lodash'
}
};
Output
Basic Output Configuration
const path = require('path');
module.exports = {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Multiple Entry Output
module.exports = {
entry: {
main: './src/index.js',
admin: './src/admin.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Output with Hashing
module.exports = {
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
}
};
Public Path Configuration
module.exports = {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/assets/'
}
};
Library Output
module.exports = {
output: {
filename: 'my-library.js',
path: path.resolve(__dirname, 'dist'),
library: {
name: 'MyLibrary',
type: 'umd'
}
}
};
Loaders
CSS Loaders
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
}
};
JavaScript Loaders
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}
};
File Loaders
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource'
},
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader']
},
{
test: /\.xml$/i,
use: ['xml-loader']
}
]
}
};
Asset Modules
module.exports = {
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource'
},
{
test: /\.html/,
type: 'asset/resource'
},
{
test: /\.txt/,
type: 'asset/source'
},
{
test: /\.jpg/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 // 4kb
}
}
}
]
}
};
Loader Options
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true
}
}
]
}
]
}
};
Plugins
HTML Webpack Plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
]
};
Extract CSS Plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]
};
Define Plugin
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.API_URL': JSON.stringify('https://api.example.com')
})
]
};
Copy Webpack Plugin
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'public', to: 'public' },
{ from: 'assets/images', to: 'images' }
]
})
]
};
Bundle Analyzer Plugin
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
})
]
};
Clean Webpack Plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin()
]
};
Mode
Development Mode
module.exports = {
mode: 'development',
devtool: 'eval-source-map'
};
Production Mode
module.exports = {
mode: 'production',
devtool: 'source-map'
};
Mode-specific Configuration
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
mode: argv.mode,
devtool: isProduction ? 'source-map' : 'eval-source-map',
optimization: {
minimize: isProduction
}
};
};
Development Server
Basic Dev Server
module.exports = {
devServer: {
static: './dist',
port: 3000,
open: true
}
};
Advanced Dev Server Configuration
module.exports = {
devServer: {
static: {
directory: path.join(__dirname, 'dist')
},
compress: true,
port: 3000,
hot: true,
open: true,
historyApiFallback: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
HTTPS Dev Server
module.exports = {
devServer: {
https: true,
// or with custom certificates
https: {
key: fs.readFileSync('/path/to/server.key'),
cert: fs.readFileSync('/path/to/server.crt'),
ca: fs.readFileSync('/path/to/ca.pem')
}
}
};
Code Splitting
Entry Point Splitting
module.exports = {
entry: {
main: './src/index.js',
vendor: './src/vendor.js'
}
};
Dynamic Imports
// In your JavaScript code
import('./math.js').then(math => {
console.log(math.add(16, 26));
});
// Or with async/await
async function loadMath() {
const math = await import('./math.js');
return math.add(16, 26);
}
SplitChunks Plugin
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
enforce: true
}
}
}
}
};
Advanced Code Splitting
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 244000,
cacheGroups: {
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
},
vendor: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all'
}
}
}
}
};
Optimization
Minification
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true
}
}
})
]
}
};
CSS Optimization
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
};
```### 트리 쉐이킹
```javascript
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false
}
};
```### 런타임 청크
```javascript
module.exports = {
optimization: {
runtimeChunk: 'single'
}
};
```### 모듈 연결
```javascript
module.exports = {
optimization: {
concatenateModules: true
}
};
```## 모듈 해결
```javascript
const path = require('path');
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src'),
'components': path.resolve(__dirname, 'src/components'),
'utils': path.resolve(__dirname, 'src/utils')
},
modules: [
'node_modules',
path.resolve(__dirname, 'src')
]
}
};
```### 해결 구성
```javascript
module.exports = {
resolve: {
fallback: {
"fs": false,
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify")
}
}
};
```### 해결 대체
```javascript
const webpack = require('webpack');
module.exports = {
devServer: {
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
```## 핫 모듈 교체
```javascript
// In your JavaScript modules
if (module.hot) {
module.hot.accept('./library.js', function() {
console.log('Accepting the updated library module!');
// Re-render or update your app
});
}
```### HMR 활성화
```javascript
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
plugins: ['react-refresh/babel']
}
}
]
}
]
},
plugins: [
new ReactRefreshWebpackPlugin()
]
};
```### 코드의 HMR
```javascript
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL || 'http://localhost:3000')
})
]
};
```### React 핫 리로드
```javascript
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
mode: argv.mode,
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(argv.mode),
'process.env.API_URL': JSON.stringify(
isProduction ? 'https://api.production.com' : 'http://localhost:3000'
)
})
]
};
};
```## 환경 변수
```javascript
const Dotenv = require('dotenv-webpack');
module.exports = {
plugins: [
new Dotenv({
path: './.env',
safe: true,
systemvars: true
})
]
};
```### 환경 변수를 위한 DefinePlugin
```javascript
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true
}
}
}),
new CssMinimizerPlugin()
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
},
runtimeChunk: 'single'
}
};
```### 환경별 구성
```json
{
"scripts": {
"build": "webpack --mode production",
"build:analyze": "webpack --mode production --env analyze",
"build:stats": "webpack --mode production --json > stats.json"
}
}
```### DotEnv 플러그인
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js',
contact: './src/contact.js'
},
plugins: [
new HtmlWebpackPlugin({
filename: 'home.html',
template: './src/home.html',
chunks: ['home']
}),
new HtmlWebpackPlugin({
filename: 'about.html',
template: './src/about.html',
chunks: ['about']
}),
new HtmlWebpackPlugin({
filename: 'contact.html',
template: './src/contact.html',
chunks: ['contact']
})
]
};
```## 프로덕션 빌드
```javascript
const ModuleFederationPlugin = require('@module-federation/webpack');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'shell',
remotes: {
mfe1: 'mfe1@http://localhost:3001/remoteEntry.js',
mfe2: 'mfe2@http://localhost:3002/remoteEntry.js'
}
})
]
};
```### 프로덕션 구성
```javascript
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
plugins: [
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
]
};
```### 빌드 스크립트
```javascript
// custom-loader.js
module.exports = function(source) {
// Transform the source
return `export default ${JSON.stringify(source)}`;
};
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.custom$/,
use: path.resolve(__dirname, 'custom-loader.js')
}
]
}
};
```## 고급 구성
```javascript
class MyCustomPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('MyCustomPlugin', (compilation, callback) => {
console.log('This is an example plugin!');
callback();
});
}
}
module.exports = {
plugins: [
new MyCustomPlugin()
]
};
```### 다중 페이지 애플리케이션
```javascript
module.exports = {
performance: {
maxAssetSize: 250000,
maxEntrypointSize: 250000,
hints: 'warning'
}
};
```### 마이크로 프론트엔드 구성
```javascript
// Dynamic imports for lazy loading
const LazyComponent = React.lazy(() => import('./LazyComponent'));
// Webpack magic comments
import(
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
'./modules/my-module.js'
);
```### 프리페칭과 프리로딩
```javascript
// Prefetch
import(
/* webpackPrefetch: true */
'./modules/LoginModal.js'
);
// Preload
import(
/* webpackPreload: true */
'./modules/ChartingLibrary.js'
);
```### 번들 분석
```bash
# Generate stats file
webpack --profile --json > stats.json
# Analyze with webpack-bundle-analyzer
npx webpack-bundle-analyzer stats.json
# Use webpack-bundle-analyzer plugin
npm install --save-dev webpack-bundle-analyzer
```## 문제 해결
```javascript
// Check resolve configuration
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'@': path.resolve(__dirname, 'src')
}
}
};
```#### 모듈을 찾을 수 없음
```bash
# Increase Node.js memory limit
node --max-old-space-size=4096 node_modules/.bin/webpack
# Or in package.json
{
"scripts": {
"build": "node --max-old-space-size=4096 node_modules/.bin/webpack"
}
}
```#### 메모리 문제
```javascript
module.exports = {
// Use cache
cache: {
type: 'filesystem'
},
// Exclude node_modules from babel-loader
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
// Use thread-loader for expensive loaders
module: {
rules: [
{
test: /\.js$/,
use: [
'thread-loader',
'babel-loader'
]
}
]
}
};
```#### 느린 빌드 시간
```javascript
module.exports = {
// Different source map options
devtool: 'eval-source-map', // Development
devtool: 'source-map', // Production
devtool: 'cheap-module-source-map', // Faster builds
devtool: false // No source maps
};
```#### 소스 맵 문제
```javascript
module.exports = {
stats: {
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}
};
```### 디버깅 구성
```javascript
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
// webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-source-map',
devServer: {
static: './dist'
}
});
// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});
```## 모범 사례
### 구성 조직화
### 성능 최적화
- **프로덕션 모드 사용**하여 최적화
- **트리 쉐이킹 활성화**하여 사용하지 않는 코드 제거
- **청크 분할**하여 캐싱 개선
- **콘텐츠 해싱 사용**하여 장기 캐싱
- **적절한 로더와 플러그인으로 번들 크기 최소화**
### 개발 경험
- **HMR 사용**하여 개발 속도 향상
- **디버깅을 위해 소스 맵 구성**
- **API 호출을 위한 프록시로 개발 서버 설정**
- **webpack-bundle-analyzer 사용**하여 번들 구성 이해
### 코드 조직화
- **환경별로 구성 분리**
- **더 깔끔한 임포트를 위해 별칭 사용**
- **파일 유형별로 로더 구성**
- **관련 플러그인 그룹화**
---
## 요약
Webpack은 현대 웹 애플리케이션의 복잡한 빌드 요구 사항을 처리할 수 있는 강력하고 유연한 모듈 번들러입니다. 주요 기능은 다음과 같습니다:
- **모듈 번들링**: 모듈을 최적화된 번들로 결합
- **로더**: 빌드 프로세스 중 파일 변환
- **플러그인**: webpack 기능 확장
- **코드 분할**: 성능 향상을 위해 코드를 더 작은 청크로 분할
- **핫 모듈 교체**: 전체 페이지 리로드 없이 모듈 업데이트
- **트리 쉐이킹**: 번들에서 사용하지 않는 코드 제거
- **에셋 관리**: 다양한 파일 유형 및 에셋 처리
webpack 구성을 숙달하고 모범 사례를 따르면 개발 경험과 애플리케이션 성능을 모두 개선할 수 있는 효율적인 빌드 프로세스를 만들 수 있습니다.
<script>
function copyToClipboard() {
const commands = document.querySelectorAll('code');
let allCommands = '';
commands.forEach(cmd => allCommands += cmd.textContent + '\n');
navigator.clipboard.writeText(allCommands);
alert('모든 명령어가 클립보드에 복사되었습니다!');
}
function generatePDF() {
window.print();
}
</script>