Webpack
1、 webpack 的工作流程
webpack 的工作流程可以分为以下几个阶段:
1.1、 初始化
在初始化阶段,webpack 会做以下事情:
- 读取配置文件和命令行参数,并将其合并成最终的配置对象: webpack 的配置文件通常是 webpack.config.js 文件。在这个文件中,可以配置 webpack 的各种选项,例如入口文件、输出目录、Loader 等。 命令行参数可以用来覆盖配置文件中的配置。例如,可以使用 --entry 参数指定入口文件,使用 --output 参数指定输出目录。
- 初始化 Compiler 对象: Compiler 对象是 webpack 的核心对象。它负责管理 webpack 的整个构建过程。加载所有配置的插件。插件可以扩展 webpack 的功能。例如,可以使用插件来压缩代码、添加版权信息等。
1.2、 编译
在这个阶段,webpack 会从入口文件开始,递归地解析所有依赖的模块。对于每个模块,webpack 会做以下事情:
- 使用相应的 Loader 来转换模块内容: Loader 可以用来将模块内容转换为 webpack 可以理解的格式。例如,可以使用 babel-loader 来将 ES6 代码转换为 ES5 代码,可以使用 css-loader 来将 CSS 代码转换为 JavaScript 代码。
- 找出该模块依赖的其他模块,并递归地进行编译: webpack 会使用依赖分析算法来找出所有依赖的模块。依赖分析算法会从入口文件开始,逐个分析每个模块的依赖关系。
1.3、 生成
在这个阶段,webpack 会将编译后的模块打包成最终的资源文件。具体来说,webpack 会做以下事情:
- 将所有模块的代码合并成一个或多个 JavaScript 文件: webpack 可以使用各种模式来合并代码。例如,可以使用 development 模式来生成未压缩的代码,可以使用 production 模式来生成压缩的代码。
- 将所有资源文件(如图片、字体等)复制到输出目录: webpack 可以使用各种方式来处理资源文件。例如,可以使用 url-loader 来将资源文件转换为DataURL,可以使用 file-loader 来将资源文件复制到输出目录。
2、 配置webpack打包多页
要配置 Webpack 打包多页,需要在配置文件中设置多个入口文件和多个输出文件。
HtmlWebpackPlugin 插件可以自动生成 HTML 文件,并将其注入到 Webpack 打包后的 JavaScript 文件中。
配置示例
以下示例演示了如何使用 HtmlWebpackPlugin 插件配置 Webpack 打包两个页面:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
about: './src/about.js',
},
output: {
filename: '[name].bundle.js',
path: './dist',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['index'],
}),
new HtmlWebpackPlugin({
template: './src/about.html',
filename: 'about.html',
chunks: ['about'],
}),
],
};
在这个示例中,我们使用 HtmlWebpackPlugin 插件生成了两个 HTML 文件:./dist/index.html 和 ./dist/about.html。我们还使用 chunks 选项指定了每个 HTML 文件要包含的 JavaScript 文件。
3、 splitChunk拆分打包文件
在 webpack 中,总共提供了三种方式来实现代码拆分(Code Splitting):
- entry 配置:通过多个 entry 文件来实现;
- 动态加载(按需加载) :通过写代码时主动使用
import()来动态加载; - 抽取公共代码:使用
splitChunks配置来抽取公共代码。
这里我们主要讲如何通过splitChunks抽取公共代码。在讲解之前,再来复习下 webpack 中三个重要的概念:module、chunks、bundle。
- module:就是 JavaScript 的模块,简单来说就是你通过
import、require语句引入的代码,也包括 css、图片等资源; - chunk:chunk 是 webpack 根据功能拆分出来的,chunk 包含着 module,可能是一对多也可能是一对一,chunk 包含三种情况,就是上面介绍的三种实现代码拆分的情况。
- bundle:bundle 是 webpack 打包之后的各个文件,一般就是和 chunk 是一对一的关系,bundle 就是对 chunk 进行编译压缩打包等处理之后的产出。
4、 splitChunks 默认配置
由于 Webpack 做到了开箱即用,所以splitChunks是有默认配置的:
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
name: true,
cacheGroups: {
vendors: {
// // 正则规则,如果符合就提取 chunk
test: /[\\/]node_modules[\\/]/,
// 缓存组优先级,当一个模块可能属于多个 chunkGroup,这里是优先级
priority: -10
},
default: {
minChunks: 2,
priority: -20,
// 如果该chunk包含的modules都已经另一个被分割的chunk中存在,那么直接引用已存在的chunk,不会再重新产生一个
reuseExistingChunk: true
}
}
}
}
};
- chunks: 可选值有"initial" | "all" | "async" (默认),下面会对这三个值进行详细介绍。
- minSize: 最小尺寸,默认是30K,development 下是10k,设置的越大满足该尺寸的chunk 数就会变少(针对于提取公共 chunk 的时候,不管再大也不会把动态加载的模块合并到初始化模块中),当这个值很大的时候就不会做公共部分的抽取了。
- maxSize: 文件的最大尺寸,0为不限制。
- name: 拆分出来文件的名字,默认为 true,表示自动生成文件名,如果设置为固定的字符串那么所有的 chunk 都会被合并成一个。
5、 不打包无用的资源
在 Webpack 打包中,可以通过 Tree Shaking、Commons Chunks Plugin、SplitChunksPlugin 来避免打包无用的资源。
5.1、 使用 Tree Shaking
Tree Shaking 是 Webpack 的一项核心功能,可以自动分析代码并删除未使用的代码。要使用 Tree Shaking,需要满足以下条件:
- 使用 ES Modules 语法。
- 未使用的代码必须是静态可分析的。
module.rules = [
{
test: /\.js$/,
use: [
'esmodule-loader',
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
]
}
];
5.2、 使用 Commons Chunks Plugin
Commons Chunks Plugin 可以将多个入口 chunk 中共用的代码提取到一个单独的 chunk 中,从而避免重复打包。要使用 Commons Chunks Plugin,需要在 Webpack 配置文件中设置 plugins 选项中的 new CommonsChunkPlugin 属性。
plugins: [
new CommonsChunkPlugin({
name: 'common',
chunks: ['app1', 'app2']
})
]
在以上配置中,common chunk 将包含 app1 和 app2 chunk 中共用的代码。
5.3、 使用 SplitChunksPlugin
SplitChunksPlugin 可以根据代码块的大小或内容来提取代码块。要使用 SplitChunksPlugin,需要在 Webpack 配置文件中设置 plugins 选项中的 new SplitChunksPlugin 属性。
plugins: [
new SplitChunksPlugin({
chunks: 'all',
minSize: 30000,
minChunks: 2
})
]
在以上配置中,如果一个代码块的大小超过 30000 字节,并且被至少引用 2 次,则该代码块将被提取到一个单独的 chunk 中。