19. Tree shaking

134 阅读2分钟

相关代码

Tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它是基于 ES2015 模块语法的静态结构特性,例如 importexport

Webpack2 正式版本内置支持 ES2015 模块(也叫做 harmony modules)和未使用模块检测能力。Webpack4 正式版本扩展了此检测能力,通过 package.json 的 sideEffects 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 “pure(纯正 ES2015 模块)”,由此可以安全地删除文件中未使用的部分。

1. Tree shaking 示例

假设有以下文件:

// math.js

export const add = (x, y) => {
    return x + y
}
export const minus = (x, y) => {
    return x - y
}
// app.js

import { add, minus } from './math'
console.log(add(1, 2))
// webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  mode: 'production',
  entry: './src/app.js',
  plugins: [
    new HtmlWebpackPlugin()
  ],
  optimization: {
    usedExports: true
  }
}

执行 npx webpack 后,查看 dist/main.js:

(()=>{"use strict";console.log(3)})();

可以看到,打包后的文件直接获取了 add 方法执行后的值,引入的 minus 方法没有使用,所以 main.js 中没有任何 minus 相关的代码。

2. sideEffects

Webpack 不能百分百安全地进行 tree-shaking。有些模块只要被引入,就会对应用程序产生重要的影响。比如全局样式表,或者设置全局配置的 JavaScript 文件。

Webpack 认为这样的文件有 “副作用”。具有 “副作用” 的文件不应该做 tree-shaking,因为这将破坏整个应用程序。

Webpack 的设计者清楚地认识到在不知道哪些文件有 “副作用” 的情况下,打包代码是有风险的。因此 Webpack4 默认地将所有代码视为有 “副作用”。这可以避免删除必要的文件,但这也意味着 Webpack 的默认行为实际上是不进行 tree-shaking 的。而在 Webpack5 中,又是默认会进行 tree-shaking 的。

通过在 package.json 中设置 sideEffects 属性,可以告诉 Webpack 你的代码有没有 “副作用”:

// package.json

{
    "sideEffects": true,     // 表示所有的文件都有副作用,不能进行 tree-shaking
    "sideEffects": false,    // 表示所有的文件都没有副作用,所有文件都可以进行 tree-shaking
    "sideEffects": ["*.css", "*.global.js"],  // 表示数组中的文件有副作用不能进行 tree-shaking,除了数组中的文件,其他的文件都可以进行 tree-shaking
}