文章目录
- 从0开始搭建一个简单webpack用例
- [Webpack 核心模块](#Webpack 核心模块)
-
- Loader
-
- [图片资源:file-loader / url-loader](#图片资源:file-loader / url-loader)
- [样式文件:style-loader / css-loader / postcss-loader ...](#样式文件:style-loader / css-loader / postcss-loader ...)
- production模式下打包后抽离css文件
- 字体文件
- Plugin
-
- [打包更便捷: HtmlWebpackPlugin & CleanWebpackPlugin](#打包更便捷: HtmlWebpackPlugin & CleanWebpackPlugin)
- [Entry 与 Output](#Entry 与 Output)
- Devtools
-
- [配置 source-map](#配置 source-map)
- [WebpackDevServer 配置本地开发](#WebpackDevServer 配置本地开发)
-
- devServer基本配置
- [Hot Module Replacement (HMR)](#Hot Module Replacement (HMR))
- [optimization 配置优化](#optimization 配置优化)
-
- [minimizer : css代码压缩](#minimizer : css代码压缩)
- [Tree Shaking:usedExports](#Tree Shaking:usedExports)
- [代码分割(Code Splitting):splitChunks](#代码分割(Code Splitting):splitChunks)
- [resolve : 路径解析](#resolve : 路径解析)
-
- [extensions 省略扩展名](#extensions 省略扩展名)
- [alias 简化长路径引用](#alias 简化长路径引用)
- [Webpack 常用性能优化](#Webpack 常用性能优化)
-
- 优化构建速度
-
- [babel开启缓存,exclude 限制 Loader 处理范围](#babel开启缓存,exclude 限制 Loader 处理范围)
- IngorePlugin、DllPlugin、NoParse
- [Thread-loader (5.x) / HappyPack (4.x) 多进程加速构建](#Thread-loader (5.x) / HappyPack (4.x) 多进程加速构建)
- [TerserPlugin 多进程压缩](#TerserPlugin 多进程压缩)
- [DllPulgin 生成动态链接库文件](#DllPulgin 生成动态链接库文件)
- 优化代码体积
-
- [Tree Shaking](#Tree Shaking)
- [TerserPlugin 代码压缩](#TerserPlugin 代码压缩)
- css、图片资源优化
- [SplitChunksPlugin 代码分割](#SplitChunksPlugin 代码分割)
从0开始搭建一个简单webpack用例
构建环境
初始化项目,产生package.json
ts
npm init -y
安装webpack
ts
npm install webpack webpack-cli -D
package.json

在跟目录下新建src文件夹,写一个index.js
并建立webpack的配置文件 webpack.config.js,进行基本配置:
ts
const path = require('path'); // 引入path模块,用于处理文件和目录的路径
module.exports = {
mode: 'development', // 设置模式为开发模式
entry: path.join(__dirname, 'src', 'index.js'), //'./src/index.js', // 入口文件,Webpack将从这里开始构建依赖图
output: {
filename: 'bundle.js', // 输出文件的名称
path: path.join(__dirname, 'dist') // 输出文件的目录
},
}
本地打包
package.json中增加webpack运行命令build,尝试构建
ts
"webpack-build": "webpack --config webpack.config.js"
运行:
ts
npm run webpack-build
会发现在跟文件下自动生成dist文件夹,并生成打包后的文件bundle.js

本地启动
1 在src目录下新建一个默认的html模板
2 安装html-webpack-plugin, 用来解析html的插件
3 安装webpack-dev -server, 用来启动本地服务的插件
ts
npm install html-webpack-plugin -D
npm install webpack-dev -serve -D
在webpack.config.js新增配置

package.json中增加webpack运行命令dev,尝试本地启动
- webpack serve 即为本地启动devServer的命令,它编译生成的文件并不会放在dist目录下,而是暂存在电脑缓存中
ts
"webpack-dev": "webpack serve --config webpack.config.js"
尝试运行: npm run webpack-dev
浏览器打开http://localhost:9000 会发现正常启动

配置babel
安装babel babel的作用是将js文件在打包后编译为es5语法,适配各种环境的浏览器
- core 是babel的核心模块
- preset-env 可以被看作是一组 Babel 常用插件的集合
ts
npm install @babel/core @babel/preset-env babel-loader
跟目录下建立.babelrc配置文件
ts
{
"presets": ["@babel/preset-env"]
}
webpack.config.js新增配置
- babel-loader是webpack和babel之间做了打通
- @babel/preset-env包含了es6转换es5的规则

babel-polyfill
- babel-polyfill 是一个用于模拟现代 JavaScript API 的工具库,旨在解决 Babel 仅转换语法(如箭头函数、类)而不转换新 API(如 Promise、Array.from)的问题 。它通过注入全局作用域或内置对象原型上的方法,为旧浏览器提供完整的 ES2015+ 环境支持。
安装完整依赖包
ts
npm install --save-dev @babel/plugin-transform-runtime @babel/runtime-corejs3
npm install --save core-js@3 # 需单独安装 core-js@3
引入polyfill,会自动提供完整的ES6 API
ts
import '@babel/polyfill'
const ES6LIST = ['let', 'const', 'class', 'extends', 'super', 'promise', 'async', 'await']
console.log(ES6LIST.includes('let')); // 测试babel-polyfill是否生效
🌟 通过配置采用按需引入,会减小包的体积
ts
// .babelrc 配置文件
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
],
}
babel-runtime
适用场景:
- 开发工具库或组件库,避免全局 polyfill 污染宿主环境。
ts
// .babelrc 配置文件
{
// ...
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3,
"helpers": true,
"regenerator": true
}
]
]
}
| 名称 | 特点 | 适用场景 |
|---|---|---|
| babel-polyfill | 体积较大,会引起全局污染 | 完整的独立应用 |
| babel-runtime | 体积小 | 独立组件库、包等 |
development 和 production 模式
拆分配置和merge
在webpack.config的基础上,将mode修改为production, 并为output中的fileName增加 [contenthash] 后缀,建立新的webpack.config.prod.js:
- 在production模式下,生成的打包文件会启动压缩,体积减小很多
- [contenthash]的作用是当代码发生改变,打包后会生成全新的hash随机码
在package.json中新增命令并打包生产
ts
"webpack-prod-build": "webpack --config webpack.config.prod.js",
成功运行:

安装 webpack-merge
ts
npm install webpack-merge -D
将公共部分的配置在webpack.common.js中导出

dev和prod中使用 webpack-merge 合并公共配置并导出


通过环境变量拆分配置
修改common.js 导出一个函数,根据环境判断最终导出
ts
"prod-build": "webpack --env=production --config webpack.common.js", // 生产环境打包
"dev-build": "webpack --config webpack.common.js", // 开发环境打包

多入口打包
- 在entry中配置多个入口,output中需要注意不能写死变量
ts
entry: {
home: path.join(__dirname, "src", "index.js"), //'./src/index.js',
other: path.join(__dirname, "src", "other.js"), //'./src/other.js',
},
output: {
filename: "[name].[contenthash].js", // 输出文件的名称
path: path.join(__dirname, "dist"), // 输出文件的目录
},
- plugins 中为每个入口单独配置 HtmlWebpackPlugin, 注意 splitChunks 中配置的chunk 加入对应参数
ts
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "index.html"), // 指定模板文件
filename: "index.html", // 输出的HTML文件名称
chunks: ["home", "vendors", "common"], // 关联的chunk
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "other.html"), // 指定模板文件
filename: "other.html", // 输出的HTML文件名称
chunks: ["other"], // 关联的chunk
}),
new CleanWebpackPlugin() // 默认清理 output.path 目录
],
Webpack 核心模块
Loader
Loader 是用于对模块的源代码进行转换的插件,允许你预处理文件(如将非 JavaScript 文件转为 Webpack 能处理的模块)。
loader 更详细的知识访问 webpack官网-loader
作用:
- 转换文件类型(如 .scss → .css,.ts → .js)
- 加载资源(如图片、字体)
- 代码优化(如压缩、混淆)
图片资源:file-loader / url-loader
在module中使用 file-loader 或者 url-loader 可以使图片资源正常加载
- url-loader 使用与 file-loader 类似,不过在options中增加了一个limit配置,小于该值(kb)的图片资源在经过处理后会转为base64编码置于js文件中而不是变为图片资源生成在对应目录下

样式文件:style-loader / css-loader / postcss-loader ...
- style-loader:使css样式挂在在对应的元素上
- css-loader:使webpack识别.css的文件
- postcss-loader: 使css兼容不同的浏览器
- 其它loader,按需引入,如less-loader、saas-loader等 🌟 loader的引入顺序是从后至前
配置postcss.config.js
autoprefixer会为样式自动增加兼容前缀

在webpack中新增配置,按模块化打包css
需要注意的是 namedExport 为默认true时可能无法正常导出整个样式对象,是采用ES6的按导入
| namedExport | 使用 |
|---|---|
| false | import styles from ./index.module.less |
| true | import { class } from ./index.module.less |

原代码

打包构建结果:

production模式下打包后抽离css文件
安装mini-css-extract-plugin
ts
npm install --save-dev mini-css-extract-plugin
构建结果

字体文件
Webpack 5 内置了资源模块(Asset Modules),无需额外安装 file-loader 或 url-loader,直接通过配置即可处理字体文件
ts
module.exports = {
module: {
rules: [
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource', // 直接输出文件到输出目录
generator: {
filename: 'fonts/[name][ext][query]', // 自定义输出路径和文件名
},
},
],
},
};
Webpack 4 则安装 file-loader 或 url-loader配置即可处理字体文件
ts
module.exports = {
module: {
rules: [
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]', // 输出文件名
outputPath: 'fonts/', // 输出目录
publicPath: '/fonts/', // 公共路径(用于 HTML 引用)
},
},
],
},
],
},
};
Plugin
打包更便捷: HtmlWebpackPlugin & CleanWebpackPlugin
- htmlWebpackPlugin 会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到html文件中;htmlWebpackPlugin 也可以配置一个模板
- cleanWebpackPlugin 在打包前,自动清除打包文件
ts
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "index.html"), // 指定模板文件
filename: "index.html", // 输出的HTML文件名称
}),
new CleanWebpackPlugin() // 默认清理 output.path 目录
],
Entry 与 Output
配置多入口
多入口(Multi-Entry)打包,可以将多个独立的页面或模块打包成不同的输出文件
通过 entry 配置多个入口文件,每个入口对应一个输出文件
ts
const path = require('path');
module.exports = {
entry: {
// 键:输出文件名(不含扩展名),值:入口文件路径
home: path.join(__dirname, "src", "index.js"),
other: path.join(__dirname, "src", "otherother.js.js"),
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.[contenthash].js', // [name] 会被替换为入口键名(home/about/contact)
};
打包后如图

Devtools
配置 source-map
参考 source-map配置
sourceMap 映射原始代码和打包代码之间的映射关系,也就是本地打包或者运行时,可以知道源代码中具体哪一行错误
开发模式下source-map是默认打开的,一些常用的devtool配置如下
-
source-map:打包后单独生成对映文件,较耗费性能
-
inline-source-map: 映射表直接放在bundle文件里面 具体到哪一行的哪一列出错
-
cheap-inline-source-map :具体到哪一行出错
-
cheap-module-source-map: 不仅管业务代码里面的错误 还管第三方代码和loaders里面的报错
-
带eval:效率最快,性能最好,但是复杂的内容eval提示并不全面。
development模式下推荐:cheap-module-eval-source-map
production模式下使用: cheap-module-source-map
WebpackDevServer 配置本地开发
devServer基本配置
ts
module.exports = {
// ...其他配置(entry, output等)
devServer: {
static: {
directory: path.join(__dirname, 'dist'), // 静态文件目录(默认根目录)
},
compress: true, // 启用gzip压缩
port: 9000, // 端口号(默认8080)
hot: true, // 启用热更新(HMR)
open: true, // 自动打开浏览器
historyApiFallback: true, // 支持SPA的路由回退
proxy: { //配置代理
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
},
headers: {
'Access-Control-Allow-Origin': '*',
},
};
🌟 Proxy 解决前端→后端的跨域,CORS 解决客户端→DevServer的跨域
Hot Module Replacement (HMR)
HMR的作用 :
开启后,当代码更新时,无需刷新页面,HMR 仅更新受影响的模块,不会重置整个应用。
适用场景:
- 表单输入、滚动位置、定时器等状态不会丢失
- 开发复杂交互应用(如游戏、画布编辑器)
-
修改CSS文件时,css-loader已经内置css热更新
-
在修改JS文件时,通过 module.hot.accept 自定义热更新逻辑
ts
if (module.hot) {
module.hot.accept('./updatedModule.js', () => {
console.log('模块已更新');
});
}
- React中使用 @pmmmwh/react-refresh-webpack-plugin;Vue中使用 vue-loader 支持 HMR。
optimization 配置优化
minimizer : css代码压缩
npm install terser-webpack-plugin css-minimizer-webpack-plugin --save-dev
ts
optimization: {
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
}
Tree Shaking:usedExports
只有ES Module 才会采取 Tree Shaking配置,因为ES Module 是静态引入(编译时引入),这样可以进行分析,而common.js是执行时引入,无法分析
production模式下 Tree Shaking 自动开启 ;development 模式下 Tree Shaking 默认关闭
ts
optimization: { usedExports: true }
开启 Tree Shaking 后,只会引入文件中需要的模块,降低文件体积
代码分割(Code Splitting):splitChunks
打包后的代码如何拆分代码块(如第三方库、公共模块),避免重复引用
配置:
ts
optimization: {
splitChunks: {
chunks: 'all', // 对所有入口和动态导入生效
minSize: 30000, // 模块大于 30KB 才拆分
maxSize: 0, // 不限制最大体积(0 表示无限制)
minChunks: 1, // 模块被引用至少 1 次才拆分
maxAsyncRequests: 5, // 异步加载的最大并行请求数
maxInitialRequests: 3, // 入口点的最大并行请求数
automaticNameDelimiter: '~', // 生成文件名分隔符(如 `vendors~main.js`)
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/, // 拆分 node_modules 中的模块
priority: -10, // 优先级(数值越高优先级越高)
name: 'vendors', // 生成的文件名
},
common: {
minChunks: 2, // 模块被引用至少 2 次才拆分
priority: -20,
reuseExistingChunk: true, // 复用已存在的 chunk
name: 'common',
},
},
},
}
resolve : 路径解析
extensions 省略扩展名
extensions 允许自动解析模块后缀名,允许省略扩展名
示例:import File from './file' 会依次尝试加载 ./file.js、./file.jsx
tsjavascript
resolve: {
extensions: ['.js', '.jsx', '.json'] // 默认包含 .js 和 .json
}
alias 简化长路径引用
import { func } from '@/utils' 会解析为 src/utils/index.js:
ts
const path = require('path');
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // 将 @ 指向 src 目录
'utils': path.resolve(__dirname, 'src/utils') // 精确匹配 utils
}
}
Webpack 常用性能优化
优化构建速度
babel开启缓存,exclude 限制 Loader 处理范围
ts
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules目录
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true, // 启用缓存(默认路径:node_modules/.cache/babel-loader)
cacheCompression: false, // 禁用缓存压缩(加速构建,减少CPU开销)
}
}
}
] }};
IngorePlugin、DllPlugin、NoParse
- IngorePlugin
用于显式忽略特定模块或文件,从而减少打包体积、避免引入不必要的依赖或解决潜在冲突
ts
module.exports = {
plugins: [
new IgnorePlugin(resourceRegExp, contextRegExp)
]
};
// resourceRegExp:正则表达式,匹配需要忽略的模块路径(如 './locale/en')。
// contextRegExp(可选):正则表达式,限制忽略的上下文目录(如 'moment' 表示仅在 moment 包内忽略)。
// 忽略 moment.js 的所有本地化文件
new IgnorePlugin(/^\.\/locale$/, /moment$/);
- NoParse
跳过已压缩的库(如 lodash.min.js)的依赖解析,避免重复打包
ts
// 跳过 jQuery 和 Lodash 的解析
module.exports = {
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
],
},
externals: {
// 结合 externals 从 CDN 引入
jquery: 'jQuery',
lodash: '_',
},
};
Thread-loader (5.x) / HappyPack (4.x) 多进程加速构建
多进程并行处理:将 Loader 的任务分解到多个子进程(Worker)中并行执行,子进程处理完成后将结果返回主进程
- 适合项目较大,打包较慢的工程,小项目开启多进程反倒会拖慢构建
- happyPack
ts
const HappyPack = require('happypack');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: 'happypack/loader?id=babel', // 使用 happypack/loader
exclude: /node_modules/,
},
],
},
plugins: [
new HappyPack({
id: 'babel', // 唯一标识符
loaders: ['babel-loader?cacheDirectory'], // 实际使用的 Loader
threadPool: HappyPack.ThreadPool({ size: os.cpus().length }), // 可选:共享线程池
}),
],
};
- ThreadLoader
ts
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader', // 放置在其他 Loader 之前
options: {
workers: os.cpus().length, // Worker 数量
},
},
'babel-loader', // 后续 Loader 在 Worker 池中运行
],
exclude: /node_modules/,
},
],
},
};
TerserPlugin 多进程压缩
在比较旧的版本中,可采用 ParallelUglifyPlugin
ts
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true, // 启用多进程
terserOptions: {
compress: {
drop_console: true,
warnings: false,
},
output: {
comments: false,
},
},
}),
],
},
};
DllPulgin 生成动态链接库文件
开发模式下,将依赖较多且更新频率低的第三方库,(如 react、react-dom、lodash)打包成独立的 DLL 文件,生成 manifest.json 文件,记录 DLL 中模块的映射关系,供 DllReferencePlugin 使用。
- 创建 DLL 打包配置
ts
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production', // 或 'development'
entry: {
vendor: ['react', 'react-dom', 'lodash'], // 需拆分的第三方库
},
output: {
filename: '[name].dll.js', // 输出 DLL 文件名
path: path.resolve(__dirname, 'dll'), // 输出目录
library: '[name]_[fullhash]', // 暴露的全局变量名(避免冲突)
},
plugins: [
new webpack.DllPlugin({
name: '[name]_[fullhash]', // 与 output.library 一致
path: path.join(__dirname, 'dll', '[name]-manifest.json'), // manifest 文件路径
}),
],
};
- 在主配置中引用 DLL(webpack.config.js)
ts
const path = require('path');
const webpack = require('webpack');
module.exports = {
// ...其他配置(如 entry、output、module 等)
plugins: [
new webpack.DllReferencePlugin({
manifest: require('./dll/vendor-manifest.json'), // 引入 manifest 文件
context: __dirname, // 上下文路径(需与 DLL 配置一致)
}),
],
};
- 在 HTML 中引入 DLL 文件
ts
<!-- index.html -->
<script src="./dll/vendor.dll.js"></script> <!-- 手动引入或通过插件自动插入 -->
优化代码体积
Tree Shaking
TerserPlugin 代码压缩
css、图片资源优化
- 小图片 Base64 编码:使用 url-loader 设置 limit
- MiniCssExtractPlugin 抽离配置