摇树优化

定义:

关联性不强的代码会被优化掉,关联性强的代码会留下来到最终打包的文件中

目的:

清理掉没有调用或者可以被忽略的代码,最后可以让打包后的文件体积变得更小

原理:

摇树优化(Tree Shaking),是由 rollup 这个打包工具首先普及的。
它基于 ES6 模块规范中的 importexport语法特性,在打包时分析导入/导出内容是否真正的被 JavaScript 上下文所引用,如果没有则从将其从打包结果中移除。
自 webpack 4 开始, production 模式会自动启用各种优化策略(包括摇树优化);但也可手动配置。

步骤大纲

  1. 创建新目录,并编写入口 js 和两个被入口导入的 js(其中一个含对全局对象window的操作)
  2. 编写webpack配置文件(devtool:false),打包后观察结果
  3. 启用 optimization.usedExports: true 优化项,打包后观察结果
  4. 启用 optimization.minimize: true 优化项,打包后观察结果
  5. 通过 package.json 中的 sideEffects 声明代码是否有“副作用”

具体步骤

1、创建新目录,编写以下文件

src/mod1.js

  1. // 两个简单的工具函数
  2. export function trim(str) {
  3. return str ? str.trim() : ''
  4. }
  5. export function toUpperCase(str) {
  6. return str ? str.toUpperCase() : ''
  7. }

src/mod2.js

  1. // 监听全局对象 window 的事件
  2. window.onload = function () {
  3. console.log('loaded!!!!!')
  4. }

index.js

  1. // 调用 mod1 和 mod2
  2. import { toUpperCase } from './mod1'
  3. import './mod2'
  4. const result = toUpperCase('abc')
  5. console.log(result)

2、编写 webpack 配置

  1. const path = require('path')
  2. module.exports = {
  3. entry: './src/index.js',
  4. output: {
  5. path: path.join(__dirname, 'dist'),
  6. filename: 'bundle.js'
  7. },
  8. // 关闭 devtool 以提高打包代码的可阅读性(否则会用 eval 处理代码)
  9. devtool: false,
  10. mode: 'development'
  11. }

3、执行打包

观察后可发现:在 index.js 中被导入的 mod1.js 的两个函数,只有 toUpperCase 被使用了,但最后 mod1.js 的所有代码都被打包了:

image.png

4、开始优化:配置 optimization.usedExports,让 webpack 查找和标记未使用的导出内容

  1. // ...
  2. module.exports = {
  3. // ...
  4. // 打包优化选项
  5. optimization: {
  6. // 是否删除未被使用到的导出内容
  7. usedExports: true,
  8. },
  9. }

配置后打包,发现打包后的代码中对未使用的 trim函数做了标记:

image.png

5、此时再配置 optimization.minimize,就能达到压缩代码并删除已被标记函数的效果

  1. // ...
  2. module.exports = {
  3. // ...
  4. // 打包优化选项
  5. optimization: {
  6. // 是否删除未被使用到的导出内容
  7. usedExports: true,
  8. // 是否开启代码压缩
  9. minimize: true,
  10. },
  11. }

6、另外,如 mod2.js 这种内部未导出任何内容、但含有操作全局对象的代码,也能被正确打包

这种代码被称为 “有副作用” 的代码,它们不应该进行摇树优化,否则会破坏程序正常运行。

可通过在 package.json 中设置一个 sideEffects 属性来告诉 webpack 代码是否有副作用,如有副作用则应谨慎处理。该属性可设的值:

  • true - 默认值,代表所有文件都有副作用。优化时应采用谨慎策略
  • false - 代表所有文件都无副作用。可安全优化
  • 文件路径数组 - 代表数组中的文件有副作用

做个小测试:如果在 package.json 中设置 sideEffectsfalse

  1. {
  2. "sideEffects": false
  3. }

打包后发现 mod2.js 的代码都被删除了,这肯定是不正确的!!!

因此,对于当前程序来说:

  • mod1.js 是无副作用的
  • mod2.js 是有副作用的

应该如下设置才能保证 mod2.js 代码被保留:

  1. {
  2. "sideEffects": [
  3. "./src/mod2.js"
  4. ]
  5. }

另外值得注意的是,通过 import '../main.css' 方式引用的样式文件也属于有副作用的代码,应正确设置,避免被错误优化。

