代码分割(Code Splitting)
whoitao
2021年06月02日 20:27
收录于文集
共6篇

为什么(Why)

我们知道 Webpack 是一款打包工具,但现在为什么又要进行代码分割呢?

如果把所有代码都打包到一起,可能最终的代码非常大。从而影响加载时间。

而且,很多代码是初始加载时,不需要的。因此,我们可以根据代码使用的紧急程度,将代码分割打包后,按需加载。

例如:打包后的 bundle.js 中,可能包含多个页面的 js

但是,加载首页(index.js)时,我们不需要加载 about.js。此时,我们就可以进行代码分割。

怎么做(How)

Webpack 中进行代码分割的方式有三个:

  • 多入口打包:配置 entry 加载多个入口文件

  • 提取公用模块:optimization.splitChunks.chunks: all

  • 动态导入:按需加载 | 预加载

多入口打包

  1. 将 entry 配置为对象的形式

代码块
JavaScript
自动换行
复制代码
// webpack.config.js
module.exports = (env, argv) => {
  // ......

  // 单入口文件
  // entry: './src/index.js',
  // 多入口打包
  entry: {
    'index': './src/index.js',
    'about': './src/about.js'
  },
}
复制成功
  1. 修改输出文件名

如果输出文件名称写成固定的,最后会生成一个文件,就失去了代码分割的意义。

代码块
JavaScript
自动换行
复制代码
// webpack.config.js
module.exports = (env, argv) => {
  // ......

  // 出口配置
  output: {
    // 输出目录(输出目录必须是绝对路径)
    path: resolve(__dirname, 'output'),
    // 单入口输出文件名称
    // filename: 'bundle.js'
    // 多入口输出文件名称
    filename: '[name].bundle.js'
  },
}
复制成功
  1. 不同页面(模板)加载各自的 bundle

在 HtmlWebpackPlugin 中指定 chunks 配置,表明 index.html 中加载 index.bundle.js,about.html 中加载 about.bundle.js。 如果不指定 chunks,所有页面默认加载 bundle.js

代码块
JavaScript
自动换行
复制代码
// webpack.config.js
module.exports = (env, argv) => {
  // ......

  // 插件配置
  plugins: [
    // Html 的配置
    new HtmlWebpackPlugin({
      // 指定打包后的文件名称
      filename: 'index.html',

      // 用来指定,生成 HTML 的模板
      template: './src/index.ejs',

      // 指定要加载的打包文件 - index.bundle.js
      chunks: ['index']
    }),
    
    new HtmlWebpackPlugin({
      // 指定打包后的文件名称
      filename: 'about.html',
      
      // 用来指定,生成 HTML 的模板
      template: './src/index.ejs',

      // 指定要加载的打包文件 - about.bundle.js
      chunks: ['about']
    }),
  ]
}
复制成功

提取公共模块

  1. 提取原理(为什么提取)

如果多个页面都用到了一个公共文件(例如:jQuery),每个页面都将公共文件打包一次是不合理的。

如果有 100 个页面,将 jQuery 重复打包 100 次,肯定是不合理的。

更好的办法是将公共文件提取出来。

这样,不管有多少个页面,我们只需要打包一次 jQuery 就可以了。(减少了打包体积,提高了打包效率)

  1. 具体配置

代码块
JavaScript
自动换行
复制代码
// webpack.config.js
module.exports = (env, argv) => {
  // ......
  
  // 优化策略
  optimization: {
    // 将所有公共模块单独打包
    splitChunks: {
      chunks: 'all'
    }
  },
}
复制成功

配置完成后,再次执行打包,可以在输出目录看到单独打包的文件。

动态导入

动态导入可以通过 import 函数来实现,常用的配置有两个内容:

  • 懒加载

  • 预加载

  • 先等待其他资源加载,浏览器空闲时,在加载不紧急的资源

  • webpackPrefetch: true

  • 缺点:在移动端有兼容性问题(建议:实际测试后,再酌情使用)

代码示例:

  1. 声明模块

代码块
JavaScript
自动换行
复制代码
// wp.js
// 判断模块是否加载
console.log('模块加载了')

export function desc() {
  return "Webpack 是一款前端打包工具"
}
复制成功
  1. 通过 import 引入模块

代码块
JavaScript
自动换行
复制代码
// index.js
// 验证按需加载
document.getElementById('btn').onclick = function() {
  // import 启动懒加载
  // webpackChunkName: 'desc' 指定懒加载的文件名称
  // webpackPrefetch: true 启动预加载
  import(/* webpackChunkName: 'desc', webpackPrefetch: true */'./wp').then(({ desc }) => {
    alert(desc())
  })
}
复制成功
  1. 再浏览器查看效果

打开 console,通过点击按钮,查看懒加载效果。

打开 network,查看预加载效果