Webpack性能优化:按需加载实战指南

57 阅读2分钟

为什么需要按需加载

功能全部集中的做到了一个模块里面,网页就会加载缓慢、交互卡顿。用户每一阶段只可能使用其中一部分功能,当前需要用什么功能就只加载这个功能对应的代码。

如何使用按需加载

在给单页应用做按需加载优化时,一般采用以下原则:

  • 把整个网站划分成一个个小功能,再按照每个功能的相关程度把它们分成几类;
  • 把每一类合并为一个 Chunk,按需加载对应的 Chunk;
  • 对于用户首次打开你的网站时需要看到的画面所对应的功能,不要对它们做按需加载,而是放到执行入口所在的 Chunk 中,以降低用户能感知的网页加载时间;
  • 对于个别依赖大量代码的功能点,例如依赖 Chart.js 去画图表、依赖 flv.js 去播放视频的功能点,可再对其进行按需加载;

被分割出去的代码的加载需要一定的时机去触发,也就是当用户操作到了或者即将操作到对应的功能时再去加载对应的代码。 被分割出去的代码的加载时机需要开发者自己去根据网页的需求去衡量和确定。

由于被分割出去进行按需加载的代码在加载的过程中也需要耗时,你可以预言用户接下来可能会进行的操作,并提前加载好对应的代码,从而让用户感知不到网络加载时间。

Webpack 实现按需加载

window.document
  .getElementById("btn")
  .addEventListener("click", async function () {
    const { default: _ } = await import(
      /* webpackChunkName: "show" */ "./show.js"
    );
    _("Webpack");
  });
const show =  (content) => {
  window.alert('Hello ' + content);
};
export default show;

代码中最关键的一句是 import(/* webpackChunkName: "show" */ './show'),Webpack 内置了对 import(*)语句的支持,当 Webpack 遇到了类似的语句时会这样处理:

  • ./show.js 为入口新生成一个 Chunk
  • 当代码执行到 import 所在语句时才会去加载由 Chunk 对应生成的文件;
  • import 返回一个 Promise,当文件加载成功时可以在 Promisethen 方法中获取到 show.js 导出的内容;
module.exports = {
  // JS 执行入口文件
  entry: {
    main: './main.js',
  },
  output: {
    // 为从 entry 中配置生成的 Chunk 配置输出文件的名称
    filename: '[name].js',
    // 为动态加载的 Chunk 配置输出文件的名称
    chunkFilename: '[name].js',
  }
};

其中最关键的一行是 chunkFilename: '[name].js',它专门指定动态生成的 Chunk 在输出时的文件名称。 如果没有这行,分割出的代码的文件名称将会是 [id].js