- 创建一个vuecli3项目:
vue create demo-vuecli3-ui
手动选择特性,我这里只要Babel以及Css-Professor;
然后选择Sass/SCSS,开发者按照自己的喜好来选择css预处理语言; - 启动检查是否正常,
npm run serve
:
没问题,一切正常; - 这里组件库的名字为:
demo-vuecli3-ui
,现在开始写组件,这里只写两个组件:
- pl-button
- pl-input
除了这两个组件之外,还需要有一个体积比较大的组件,不然到时候测试按需引入的时候,很难观察到只引入部分组件(比如只引入button)所带来的打包体积优化效果。这里这个体积比较大的组件,使用element-ui来替代,把element-ui当做一个组件看待;
- 安装element-ui
npm i element-ui -D
这里为什么要-D
,-D
是--save-dev
的缩写,-S
是--save
的缩写,--save
会将依赖添加到package.json
的dependency
列表中,如果是--save-dev
,会将依赖添加到devDependency
列表中。将组件打包,然后发布到npm仓库之后,用户可以通过npm i demo-vuecli2-ui --save
安装依赖,这时候,用户安装的时候也会去下载element-ui,这个可以通过观察node_modules/demo-vuecli2-ui
目录验证,这个目录下面也会有一个node_modules文件夹,其中就是demo-vuecli2-ui的dependency列表。实际上用户是不需要再次安装下载element-ui的,所以这里是-D
; - 编写组件,根目录下创建components文件夹,目录结构:
- components
- button
- index.js
- pl-button.vue
- ele
- index.js
- input
- index.js
- pl-input.vue
- index.js
文件内容:
import Button from './pl-button'
Button.install = (Vue) => Vue.component(Button.name, Button);
export default Button
<template>
<div class="pl-button">
pl-button
</div>
</template>
<script>
export default {
name: "pl-button"
}
</script>
<style lang="scss">
.pl-button {
background-color: maroon;
color: white;
}
</style>
import ELE from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
export default {
install(Vue) {
Vue.use(ELE)
},
}
import Input from './pl-input'
Input.install = (Vue) => Vue.component(Input.name, Input)
export default Input
<template>
<div class="pl-input">
pl-input
</div>
</template>
<script>
export default {
name: "pl-input"
}
</script>
<style lang="scss">
.pl-input {
background-color: #42b983;
color: white;
}
</style>
这个是总的打包入口
import Button from './button'
import Input from './input'
import Ele from './ele'
export default {
install(Vue) {
Vue.use(Button)
Vue.use(Input)
Vue.use(Ele)
},
}
这样用户在全引入组件库`demo-vuecli2-ui`,因为element-ui的存在,打包的体积会非常大,而用户在按需引入button以及input的时候,因为没有element-ui,打包的体积会大大缩小; - 修改main.js,全引入
demo-vuecli3-ui
,用来调试组件。import Vue from 'vue'
import App from './App.vue'
import DVU3 from 'demo-vuecli3-ui'
Vue.use(DVU3)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- 修改App.vue,展示组件:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<pl-input/>
<pl-button/>
<el-button>hello world</el-button>
<el-input/>
</div>
</template>
<script>
export default {
name: 'app',
}
</script>
<style lang="scss">
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
- 创建目录,build,创建文件build/utils.js:
const fs = require('fs')
const path = require('path')
const join = path.join
const resolve = (dir) => path.join(__dirname, '../', dir)
module.exports = {
resolve,
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
},
}
- 创建文件build/config.pub.js,这个是本地调试以及打包组件都需要的配置信息:
const utils = require('./utils')
module.exports = {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'src': utils.resolve('src'),
'components': utils.resolve('components'),
'demo-vuecli3-ui': utils.resolve('components/index.js'),
}
},
}
- 创建文件build/config.dev.js,这个是本地调试的时候加载的配置文件:
const pub = require('./config.pub')
module.exports = {
pages: {
index: {
entry: 'src/main.js',
template: 'public/index.html',
filename: 'index.html',
title: 'pl-app document',
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
},
configureWebpack: {
resolve: pub.resolve
},
}
- 创建文件build/config.build.js,这个是打包组件的时候,加载的配置文件:
const {resolve, getComponentEntries} = require('./utils')
const pub = require('./config.pub')
module.exports = {
outputDir: resolve('lib'),
configureWebpack: {
entry: {
...getComponentEntries('components'),
},
output: {
filename: '[name]/index.js',
libraryTarget: 'commonjs2',
libraryExport: 'default',
library: 'demo-vuecli3-ui',
},
resolve: pub.resolve,
},
css: {
sourceMap: true,
extract: {
filename: '[name]/style.css'
}
},
chainWebpack: config => {
config.optimization.delete('splitChunks')
config.plugins.delete('copy')
config.plugins.delete('preload')
config.plugins.delete('prefetch')
config.plugins.delete('html')
config.plugins.delete('hmr')
config.entryPoints.delete('app')
config.module
.rule('fonts')
.use('url-loader')
.tap(option => {
option.fallback.options.name = 'static/fonts/[name].[hash:8].[ext]'
return option
})
}
}
这里面主要讲chainWebpack中做了什么事情:
- 删除splitChunks,在打包组件的时候,并不希望抽离每个组件的公共js出来,而是每个独立打包,于是删除这个配置;
- 删除copy:不要复制public文件到打包目录;
- 删除preload以及prefetch,因为删除了html插件,所以这两个也没用;
- 删除html,只打包组件,不生成html页面;
- 删除hmr,删除hot-module-reload;
- 删除自动加上的入口:app
- 下面的配置fonts这个rule,打包字体的时候,输出到打包目录的static/fonts目录下;
- 本地调试启动,检查效果:
npm run serve
- 打包:
npm run build
,打包结果:
- 修改package.json
- 修改版本号version为
0.0.1
- 删除private:true
- 添加"main":“lib/index/index.js”
- 添加"files":[“lib”]
- 发布到npm,
npm publish
看到这个+ demo-vuecli3-ui
就表示发布成功。 - 使用上一篇创建的测试工程
test-load-on-demand
测试demo-vuecli3-ui
的按需引入功能是否完成。安装demo-vuecli3-ui:npm i demo-vuecli3-ui -S
- src/main.js中全引入demo-vuecli3-ui:
import Vue from 'vue'
import App from './App.vue'
import DVU3 from 'demo-vuecli3-ui'
import 'demo-vuecli3-ui/lib/index/style.css'
Vue.use(DVU3)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- 本地调试启动,检查效果:
可以看到,app.js大概有4.1m - 打包页面,检查效果:
可以看到,chunk-vendor有800多k - 配置按需引入,安装插件:
babel-plugin-import
npm i babel-plugin-import -D
- 配置.babelrc文件:
{
"presets": ["@vue/app", ["@babel/preset-env", { "modules": false }]],
"plugins": [
[
"import",
{
"libraryName": "demo-vuecli3-ui",
"style": true
}
]
]
}
- 配置src/main.js,按需引入Button以及Input组件:
import Vue from 'vue'
import App from './App.vue'
import {Button, Input} from 'demo-vuecli3-ui'
Vue.use(Button)
Vue.use(Input)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- 本地调试启动,检查效果:
可以看到,app.js的大小变为1.8m - 打包页面,检查效果:
可以看到,chunk-vendor变成了123k,体积大大缩小了;