Webpack 是目前最流行的前端模块打包工具,它可以将 JavaScript、CSS、图片等各种资源视为模块,通过 loader 和 plugin 进行处理,最终打包成浏览器可识别的静态资源。
Webpack 2.x 是一个重要的里程碑版本,相比 1.x 带来了原生 ES6 模块支持、Tree Shaking、配置简化、性能提升等诸多改进。本文将详细介绍如何使用 Webpack 2.x 从零构建一个前端项目,涵盖基础配置、常用 loader/plugin、开发环境、生产环境优化等内容。
一、Webpack 2.x 核心新特性
先了解一下 2.x 相比 1.x 的关键变化,方便后续配置:
- 原生 ES6 模块支持:无需额外配置即可识别
import/export,为 Tree Shaking 提供基础;
- Tree Shaking:可以“摇掉”未使用的代码,减少打包体积(仅支持 ES6 模块);
- 配置简化:
module.loaders 改为 module.rules,resolve.extensions 不再需要空字符串;
- 性能提升:构建速度更快,打包体积更小;
- 更好的代码分割:
CommonsChunkPlugin 优化,支持更灵活的公共代码提取。
二、前置准备:环境安装
1. 安装 Node.js 和 npm
Webpack 基于 Node.js 运行,首先需要安装 Node.js(建议使用 LTS 版本),安装后 npm 会自动安装。
2. 初始化项目
创建一个新目录,进入目录后初始化 npm 项目:
1 2
| mkdir webpack2-demo && cd webpack2-demo npm init -y
|
三、基础配置:从零开始
1. 安装 Webpack
1 2
| npm install webpack@2.x --save-dev
|
2. 创建项目结构
先搭建一个基础的项目目录:
1 2 3 4 5 6 7 8
| webpack2-demo/ ├── src/ # 源代码目录 │ ├── index.js # 入口文件 │ ├── module.js # 示例模块 │ └── index.css # 示例样式 ├── index.html # HTML 模板 ├── webpack.config.js # Webpack 配置文件 └── package.json
|
3. 编写基础代码
先写几个简单的文件,方便后续测试:
src/module.js
1 2 3 4 5 6 7 8 9
| export function sayHello(name) { return `Hello, ${name}!`; }
export function unusedFunction() { return 'This function is not used'; }
|
src/index.js
1 2 3 4 5 6 7 8 9 10 11 12
| import { sayHello } from './module.js'; import './index.css';
const message = sayHello('Webpack 2.x'); console.log(message);
const app = document.createElement('div'); app.textContent = message; document.body.appendChild(app);
|
src/index.css
1 2 3 4 5 6 7 8
| body { background-color: #f0f0f0; font-family: Arial, sans-serif; } div { padding: 20px; color: #333; }
|
index.html
1 2 3 4 5 6 7 8 9 10
| <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Webpack 2.x Demo</title> </head> <body> </body> </html>
|
4. 编写 Webpack 配置文件
在项目根目录创建 webpack.config.js,这是 Webpack 的核心配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const path = require('path');
module.exports = { entry: './src/index.js',
output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') },
module: { rules: [ ] },
plugins: [ ],
resolve: { extensions: ['.js', '.json', '.css'] } };
|
5. 配置 npm scripts
在 package.json 中添加打包命令:
1 2 3 4 5
| { "scripts": { "build": "webpack --config webpack.config.js" } }
|
现在执行 npm run build,Webpack 会开始打包,但因为还没配置 loader,CSS 文件会报错,接下来我们添加常用的 loader。
四、常用 Loader 配置:处理各种资源
Loader 用于将非 JS 文件转换为 Webpack 可识别的模块,以下是最常用的几个 loader。
1. 处理 CSS:style-loader、css-loader
1 2
| npm install style-loader css-loader --save-dev
|
在 webpack.config.js 的 module.rules 中添加:
1 2 3 4 5 6 7 8 9 10 11 12
| module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }
|
2. 转译 ES6+:babel-loader
Webpack 2.x 支持 ES6 模块,但为了兼容旧浏览器(如 IE),还需要用 Babel 转译 ES6+ 语法。
1 2
| npm install babel-loader@7.x babel-core@6.x babel-preset-env@1.x --save-dev
|
在项目根目录创建 Babel 配置文件 .babelrc:
1 2 3 4 5 6 7 8 9 10
| { "presets": [ ["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "ie >= 9"] } }] ] }
|
在 webpack.config.js 的 module.rules 中添加:
1 2 3 4 5 6 7 8 9 10 11 12
| module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] }
|
3. 处理图片/字体:file-loader、url-loader
1 2
| npm install file-loader url-loader --save-dev
|
在 webpack.config.js 的 module.rules 中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| module: { rules: [ { test: /\.(png|jpg|gif|svg)$/, use: [ { loader: 'url-loader', options: { limit: 8192, name: 'images/[name].[hash:8].[ext]' } } ] }, { test: /\.(woff|woff2|eot|ttf|otf)$/, use: [ { loader: 'file-loader', options: { name: 'fonts/[name].[hash:8].[ext]' } } ] } ] }
|
五、常用 Plugin 配置:增强构建功能
Plugin 用于执行更广泛的任务,比如生成 HTML、清理目录、提取 CSS 等。
1. 生成 HTML:html-webpack-plugin
自动生成 HTML 文件,并将打包后的 JS/CSS 自动插入。
1 2
| npm install html-webpack-plugin@2.x --save-dev
|
在 webpack.config.js 中配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { plugins: [ new HtmlWebpackPlugin({ template: './index.html', filename: 'index.html', inject: true, minify: { collapseWhitespace: true } }) ] };
|
2. 清理 dist 目录:clean-webpack-plugin
每次打包前自动清理 dist 目录,避免旧文件残留。
1 2
| npm install clean-webpack-plugin@0.x --save-dev
|
在 webpack.config.js 中配置:
1 2 3 4 5 6 7 8 9
| const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = { plugins: [ new CleanWebpackPlugin(['dist']), ] };
|
默认情况下 CSS 会被 style-loader 插入到 <style> 标签中,生产环境建议提取到单独的 .css 文件。
1 2
| npm install extract-text-webpack-plugin@2.x --save-dev
|
修改 webpack.config.js 中的 CSS loader 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = { module: { rules: [ { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) } ] }, plugins: [ new ExtractTextPlugin('css/[name].[contenthash:8].css'), ] };
|
六、开发环境配置:提升开发体验
1. 配置 webpack-dev-server
提供一个本地开发服务器,支持热模块替换(HMR)、自动刷新、代理等功能。
1 2
| npm install webpack-dev-server@2.x --save-dev
|
在 webpack.config.js 中添加开发服务器配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| module.exports = { devServer: { contentBase: './dist', hot: true, open: true, port: 8080, proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } }, devtool: 'cheap-module-eval-source-map' };
|
在 package.json 中添加开发命令:
1 2 3 4 5 6
| { "scripts": { "dev": "webpack-dev-server --config webpack.config.js", "build": "webpack --config webpack.config.js" } }
|
现在执行 npm run dev,Webpack 会自动启动开发服务器,打开浏览器,修改代码后会自动刷新。
2. 开启热模块替换(HMR)
在 webpack.config.js 中添加 HMR 插件:
1 2 3 4 5 6 7 8
| const webpack = require('webpack');
module.exports = { plugins: [ new webpack.HotModuleReplacementPlugin(), ] };
|
七、生产环境优化:减小体积、提升性能
生产环境需要重点关注打包体积和加载速度,以下是关键优化配置。
1. 区分开发/生产环境
创建两个配置文件:webpack.dev.js(开发环境)和 webpack.prod.js(生产环境),或者用 webpack-merge 合并公共配置。这里简化处理,直接修改 webpack.config.js,通过环境变量区分。
修改 package.json 的 scripts:
1 2 3 4 5 6
| { "scripts": { "dev": "webpack-dev-server --env.dev --config webpack.config.js", "build": "webpack --env.prod --config webpack.config.js" } }
|
修改 webpack.config.js,接收环境变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| module.exports = function(env) { const isProd = env && env.prod;
return { devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map', plugins: [ isProd && new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }) ].filter(Boolean) }; };
|
2. 开启 Tree Shaking
Tree Shaking 可以删除未使用的代码,前提是:
- 使用 ES6 模块(
import/export);
- Babel 配置中关闭模块转换(
"modules": false,之前已经配置过);
- 生产环境开启压缩(UglifyJsPlugin 会删除未使用的代码)。
在 package.json 中添加 sideEffects,告诉 Webpack 哪些文件有副作用(不能随便删):
1 2 3 4 5
| { "sideEffects": [ "*.css" ] }
|
3. 代码分割:提取公共代码
使用 CommonsChunkPlugin 提取公共代码(如 vendor 库、公共模块),减少重复打包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| module.exports = function(env) { return { entry: { main: './src/index.js', vendor: ['lodash'] }, output: { filename: '[name].[chunkhash:8].js', path: path.resolve(__dirname, 'dist') }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity }), new webpack.optimize.CommonsChunkPlugin({ name: 'manifest' }) ] }; };
|
八、完整项目结构与配置示例
最后,整理一下完整的配置和项目结构,方便直接参考:
项目结构
1 2 3 4 5 6 7 8 9
| webpack2-demo/ ├── src/ │ ├── index.js │ ├── module.js │ └── index.css ├── index.html ├── webpack.config.js ├── .babelrc └── package.json
|
完整 webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = function(env) { const isProd = env && env.prod;
return { entry: { main: './src/index.js' }, output: { filename: isProd ? '[name].[chunkhash:8].js' : '[name].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: isProd ? ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) : ['style-loader', 'css-loader'] }, { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' }, { test: /\.(png|jpg|gif|svg)$/, use: [ { loader: 'url-loader', options: { limit: 8192, name: 'images/[name].[hash:8].[ext]' } } ] } ] }, resolve: { extensions: ['.js', '.json', '.css'] }, devtool: isProd ? 'source-map' : 'cheap-module-eval-source-map', devServer: { contentBase: './dist', hot: true, open: true, port: 8080 }, plugins: [ new CleanWebpackPlugin(['dist']), new HtmlWebpackPlugin({ template: './index.html', inject: true, minify: isProd ? { collapseWhitespace: true } : false }), isProd && new ExtractTextPlugin('css/[name].[contenthash:8].css'), isProd && new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), !isProd && new webpack.HotModuleReplacementPlugin() ].filter(Boolean) }; };
|
九、常见问题与注意事项
- Loader 版本匹配:Webpack 2.x 对应的 loader/plugin 版本可能较老,安装时注意指定版本(如
babel-loader@7.x),否则可能报错。
- Tree Shaking 不生效:检查是否使用了 ES6 模块,Babel 是否配置了
modules: false,是否开启了生产环境压缩。
- 缓存问题:生产环境文件名带
hash,避免浏览器缓存旧文件;manifest 文件提取 webpack 运行时代码,避免 vendor hash 随业务代码变化。
- 性能优化:开发环境用
cheap-module-eval-source-map 提升构建速度,生产环境用 source-map 方便调试。
十、总结
Webpack 2.x 相比 1.x 有了很大的改进,配置更简洁,性能更好,Tree Shaking 和原生 ES6 模块支持是最大的亮点。掌握本文的内容,已经可以用 Webpack 2.x 构建一个完整的前端项目了。
虽然现在 Webpack 已经迭代到 5.x,但 2.x 的核心思想(入口、输出、loader、plugin)是一致的,学习 2.x 也能为后续学习新版本打下基础。