您好,登錄后才能下訂單哦!
這篇文章主要介紹“Vue中Tree-Shaking的原理是什么”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Vue中Tree-Shaking的原理是什么”文章能幫助大家解決問(wèn)題。
Tree-Shaking
這個(gè)概念在前端領(lǐng)域是因?yàn)?code>rollup.js而起,后來(lái)webpack等也加入支持Tree-Shaking
的行列中。簡(jiǎn)單來(lái)說(shuō)就是移除掉項(xiàng)目中永遠(yuǎn)不會(huì)被執(zhí)行的代碼(dead code
),實(shí)際情況中,代碼雖然依賴(lài)了某個(gè)模塊,但其實(shí)只使用其中的某些功能。通過(guò)Tree-shaking
,將沒(méi)有使用的模塊代碼移除掉,這樣來(lái)達(dá)到刪除無(wú)用代碼的目的。
實(shí)現(xiàn)tree-shaking
的基礎(chǔ)是依賴(lài)于ES6
的模塊特性,即模塊必須是ESM(ES Module)
。這是因?yàn)镋S6模塊的依賴(lài)關(guān)系是確定的、靜態(tài)的,和運(yùn)行的時(shí)的狀態(tài)無(wú)關(guān),可以進(jìn)行靜態(tài)分析。
現(xiàn)在主流的打包工具都支持Tree-shaking
,例如最早支持的rollup
,后來(lái)支持的webpack
,以及vite
等等。
有以下代碼,其中工具函數(shù)文件中包含了foo
與bar
,在shaking
文件中只使用了foo
,在main
文件中引用了foo
,但沒(méi)有使用:
// 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()
現(xiàn)在分包使用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
先來(lái)看bundle.js
文件的內(nèi)容,utils
文件中foo
打包進(jìn)去,而bar
沒(méi)有被引用,則被移除。
const foo = () => { console.log('foo'); }; const fn = () => { console.log('fn'); foo(); }; fn();
再來(lái)看main-bundle.js
文件的內(nèi)容,utils
文件中bar
打包進(jìn)去,而foo
雖然被引用,但是沒(méi)有在main.js
文件中使用,則被移除。
const bar = () => { console.log('bar'); }; const main = () => { console.log('main'); bar(); }; main();
有些代碼看著無(wú)用,但是確不能被Tree-shaking
移除,例如我們對(duì)上面的代碼進(jìn)行重寫(xiě)
// utils.js // 新增以下代碼 export default { name: function () { console.log('絕對(duì)零度') }, 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('絕對(duì)零度'); }, age: () => { console.log(18); } }; const fn = () => { console.log('fn'); userInfo.name(); foo(); }; fn();
有意思的問(wèn)題來(lái)了,這次我們僅僅使用name
方法,而age
方法也被打包進(jìn)來(lái),說(shuō)明Tree-shaking
沒(méi)有生效。究其原因,export default
導(dǎo)出的是一個(gè)對(duì)象,無(wú)法通過(guò)靜態(tài)分析判斷出一個(gè)對(duì)象的哪些變量未被使用,所以tree-shaking
只對(duì)使用export
導(dǎo)出的變量生效。
另外一個(gè)問(wèn)題是,如果一個(gè)函數(shù)被調(diào)用的時(shí)候會(huì)產(chǎn)生副作用,那么就不會(huì)被移除。再次在utils文件中增加下面代碼
// utils.js新增的代碼 export const empty = () => { const a = 1 } export const effect = (obj) => { obj && obj.a }
再次導(dǎo)入使用然后打包
// shaking.js文件 import userInfo, { foo, empty, effect } from './utils.js' const fn = () => { console.log('fn') userInfo.name() empty() effect() foo() } fn()
打包后發(fā)現(xiàn)新增加了一個(gè)effect
函數(shù),而同時(shí)新增的empty
函數(shù)被移除,分析原因發(fā)現(xiàn)effect
函數(shù)就是一個(gè)純讀取函數(shù),但是這個(gè)函數(shù)可能會(huì)產(chǎn)生副作用。試想一下,如果obj
對(duì)象是一個(gè)通過(guò)Proxy
創(chuàng)建的代理對(duì)象,那么當(dāng)我們讀取對(duì)象屬性時(shí),就會(huì)觸發(fā)代理對(duì)象的get
方法,在get
方法中是可能產(chǎn)生副作用的,比如調(diào)用其它的方法或者修改一些變量等等。
const foo = () => { console.log('foo'); }; const effect = (obj) => { obj && obj.a; }; var userInfo = { name: function () { console.log('絕對(duì)零度'); }, age: () => { console.log(18); } }; const fn = () => { console.log('fn'); userInfo.name(); effect(); foo(); }; fn();
由于rollup.js分析靜態(tài)代碼很困難,所以他們給我們提供一個(gè)機(jī)制,明確告訴rollup,這部分代碼沒(méi)有副作用可以移除。/*#__PURE__*/
就是解決這個(gè)問(wèn)題的辦法,只需要在effect方法前面加上上面的代碼,程序運(yùn)行的時(shí)候就會(huì)認(rèn)為他是沒(méi)有副作用的,可以放心的進(jìn)行Tree-shaking
。
/*#__PURE__*/const effect = (obj) => { obj && obj.a; };
在Vue的框架源碼中,存在這大量的特性開(kāi)關(guān),打包編譯或者使用的時(shí)候通過(guò)配置特性開(kāi)關(guān)可以通過(guò)Tree-shaking
機(jī)制讓代碼資源最優(yōu)化。
比如Vue3
為了支持Vue2
的options Api
,寫(xiě)了大量的兼容代碼,但是如果我們?cè)偈褂?code>Vue3中不使用options Api
,就可以通過(guò)一個(gè)叫做__VUE_OPTIONS_API__
的特性開(kāi)關(guān)去關(guān)閉這個(gè)特性,這樣最終打包的Vue代碼就不會(huì)包含這部分,進(jìn)而減少代碼體積。
關(guān)于“Vue中Tree-Shaking的原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。