# 优化运行时体验
运行时优化的核心就是提升首屏的加载速度,主要的方式就是
降低首屏加载文件体积,首屏不需要的文件进行预加载或者按需加载
# 3.1 入口点分割
配置多个打包入口,多页打包,这里不过多介绍
# 3.2 splitChunks 分包配置
optimization.splitChunks 是基于 SplitChunksPlugin 插件实现的 默认情况下,它只会影响到按需加载的 chunks,因为修改 initial chunks 会影响到项目的 HTML 文件中的脚本标签。 webpack 将根据以下条件自动拆分 chunks:
- 新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹
- 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
- 当按需加载 chunks 时,并行请求的最大数量小于或等于 30
- 当加载初始化页面时,并发请求的最大数量小于或等于 30
- 默认配置介绍
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async', // 有效值为 `all`,`async` 和 `initial`
minSize: 20000, // 生成 chunk 的最小体积(≈ 20kb)
minRemainingSize: 0, // 确保拆分后剩余的最小 chunk 体积超过限制来避免大小为零的模块
minChunks: 1, // 拆分前必须共享模块的最小 chunks 数。
maxAsyncRequests: 30, // 最大的按需(异步)加载次数
maxInitialRequests: 30, // 打包后的入口文件加载时,还能同时加载js文件的数量(包括入口文件)
enforceSizeThreshold: 50000,
cacheGroups: { // 配置提取模块的方案
defaultVendors: {
test: /[\/]node_modules[\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};
- 项目中的使用
const config = {
//...
optimization: {
splitChunks: {
cacheGroups: { // 配置提取模块的方案
default: false,
styles: {
name: 'styles',
test: /\.(s?css|less|sass)$/,
chunks: 'all',
enforce: true,
priority: 10,
},
common: {
name: 'chunk-common',
chunks: 'all',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 1,
enforce: true,
reuseExistingChunk: true,
},
vendors: {
name: 'chunk-vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
priority: 2,
enforce: true,
reuseExistingChunk: true,
},
// ... 根据不同项目再细化拆分内容
},
},
},
}
# 3.3 代码懒加载
针对首屏加载不太需要的一些资源,我们可以通过懒加载的方式去实现,下面看一个小🌰
需求:点击图片给图片加一个描述
- 新建图片描述信息
desc.js
const ele = document.createElement('div')
ele.innerHTML = '我是图片描述'
module.exports = ele
- 点击图片引入描述 index.js
import './main.css';
import './sass.scss'
import logo from '../public/avatar.png'
import '@/fonts/iconfont.css'
const a = 'Hello ITEM'
console.log(a)
const img = new Image()
img.src = logo
document.getElementById('imgBox').appendChild(img)
// 按需加载
img.addEventListener('click', () => {
import('./desc').then(({ default: element }) => {
console.log(element)
document.body.appendChild(element)
})
})
- 查看效果
- 点击前
- 点击后
# 3.4 prefetch 与 preload
上面我们使用异步加载的方式引入图片的描述,但是如果需要异步加载的文件比较大时,在点击的时候去加载也会影响到我们的体验,这个时候我们就可以考虑使用 prefetch 来进行预拉取
# 3.4.1 prefetch
prefetch (预获取):浏览器空闲的时候进行资源的拉取 改造一下上面的代码
// 按需加载
img.addEventListener('click', () => {
import( /* webpackPrefetch: true */ './desc').then(({ default: element }) => {
console.log(element)
document.body.appendChild(element)
})
})
# 3.4.2 preload
preload (预加载):提前加载后面会用到的关键资源 ⚠️ 因为会提前拉取资源,如果不是特殊需要,谨慎使用
官网示例:
import(/* webpackPreload: true */ 'ChartingLibrary');