# 组件按需引入
# 一次性全部引入
组件库一开始只提供了一次性全部引入的方式。
# 导出组件库
- 组件目录
├─packages
├─button
│ └─button.vue
│ └─button.scss
├─input
│ └─input.vue
│ └─input.scss
├─...
│
│ index.js # 所有组件的入口
- packages/index.js
import XButton from './button/button.vue'
const components = [
XButton,
...
]
// 全局注册组件
const install = Vue => {
components.forEach(c => {
Vue.component(c.name, c)
})
}
/**
* 有可能组件会通过script标签引入,如<script src='https://xxx/xqh-vue-ui'></script>
*/
if (typeof Window.Vue !== 'undefined') {
install(Vue) // 全局直接通过script 引用的方式会默认调用install方法
}
export default {
install
}
# 打包组件库
- 在
package.json
中增加打包组件库指令
"script":{
// 利用vue自带的工具 构建 目标(库) 库的名字xqh-vue-ui 当前的入口文件
"lib": "vue-cli-service build --target lib --name xqh-vue-ui packages/index.js"
}
打包后的目录
├─lib
├── demo.html
├── xqh-vue-ui.common.js
├── xqh-vue-ui.css
├── xqh-vue-ui.umd.js
└── xqh-vue-ui.umd.min.js
# 上传 npm
- 配置
package.json
文件
{
"name": "xqh-vue-ui",
"version": "1.0.0",
"private": false,
"main": "lib/xqh-vue-ui.umd.min.js",
...
}
# 导入组件库
- 安装
npm install xqh-vue-ui
- 使用
import Vue from 'vue'
import xqhVueUI from 'xqh-vue-ui'
import 'xqh-vue-ui/lib/xqh-vue-ui.css'
Vue.use(xqhVueUI)
缺点:有些项目只需要用到某几个组件,引入整个组件库,导致项目打包后体积庞大。
# 按需引入
为了降低首屏代码大小,对于一些大的第三方库或者团队的基础工具库,需要按需导入模块。因此本组件也增加了按需引入的方式。
核心思想:webpack 多入口打包。
# 配置生产环境和开发环境
- process.env.NODE_ENV
process.env
是Node.js
中的一个环境对象。其中保存着系统的环境的变量信息。而NODE_ENV
就是其中的一个环境变量。这个变量主要用于标识当前的环境(生产环境,开发环境)。默认是没有这个环境变量的,需要自己手动配置。- 默认情况下,一个 Vue CLI 项目有三个模式:
- development 模式:用于 vue-cli-service serve
- production 模式:用于 vue-cli-service build 和 vue-cli-service test:e2e
- test 模式:用于 vue-cli-service test:unit
- 在
Vue
中,NODE_ENV
可以通过.env
文件或者.env.[mode]
文件配置。配置过后,运行Vue CLI
指令(npm run dev(serve)
,npm run build
)时,就会将该模式下的NODE_ENV
载入其中了。
.env.dev
NODE_ENV = 'development'
.env.prod
NODE_ENV = 'production'
- 修改组件库脚手架工具,增加额外打包配置。
vue.config.js
const devConfig = require('./config/config.dev')
const buildConfig = require('./config/config.build')
module.exports = process.env.NODE_ENV === 'development' ? devConfig : buildConfig
config/config.dev.js
let devConfig = {
...
}
module.exports = devConfig;
config/config.build.js
let buildConfig = {
...
}
module.exports = buildConfig;
package.json
"script":{
"lib:dev": "vue-cli-service build --mode dev --target lib --name xqh-vue-ui --dest lib packages/index.js",
"lib:prod": "vue-cli-service build --mode prod"
}
# buildConfig
核心:config/config.build.js
const { resolve, getComponentEntries } = require('./utils')
let buildConfig = {
// 输出文件目录
outputDir: resolve('lib'),
productionSourceMap: false,
// webpack配置
configureWebpack: {
// 入口文件 多入口对象
entry: getComponentEntries('packages'),
// 输出配置 按需引入的关键!
output: {
// 文件名称
filename: '[name]/index.js',
// 构建依赖类型
libraryTarget: 'umd',
// 依赖输出
libraryExport: 'default',
// 依赖名称
library: 'xqh-vue-ui'
},
// 防止将某些 import 的包(Vue)打包到bundle中,而是在运行时再去从外部获取这些外部依赖模块。
externals: {
vue: {
root: 'Vue',
commonjs: 'vue',
commonjs2: 'vue',
amd: 'vue'
}
}
},
// 样式输出
css: {
sourceMap: true,
extract: {
filename: '[name]/style.css'
}
},
chainWebpack: config => {
// 删除Vue CLI原先打包编译的一些无用功能
config.optimization.delete('splitChunks') // 因为每个组件是独立打包,不需要抽离每个组件的公共js出来。
config.plugins.delete('copy') // 不要复制public文件夹内容到lib文件夹中。
config.plugins.delete('html') // 只打包组件,不生成html页面。
config.plugins.delete('preload')
config.plugins.delete('prefetch')
config.plugins.delete('hmr')
config.entryPoints.delete('app')
}
}
module.exports = buildConfig
config/utils.js
const fs = require('fs')
const { join } = require('path')
const resolve = dir => join(__dirname, '../', dir)
/**
* @desc 大写转横杠
* @param {*} str
*/
function upperCasetoLine(str) {
let temp = str.replace(/[A-Z]/g, function (match) {
return '-' + match.toLowerCase()
})
if (temp.slice(0, 1) === '-') {
temp = temp.slice(1)
}
return temp
}
/**
* @desc 获取组件入口
* @param {*} path
*/
function getComponentEntries(path) {
let files = fs.readdirSync(resolve(path))
const componentEntries = files.reduce((fileObj, item) => {
// 文件路径
const itemPath = join(path, item)
// 在文件夹中
const isDir = fs.statSync(itemPath).isDirectory()
const [name, suffix] = item.split('.')
// 文件中的入口文件
if (isDir) {
fileObj[`x-${upperCasetoLine(item)}`] = resolve(join(itemPath, 'index.js'))
}
// 文件夹外的入口文件
else if (suffix === 'js') {
fileObj[name] = resolve(`${itemPath}`)
}
return fileObj
}, {})
return componentEntries
}
module.exports = {
resolve,
upperCasetoLine,
getComponentEntries
}
# 导出组件库
- 组件目录
在 button 文件夹新增 index.js 文件,对外提供对组件的引用
├─packages
├─button
│ └─button.vue
│ └─button.scss
│ └─index.js # button组件的入口
├─...
│
│ index.js # 所有组件的入口
- button/index.js:单独提供 install 方法
需要注意的是:指令式组件有些许不同,如果 js 文件里已经有了 install 方法,就不用重复操作了。
import XButton from './button.vue'
XButton.install = function (Vue) {
Vue.component(XButton.name, XButton)
}
export default XButton
- packages/index.js:不仅要导出整个组件的 install 方法,还要导出每个组件的。
import XButton from './button/button.vue'
const components = [
XButton,
...
]
// 全局注册组件
const install = Vue => {
if (install.installed) return
components.forEach(c => {
Vue.use(c)
})
}
/**
* 有可能组件会通过script标签引入,如<script src='https://xxx/xqh-vue-ui'></script>
*/
if (typeof Window.Vue !== 'undefined') {
install(Vue) // 全局直接通过script 引用的方式会默认调用install方法
}
export default {
install,
XButton,
...
}
# 打包组件库
- 打包后的目录
.
├── index
│ ├── index.js
│ └── style.css
├── x-button
│ ├── index.js
│ └── style.css
├── ...
# 上传 npm
- 配置
package.json
文件
{
"name": "xqh-vue-ui",
"version": "1.0.0",
"private": false,
"main": "lib/index/index.js",
...
}
# 导入组件库
- 安装
npm install xqh-vue-ui
- 按需引入(原生的)
import Vue from 'vue'
import XButton from 'xqh-vue-ui/lib/x-button'
import 'xqh-vue-ui/lib/x-button/style.css'
Vue.use(XButton)
还要知道单独组件的样式文件在哪里,麻烦!
- 按需引入(借助插件)
babel-plugin-import:为组件库实现单组件按需加载并且自动引入其样式。
npm install babel-plugin-import
在 babel.config.js 中配置
plugins: [
[
'import',
{
libraryName: 'xqh-vue-ui',
style: name => {
return `${name}/style.css`
},
}
]
]
使用
import Vue from 'vue'
import { XButton } from 'xqh-vue-ui'
Vue.use(XButton)
← 文档部署