Vue组件库实现按需加载功能
文章目录简述示例原理babel-plugin-componentelement-ui按需引入babel-plugin-import组件分开打包以及全部打包组件分开打包组件全部打包入口测试按需引入简述按需加载就是需要什么,就只要什么,其他的东西不要。这样做的目的是为了缩小打包体积。示例比如当前流行的web端组件库ElementUI,就有这个按需加载功能;一个系统的登录页,需要的组件是非常少的...
文章目录
简述
按需加载就是需要什么,就只要什么,其他的东西不要。这样做的目的是为了缩小打包体积。
示例
比如当前流行的web端组件库ElementUI,就有这个按需加载功能;一个系统的登录页,需要的组件是非常少的,大多数都是只用到Input输入框以及Button按钮。所以为了能够提高登录页面的加载速度,需要使用ElementUI的按需加载功能,只引入输入框以及按钮,这样用户在打开登录页的时候,就不需要等待太久,会有一个比较好的用户体验;
原理
本文的原理参考ElementUI,只不过要做的东西比element要简单很多。element在使用按需引入的时候,需要开发者在自己的项目上使用插件babel-plugin-component,这个插件可以将代码中的引入代码进行转换
babel-plugin-component
import { Button } from 'components'
这句代码会被转换成:
var button = require('components/lib/button')
require('components/lib/button/style.css')
这个components
就是依赖的名称,比如element-ui
,那它怎么知道引入的是lib目录下的button,而不是其他目录下的button,这个是需要配置.babelrc
这个配置文件,接下来以element-ui的按需引入配置进行示例说明。
element-ui按需引入
配置.babelrc
文件
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
以下代码,会被转换:
import {Button,Icon} fron 'element-ui'
会被转换成以下代码
const Button = require('element-ui/lib/button.js`)
require('element-ui/theme-chalk/button.css')
const Icon = require('element-ui/lib/icon.js')
require('element-ui/theme-chalk/icon.css')
其中在引入css的时候,其中的theme-chalk
路径是通过.babelrc文件中的styleLibraryName
确定的,
引入js的时候,其中的lib
是通过.babelrc文件中的libDir
属性决定的,只不过这个属性的默认值是lib;
接下来看一下,在node_modules中的element-ui的结构,先看js
再看css:
看package.json中的main:
看完这个结构之后,大家应该明白了,当全引入的时候:
import ELEMENT from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
这两句代码,就相当于引入截图中的element-ui.common.js
以及theme-chalk/index.css
;当按需引入组件的时候,就是分别引入对应组件的js以及css文件,而babel-plugin-component
只是帮忙转换了一下语法而已,所以说,按需引入,是需要组件库打包出来的文件支持的,如果element-ui没有分别打包这些组件,那么调用者是无法实现按需引入功能的;
babel-plugin-import
因为现在使用vue-cli3脚手架创建的vue工程是使用babel7编译的,babel-plugin-component
已经不再适用于babel7,文本将会使用babel-plugin-import实现按需引入的功能。其实babel-plugin-import
与babel-plugin-component
差异不大,就是做一下语法转换。
组件分开打包以及全部打包
刚刚在分析element-ui的打包目录可以知道,当需要按需引入的时候,会分别引入对应组件的js以及css,所以不同的组件都需要打包,所以在webpack配置中,每个组件都需要有一个打包入口。同时还需要有一个总的打包入口,这个入口文件引入所有的组件并且注册
组件分开打包
组件库中的组件是非常多的,如果每一个入口文件都是手动在webpack配置文件中维护的话,会非常麻烦,这里设定一个规则,所有的组件都放在某个目录下,这里为components
,打包的时候,自动扫描这个目录。自动生成入口配置信息。示例:
- components
- button
- pl-button.vue
- index.js
- ele
- index.js
- icon
- pl-icon.vue
- index.js
- input
- pl-input.vue
- index.js
里面的index.js就是每一个组件的入口文件,组件的入口文件暴露一个install方法,用来注册组件,比如button中的入口文件:
import Button from './pl-button'
Button.install = (Vue) => Vue.component(Button.name, Button)
export default Button
当需要按需引入button的时候,可以通过以下方式使用这个组件:
const Button = require('[button打包之后得到的js地址]')
Vue.use(Button)
扫描组件入口信息:
/*build/utils.js*/
const fs = require('fs')
const path = require('path')
const join = path.join
const resolve = (dir) => path.join(__dirname, '../', dir)
function getComponentEntries(path) {
let files = fs.readdirSync(resolve(path));
const componentEntries = files.reduce((ret, item) => {
const itemPath = join(path, item)
const isDir = fs.statSync(itemPath).isDirectory();
if (isDir) {
ret[item] = resolve(join(itemPath, 'index.js'))
} else {
const [name] = item.split('.')
ret[name] = resolve(`${itemPath}`)
}
return ret
}, {})
console.dir(componentEntries)
return componentEntries
}
getComponentEntries('components')
得到的结果:
这样就得到的所有组件的入口配置信息;
组件全部打包入口
当不需要按需引入的时候,开发者引入的是总的打包文件,这个总的打包文件是通过总的打包入口文件打包而来的,根据上面的组件信息,总的打包入口文件:
/*src/index.js*/
import Button from 'components/button'
import Icon from 'components/icon'
import Ele from 'components/ele'
const PlainApp = {
install(Vue) {
Vue.use(Button)
Vue.use(Icon)
Vue.use(Ele)
}
}
export default PlainApp
同时,还需要在打包入口中增加总的打包入口文件地址:
entry:{
index: resolve('src/index.js'),
},
所以,最后的入口信息为:
entry: {
...getComponentEntries('components'),
index: resolve('src/index.js'),
},
测试按需引入
为了测试我们自己创建的组件库能够支持按需引入,我们需要创建一个示例工程,用来测试按需引入是否成功,这里我们使用vuecli3脚手架创建的工程来测试,不过在测试我们自己创建的组件库之前,先测试element-ui的按需引入功能,看看有哪些特性
- 创建一个vuecli3工程:
配置随意,我这里选手动选择特性,只要vue create test-load-on-demend
Babel
以及Css Pre-preocessor
然后选择Sass/SCSS
,剩下的随意。 - 启动测试
npm run serve
一切正常 - 安装element-ui
npm i element-ui -S
- 在main.js中全部安装element-ui
import Vue from 'vue' import App from './App.vue' import ELEMENT from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ELEMENT) Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
- 在App.vue中使用element的button组件以及input组件,同时去掉App.vue中自带的HellWorld组件,以及删除HelloWorld.vue这个文件,因为不需要这个。
/*src/App.Vue*/ <template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> <el-button>hello world</el-button> <el-input/> </div> </template> <script> export default { name: 'app', } </script> <style lang="scss"> </style>
- 启动,勾上这个
Disabled cache
,在刷新一下页面。
可以看到,app.js的大小为6.7M - 在根目录下创建
vue.config.js
,配置publicPath
为./
;
这么做可以使得打包出来的文件,可以通过file协议打打开,查看效果。/*vue.config.js*/ module.exports = { publicPath: './' }
- 打包页面
在生成的dist目录中,直接打开index.htmlnpm run build
同理,打开之后,调出控制台,勾上Disabled cache
,刷新:
可以看到,chunk-vendor文件的大小为700多k。 - 现在配置按需引入,只要button以及input组件,首先删除根目录下的babel.config.js,新建一个.babelrc文件:
/*.babelrc*/ { "presets": ["@vue/app", ["@babel/preset-env", { "modules": false }]], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
- 安装
babel-plugin-component
npm i babel-plugin-component -S
- 修改
main.js
,调整为按需引入组件,只要Button以及Inputimport Vue from 'vue' import App from './App.vue' /*import ELEMENT from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ELEMENT)*/ import {Button,Input} from 'element-ui' Vue.use(Button) Vue.use(Input) Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
- 启动,同样的,查看app.js大小
可以看到,app.js的大小变为2m左右了; - 接下来打包
会稍微感觉到,打包要比上次快了很多,因为只打包了两个组件。打包完之后,打开index.html:npm run build
可以看到,chunk-vendor只剩下33k左右,性能上有了巨大的优化。
组件库按需引入实现
好了,现在已经准备好了测试工程,准备开始实现我们自己的组件库工程,使得自己开发的组件库工程也有按需引入的功能,下面介绍两种方式创建组件库工程,实现按需引入功能
- 基于vuecli2创建的webpack工程,基于这个工程开发组件库,并实现按需引入功能
- 基于vuecli3创建的webpack工程,基于这个工程开发组件,并且实现按需引入功能
这里为什么要分为两种方式,一个是vuecli2创建的webpack工程,配置可以自主定义,较为灵活,因为webpack的配置文件都暴露出来了;另一个vuecli3创建的工程使用方便,简化了配置文件,同时很方便配置多单页面应用,以及其他打包配置。但是,两个工程实现按需引入功能的方式,却是有很大的差别。
test-load-on-demand工程地址
vuecli2创建的组件库工程实现按需引入
vuecli3创建的组件库工程实现按需引入
更多推荐
所有评论(0)