前言
在之前的文章中,我们已经知道怎么去创建一个组件了,并且怎么初始化,但是有没有发现一个细节,就是 element-ui
除了完整引入的方式,比如:1
2
3
4import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
还支持按需引入的方式:1
2
3
4
5
6
7
8import { Button, Select } from 'element-ui';
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
/* 或写为
* Vue.use(Button)
* Vue.use(Select)
*/
听说这种方式可以减少项目体积。 如果本节讲一下 air-ui
怎么做到按需引入。
按需引入
说道按需引入,我的想法就是先将 components/index.js
这个入口文件,除了导出 intall
方法, 其他的组件也应该可以被导出来:
所以原先是这样子的:1
2
3export default {
install
}
改成这样子:1
2
3
4
5
6
7export default {
install,
Button,
ButtonGroup,
Notification,
Loading
}
这样子现有的几个已经做好的组件也可以一起导出来了。 然后我们改一下 main.js
的方式, 改成:1
2
3
4
5
6// import AirUI from './components/index'
import { Button } from './components/index'
import './styles/index.scss'
// Vue.use(AirUI)
Vue.use(Button)
但是编译的时候,报错了:
后面查了一下,好像 export default
导出的方式,不支持导出多个命名模块,只能导出一个默认模块。 所以如果要导出多个命名模块的话,那么只能用 export
来导出模块,所以改成这样子:1
2
3
4
5
6
7module.exports = {
install,
Button,
ButtonGroup,
Notification,
Loading
}
但是发现还是报一样的错误,好像没有起效果?? 后面在网上查了一下,好像改成这样还不够,还需要 babel
兼容 es2015
, 所以我在 .babelrc
加上这一行:1
["es2015", { "loose": true }],
然后还得安装对应的 babel 插件:1
"babel-preset-es2015": "^6.24.1",
1 | yarn add babel-preset-es2015 --dev |
这样子构建就正常了。 可以看到
按钮是显示正常的,但是原先的那个按钮组显示确实有问题的?? 这个是因为我没有在 main.js
引用这个 button-group
组件,所以 vue 找不到这个组件:
所以只要再把这个加上去就行了,所以改成1
2
3
4
5
6import { Button, ButtonGroup } from './components/index'
import './styles/index.scss'
// Vue.use(AirUI)
Vue.use(Button)
Vue.use(ButtonGroup)
这样就正常了
这边需要注意一点的是,要完成这种语法糖,上面两个条件都要满足:
export default
改成module.exports
- 安装
babel-preset-es2015
并修改.babelrc
如果只加了 es2015
的 babel
支持,但是 export
没有改成 module.exports
的方式,虽然构建不会失败,但是界面是有问题的:
没法实现按需引入?
首先需要恭喜的是,我们完成了组件库中部分引入的语法糖。但是下一个问题就是,我们要实现部分引入的写法是为了按需引入从而减少项目体积。但是上面那种写法是根本不能减少项目体积,他的原理还是将整个组件库都引入,只不过使用的是导出的那几个组件。并不会减少体积。那么 element ui
是怎么实现按需引入的,又是怎么在不将export default
改成 module.exports
的情况下,实现部分引入的语法糖的?
element ui 怎么实现部分导出的语法糖?
我们通过上述的实践发现,要满足两个条件,才能实现这种部分组件导出的语法糖1
import { Button, ButtonGroup } from './components/index'
那为啥 element-ui
在 src/index.js
中用的也是默认的 export default {
的语法,那么为啥他也可以实现部分导出的语法糖??
我们来做个试验,在 element-ui
的源码项目,对 examples/entry.js
这个入口文件做一下调整,也换成这个这种部分导出的方式:1
2
3
4
5
6
7
8
9// import Element from 'main/index.js';
import {
Button,
ButtonGroup
} from 'main/index.js';
// Vue.use(Element);
Vue.use(Button);
Vue.use(ButtonGroup);
其他代码不变,还是用 export default
导出组件,然后运行一下,发现还是报错了:1
2
3
4
5
6
7WARNING in ./examples/entry.js 26:8-14
"export 'Button' was not found in 'main/index.js'
@ multi (webpack)-dev-server/client?http://0.0.0.0:8085 (webpack)/hot/dev-server.js ./examples/entry.js
WARNING in ./examples/entry.js 27:8-19
"export 'ButtonGroup' was not found in 'main/index.js'
@ multi (webpack)-dev-server/client?http://0.0.0.0:8085 (webpack)/hot/dev-server.js ./examples/entry.js
还是显示找不到组件,这个说明一个问题,就是源码的 dev 环境的 demo 下,也是不能用这种部分导出的语法糖,但是下载的第三方包的 element-ui
确实是支持这种语法的。所以我怀疑它是在打组件包的过程中,是有进行一些处理的。至于是什么处理,这个后面我再说。
element ui 按需引入是否真的能节省体积?
接下来我们在实验一下用 element ui 的按需引入是否真的可以节省体积?
实验基础
先用 vue-cli
搭建一个基础项目,然后安装 element 依赖。 然后在项目默认自带的 HelloWorld.vue
加上这些组件引用:1
2
3
4
5<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
接下来会有各种条件,但是都是打成 pord 环境的包,然后对比 js 和 css 的大小,从而得出是否有减少体积。其中 prod 打包指令为:1
npm run build
然后为了验证界面正常,我们也会启用静态 webserver 将 dist 目录开起来:1
http-server ./dist -p 8089
而且打完包 dist/static
目录下的 js 目录会有三个文件, app.xxx.js
, manifest.xxx.js
, vendor.xxx.js
, 而 element-ui
是属于第三方工具包,所以我们只看 vendor.xxx.js
和 css 目录下的app.xxx.css
的体积变化。
1.不引入 element 打包
啥都不引入,打完之后:1
2vendor.xxx.js -> 119kb
app.xxx.css -> 1kb
2.全部引入 element
1 | import ElementUI from 'element-ui' |
打完之后:1
2vendor.xxx.js -> 803kb
app.xxx.css -> 229kb
可以很明显的看到,体积都大了
3.部分引入 button, css 全部引入
1 | import { Button } from 'element-ui' |
打完之后:1
2vendor.xxx.js -> 803kb
app.xxx.css -> 229kb
发现没有任何变化?? 这个说明按需引入和全部引入没有半毛钱差别?? 后面查了一下,发现我们漏了一个环境,原来按需引入是要配置一下环境的:
4.配置后的部分引入 button, css 全部引入
我们按照它的指导配置一下, 安装插件:1
yarn add babel-plugin-component --dev
然后修改 .babelrc
:1
2
3
4
5
6
7
8
9
10
11
12{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
改为之后,发现打包会报错:
后面查了一下,发现少了一个依赖,然后再装:1
yarn add babel-preset-es2015 --dev
这下子终于打包正常了,打完包之后:1
2vendor.xxx.js -> 672kb
app.xxx.css -> 229kb
我们发现 vendor 的体积真的变少了,从 803kb
减少到 672kb
。 样式还是没有变。 但是感觉减的不是很多啊,我只引入了一个 button
组件而已,js 的体积也从 119kb
变成 672kb
,感觉也不划算,我还不如全部引入呢!!
5.配置后的部分引入 button, css 不引入
接下来我们试下一样部分引入,但是不显示的引入 css 文件了。结果打完包之后发现:1
2vendor.xxx.js -> 672kb
app.xxx.css -> 229kb
跟上面的结果一样。这个说明 element-ui
按需引入的时候,会自动加载 index.css
文件,而不管 main.js
是否有引入 css 文件。
结论
通过上面的测试来看,element-ui
配合一些配置的话,还是可以实现按需引入,从而减少体积的。
air-ui 的按需引入
air-ui
其实也是有按需引入的,只不过是组件单独引入的方式,以目前第一版的来看,还是在一个初始化的 vue-cli
项目中,我们在 dependencies
中加入 air-ui:1
"air-ui": "git+ssh://git@gitlab.xxx.com:air-ui.git#v0.0.30"
然后执行 yarn
安装依赖,这时候就安装成功了
我们还是一样只引入 button
组件,同时在默认的 HelloWorld.vue
补上对应的 html 代码:1
2
3
4
5<air-button type="primary">主要按钮</air-button>
<air-button type="success">成功按钮</air-button>
<air-button type="info">信息按钮</air-button>
<air-button type="warning">警告按钮</air-button>
<air-button type="danger">危险按钮</air-button>
然后部分引入的代码如下:1
2
3
4import Button from 'air-ui/lib/button'
import 'air-ui/lib/styles/button.css'
Vue.use(Button)
最后打包之后的体积如下:1
2vendor.xxx.js -> 121kb
app.xxx.css -> 11kb
可以看到如果只是少数的组件的话,同样的界面,但是这种单独引入的方式,无论是 js 的体积,还是 css 的体积,都会少非常多,因为这个才是真正的只引入组件相关的逻辑和样式,其他不相干的,全部不加载。 而且还不需要对环境进行额外的配置。这一点 element-ui
是需要的,不然他的这种语法糖也没能起到节省体积的作用。
关于单个组件怎么打包出来的,这一点会在讲打包构建的时候,一起讲。
总结
目前 air-ui
通过部分导入的语法糖并不能真正的实现按需引入和节省体积。这一点后面可以改成跟 element-ui
一样,甚至更方便。 (作为一个 todo 项)
但是说真的,如果真的对体积太过 care 的话,其实 air-ui
的那种组件单个引入的方式更能节省体积,就是写法上没有那么优雅就是了。
系列文章:
自建vue组件 air-ui (1) -- 为啥我要自建一个类 element ui 的组件
自建vue组件 air-ui (2) -- 先分析一下 element ui 项目
自建vue组件 air-ui (3) -- css 开发规范
自建vue组件 air-ui (4) -- air-ui 环境搭建和目录结构
自建vue组件 air-ui (5) -- 创建第一个组件 Button
自建vue组件 air-ui (6) -- 创建内置服务组件
自建vue组件 air-ui (7) -- 创建指令组件
自建vue组件 air-ui (8) -- 实现部分引入组件
自建vue组件 air-ui (9) -- 用 vuepress 写文档
自建vue组件 air-ui (10) -- vuepress 写文档 (进阶版)
自建vue组件 air-ui (11) -- vuepress 写文档 (爬坑版)
自建vue组件 air-ui (12) -- 国际化机制
自建vue组件 air-ui (13) -- 国际化机制(进阶版)
自建vue组件 air-ui (14) -- 打包构建(dev 和 dist)
自建vue组件 air-ui (15) -- 主题定制
自建vue组件 air-ui (16) -- 打包构建 pub 任务
自建vue组件 air-ui (17) -- 开发爬坑篇以及总结