您的位置:

从多个方面详解tree-shaking

一、treeshaking原理

Tree-shaking的原理是利用ES6模块化规范的特性,在编译时通过静态分析代码,识别出未被使用的代码(dead code)并在打包时去除。具体来说,比如在代码中引入了一个模块,但实际上只使用了其中的一部分代码,通过静态分析可以识别出未被使用的代码,删掉这部分代码从而减小bundle的大小。

Tree-shaking的实现借助了ES6模块化的特性,ES6模块化规范是静态的,也就是说,在编译时就可以确定模块的依赖关系,因此可以通过静态分析来判断哪些代码没有被使用。

二、谢可寅shaking

treeshaking的发明人是谢可寅,tree-shaking这个词的由来其实是源于webpack社区的。webpack的开发者认为把未使用的代码从打包结果中摇掉很像树上的果实,因此用tree-shaking来形容这个过程。

三、treeshaking配置

对于webpack用户来说,使用tree-shaking非常方便,只需要在webpack配置文件中开启optimization.minimize选项就可以了。optimization.minimize选项默认会开启tree-shaking,并使用内置的UglifyJsPlugin压缩代码,从而生成一个更小的bundle。

// webpack.config.js
const path = require('path');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  optimization: {
    minimize: true,
  },
};

需要注意的是,只有引入ES6 module的代码才能启用tree-shaking。对于CommonJS或AMD模块化的代码,由于不带有静态分析的特性,无法利用tree-shaking功能。

四、treeshaking怎么读

对于英文不太好的开发者来说,"tree-shaking"这个词还是挺难理解的。它到底是什么意思呢?

实际上,tree-shaking这个词的意思可以通过拆分词汇来理解。Tree是树的意思,是一种数据结构。Shake是摇动的意思,可以引申为“震动”。因此,treeshaking可以理解为“震动树”(摇动树的果实掉落下来的意思)。

五、treeshaking不生效

虽然tree-shaking看上去很美好,但实际上开发者们会发现有些时候它并不会生效。有以下一些情况可能导致tree-shaking不生效。

  1. 在代码中使用了process.env.NODE_ENV变量,会导致webpack将整个模块打包进去。
  2. 有些库会使用类似于全局注册的方式注册组件,比如Ant Design Vue的组件,这会导致tree-shaking失效,因为在编译时无法知道哪些组件被使用。
  3. 使用动态导入(如import())时,由于要在运行时决定使用哪个模块,编译时不会对这部分代码进行分析。
  4. 代码中使用了webpack的require.ensure()或require.include()等动态加载模块的方式。

需要注意的是,尽管使用tree-shaking会减小bundle的大小,但并不一定会提升应用程序的性能。这是因为虽然tree-shaking会减小bundle的大小,但整个应用程序的总体积可能并没有得到明显的减少,因为一些库的体积可能还是非常大。

六、treeshaking副作用

虽然tree-shaking在很多情况下可以减小bundle的大小,但使用不当也会带来一些副作用。

  1. 可读性差。优化过度的代码可能会失去可读性,这会给维护和代码优化带来困难。
  2. 可能会破坏代码的正确性。对一些代码进行tree-shaking可能会破坏代码的正确性,导致应用程序无法正常运行。
  3. 代码冗余。有时候对代码进行tree-shaking会导致生成更多的代码,这可能会导致bundle的大小反而更大。

七、treeshaking对怎样的包不生效

treeshaking并不是万能的,对某些类型的包并不会起作用。比如:

  1. 对于只有一个入口文件的包或库,tree-shaking会对整个文件进行编译,而不是只编译其中被使用的部分。
  2. 对于内置模块(比如fs、http等),由于它们没有使用ES6的模块化规范,所以tree-shaking并不会起作用。

最后,需要注意一点的是,虽然tree-shaking非常方便,但也不是解决所有性能问题的银弹。代码优化应该是一个综合性的过程,需要综合考虑代码的质量、代码的体积、代码的可读性以及代码的运行效率等多个方面。

完整代码示例

// index.js
import { sum } from './math';

console.log(sum(1, 2));


// math.js
export function sum(a, b) {
  return a + b;
}

export function minus(a, b) {
  return a - b;
}