# 优化运行时体验

运行时优化的核心就是提升首屏的加载速度,主要的方式就是

降低首屏加载文件体积,首屏不需要的文件进行预加载或者按需加载

# 3.1 入口点分割

配置多个打包入口,多页打包,这里不过多介绍

# 3.2 splitChunks 分包配置

optimization.splitChunks 是基于 SplitChunksPlugin 插件实现的 默认情况下,它只会影响到按需加载的 chunks,因为修改 initial chunks 会影响到项目的 HTML 文件中的脚本标签。 webpack 将根据以下条件自动拆分 chunks:

  • 新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹
  • 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
  • 当按需加载 chunks 时,并行请求的最大数量小于或等于 30
  • 当加载初始化页面时,并发请求的最大数量小于或等于 30
  1. 默认配置介绍
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,
        },
      },
    },
  },
};
  1. 项目中的使用
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 代码懒加载

针对首屏加载不太需要的一些资源,我们可以通过懒加载的方式去实现,下面看一个小🌰

需求:点击图片给图片加一个描述

  1. 新建图片描述信息

desc.js

const ele = document.createElement('div')
ele.innerHTML = '我是图片描述'
module.exports = ele
  1. 点击图片引入描述 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)
  })
})
  1. 查看效果
  • 点击前

  • 点击后

# 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');