前言
我們?cè)谑褂媚_手架工具的時(shí)候一定是離不開webpack,但是很多人對(duì)于是不是一定要避免全局引入院仿、全模塊引入還很模糊,今天我做一系列實(shí)驗(yàn)來測(cè)試一下速和。
全文件模塊引入VS文件內(nèi)部分模塊按需引入
全文件模塊引入也就是:
import abc from '@/modules/abc.js'
abc.a()
文件內(nèi)部分模塊按需引入也就是:
import {a} from '@/modules/abc.js'
a()
我們搭建一個(gè)vue-cli 4歹垫,注意關(guān)掉eslint。然后測(cè)試這兩種寫法帶來的dist文件大小差距颠放。先說上面代碼的對(duì)比排惨,導(dǎo)致的大小差距應(yīng)該就是大約4個(gè)字節(jié)的差別,差別不明顯碰凶,我們的abc.js要寫的大一點(diǎn)暮芭,比如:
全文件模塊引入的abc.js:
export default {
a() {
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
},
b() {
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
},
c() {
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
},
}
文件內(nèi)部分模塊按需引入的abc.js:
export function a() {
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
}
export function b() {
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
console.log('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')
}
export function c() {
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
console.log('ccccccccccccccccccccccccccccccccccccccccccccc')
}
再分別寫上對(duì)應(yīng)的import寫法,然后yarn build欲低,之后查看js文件夾三個(gè)js文件的大小之和:
全文件模塊引入:151,657 字節(jié)
文件內(nèi)部分模塊按需引入:150,402 字節(jié)
相差1200多字節(jié)辕宏!那么我們?cè)偎阉芽矗葱枰氲膉s文件里面有沒有一連串的a
字符呢砾莱?答案是有瑞筐,然后再試試搜一連串的b
和c
字符呢?答案是搜不到腊瑟。
結(jié)論一:按需引入聚假,真的可以減小dist體積块蚌。
第二個(gè)問題:按需引入前提下,export之外的代碼膘格,會(huì)被打包嗎峭范?
在abc.js頂部加上const x = 'xxxxxxxxxxxxxxx'
,然后在a模塊console.log(x)
瘪贱。yarn build之后纱控,搜索dist的js,搜一連串x政敢,結(jié)果能搜到其徙。
然后,把a(bǔ)模塊的console.log(x)
挪到b模塊喷户,重新build唾那。搜索dist的js,搜一連串x褪尝,結(jié)果搜不到闹获。
結(jié)論二:webpack會(huì)判斷export之外的代碼是否需要引入,需要的話河哑,也會(huì)打包避诽。不需要就不打包。
有人說璃谨,我在export之外敲一個(gè)console.log('yyyyyyyyyyyyyy')
沙庐,結(jié)果被打包了,怎么解釋佳吞?
很好解釋啊拱雏,這行代碼,以webpack的智慧底扳,不可能判斷出它是對(duì)項(xiàng)目有用的還是沒用的铸抑,所以只好給打包上了。而且衷模,在export之外寫跟模塊無關(guān)的代碼鹊汛,是不是腦抽?
結(jié)論三:export之外的代碼阱冶,凡是webpack無法判斷有沒有用的刁憋,它會(huì)按照有用來處理。請(qǐng)不要寫與模塊無關(guān)的代碼熙揍,也不要為難webpack职祷,錯(cuò)在你,不在于webpack。
有人問有梆,一個(gè)vue文件使用了a模塊是尖,另一個(gè)vue文件使用了b和c模塊,按需引入還有意義嗎泥耀?
繼續(xù)做實(shí)驗(yàn)饺汹。
全文件引入寫法,dist的js文件之和是151,752 字節(jié)
按需引入寫法痰催,dist的js文件之和是151,860 字節(jié)
相差108個(gè)字節(jié)兜辞。差距應(yīng)該是體現(xiàn)在了按需引入方案webpack打包之后的一些邊邊角角的引入語句上,畢竟拆開引入要重復(fù)寫若干遍引入語句夸溶。
結(jié)論四:文件的所有模塊都用得到的前提下逸吵,還是全文件引入的寫法節(jié)省字節(jié)(盡管節(jié)省的很有限),而且缝裁,全文件寫法還有一個(gè)更大的優(yōu)點(diǎn)就是扫皱,它的執(zhí)行是abc.a()
,而按需引入是a()
捷绑,無疑韩脑,abc.a()
會(huì)讓你知道a方法是從哪來的,書寫更為清晰粹污。
結(jié)論五:開發(fā)者自己編的模塊段多,要分成兩類:
1、針對(duì)服務(wù)全局的模塊壮吩;
2进苍、針對(duì)服務(wù)某個(gè)頁面或組件的模塊。
對(duì)于針對(duì)服務(wù)全局的模塊鸭叙,應(yīng)當(dāng)按需引入琅捏,理由在本文后半部分有討論。
對(duì)于針對(duì)服務(wù)某個(gè)頁面或組件的模塊递雀,應(yīng)在頁面或組件里全文件引入,這樣思路更簡單蚀浆,代碼清晰度更高缀程。
同理,對(duì)于開源組件庫的引入市俊,如果你能確定所有組件全用得到(這一點(diǎn)很難做到杨凑,比如一個(gè)組件庫提供50個(gè)組件,你敢說你50個(gè)你會(huì)全用遍摆昧?)撩满,就一定要全文件引入,否則,還是按需引入的好伺帘。
本文附贈(zèng)一個(gè)實(shí)驗(yàn)昭躺,拿Vant組件庫的幾種引入方法,做實(shí)驗(yàn)測(cè)試一下伪嫁。
現(xiàn)在打開Vant的官網(wǎng)看它的手冊(cè)领炫,它介紹了幾種引入方法,我們一一測(cè)試张咳。
Vant兩種引入模式測(cè)試
yarn add vant
安裝是沒啥說的帝洪。
方式一. 自動(dòng)按需引入組件(Vant官方推薦)
官方要求安裝babel-plugin-import,由于它只作為dev依賴脚猾,不影響打包體積葱峡,所以咱們放心裝上:yarn add babel-plugin-import --dev
。然后在babel.config.js中配置龙助,也不多說砰奕。然后使用import { Button } from 'vant';
來引用組件即可,并不需要Vue.use(Button);
泌参。
然后我們?cè)贖ome.vue寫一個(gè)button脆淹。
<van-button type="default">這是個(gè)按鈕</van-button>
import {Button} from 'vant'
components: {
VanButton: Button
}
dist得到146,791字節(jié)。
方式二沽一、手動(dòng)按需引入組件
去babel.config.js刪除掉配置盖溺,改用方式二,也就是引入方式有區(qū)別铣缠。
import Button from 'vant/lib/button';
import 'vant/lib/button/style';
dist得到150,926字節(jié)烘嘱。
結(jié)論六:Vant官方推薦的引入方式確實(shí)能節(jié)省體積。
到此蝗蛙,全文件引入和按需引入的對(duì)比就結(jié)束了蝇庭,然后我們實(shí)驗(yàn)一下某個(gè)組件全局引入和局部引入的區(qū)別。
單一組件全局引入VS局部引入
拿Vant的Icon組件做一個(gè)測(cè)試捡硅。
局部引入
首先我們?cè)?個(gè).vue文件內(nèi)局部引入Icon組件哮内。
<van-icon name="close" /><van-icon name="chat" info="99+" />
import {Icon} from 'vant';
components: {
VanIcon: Icon
}
dist得到144,325字節(jié)。
全局引入
main.js:
const globalComponents = {
install: () => {
Vue.component('VanIcon', Icon)
}
}
Vue.use(globalComponents)
組件內(nèi)去掉import和components變量壮韭。
dist得到144,332 字節(jié)北发。
相比之下,兩種方式相差7字節(jié)喷屋,局部引入方式體積小琳拨。但是!因?yàn)槿忠雽懥艘粋€(gè)install方法占了100多字節(jié)屯曹,而局部引入多寫的那些代碼加起來也沒有90字節(jié)狱庇。所以結(jié)論是:
結(jié)論七:全局引入節(jié)省字節(jié)惊畏,其實(shí)這很好理解,一次引入密任,全局使用颜启,當(dāng)然省字節(jié)。而且項(xiàng)目越大批什,全局引入就越節(jié)省字節(jié)农曲。
其實(shí),這兩種方式對(duì)于代碼量的差別已經(jīng)是次要矛盾驻债,因?yàn)閮煞N引入方式打包進(jìn)來的組件體積是差不多的乳规,并不是說局部多次引入就會(huì)多次打包,這個(gè)常識(shí)我就不做實(shí)驗(yàn)了合呐。主要矛盾集中在內(nèi)存占用和js文件按需加載方面暮的。
全局引入的優(yōu)勢(shì):
- 一次引入,全局使用淌实,無需任何局部引入的語句冻辩。
局部引入的優(yōu)勢(shì):
最大優(yōu)勢(shì)就是拆分js文件帶來的優(yōu)勢(shì),也就是說拆祈,一些組件只在某些.vue里使用恨闪,結(jié)合webpack的路由懶加載,那么這些Vant組件所在的js文件將會(huì)在即將被使用的時(shí)候才會(huì)網(wǎng)絡(luò)請(qǐng)求它放坏,這樣會(huì)提高首屏打開速度咙咽。
默認(rèn)不加載一些Vant組件,也會(huì)降低JS的內(nèi)存占用淤年。
這時(shí)候結(jié)論差不多可以總結(jié)一下了:
結(jié)論八:如果一個(gè)Vant組件在80%的頁面都會(huì)用到钧敞,尤其是首頁會(huì)用到,比如一個(gè)移動(dòng)項(xiàng)目麸粮,NavBar溉苛、Icon和Button在95%的頁面都有用到,那么一定要全局引入它弄诲。如果一個(gè)Vant組件在20%或更少的頁面用到愚战,比如Uploader組件,應(yīng)當(dāng)局部引入它齐遵。