Vue中的Tree-Shaking介绍及原理

 更新时间:2023年04月27日 09:50:43   作者:绝对零度HCL  
这篇文章主要介绍了Vue中的Tree-Shaking是什么,通过Tree-shaking,将没有使用的模块代码移除掉,这样来达到删除无用代码的目,本文结合实例代码详解详解,需要的朋友可以参考下

什么是Tree-Shaking

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

Tree-shaking的原理和支持

  • 实现tree-shaking的基础是依赖于ES6的模块特性,即模块必须是ESM(ES Module)。这是因为ES6模块的依赖关系是确定的、静态的,和运行的时的状态无关,可以进行静态分析。
  • 现在主流的打包工具都支持Tree-shaking,例如最早支持的rollup,后来支持的webpack,以及vite等等。

可以被Tree-shaking

有以下代码,其中工具函数文件中包含了foobar,在shaking文件中只使用了foo,在main文件中引用了foo,但没有使用:

// utils.js
export const foo = () => {
    console.log('foo')
}
export const bar = () => {
    console.log('bar')
}
// shaking.js
import { foo } from './utils.js'
const fn = () => {
    console.log('fn')
    foo()
}
fn()
// main.js
import { foo, bar } from './utils.js'
const main = () => {
    console.log('main')
    bar()
}
main()

现在分包使用rollup.js打包shaking.jsmain.js文件

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

先来看bundle.js文件的内容,utils文件中foo打包进去,而bar没有被引用,则被移除。

const foo = () => {
    console.log('foo');
};
const fn = () => {
    console.log('fn');
    foo();
};
fn();

再来看main-bundle.js文件的内容,utils文件中bar打包进去,而foo虽然被引用,但是没有在main.js文件中使用,则被移除。

const bar = () => {
    console.log('bar');
};
const main = () => {
    console.log('main');
    bar();
};
main();

不可以被Tree-shaking

有些代码看着无用,但是确不能被Tree-shaking移除,例如我们对上面的代码进行重写

// utils.js
// 新增以下代码
export default {
    name: function () {
        console.log('绝对零度')
    },
    age: () => {
        console.log(18)
    }
}
// shaking.js
import userInfo,  { foo } from './utils.js'
const fn = () => {
    console.log('fn')
    userInfo.name()
    foo()
}
fn()

再次使用rollup.js打包文件

const foo = () => {
    console.log('foo');
};
var userInfo = {
    name: function () {
        console.log('绝对零度');
    },
    age: () => {
        console.log(18);
    }
};
const fn = () => {
    console.log('fn');
    userInfo.name();
    foo();
};
fn();

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

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

// utils.js新增的代码
export const empty = () => {
    const a = 1
}
export const effect = (obj) => {
    obj && obj.a
}

再次导入使用然后打包

// shaking.js文件
import userInfo,  { foo, empty, effect } from './utils.js'
const fn = () => {
    console.log('fn')
    userInfo.name()
    empty()
    effect()
    foo()
}
fn()

打包后发现新增加了一个effect函数,而同时新增的empty函数被移除,分析原因发现effect函数就是一个纯读取函数,但是这个函数可能会产生副作用。试想一下,如果obj对象是一个通过Proxy创建的代理对象,那么当我们读取对象属性时,就会触发代理对象的get方法,在get方法中是可能产生副作用的,比如调用其它的方法或者修改一些变量等等。

const foo = () => {
    console.log('foo');
};
const effect = (obj) => {
    obj && obj.a;
};
var userInfo = {
    name: function () {
        console.log('绝对零度');
    },
    age: () => {
        console.log(18);
    }
};
const fn = () => {
    console.log('fn');
    userInfo.name();
    effect();
    foo();
};
fn();

由于rollup.js分析静态代码很困难,所以他们给我们提供一个机制,明确告诉rollup,这部分代码没有副作用可以移除。/*#__PURE__*/就是解决这个问题的办法,只需要在effect方法前面加上上面的代码,程序运行的时候就会认为他是没有副作用的,可以放心的进行Tree-shaking

/*#__PURE__*/const effect = (obj) => {
    obj && obj.a;
};

Vue中的应用

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

到此这篇关于理解Vue中的Tree-Shaking的文章就介绍到这了,更多相关Vue中的Tree-Shaking内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 深入理解vue路由的使用

    深入理解vue路由的使用

    vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
    2017-03-03
  • 在vue中动态修改css其中一个属性值操作

    在vue中动态修改css其中一个属性值操作

    这篇文章主要介绍了在vue中动态修改css其中一个属性值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • validate 注册页的表单数据校验实现详解

    validate 注册页的表单数据校验实现详解

    这篇文章主要为大家介绍了validate 注册页的表单数据校验实现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 在IDEA中安装vue插件全过程

    在IDEA中安装vue插件全过程

    这篇文章主要介绍了在IDEA中安装vue插件全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • 基于Vue实现HTML转PDF并导出

    基于Vue实现HTML转PDF并导出

    这篇文章主要为大家介绍了三种方法,可以实现将HTML页面转为PDF并实现下载。文中的示例代码讲解详细,感兴趣的小伙伴可以学习一下
    2022-04-04
  • 使用websocket和Vue2中的props实时更新数据方式

    使用websocket和Vue2中的props实时更新数据方式

    这篇文章主要介绍了使用websocket和Vue2中的props实时更新数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Vue组件的使用及个人理解与介绍

    Vue组件的使用及个人理解与介绍

    本文介绍了VUE中组件的基本使用以及个人对VUE组件的理解,希望能帮助到大家
    2019-02-02
  • Vue中Object.defineProperty用法示例

    Vue中Object.defineProperty用法示例

    Vue中的Object.defineProperty是一个比较重要的方法,它是可以定义对象中属性的一个方法,相比于在对象中直接定义的对象,它更具有灵活性,本文将通过代码示例给大家简单介绍一下Vue中的Object.defineProperty,需要的朋友可以参考下
    2023-08-08
  • vue绑定事件后获取绑定事件中的this方法

    vue绑定事件后获取绑定事件中的this方法

    今天小编就为大家分享一篇vue绑定事件后获取绑定事件中的this方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vue实现滚动底部加载下一页指令的示例代码

    vue实现滚动底部加载下一页指令的示例代码

    vue中监控滚动事件可以直接在mounted中绑定滚动事件,然后在销毁前解绑滚动事件,本文通过实例代码介绍vue实现滚动底部加载下一页指令的过程,感兴趣的朋友跟随小编一起看看吧
    2023-10-10

最新评论