作用域提升

通过”提升“被导入的模块代码的作用域,达到提升代码性能和减少代码量的效果

核心内容:

  1. 作用域提升的概念和作用
  2. 使用插件完成作用域提升

众所周知,JavaScript 存在 ”函数提升“ 和 ”变量提升“ 的概念,即 JavaScript 运行时会把函数和变量声明提升到当前作用域的顶部。
而 webpack 中的 ”作用域提升“ 功能也与之类似,它会把被引用的 js 文件合并且放置到引入 js 文件的顶部

作用域提升优化后的效果:

  • 减少打包后的代码量
  • 减少代码运行时占用的内存
  • 提升代码运行的速度

步骤大纲

  1. 创建新目录,并编写三个依赖关系为 index -> a -> b 的模块
  2. 编写 webpack 配置文件,打包后观察结果模块的结构
  3. 启用 optimization.concatenateModules: true 优化项,打包后观察结果

具体步骤:

1、创建新项目,编写如下文件

src/b.js

  1. export function printMessage(str) {
  2. console.log(`打印消息:${str}`)
  3. }

src/a.js

  1. import { printMessage } from './b'
  2. export function printA() {
  3. printMessage("这是a模块中打印的消息")
  4. }

src/index.js

  1. import { printA } from './a'
  2. printA()

2、编写打包配置文件 webpack.config.js

  1. const path = require('path')
  2. module.exports = {
  3. mode: 'development',
  4. devtool: false,
  5. entry: './src/index.js',
  6. output: {
  7. path: path.join(__dirname, 'dist'),
  8. filename: 'app.bundle.js'
  9. },
  10. }

此时还未使用作用域提升进行优化,因此打包后的代码中各模块都还是独立的:
image.png

3、配置优化选项 optimization.concatenateModules

  1. // ...
  2. module.exports = {
  3. // ...
  4. optimization: {
  5. concatenateModules: true
  6. }
  7. }

再次打包后:a、b 模块的代码都以内联的方式直接放到了 index 前面:
image.png
效果验证:

  • 减少代码量 —> 确实变少了
  • 减少内存占用 —> 因为代码被简化后包装函数减少了,降低了本来要分配给这些函数的内存
  • 提升运行速度 —> 因为不用通过 webpack_require 调用模块了

【重要说明】
当然,webpack 也不会一股脑把所有模块都堆砌到一个模块中,比如以下情况下模块们依然会被一一拆分开:

  • 使用非 ES6 的模块机制
  • 使用 import() 异步导入

添加 CSS 前缀

自动为 css 样式属性添加跟浏览器相关的前缀,提高样式代码兼容性

核心内容:

  1. 安装和配置 postcss-loader ,通过 PostCSS 添加样式前缀

步骤大纲

  1. 创建新目录,编写一些在多种浏览器上可能存在兼容性写法的样式(如 flex 相关样式)
  2. 创建入口 js 并引入样式
  3. 安装常用处理 css 的一些 loader,及 postcss-loader 和相关依赖包
  4. 编写 webpack 配置,使用 postcss-loader 作为第一道处理 css 的 loader
  5. 打包并观察结果

具体步骤

1、新建项目,编写如下文件

src/main.css

  1. .test {
  2. display: flex;
  3. flex-direction: column;
  4. }

src/index.js

import './main.css'

2、安装css-loader, mini-css-extract-plugin, postcss-loader 及相关依赖包

npm i css-loader mini-css-extract-plugin -D
npm i postcss-loader postcss postcss-preset-env -D

3、配置 webpack

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const path = require('path')

module.exports = {
  mode: 'development',

  entry: './src/index.js',

  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'app.bundle.js'
  },

  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          // 用 PostCSS 处理样式文件
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  ["postcss-preset-env", {
                    //兼容到浏览器版本的的倒数第二个版本
                    browsers: ['last 2 versions']
                  }]
                ],
              },
            }
          }
        ]
      }
    ]
  },

  plugins: [
    new MiniCssExtractPlugin()
  ]
}

配置后打包,能看到某些样式已添加前缀:

.test {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -ms-flex-direction: column;
  flex-direction: column;
}

压缩 CSS

让打包输入的 css 文件进行压缩处理,减少文件体积

核心内容:

  1. 通过插件css-minimizer-webpack-plugin 来压缩样式代码

