Tree Shaking 在计算机中表示消除死代码。
Tree Shaking 最早源于 LISP,用于消除未调用的代码,后来也被应用于其他的语言,例如 JavaScript、Dart 等。
JavaScript 中的 Tree Shaking 依赖于 ESModule 的静态语法分析,不执行任何代码,就可以明确地知道模块的依赖关系。最早源自打包工具 rollup,rollup 主要用于对 ESModule 相关的代码进行打包。Webpack2 开始内置支持 ESModule 和检测未使用模块的能力;Webpack4 正式扩展了这个能力,并且通过 pacjage.json 中的 sideEffects 属性作为标记,告知 Webpack 在编译时哪些文件可以安全地被删除掉;在 Webpack5 中,也提供了对部分 CommonJS 语句的 Tree Shaking 支持。
在 Webpack 中实现 Tree Shaking 可以采用两种不同的方案:usedExports 或者 sideEffects。这两种方案可以独立使用,也可以结合使用。
usedExports:
usedExports:对未使用的函数进行标记,然后就可以通过 Terser 将其删除掉。
production 模式下默认会开启。
- 新建
src/math.js和src/index.js,并编写代码。// src/math.js export const increase = (num1, num2) => { return num1 + num2 } export const decrease = (num1, num2) => { return num1 - num2 }// src/index.js import {increase} from './math' console.log(increase(10, 20)) - 在
webpack.config.js配置文件中进行配置。// webpack.config.js module.exports = { // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式 mode: 'development', // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容 devtool: 'source-map', } - 运行
webpack命令进行打包,会发现,即使src/math.js中的 decrease 函数并没有被导入使用,也还是被导出了。

- 在
webpack.config.js配置文件中进行配置。module.exports = { // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式 mode: 'development', // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容 devtool: 'source-map', optimization: { // 对未使用的函数进行标记 usedExports: true, } } - 运行
webpack命令进行打包,会发现,src/math.js中的 decrease 函数没有再被导出了,并且被标记多了一行注释/* unused harmony export decrease */。如果配置了 Terser,这行注释将会被 Terser 解析,然后 Terser 就会根据这行注释将 decrease 函数删除掉。

- 在
webpack.config.js配置文件中进行配置。const TerserPlugin = require('terser-webpack-plugin') module.exports = { // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式 mode: 'development', // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容 devtool: 'source-map', optimization: { // 对未使用的函数进行标记 usedExports: true, // 使用 Terser 将未使用的函数删除掉 minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { keep_fnames: true, } }) ] } } - 运行
webpack命令进行打包,会发现,src/math.js中的 decrease 函数没有再被打包到输出文件中了。

通过配置 usedExports 实现对整个模块的 Tree Shaking 存在的问题:
- 新建
src/format.js和src/index.js文件,并编写代码。// src/format.js export const dateFormat = () => { return '2023-10-28' }src/index.js import './format' console.log('index') - 在
webpack.config.js配置文件中进行配置。const TerserPlugin = require('terser-webpack-plugin') module.exports = { // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式 mode: 'development', // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容 devtool: 'source-map', optimization: { // 对未使用的函数进行标记 usedExports: true, // 使用 Terser 将未使用的函数删除掉 minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { keep_fnames: true, } }) ] } } - 运行
webpack命令进行打包,会发现,配置 usedExports 后,dateForamt 函数确实没有被打包到输出文件中,但是对src/format.js文件的引入还存在。

sideEffects:
sideEffects:告知 Webpack Compiler 哪些模块有副作用。如果模块有副作用的话,导入了该模块但是并没有使用,打包时该模块将不会被删除掉;如果模块没有副作用的话,导入了该模块但是并没有使用,打包时该模块将会直接被删除掉。
模块有副作用的意思是:模块中的代码有执行一些有副作用的操作。
- 新建
src/format.js、src/format.js和src/index.js文件,并编写代码。// src/format.js export const dateFormat = () => { return '2023-10-28' } // 没有副作用// src/math.js export const sum = () => { return 30 } // 有副作用 window.message = 'Hello World'src/index.js import './format' import './math' console.log('index') - 在
webpack.config.js配置文件中进行配置。module.exports = { // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式 mode: 'development', // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容 devtool: 'source-map', } - 在
package.json中配置 sideEffects 来告知 Webpack Compiler 哪些模块有副作用。// package.json "sideEffects": [ "./src/math.js", // 如果属性值是一个数组,需要为数组添加一个项 `**.css` 来对 CSS 文件进行配置,否则的话,项目中引入的 CSS 文件会被作为没有副作用的模块,在打包时被删除掉。 "**.css" ],sideEffects 的属性值可以是数组,来表示哪些模块有副作用;也可以是布尔值,为 true 表示所有模块都有副作用,为 false 表示所有模块都没有副作用。
在开发中,更推荐编写纯模块。因此,更推荐配置"sideEffects": false来将所有模块都作为没有副作用的模块,此时对 CSS 的配置可以放到webpack.config.js配置文件中。// webpack.config.js module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader"], // 将匹配到的所有 CSS 文件都作为有副作用的文件 sideEffects: true, } ] } - 运行
webpack命令进行打包,会发现,没有副作用的src/format.js整个文件都没有被打包到输出文件中,有副作用的src/math.js被保留了下来。

文章介绍了TreeShaking在计算机科学中的概念,特别关注其在JavaScript和Webpack中的实现,包括依赖关系分析、ESModule的使用、sideEffects和usedExports策略,以及如何通过配置Webpack进行代码优化以消除未使用的代码。
1388

被折叠的 条评论
为什么被折叠?



