摇树优化(Tree Shaking)

1. 摇树优化简介

1.1 摇树优化的应用场景

  • 在大型项目中,多需求,多产品,多开发的背景下版本不断迭代,项目里会出现很多已被重构废弃掉的页面,会出现已经删除未使用的方法,会有很多已经删除了HTML结构但是未删除对应的CSS样式,这样在编译的时候,速度非常慢,打包后的体积也很大,浏览器将花费更多的时间去下载、解压、转码和执行他们。
  • 因为这些代码存在历史悠久,直接废弃又无法完全保证功能不被影响,测试可能有无法涵盖的场景,容易产生一系列的问题。所以,我们可以采用摇树优化Tree Shaking

1.2 什么是摇树优化

  • 摇树优化(Tree Shaking)是一种用来优化代码体积的技术,它能在构建过程中剔除无用的代码,从而减少最终生成的文件的大小。摇树优化的原理是基于静态代码分析,通过识别和删除未被使用的代码,从而实现代码精简和优化。
  • 在前端的性能优化中,ES6推出了Tree Shaking机制,当我们在项目中引入其他模块时,会自动将我们用不到的代码,或者永远不会执行的代码摇掉,在Uglify阶段查出,不打包到bundle中。

1.3 摇树优化注意事项

  • Tree Shaking只支持ESM的引入方式,不支持CommonJS引入方式
    • ESM: export + import
    • CommonJS: module.exports + require
  • 如果想要做到Tree Shaking,在引入模块时就应该避免将内容全部引入,应该局部按需引入才会触发Tree Shaking机制。

2. 摇树优化应用

Vue 2中通过webpack配置摇树优化。

2.1 package.json配置打包指令

开发环境和生产环境
摇树优化(Tree Shaking)_第1张图片

2.2 vue.config.js中进行webpack配置

dev环境需要配置usedExports
production环境默认开启
摇树优化(Tree Shaking)_第2张图片

2.3 定义三种类型的方法

  • func.js 定义函数
// 引用并被调用的方法
export function quoteAndUse() {
  console.log('这是use专属的方法,别人都')
  return
  console.log('这是use中return后面的')
}
// 引用但是未被调用的方法
export function quoteButNotUse() {
  console.log('这是quoteButNotUse方法')
}
// 未被引用的方法
export function notQuote() {
  console.log('这是未被引用的方法')
}

  • 在页面中不同场景进行使用
    • notQuote 未被引用的方法
    • quoteButNotUse 引用但是未被调用的方法
    • quoteAndUse 引用切已被调用的方法
import { quoteButNotUse, quoteAndUse } from './func'

testUse() {
  quoteAndUse()
}

2.4 不同环境打包

  • dev环境打包 yarn build:dev
    摇树优化(Tree Shaking)_第3张图片

打包结果发现,所有的代码都被打包了,三种方法均存在,但是下面两个未被引用或使用的方法被标注了unused harmony export

  • prod环境打包 yarn build
    在这里插入图片描述

打包结果发现,

  • 无法到达的代码(例如 return后面的代码)
  • 引用未被使用的方法
  • 未被引用的方法
  • 注释信息

都不会被打包到bundle.js中

3. 摇树优化副作用

sideEffects 指的是有副作用的代码,假如模块A中包含一些影响全局作用域(非模块作用域)的代码,如果改变了全局的变量或对象的变量,模块B引入了模块A,但并未使用。在这种情况下,模块A就被认为是有副作用的,webpack是不会删除模块A中所有未使用的代码的,它还会保留模块A中立即执行并对全局环境有影响的代码。

  • 新建about.js文件: 编写about方法,挂载到全局,在main.js中引入,但未真正调用
    摇树优化(Tree Shaking)_第4张图片
    摇树优化(Tree Shaking)_第5张图片

  • 打包后:我们会发现about会被打包在bundle.js 中

  • 如果我们知道所有模块都是没有副作用的(此处我的理解是: 如果没有引用就表示没有使用,称为没有副作用),不想让webpack打包他们,那么可以在webpack配置中奖package.json的sideEffects设为false,这样可以提高删除未使用代码的编译速度。
    摇树优化(Tree Shaking)_第6张图片

  • 配置完该属性后,再次打包,我们会发现about方法没有被打包在bundle.js中了

  • 请注意: 任何导入的文件都会收到树抖动的影响。如果css-loader在项目中使用类似的东西并导入css文件,则需要将其添加到副作用列表中,这样它就不会在生产模式下无意中被删除

  • 如果有某些模块是有副作用的,那么可以将它的路径加入package.json的sideEffects数组选项中,这样也能提高删除未使用代码的速度

  • 通过以上描述,我们可以把样式文件和我们最开始的about文件添加在副作用数组中

    {
      "name": "your-project",
       "sideEffects": ["about.js", "*.css"],
    }
    

使用示例对比:

  • 新建index.css文件,用于编写样式
    摇树优化(Tree Shaking)_第7张图片

  • 在main.js中进行引入
    摇树优化(Tree Shaking)_第8张图片

  • 此时,

    • 如果我们在package.json中设置 sideEffects: false 表示,所有内容都没有副作用,那么结果是样式不生效,打包后也没有about方法。
    • 如果我们在package.json中设置 sideEffects: [“about.js”, “*.css”],表示,这两个内容是有副作用的,可能没有引入,但是全局自动生效,那么样式生效,打包后有about方法

4. 摇树优化性能优化

最后,我们通过打包后文件大小来直观的体验一下摇树优化带来的性能优化。
摇树优化(Tree Shaking)_第9张图片

  • 此时我们打包后bundle.js打包体积为57kb
  • 在开发环境配置摇树优化之后进行打包,打包后的体积开始57kb. 在开发环境进行摇树优化打包,bundle.js的体积不会变小,原因是他只是标记未使用的代码,但并不会真正的清除他们。
  • 在生产环境打包(默认会开启摇树优化),bundle.js的体积15kb

一个简单的demo从57kb减小到了15kb。

总结

为了利用tree shaking的优势,必须满足一下几点:

  • 使用ESM方式对模块进入操作 import / export
  • 确保没有编译器将ESM语法转换成CommonJS语法(这是流行的Babel预设 @babel/preset-env的默认行为)
  • 将sideEffects属性根据需求应用到package.json中

文章学习参考来源

你可能感兴趣的:(摇树优化)