步骤大纲

  1. 安装 css-minimizer-webpack-plugin
  2. 使用 optimization.minimizer 优化项来指定压缩 css 的插件
  3. 打包后观察结果

具体步骤

1、在之前案例基础上,安装 css-minimizer-webpack-plugin

npm i css-minimizer-webpack-plugin -D

2、配置 webpack

// ...
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
  // ...
  optimization: {
    minimize: true,
    minimizer: [
      // 表示保留当前已有的压缩器
      `...`,
      // 添加 CSS 压缩器
      new CssMinimizerPlugin()
    ]
  }
}

配置后打包,能看到样式文件已被压缩。

抽取公共模块

将多个入口代码中都引用的 js 模块,抽取成独立文件,达到拆分公共代码的目的(有利于文件缓存)

核心内容:

  1. 了解为什么要抽取公共模块
  2. 使用 optimization.spliatChunks 配置公共代码抽取

不抽取前的问题:

如果一个项目含有多个入口,且它们又都引入了一些相同的模块,则打包后各入口对应的结果文件中都会包含相同的代码,产生冗余问题:
image.png

解决方法

在 webpack 4 之前,一般使用 CommonsChunkPlugin 插件来解决该问题,不过它的功能较弱。
从 webpack 4 开始它被 SplitChunksPlugin 插件取代,且默认就已启用,在不做任何配置的情况下,如当前代码文件符合下列条件,就会自动被拆分:

  • 当一个 chunk 被其他多个 chunk 共享,或模块来自于 node_modules 文件夹
  • 当一个 chunk 体积在进行 min + gz 之前的尺寸 > 20kb
  • 当一个 chunk 在按需加载时最大的并行请求数 <= 30
  • 当加载初始页面时的最大并发请求数 <= 30

SplitChunksPlugin 的使用方式和其他插件也不同,它通过 optimization.splitChunks 来配置。

步骤大纲

  1. 创建新目录,编写一个公用工具模块
  2. 编写两个入口 js 文件,它们都引用了上面的工具模块
  3. 安装 jquery 并在上面其中一个模块中调用
  4. 编写 webpack 配置,处理多入口,并通过 optimization.splitChunks 配置项设置分别对工具模块、npm 安装的模块进行抽取
  5. 打包并观察结果

具体步骤

1、创建新项目,编写以下文件

公共模块:src/common/index.js

export function toUpperCase(str) {
   return str ? str.toUpperCase() : ''
 }

 export function formatDate(timestamp) {
   const date = new Date(timestamp)
   const year = date.getFullYear()
   const month = date.getMonth() + 1
   const day = date.getDate()
   return `${year}年${month}月${day}日`
 }

页面入口1:src/index1.js

// 用到了 jquery,请用 npm 安装依赖包
 import jquery from 'jquery'
 import { toUpperCase } from './common'

 const text = toUpperCase('hello,world')
 console.log(text)

 // 调用 node_moudules 中的模块
 console.log(jquery('.btn'))

页面入口2:src/index2.js

import { formatDate } from './common'

 const date = formatDate(Date.now())
 console.log(date)

2、配置 webpack

 const path = require('path')

 module.exports = {
   mode: 'development',

   devtool: false,

   entry: {
     app1: './src/index1.js',
     app2: './src/index2.js',
   },

   output: {
     path: path.join(__dirname, 'dist'),
     filename: '[name].bundle.js'
   },

   optimization: {
     splitChunks: {
       cacheGroups: {
         // 抽取我们自己编写的公共代码
         commons: {
           minChunks: 2,
           chunks: 'initial',
           name: 'commons',
           // 由于当前我们的 common 模块代码较少(小于20K),
           // 所以默认不会生成独立的 chunk 文件的,而使用 enforce 可强制生成
           enforce: true,
         },

         // 抽取通过 npm 安装的 node_modules 下的模块
         vendors: {
           ctest: /[\\/]node_modules[\\/]/,
           chunks: 'all',
           name: 'vendors',
         },
       },
     }
   }
 }

执行打包后观察结果文件:
image.png

使用动态导入按需加载

使用 webpack 的按需导入函数作模块的按需加载,并为这些模块生成独立的 js 文件

核心内容:

  1. 按需导入函数 import()
  2. 通过 webpack 为按需导入的模块生成独立的 js 文件

