webpack基础配置详解

前言

webpack是一个模块打包工具,其最新版本是webpack5,它可以将多个模块进行打包,并生成一个或多个静态资源文件。webpack的配置文件为webpack.config.js,该文件包含webpack的配置信息,如入口文件、输出文件、模块加载规则、插件等。下面我们将以一个简单的webpack配置文件为例,对webpack配置项进行介绍。

webpack编译流程

  1. 读取配置文件:webpack会从配置文件和shell中读取配置信息,并生成一个配置对象。
  2. 开始编译:初始化Compiler对象,并调用Compiler对象的run方法,开始编译。
  3. 解析入口文件:根据配置文件中的入口文件路径,解析入口文件。
  4. 编译模块:从入口文件开始,根据正则匹配到的loader对模块进行转换,生成输出文件,找到模块所依赖的模块,通过递归本步骤直到所有依赖的模块都转换完毕。
  5. 完成模块编译:得到所有模块编译后的内容以及他们的依赖关系生成一个依赖图。依赖图是一个对象,包含了所有模块的依赖关系。
  6. 输出资源:包含多个模块的chunk,每个chunk转换成单独的文件,加入到输出列表,此时可以对这些内容进行修改。
  7. 输出文件:根据配置确定输出的文件名和路径,创建输出文件,将模块内容写入文件中,并完成其他必要的操作,如添加头部信息、压缩代码等。
  8. 监听文件变化:根据配置文件中的监听文件路径,监听文件变化,并重新构建。

在上述过程中webpack会在1-6的各个阶段广播事件,插件可以通过监听这些事件调用webpack的API来执行自定义的操作。

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
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

/**
* @type {import('webpack').Configuration}
*/
const path = require('path');

// 1、指定html模版 2、创建html文件 3、自动引入打包后的文件 4、压缩html文件 5、配置页面标题,指定js文件引入位置(head/body)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 定义页面配置(如果是react或者vue项目可以配置为单入口的单页面应用,此处我以js项目为例,配置多页面应用)
const pages = [
{
name: 'home',
entry: './src/pages/home/index.js', // 页面入口文件
template: './src/pages/home/index.html', // 页面模板
title: '首页',
chunks: ['home', 'vendor', 'common'] // 指定需要引入的chunk
},
{
name: 'about',
entry: './src/pages/about/index.js',
template: './src/pages/about/index.html',
title: '关于我们',
chunks: ['about', 'vendor', 'common']
},
{
name: 'contact',
entry: './src/pages/contact/index.js',
template: './src/pages/contact/index.html',
title: '联系我们',
chunks: ['contact', 'vendor', 'common']
}
]

module.exports = {
mode: 'development', // or 'production'
entry: pages.reduce((acc, page) => {
acc[page.name] = page.entry;
return acc;
}, {}),
output: {
path: path.resolve(__dirname, 'dist'), // 输出路径
filename: 'js/[name].[contenthash].js', // 输出文件名
clean: true // 清空dist目录
},
// 排除某些模块,使其不被打包,而是通过外部方式(如 CDN)引入。
// 与splitChunks的区别是:externals会通过外部方式(如 CDN)引入减少包的体积,
// 而splitChunks会根据代码中引用的模块进行拆分然后打包进vendor中。
externals: {
'react': 'React',
},
optimization: {
splitChunks: {
// chunks 分割代码块 取值 all、async、initial,
// async 表示分割异步代码块,initial 表示分割同步代码块,all 表示分割所有代码块
chunks: 'all',
minSize: 30000, // 生成块的最小字节数, 默认值 30kb
maxSize: 0, // 生成块的最大字节数, 为0byte表示不限制
minChunks: 1, // 引用次数超过该次数的代码块才会被分割
maxAsyncRequests: 30, // 按需加载的最大异步请求数
maxInitialRequests: 30, // 入口点的最大并行请求数
automaticNameDelimiter: '~', // 生成文件名的分隔符
cacheGroups: { // 缓存组
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
priority: -10, // 缓存优先级,数字越大,优先级越高
},
common: {
test: /[\\/]src[\\/]components[\\/]/,
name: 'common',
minChunks: 2, // 覆盖默认配置, 被引用次数超过2的模块会被抽离成公共模块
},

default: {
reuseExistingChunk: true, // 重用已有的块
}
}
}
},
module: {
rules: [
{
test: /\.ts?$/,
exclude: /node_modules/,
use: 'ts-loader'
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},

]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[conntenthash].css'
}),
// 为每个页面创建独立的HtmlWebpackPlugin实例
...pages.map(page => new HtmlWebpackPlugin({
template: path.resolve(__dirname, page.template),
filename: `${page.filename}.html`,
// 指定要使用的chunk 引入的chunk,
// 使用 excludeChunks: ['common']指定不引入的chunk
chunks: page.chunks,
title: page.title, // 设置页面标题
inject: 'body', // or 'head' 表示要插入的标签位置
scriptLoading: 'defer', // 添加 defer 属性
env: {
APP_ENV: process.env.APP_ENV, // 设置环境变量 在模板中通过 <%= APP_ENV %> 访问
},
minify: {
removeComments: true, // 删除注释
collapseWhitespace: true, // 删除空格
removeRedundantAttributes: true, // 删除冗余属性
minifyCSS: true, // 压缩css
minifyJS: true, // 压缩js
}
}))
],
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true, // 启用gzip压缩
port: 9000, // 端口号
hot: true, // 启用热更新
open: true, // 自动打开浏览器
}

}

总结

external 和 splitChunks优化策略的区别

  1. splitChunks 和 externals 是两种不同的代码优化策略,它们的核心区别在于:是否将依赖打包到最终产物中

  2. externals 可以将某些依赖从最终产物中排除,从而减少最终产物的体积。例如,如果你的代码中引入了 jQuery,你可以将 jQuery 设置为 external,这样 jQuery 就不会被打包进最终产物中。

  3. splitChunks:适合优化内部代码结构,提取公共依赖,实现按需加载。
    externals:适合排除大型第三方库,减少打包体积,利用 CDN 加速或共享全局资源。

splitChunks性能优化建议

  1. 合理设置 minSize:过小会导致生成过多小文件,增加请求数,过大会导致单个文件过大,影响加载速度
  2. 控制缓存组优先级:第三方库优先级应高于公共组件(如 vendor 设为 -10,common 设为 -20)避免过度拆分:
  3. 不要为每个模块创建单独的 chunk,否则会导致请求数过多
  4. 结合 CDN 使用:将 vendor chunk 部署到 CDN,利用浏览器缓存
  5. 使用 webpack-bundle-analyzer 分析打包结果,以确定哪些模块需要拆分
文章作者: Sir_Liu
文章链接: https://gofugui.github.io/2025/05/26/webpack基础配置详解/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Coding Your Life