前言
因为最近一些实习的事情耽搁了博客文章的输出,但是还是在保持学习,今天刚好是周末,就继续接着上次的总结,总结一下webpack知识点。
Webpack中的Prefetch和Preload
-
prefetch(预获取):将来某些导航下可能需要的资源
-
preload(预加载):当前导航下可能需要资源
在使用import函数导入资源文件的时候,可以通过注释来说明是用prefetch还是preload。

与 prefetch 指令相比,preload 指令有许多不同之处:
- preload chunk 会在父 chunk 加载时,以并行方式开始加载。
- prefetch chunk 会在父 chunk 加载结束后开始加载。
- preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
- preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
Webpack中的CDN
CDN称之为内容分发网络(Content Delivery Network或Content Distribution Network,缩写:CDN)
- 它是指通过相互连接的网络系统,利用最靠近每个用户的服务器;
- 更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户;
- 来提供高性能、可扩展性及低成本的网络内容传递给用户;
在开发完成后,我们的资源很有可能是放在CDN服务器上的,这个时候就需要在Webpack中配置一个公共前缀。
js
output: {
clean: true,
path: path.resolve(__dirname, './build'),
// placeholder
filename: '[name]-bundle.js',
// 单独针对分包的文件进行命名
chunkFilename: '[name]_chunk.js',
//CDN地址前缀
publicPath: 'http://aliyun.com/'
},
但是有时候我们还面临一种情况,就是我们依赖的第三方库,我们不想自己打包,希望通过第三方CDN引入(国内外有很多免费的CDN开源库链接),
- 国际上使用比较多的是unpkg、JSDelivr、cdnjs;
- 国内也有一个比较好用的CDN是bootcdn;
首先,我们需要告诉Webpack不要打包这些依赖的第三方库,随后,我们再把依赖的第三方库的开源CDN链接配置到html文件中即可。
在webpack配置externals模块
js
externals: {
react: "React",
// key属性名: 排除的框架的名称
// value值: 从CDN地址请求下来的js中提供对应的名称
axios: "axios"
},
在html文件中加入CDN链接
js
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react/18.2.0/umd/react.production.min.js"</script>
Shimming
shimming是一个概念,是某一类功能的统称:
- shimming翻译过来我们称之为 垫片,相当于给我们的代码填充一些垫片来处理一些问题;
- 比如我们现在依赖一个第三方的库,这个第三方的库本身依赖lodash,但是默认没有对lodash进行导入(认为全局存在 lodash),那么我们就可以通过ProvidePlugin来实现shimming的效果;
注意:webpack并不推荐随意的使用shimming ,Webpack背后的整个理念是使前端开发更加模块化;也就是说,需要编写具有封闭性的、不存在隐含依赖(比如全局变量)的彼此隔离的模块;
我们可以通过使用ProvidePlugin来实现shimming的效果:
- ProvidePlugin能够帮助我们在每个模块中,通过一个变量来获取一个package;
- 如果webpack看到这个模块,它将在最终的bundle中引入这个模块;
- 另外ProvidePlugin是webpack默认的一个插件,所以不需要专门导入;
js
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
}),
//shimming
new ProvidePlugin({
axios: ['axios', 'default'],
// get: ['axios', 'get'],
dayjs: 'dayjs'
})
]
这段代码的本质是告诉webpack:如果你遇到了至少一处用到 axios变量的模块实例,那请你将 axios package 引入进来,并将其提供给需要用到它的模块。
DLL库
DLL是什么呢?
- DLL全程是动态链接库(Dynamic Link Library),是为软件在Windows中实现共享函数库的一种实现方式;
- 那么webpack中也有内置DLL的功能,它指的是我们可以将能够共享,并且不经常改变的代码,抽取成一个共享的库;
- 这个库在之后编译的过程中,会被引入到其他项目的代码中;
DDL库的使用分为两步:
- 第一步:打包一个DLL库;
- 第二步:项目中引入DLL库;
注意:在升级到webpack4之后,React和Vue脚手架都移除了DLL库(下面的vue作者的回复),所以知道有这么一个概念即可。

Terser
什么是Terser呢?
- Terser是一个JavaScript的解释(Parser)、Mangler(绞肉机)/Compressor(压缩机)的工具集;
- 早期我们会使用 uglify-js来压缩、丑化我们的JavaScript代码,但是目前已经不再维护,并且不支持ES6+的语法;
- Terser是从 uglify-es fork 过来的,并且保留它原来的大部分API以及适配 uglify-es和uglify-js@3等;
也就是说,Terser可以帮助我们压缩、丑化我们的代码,让我们的bundle变得更小。
真实开发中,我们不需要手动的通过terser来处理我们的代码,我们可以直接通过webpack来处理:
- 在webpack中有一个minimizer属性,在production模式下,默认就是使用TerserPlugin来处理我们的代码的;
- 如果我们对默认的配置不满意,也可以自己来创建TerserPlugin的实例,并且覆盖相关的配置;
js
minimizer: [
// JS代码简化
new TerserPlugin({
extractComments: false
})
]
TreeShaking
什么是Tree Shaking呢?
- Tree Shaking是一个术语,在计算机中表示消除死代码(dead_code);
- 最早的想法起源于LISP,用于消除未调用的代码(纯函数无副作用,可以放心的消除,这也是为什么要求我们在进行函数式 编程时,尽量使用纯函数的原因之一);
- 后来Tree Shaking也被应用于其他的语言,比如JavaScript、Dart;
事实上webpack实现Tree Shaking采用了两种不同的方案:
- usedExports:通过标记某些函数是否被使用,之后通过Terser来进行优化的;
- sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用;
将mode设置为development模式:
为了可以看到 usedExports带来的效果,我们需要设置为 development 模式
因为在 production 模式下,webpack默认的一些优化会带来很大的影响(production模式下默认开启usedExports)。
设置usedExports为true和false对比打包后的代码:
在usedExports设置为true时,会有一段注释:unused harmony export mul;
这段注释的意义是什么呢?告知Terser在优化时,可以删除掉这段代码;
所以,usedExports实现Tree Shaking是结合Terser来完成的。
js
optimization: {
// 导入模块时, 分析模块中的哪些函数有被使用, 哪些函数没有被使用(tree shaking)
usedExports: true,
chunkIds: 'deterministic',
// runtime的代码是否抽取到单独的包中(早Vue2脚手架中)
runtimeChunk: {
name: "runtime"
},
// 分包插件: SplitChunksPlugin
splitChunks: {
chunks: "all",
minSize: 10,
// 自己对需要进行拆包的内容进行分包
cacheGroups: {
utils: {
test: /utils/,
filename: "js/[id]_utils.js"
},
vendors: {
// /node_modules/
// window上面 /\
// mac上面 /
test: /[\\/]node_modules[\\/]/,
filename: "js/[id]_vendors.js"
}
}
},
sideEffects用于告知webpack compiler哪些模块时有副作用的:
副作用的意思是这里面的代码有执行一些特殊的任务,不能仅仅通过export来判断这段代码的意义;
在package.json中设置sideEffects的值:
如果我们将sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports;
如果有一些我们希望保留,可以设置为数组;
比如我们有一个format.js、style.css文件:
该文件在导入时没有使用任何的变量来接受;
那么打包后的文件,不会保留format.js、style.css相关的任何代码;
js
//package.json
//保留所有css文件
"'sideEffects'":["*.css"],