一定要避免全文件模块引入、全局引入吗?实验告诉你答案

前言

我们在使用脚手架工具的时候一定是离不开webpack,但是很多人对于是不是一定要避免全局引入、全模块引入还很模糊,今天我做一系列实验来测试一下。

全文件模块引入VS文件内部分模块按需引入

全文件模块引入也就是:

import abc from '@/modules/abc.js'
abc.a()

文件内部分模块按需引入也就是:

import {a} from '@/modules/abc.js'
a()

我们搭建一个vue-cli 4,注意关掉eslint。然后测试这两种写法带来的dist文件大小差距。先说上面代码的对比,导致的大小差距应该就是大约4个字节的差别,差别不明显,我们的abc.js要写的大一点,比如:

全文件模块引入的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')
  },
}

文件内部分模块按需引入的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')
  }

再分别写上对应的import写法,然后yarn build,之后查看js文件夹三个js文件的大小之和:

全文件模块引入:151,657 字节
文件内部分模块按需引入:150,402 字节

相差1200多字节!那么我们再搜搜看,按需引入的js文件里面有没有一连串的a字符呢?答案是有,然后再试试搜一连串的bc字符呢?答案是搜不到。

结论一:按需引入,真的可以减小dist体积。

第二个问题:按需引入前提下,export之外的代码,会被打包吗?

在abc.js顶部加上const x = 'xxxxxxxxxxxxxxx',然后在a模块console.log(x)。yarn build之后,搜索dist的js,搜一连串x,结果能搜到。

然后,把a模块的console.log(x)挪到b模块,重新build。搜索dist的js,搜一连串x,结果搜不到。

结论二:webpack会判断export之外的代码是否需要引入,需要的话,也会打包。不需要就不打包。

有人说,我在export之外敲一个console.log('yyyyyyyyyyyyyy'),结果被打包了,怎么解释?

很好解释啊,这行代码,以webpack的智慧,不可能判断出它是对项目有用的还是没用的,所以只好给打包上了。而且,在export之外写跟模块无关的代码,是不是脑抽?

结论三:export之外的代码,凡是webpack无法判断有没有用的,它会按照有用来处理。请不要写与模块无关的代码,也不要为难webpack,错在你,不在于webpack。

有人问,一个vue文件使用了a模块,另一个vue文件使用了b和c模块,按需引入还有意义吗?

继续做实验。

全文件引入写法,dist的js文件之和是151,752 字节
按需引入写法,dist的js文件之和是151,860 字节

相差108个字节。差距应该是体现在了按需引入方案webpack打包之后的一些边边角角的引入语句上,毕竟拆开引入要重复写若干遍引入语句。

结论四:文件的所有模块都用得到的前提下,还是全文件引入的写法节省字节(尽管节省的很有限),而且,全文件写法还有一个更大的优点就是,它的执行是abc.a(),而按需引入是a(),无疑,abc.a()会让你知道a方法是从哪来的,书写更为清晰。

结论五:开发者自己编的模块,要分成两类:
1、针对服务全局的模块;
2、针对服务某个页面或组件的模块。
对于针对服务全局的模块,应当按需引入,理由在本文后半部分有讨论。
对于针对服务某个页面或组件的模块,应在页面或组件里全文件引入,这样思路更简单,代码清晰度更高。
同理,对于开源组件库的引入,如果你能确定所有组件全用得到(这一点很难做到,比如一个组件库提供50个组件,你敢说你50个你会全用遍?),就一定要全文件引入,否则,还是按需引入的好。

本文附赠一个实验,拿Vant组件库的几种引入方法,做实验测试一下。

现在打开Vant的官网看它的手册,它介绍了几种引入方法,我们一一测试。

Vant两种引入模式测试

yarn add vant安装是没啥说的。

方式一. 自动按需引入组件(Vant官方推荐)

官方要求安装babel-plugin-import,由于它只作为dev依赖,不影响打包体积,所以咱们放心装上:yarn add babel-plugin-import --dev。然后在babel.config.js中配置,也不多说。然后使用import { Button } from 'vant';来引用组件即可,并不需要Vue.use(Button);

然后我们在Home.vue写一个button。

<van-button type="default">这是个按钮</van-button>
import {Button} from 'vant'
  components: {
    VanButton: Button
  }

dist得到146,791字节。

方式二、手动按需引入组件

去babel.config.js删除掉配置,改用方式二,也就是引入方式有区别。

import Button from 'vant/lib/button';
import 'vant/lib/button/style';

dist得到150,926字节。

结论六:Vant官方推荐的引入方式确实能节省体积。

到此,全文件引入和按需引入的对比就结束了,然后我们实验一下某个组件全局引入和局部引入的区别。

单一组件全局引入VS局部引入

拿Vant的Icon组件做一个测试。

局部引入

首先我们在2个.vue文件内局部引入Icon组件。

<van-icon name="close" /><van-icon name="chat" info="99+" />
import {Icon} from 'vant';
  components: {
    VanIcon: Icon
  }

dist得到144,325字节。

全局引入

main.js:

const globalComponents = {
  install: () => {
    Vue.component('VanIcon', Icon)
  }
}
Vue.use(globalComponents)

组件内去掉import和components变量。

dist得到144,332 字节。

相比之下,两种方式相差7字节,局部引入方式体积小。但是!因为全局引入写了一个install方法占了100多字节,而局部引入多写的那些代码加起来也没有90字节。所以结论是:

结论七:全局引入节省字节,其实这很好理解,一次引入,全局使用,当然省字节。而且项目越大,全局引入就越节省字节。

其实,这两种方式对于代码量的差别已经是次要矛盾,因为两种引入方式打包进来的组件体积是差不多的,并不是说局部多次引入就会多次打包,这个常识我就不做实验了。主要矛盾集中在内存占用和js文件按需加载方面。

全局引入的优势:

  1. 一次引入,全局使用,无需任何局部引入的语句。

局部引入的优势:

  1. 最大优势就是拆分js文件带来的优势,也就是说,一些组件只在某些.vue里使用,结合webpack的路由懒加载,那么这些Vant组件所在的js文件将会在即将被使用的时候才会网络请求它,这样会提高首屏打开速度。

  2. 默认不加载一些Vant组件,也会降低JS的内存占用。

这时候结论差不多可以总结一下了:

结论八:如果一个Vant组件在80%的页面都会用到,尤其是首页会用到,比如一个移动项目,NavBar、Icon和Button在95%的页面都有用到,那么一定要全局引入它。如果一个Vant组件在20%或更少的页面用到,比如Uploader组件,应当局部引入它。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容