与 ES6 import 关键字不同,import() 是 webpack 提供的函数,用于在代码执行到当前调用的地方时再去加载指定的模块文件,即按需加载。按需加载的文件将被 webpack 打包成独立的文件。

步骤大纲

  1. 编写一个简单的js模块
  2. 在入口js中通过 import() 函数加载以上 js 模块
  3. 打包并观察结构,看是否为该模块生成了独立文件

具体步骤

1、在之前章节代码的基础上,编写如下代码

  • 新增:src/dynamic/dyna1.js
  • 修改:src/index2.js

src/dynamic/dyna1.js

console.log('>>>>>Test Daynamic Module')

src/index2.js

import { formatDate } from './common'

const date = formatDate(Date.now())
console.log(date)

// 使用 import() 函数动态导入
import('./dynamic/dyna1')

2、执行打包,可以看到生成了 dyna1.js 对应的文件

image.png

之前章节讲到,webpack 的默认抽取规则为:“当 chunk 在按需加载时最大的并行请求数 <= 30” ,就会自动生成独立文件:

  • 当前示例代码中只有一个地方通过 import() 加载 dyna1.js ,满足该条件,所以生成了独立文件
  • 如果代码中存在 30 次以上的 import() 加载 dyna1.js,则就不会生成独立文件

如想改变以上阈值,可通过 optimization.splitChunks 下的配置项:

  • maxAsyncRequests - 最大异步请求数
  • maxInitialRequests - 最大初始请求数

忽略对无需解析文件的处理

让 webpack 忽略解析通过 npm 安装的模块,提高构建速度


核心内容:

  1. 提升原理
  2. webpack 配置:module.noParse的配置

解析和不解析的区别:

  • 解析:读懂内容
  • 不解析:无脑 CV

默认情况下 webpack 会对任意引用到的模块进行解析,当解析较大型第三方库的代码时会消耗很多时间。

其实大多数从 npm 下载的包都已自行做了构建处理,无需再次进行解析。

通过 webpack 配置项 noParse ,可以让 webpack 忽略对指定文件的解析。该值是一个用来匹配文件路径的正则。(需要注意的是:被忽略的文件中不能使用任何模块化机制)。

步骤大纲

  1. 查看当前项目的打包消耗时间
  2. 配置 webpack 的 noParse,忽略对第三方包的解析(比如jquery)
  3. 再次打包,观察消耗时间

具体步骤

1、在之前的案例中引入了 jquery,我们在打包后查看当前花费的时间

image.png

2、配置 webpack

// ...
module.exports = {
  // ...
  module: {
    //不解析 jquery 包
    noParse: /jquery/,
  }
}

再次执行打包,查看消耗时间:

image.png

排除无需打包的文件

将不需要的文件排除在打包结果之外,仅打包所需的文件,减少打包后的文件大小
(一般用于打包第三方提供的库时,会遇到这样的场景)

核心内容:

  1. 场景说明
  2. 通过 webpack 插件 IgnorePlugin 实现该优化

成熟的第三方库一般为满足尽可能多的用户,会提供比较细致完善的功能。比如:很多涉及多语言的库,就会提供很多国家的语言文件包,且默认将它们全部打包。但有的开发者只需一两种语言就够了,如果采用默认打包方式就会让打包后的文件很大。

webpack 内置的 IgnorePlugin 可用来指定哪些文件无需打包。

下面以 moment 库为例。

步骤大纲

  1. 为项目安装 moment,并在代码中使用 moment
  2. 打包并观察结果文件
  3. 本地安装 webpack 包,并配置 IgnorePlugin 插件来忽略 moment 库中所有 locale 目录下的文件
  4. 打包并观察结果文件
  5. 单独引入所需的语言文件
  6. 打包并观察结果文件

具体步骤

1、创建新项目,并安装 moment

npm i moment -D

2、编写 src/index.js

// 导入 moment
import moment from 'moment'

// 设置语言
moment.locale('zh-cn')

// 调用 moemnt 来处理日期
const result = moment().endOf('day').fromNow()

console.log(result)

3、安装 webpack,并编写 webpack 配置

npm i webpack -D

webpack.config.js

const path = require('path')

module.exports = {
  mode: 'development',

  entry: './src/index.js',

  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'app.bundle.js'
  },
}

