Webpack is a powerful build tool based on Node.js that enables modular frontend development. It handles code splitting, minification, polyfills for browser compatibility, and performance optimization. Modern frameworks like Vue and React rely on webpack for their build processes.
Project Setup
Initialize a new project and create the necessary directory structure:
mkdir my-project
cd my-project
npm init -y
Create the source directory structure:
src/
├── index.html
└── index.js
Install jQuery as an example dependency:
npm install jquery -S
Installing Webpack
Install webpack and its CLI as development dependencies:
npm install webpack@5.42.1 webpack-cli@4.7.2 -D
Basic Configuration
Create webpack.config.js in the project root:
const path = require('path');
module.exports = {
mode: 'development',
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
}
};
The mode option accepts either development or production. Development mode prioritizes build speed, while production mode enables code minification and optimization.
Add a script to package.json:
{
"scripts": {
"dev": "webpack"
}
}
Run the development build:
npm run dev
Development Server Configuration
Install the development server for hot module replacement:
npm install webpack-dev-server@3.11.2 -D
Update the script in package.json:
{
"scripts": {
"dev": "webpack serve"
}
}
Modify webpack.config.js to include dev server options:
const path = require('path');
module.exports = {
mode: 'development',
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
},
devServer: {
open: true,
port: 8080,
host: '127.0.0.1'
}
};
The dev server stores bundled files in memory rather than the physical disk, enabling faster rebuilds.
HTML Plugin Configuration
Install the HTML plugin to auto-generate the HTML file:
npm install html-webpack-plugin@5.3.2 -D
Update the configuration:
const path = require('path');
const HtmlPlugin = require('html-webpack-plugin');
const htmlPlugin = new HtmlPlugin({
template: './src/index.html',
filename: './index.html'
});
module.exports = {
mode: 'development',
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
},
plugins: [htmlPlugin],
devServer: {
open: true,
port: 8080
}
};
Loader Configuration
Webpack can only process JavaScript files by default. Additional loaders are required for other file types.
CSS Loader
npm install style-loader@3.0.0 css-loader@5.2.6 -D
Less Loader
npm install less-loader@10.0.1 less@4.1.1 -D
File and URL Loaders
npm install url-loader@4.1.1 file-loader@6.2.0 -D
Babel Loader
npm install babel-loader@8.2.2 @babel/core@7.14.6 @babel/plugin-proposal-decorators@7.14.5 -D
Create babel.config.js in the project root:
module.exports = {
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }]
]
};
Update webpack.config.js with loader rules:
const path = require('path');
const HtmlPlugin = require('html-webpack-plugin');
const htmlPlugin = new HtmlPlugin({
template: './src/index.html',
filename: './index.html'
});
module.exports = {
mode: 'development',
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
},
plugins: [htmlPlugin],
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
{ test: /\.jpg|png|gif$/, use: 'url-loader?limit=470&outputPath=images' },
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
}
};
Production Build
Add a build script to package.json:
{
"scripts": {
"dev": "webpack serve",
"build": "webpack --mode production"
}
}
Run the production build:
npm run build
Cleen Old Build Files
Install the clean plugin to remove old files before each build:
npm install clean-webpack-plugin@3.0.0 -D
Update the configuration:
const path = require('path');
const HtmlPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const htmlPlugin = new HtmlPlugin({
template: './src/index.html',
filename: './index.html'
});
const cleanPlugin = new CleanWebpackPlugin();
module.exports = {
mode: 'development',
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
},
plugins: [htmlPlugin, cleanPlugin],
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
{ test: /\.jpg|png|gif$/, use: 'url-loader?limit=470&outputPath=images' },
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
}
};
Source Map Configuration
Source maps enable debugging minified code by mapping compiled code back to the original source.
For development, use eval-source-map to maintain accurate line numbers:
module.exports = {
mode: 'development',
devtool: 'eval-source-map',
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
},
plugins: [htmlPlugin, cleanPlugin],
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
{ test: /\.jpg|png|gif$/, use: 'url-loader?limit=470&outputPath=images' },
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
}
};
For production, disable source maps or use nosources-source-map to prevent source code exposure:
devtool: 'nosources-source-map'
Path Alias Configuration
Configure a path alias to simplify imports:
module.exports = {
resolve: {
alias: {
'@': path.join(__dirname, './src')
}
}
};