Vue中Tree-Shaking的原理是什么
这篇文章主要介绍“Vue中Tree-Shaking的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue中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
有以下代码,其中工具函数文件中包含了foo
与bar
,在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.js
与main.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
为了支持Vue2
的options Api
,写了大量的兼容代码,但是如果我们再使用Vue3
中不使用options Api
,就可以通过一个叫做__VUE_OPTIONS_API__
的特性开关去关闭这个特性,这样最终打包的Vue代码就不会包含这部分,进而减少代码体积。
关于“Vue中Tree-Shaking的原理是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注蜗牛博客行业资讯频道,小编每天都会为大家更新不同的知识点。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
评论