配置后打包,在打包结果中能看到各种 moment 语言信息。

4、添加 IgnorePlugin 配置

// ...
const { IgnorePlugin } = require('webpack')

module.exports = {
  // ...
  plugins: [
    new IgnorePlugin({
      //要排除的模块名字
      contextRegExp: /moment/,
      //要排除的模块的路径
      resourceRegExp: /\.\/locale/,
    })
  ]
}

配置后打包,打包结果中一个语言信息都没了。

5、在 src/index.js 中通过 import 只导入中文语言

// 只导入中文语言包
import 'moment/locale/zh-cn'

再次打包,打包结果中只包含了中文语言信息。

并行构建

让原本单进程的构建过程,变成多进程并行构建,提高打包速度

核心内容:

  1. webpack 单进程的特性介绍
  2. 通过使用 HappyPack 插件实现多进程方式的构建

要解决的问题?

由于 Node.js 是单线程模型,所以 Webpack 只能一个个文件依次处理,不能同时进行。

当构建文件数量较多的中大型项目时,就会花费很长时间。

解决方案?

可使用插件 HappyPack ,让 Webpack 能同时处理多个任务。

它的原理:主进程创建多个子进程,将要处理的文件委托这些子进程进行并发处理,处理完成后再把结果发回主进程进行合并。这能减少总的构建时间。
image.png

步骤大纲

  1. 在项目中安装 happypack
  2. 在配置文件中创建 HappyPack 进程池
  3. 在配置文件中创建 HappyPack实例,关联进程池,并指定要通过 HappyPack 代理处理的 loader
  4. 打包

具体步骤

1、在任意 webpack 项目中,安装 happypack (本案例基于之前 babal-loader 示例代码)

npm i happypack -D

2、在 webpack.config.js 中创建 HappyPack 进程池

const HappyPack = require('happypack')
const os = require('os')

// HappyPack 进程池
const threadPool = HappyPack.ThreadPool({
  // 根据当前计算机的 CUP 数量来决定进程池的进程数量
  size: os.cpus().length
})

3、配置 HappyPack 插件来委托运行原先的 babal-loader

// ...
module.exports = {
  // ...
  module: {
    rules: [
      // ...
      {
        // 处理 js 文件
        test: /\.js$/,
        // 记得一定要排除掉通过包管理器安装的代码目录,否则转换会非常慢
        exclude: /node_modules/,
        // 配置 babel-loader (通过 happypack 运行)
        use: 'happypack/loader?id=happyBabel'
      }
    ]
  },

  // 插件
  plugins: [
    // ...
    new HappyPack({
      //每一个进程需要一个独一无二的id
      id: 'happyBabel',
      //需要使用happyhapck执行的loader
      loaders: [{
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-transform-runtime']
        }
      }],
      threadPool,
    })
  ]
}

配置后打包,可看到如下信息则说明 HappyPack 已生效:

image.png

重要说明:

  1. 在文件较少时,使用 HappyPack 其实反而会增加构建时间,因为创建和管理额外的进程也需要时间。建议在文件较多的项目中使用,才能体现出整体性价比
  2. 另外 HappyPack 目前还未完全支持 webpack 5,有些 loader 会运行失败,使用时需要注意

利用浏览器缓存文件

通过为打包生成的文件指定特定文件名,让浏览器能缓存没有变化的文件

核心内容:

  1. 浏览器对文件的缓存机制
  2. 配置 webpack,生成特定文件名的结果文件

URL对缓存的影响:

http://www.abc.com/test.js (使用缓存)

http://www.abc.com/test.js?v=时间戳 (不使用缓存)

http://www.abc.com/test.xxxxx.js (当 xxxxx 变动时,不使用缓存)

浏览器通过内存或磁盘对文件进行缓存:
image.png

具体步骤

1、以下面的 webpack.config.js 配置为例,打包后生成的文件名永远是 bundle.js

const path = require('path')

module.exports = {
  mode: 'development',

  entry: './src/index.js',

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  }
}

当页面中引入该 js 文件时,浏览器后续会会尝试从缓存中加载该文件,而不是从后端请求。

但如果发布了新版本,而打包文件仍为 bundle.js ,这时就会有问题:用户浏览器不一定能重新从我们的服务器获取最新代码。

