
8、webpack-性能优化 - 分包
多入口
webpack 默认会从.index.js 文件入口开始打包,打包完成到 build 目录下的 bundle.js 文件下
这样有很多问题
- bundle.js 包很大,不方便处理
- 不利于首屏渲染,请求加载会浪费很多时间
所以可以进行多入口打包形成分包
1 | entry: { |
这样打包以后就会有多个包
build/
1 | index - bundle.js; |
问题:如果多入口文件使用了同一个库,会造成每个入口文件都打包一遍(如 axios)
办法:shared
1 | entry: { |
这样打包后的 build
1 | index - bundle.js; |
动态导入
比如路由,点击到对应页面才加载对应的 js 文件,可以减少首屏的加载速度
因为不在 bundle.js 这个包里,是单独的打包出来的
1 | const btn1 = document.createElement("button"); |
打包后 build/
1 | src_router_about_js - bundle.js; |
这个包当我点击对应按钮才会去请求,默认是不请求这个文件的
取值
默认 import()是可以拿到对应导入文件里的内容的
about.js
1 | console.log(6); |
index.js
1 | const btn1 = document.createElement("button"); |
res 就相当于 about 这个模块
导出命名
1 | output: { |
1 | src_router_about_js - src_router_about_js - chunk.js; |
也可以通过魔法注释进行自定义
1 | btn1.onclick = function () { |
打包后
1 | about - about - chunk.js; |
SplitChunks
另外一种分包的模式是 splitChunk,它是使用 SplitChunksPlugin 来实现的:
因为该插件 webpack 已经默认安装和集成,所以我们并不需要单独安装和直接使用该插件;
只需要提供 SplitChunksPlugin 相关的配置信息即可;
Webpack 提供了 SplitChunksPlugin 默认的配置,我们也可以手动来修改它的配置:
比如默认配置中,chunks 仅仅针对于异步(async)请求,我们可以设置为 initial 或者 all;
initial为同步
all为全部
1 | optimization: { |
SplitChunks 自定义配置
1 | optimization: { |
Chunks:
默认值是 async
另一个值是 initial,表示对通过的代码进行处理
all 表示对同步和异步代码都进行处理
minSize:
拆分包的大小, 至少为 minSize;
如果一个包拆分出来达不到 minSize,那么这个包就不会拆分;
maxSize:
- 将大于 maxSize 的包,拆分为不小于 minSize 的包;
minChunks:
至少被引入的次数,默认是 1;
如果我们写一个 2,但是引入了一次,那么不会被单独拆分;
name:设置拆包的名称
可以设置一个名称,也可以设置为 false;
设置为 false 后,需要在 cacheGroups 中设置名称;
cacheGroups:
用于对拆分的包就行分组,比如一个 lodash 在拆分之后,并不会立即打包,而是会等到有没有其他符合规则的包一起来打包;
test 属性:匹配符合规则的包;
name 属性:拆分包的 name 属性;
filename 属性:拆分包的名称,可以自己使用 placeholder 属性;
一般默认 Chunks 为 all,其他不做配置,使用默认即可
optimization.chunkIds 配置
optimization.chunkIds 配置用于告知 webpack 模块的 id 采用什么算法生成。
有三个比较常见的值:
natural:按照数字的顺序使用 id;
named:development 下的默认值,一个可读的名称的 id;
deterministic:确定性的,在不同的编译中不变的短数字 id
- 在 webpack4 中是没有这个值的;
**最佳实践:
**
**开发过程中,我们推荐使用 named;
**
打包过程中,我们推荐使用 deterministic;
optimization. runtimeChunk 配置
配置 runtime 相关的代码是否抽取到一个单独的 chunk 中:
runtime 相关的代码指的是在运行环境中,对模块进行解析、加载、模块信息相关的代码;
比如 component、bar 两个通过 import 函数相关的代码加载,就是通过 runtime 代码完成的;
抽离出来后,有利于浏览器缓存的策略:
比如我们修改了业务代码(main),那么 runtime 和 component、bar 的 chunk 是不需要重新加载的;
比如我们修改了 component、bar 的代码,那么 main 中的代码是不需要重新加载的;
设置的值:
- true/multiple:针对每个入口打包一个 runtime 文件,比如 main index 会打包两个;
- single:不论几个入口都打包一个 runtime 文件;
- 对象:name 属性决定 runtimeChunk 的名称,可以是字符串也可以是函数;
Prefetch 和 Preload
webpack v4.6.0+ 增加了对预获取和预加载的支持。
在声明 import 时,使用下面这些内置指令,来告知浏览器:
prefetch(预获取):将来某些导航下可能需要的资源
preload(预加载):当前导航下可能需要资源
与 prefetch 指令相比,preload 指令有许多不同之处:
- preload chunk 会在父 chunk 加载时,以并行方式开始加载。
- **prefetch chunk 会在父 chunk 加载结束后始加载。
** - **preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
** - preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻
prefetch在其他需要的资源下载完成以后,浏览器空闲时预先下载
preload 会在父 chunk 加载结束后开始加载
prefetch会在不使用时在控制台显示出来,preload 在不使用时不会显示