vuecli3创建的组件库工程实现按需引入
工程地址创建一个vuecli3项目:vue create demo-vuecli3-ui手动选择特性,我这里只要Babel以及Css-Professor;然后选择Sass/SCSS,开发者按照自己的喜好来选择css预处理语言;...
·
- 创建一个vuecli3项目:
手动选择特性,我这里只要Babel以及Css-Professor;vue create demo-vuecli3-ui
然后选择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
/*components/button/index.js*/ import Button from './pl-button' Button.install = (Vue) => Vue.component(Button.name, Button); export default Button
/*components/button/pl-button.vue*/ <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>
/*components/ele/index.js*/ import ELE from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' export default { install(Vue) { Vue.use(ELE) }, }
/*components/input/index.js*/ import Input from './pl-input' Input.install = (Vue) => Vue.component(Input.name, Input) export default Input
这个是总的打包入口/*components/input/pl-input.vue*/ <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>
/*components/index.js*/ 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: { // page 的入口 entry: 'src/main.js', // 模板来源 template: 'public/index.html', // 在 dist/index.html 的输出 filename: 'index.html', // 当使用 title 选项时, // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title> title: 'pl-app document', // 在这个页面中包含的块,默认情况下会包含 // 提取出来的通用 chunk 和 vendor chunk。 chunks: ['chunk-vendors', 'chunk-common', 'index'] }, }, configureWebpack: { resolve: pub.resolve }, }
- 创建文件build/config.build.js,这个是打包组件的时候,加载的配置文件:
这里面主要讲chainWebpack中做了什么事情: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 }) } }
- 删除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”]
- 修改版本号version为
- 发布到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,体积大大缩小了;
- 至此,vuecli3工程组件库按需引入说明已经结束
更多推荐
已为社区贡献13条内容
所有评论(0)