2、可借助 webpack 的 hash 生成功能,为文件名携带唯一的 hash 值

// ...
module.exports = {
  // ...
  output: {
        // ..
    // [hash] 表示一个占位符,用 hash 内容填充
    filename: 'bundle.[fullhash].js'
  }
}

打包后的文件名:

image.png

可用的 hash 生成器有3个:

  • **fullhash** - 只要有一个文件发生改动,则会为所有打包文件的名称生成新的 hash,即所有缓存的文件都会失效【工程级别缓存】
  • **chunkhash** - 一个入口所关联的文件内容发生改动,则为该入口所依赖的所有文件生成新 hash【入口级别缓存】
  • **contenthash** - 只为改动过的模块生成新 hash【文件级别缓存】

对打包结果进行分析

通过使用分析工具,生成构建分析报告,帮助找出可优化的地方

核心内容:

  1. 优化的思想
  2. 分析工具的使用

任何优化操作都不会是盲目开展的,而是遵循一些基本规则:

  1. 首先,要知道问题出在哪里,即要优化什么
  2. 其次,针对可以优化的点,选择相应的优化方案
  3. 最后,要衡量优化前后对项目产生的影响

几种可视化分析工具

  1. webpack-bundle-analyzer 插件
  2. webpack visualizer
  3. webpack analyse

具体步骤

工具一:webpack-bundle-analyzer 插件的使用

1、在项目中安装 webpack-bundle-analyzer

npm i webpack-bundle-analyzer --save-dev

2、配置 webpack
// ...
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

 module.exports = {
   // ...
   plugins: [
     // ...
     // 开启 BundleAnalyzerPlugin
     new BundleAnalyzerPlugin(),
   ],
 }

执行打包后,会自动打开打包结果的图形化分析网页,查看使用到的模块及依赖关系:
image.png

工具二:webpack visualizer 的使用

1、生成统计文件 stats.json
webpack --profile --json > stats.json

2、 打开工具主页 http://chrisbateman.github.io/webpack-visualizer/,并上传 stats.json

image.png
Webpack Visualizer 能以可视化方式展示您的 webpack 捆绑包的分析结果,可以清晰的看到哪些模块正在占用空间、哪些可能是重复的。

工具三:webpack analyse 的使用

1、生成 stats.json

2、从 GitHub 克隆代码: https://github.com/webpack/analyse

克隆完代码后,安装 npm 依赖包,然后执行 npm run dev 启动服务。

3、上传 stats.json

Webpack Analyse 提供了对包的更全面的分析,能绘制项目中所有依赖模块的图形,对于依赖关系较少的项目非常有用。
(但依赖关系多的话,看起来真的非常费力!)
image.png
更多工具参考

预拉取和预加载

使用import()进行模块懒加载时,可通过在网络空闲时预先下载 chunk 代码,来实现用户体验的提升

核心内容:

  1. 使用懒加载时的问题
  2. 解决方案:预拉取和预加载的使用

在使用模块懒加载的情况下,只有当执行到懒加载的代码时才会开始下载和执行。这有可能会导致出现用户的交互失败或延迟的情况。

解决该问题的方式是:使用 webpack 提供的预拉取 (prefetch) 和预加载 (preload) 。

用法是在 import() 函数中使用”魔法注释“:

/ webpackPrefetch: true /

/ webpackPreload: true /

const Home = () => import(/* webpackPrefetch: true */ './...../Home.vue')

preload 和 prefetch 的区别:

  • preload 文件会和父文件一起同时加载;而 prefetch 文件会在父文件加载后才开始加载
  • preload 文件会立即下载;而 prefetch 文件只在浏览器闲置时才下载
  • 浏览器支持程度不同

具体步骤

1、在通过 import() 函数进行懒加载的代码上,添加魔法注释:

const Home = () => import(
  /* webpackPrefetch: true */
  '@/views/Home/index.vue'
)

const About = () => import(
  /* webpackPreload: true */
  '@/views/About/index.vue'
)

2、打包后,index.html 中的 <head> 下会添加类似如下标签

<link rel="prefetch" as="script" href="./src_views_Home_index_vue.app.bundle.js">
<link rel="prefetch" as="script" href="./src_views_About_index_vue.app.bundle.js">

3、运行页面后可观察到:目前暂时没被执行到的 chunk 代码包也会被下载下来

更多参考