Vue中Tree-Shaking的原理是什么

其他教程   发布日期:2025年04月06日   浏览次数:89

这篇文章主要介绍“Vue中Tree-Shaking的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue中Tree-Shaking的原理是什么”文章能帮助大家解决问题。

什么是Tree-Shaking

  1. Tree-Shaking
这个概念在前端领域是因为
  1. rollup.js
而起,后来webpack等也加入支持
  1. Tree-Shaking
的行列中。简单来说就是移除掉项目中永远不会被执行的代码(
  1. dead code
),实际情况中,代码虽然依赖了某个模块,但其实只使用其中的某些功能。通过
  1. Tree-shaking
,将没有使用的模块代码移除掉,这样来达到删除无用代码的目的。

Tree-shaking的原理和支持

  • 实现

    1. tree-shaking
    的基础是依赖于
    1. ES6
    的模块特性,即模块必须是
    1. ESMES Module
    。这是因为ES6模块的依赖关系是确定的、静态的,和运行的时的状态无关,可以进行静态分析。
  • 现在主流的打包工具都支持

    1. Tree-shaking
    ,例如最早支持的
    1. rollup
    ,后来支持的
    1. webpack
    ,以及
    1. vite
    等等。

可以被Tree-shaking

有以下代码,其中工具函数文件中包含了

  1. foo
  1. bar
,在
  1. shaking
文件中只使用了
  1. foo
,在
  1. main
文件中引用了
  1. foo
,但没有使用:
  1. // utils.js
  2. export const foo = () => {
  3. console.log('foo')
  4. }
  5. export const bar = () => {
  6. console.log('bar')
  7. }
  8. // shaking.js
  9. import { foo } from './utils.js'
  10. const fn = () => {
  11. console.log('fn')
  12. foo()
  13. }
  14. fn()
  15. // main.js
  16. import { foo, bar } from './utils.js'
  17. const main = () => {
  18. console.log('main')
  19. bar()
  20. }
  21. main()

现在分包使用

  1. rollup.js
打包
  1. shaking.js
  1. main.js
文件
  1. # 打包shaking文件
  2. npx rollup shaking.js -f esm -o bundle.js
  3. # 打包main文件
  4. npx rollup main.js -f esm -o mian-bundle.js

先来看

  1. bundle.js
文件的内容,
  1. utils
文件中
  1. foo
打包进去,而
  1. bar
没有被引用,则被移除。
  1. const foo = () => {
  2. console.log('foo');
  3. };
  4. const fn = () => {
  5. console.log('fn');
  6. foo();
  7. };
  8. fn();

再来看

  1. main-bundle.js
文件的内容,
  1. utils
文件中
  1. bar
打包进去,而
  1. foo
虽然被引用,但是没有在
  1. main.js
文件中使用,则被移除。
  1. const bar = () => {
  2. console.log('bar');
  3. };
  4. const main = () => {
  5. console.log('main');
  6. bar();
  7. };
  8. main();

不可以被Tree-shaking

有些代码看着无用,但是确不能被

  1. Tree-shaking
移除,例如我们对上面的代码进行重写
  1. // utils.js
  2. // 新增以下代码
  3. export default {
  4. name: function () {
  5. console.log('绝对零度')
  6. },
  7. age: () => {
  8. console.log(18)
  9. }
  10. }
  11. // shaking.js
  12. import userInfo, { foo } from './utils.js'
  13. const fn = () => {
  14. console.log('fn')
  15. userInfo.name()
  16. foo()
  17. }
  18. fn()

再次使用

  1. rollup.js
打包文件
  1. const foo = () => {
  2. console.log('foo');
  3. };
  4. var userInfo = {
  5. name: function () {
  6. console.log('绝对零度');
  7. },
  8. age: () => {
  9. console.log(18);
  10. }
  11. };
  12. const fn = () => {
  13. console.log('fn');
  14. userInfo.name();
  15. foo();
  16. };
  17. fn();

有意思的问题来了,这次我们仅仅使用

  1. name
方法,而
  1. age
方法也被打包进来,说明
  1. Tree-shaking
没有生效。究其原因,
  1. export default
导出的是一个对象,无法通过静态分析判断出一个对象的哪些变量未被使用,所以
  1. tree-shaking
只对使用
  1. export
导出的变量生效。

另外一个问题是,如果一个函数被调用的时候会产生副作用,那么就不会被移除。再次在utils文件中增加下面代码

  1. // utils.js新增的代码
  2. export const empty = () => {
  3. const a = 1
  4. }
  5. export const effect = (obj) => {
  6. obj && obj.a
  7. }

再次导入使用然后打包

  1. // shaking.js文件
  2. import userInfo, { foo, empty, effect } from './utils.js'
  3. const fn = () => {
  4. console.log('fn')
  5. userInfo.name()
  6. empty()
  7. effect()
  8. foo()
  9. }
  10. fn()

打包后发现新增加了一个

  1. effect
函数,而同时新增的
  1. empty
函数被移除,分析原因发现
  1. effect
函数就是一个纯读取函数,但是这个函数可能会产生副作用。试想一下,如果
  1. obj
对象是一个通过
  1. Proxy
创建的代理对象,那么当我们读取对象属性时,就会触发代理对象的
  1. get
方法,在
  1. get
方法中是可能产生副作用的,比如调用其它的方法或者修改一些变量等等。
  1. const foo = () => {
  2. console.log('foo');
  3. };
  4. const effect = (obj) => {
  5. obj && obj.a;
  6. };
  7. var userInfo = {
  8. name: function () {
  9. console.log('绝对零度');
  10. },
  11. age: () => {
  12. console.log(18);
  13. }
  14. };
  15. const fn = () => {
  16. console.log('fn');
  17. userInfo.name();
  18. effect();
  19. foo();
  20. };
  21. fn();

由于rollup.js分析静态代码很困难,所以他们给我们提供一个机制,明确告诉rollup,这部分代码没有副作用可以移除。

  1. /*#__PURE__*/
就是解决这个问题的办法,只需要在effect方法前面加上上面的代码,程序运行的时候就会认为他是没有副作用的,可以放心的进行
  1. Tree-shaking
  1. /*#__PURE__*/const effect = (obj) => {
  2. obj && obj.a;
  3. };

Vue中的应用

在Vue的框架源码中,存在这大量的特性开关,打包编译或者使用的时候通过配置特性开关可以通过

  1. Tree-shaking
机制让代码资源最优化。
比如
  1. Vue3
为了支持
  1. Vue2
  1. options Api
,写了大量的兼容代码,但是如果我们再使用
  1. Vue3
中不使用
  1. options Api
,就可以通过一个叫做
  1. __VUE_OPTIONS_API__
的特性开关去关闭这个特性,这样最终打包的Vue代码就不会包含这部分,进而减少代码体积。

以上就是Vue中Tree-Shaking的原理是什么的详细内容,更多关于Vue中Tree-Shaking的原理是什么的资料请关注九品源码其它相关文章!