第一次在掘金发文章,有点啰里啰嗦,你们见谅。javascript
当前大部分UI框架设计的Webpack配置都相对复杂,例如Element、Ant Design Vue和Muse-UI等Vue组件库。例如Element,为了实现业务层面的两种引入形式(完整引入和按需引入),以及抛出一些可供业务层面通用的utils
、i18n
等,Webpack配置变得很是复杂。为了简化UI框架的设计难度,这里介绍一种简单的UI框架设计,在此以前先简单介绍一下Element的构建流程,以便对比新的UI框架设计。css
通常组件库的设计者将引入形式设计成完整引入和按需引入两种形式:完整引入的开发相对便利,针对一些大型业务或者对于打包体积不是特别注重的业务,按需引入开发的颗粒度相对精细,能够减小业务的打包体积。html
设计的UI框架实践项目的github地址是ziyi2/vue-cli3-lerna-ui,包括了preset.json
、本身设计的Vue CLI插件以及本身设计的一系列UI组件(和生成的UI框架示例稍有不一样),若是以为总体结构有不合理的或者考虑不够全面的地方,欢迎你们提issue,这样我也能够对它进行完善。若是你们感兴趣,但愿你们可以Star一下,这里拜谢你们了!vue
首先了解Element
的构建流程,查看Element2.7.0
版本package.json
的npm 脚本:java
// 其中的`node build/bin/build-entry.js` 生成Webpack构建入口
"build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js",
// 构建css样式
"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",
// 构建commonjs规范的`utils`
"build:utils": "cross-env BABEL_ENV=utils babel src --out-dir lib --ignore src/index.js",
// 构建umd模块的语言包
"build:umd": "node build/bin/build-locale.js",
// 清除构建文件夹`lib`
"clean": "rimraf lib && rimraf packages/*/lib && rimraf test/**/coverage",
// 整体构建
"dist": "npm run clean && npm run build:file && npm run lint && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run build:utils && npm run build:umd && npm run build:theme",
// 执行eslint校验
"lint": "eslint src/**/* test/**/* packages/**/* build/**/* --quiet"
复制代码
这里重点关注Element的构建脚本,忽略测试、发布、启动开发态调试页面、构建演示页面等脚本。node
npm run dist
与Element
构建相关的npm脚本繁多,可是整体构建脚本是dist
:webpack
"dist": "npm run clean && npm run build:file && npm run lint && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run build:utils && npm run build:umd && npm run build:theme"
复制代码
&&
是继发执行,只有当前任务成功,才能执行下一个任务。git
整体构建脚本包含了如下按顺序执行的脚本命令es6
npm run clean
- 清除构建文件夹lib
npm run build:file
- 其中的node build/bin/build-entry.js
生成Webpack构建入口npm run lint
- 执行eslint校验webpack --config build/webpack.conf.js
- 构建umd总文件webpack --config build/webpack.common.js
- 构建commonjs2总文件webpack --config build/webpack.component.js
- 构建commonjs2组件(提供按需引入)npm run build:utils
- 构建commonjs的utils
(供commonjs2总文件、commonjs2组件以及业务使用)npm run build:umd
- 构建umd语言包npm run build:theme
- 构建css样式若是对于对于
umd
、commonjs2
、amd
等模块定义不是特别清晰,可参考Webpack文档模块定义系统。github
执行npm run dist
后会在当前根目录生成新的lib
文件夹,包含如下构建内容:
lib
├── directives # commonjs指令(这里归为utils)
├── locale # commonjs国际化(commonjs语言包和API)
├── mixins # commonjs mixins(这里归为utils)
├── theme-chalk # css 样式文件
├── transitions # commonjs transitions(这里归为utils)
├── umd # umd语言包
├── utils
├── alert.js # commonjs组件
├── aside.js
├── ...
├── element-ui.common.js # commonjs2总文件
├── ...
├── index.js # umd总文件
├── ...
复制代码
从Element官方文档的使用指南结合lib
能够看出,Element
为咱们提供了如下能力:
utils
方法(官方文档没有说明,但事实上业务可使用)CDN引入的umd总文件通常是全量构建的,不会有依赖问题,可是commonjs2模块的文件须要在业务层面再次使用Webpack构建。例如须要在业务层面支持国际化和提供utils的功能,那么就不能将国际化和提供utils的代码bundle到commonjs2总文件或commonjs2的全部UI组件中(每个组件都bundleutils
的方法或者国际化API显然是不合理的),若是须要在业务层面支持按需引入的功能,那么不建议将全部UI组件的源码bundle到commonjs2总文件中,这样即可以实现层层引用,对外抛出功能的同时在业务层面能够防止Webpack二次打包,从而致使引入两遍甚至多遍相同的代码的问题。
在组件库中开发时,为了构建commonjs2模块的文件,须要对各个
utils
、组件等引入的路径作出强约定,这样不只产生的Webpack配置会变得很难维护,对于开发者的开发也须要作出必定的规范限制。
接下来分析一下各个脚本的构建功能。
npm run build:file
build:file
脚本是自动生成一些源码文件的脚本:
"build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js",
复制代码
其中与构建相关的脚本是node build/bin/build-entry.js
,主要用于生成Webpack构建的入口源文件src/index.js
:
// 注释说明该文件由build-entry.js脚本自动生成
/* Automatically generated by './build/bin/build-entry.js' */
import Pagination from '../packages/pagination/index.js';
// ... 这里省略大部分组件引入
import TimelineItem from '../packages/timeline-item/index.js';
import locale from 'element-ui/src/locale';
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';
const components = [
Pagination,
// ... 这里省略大部分组件
TimelineItem,
CollapseTransition
];
const install = function(Vue, opts = {}) {
locale.use(opts.locale);
locale.i18n(opts.i18n);
components.forEach(component => {
Vue.component(component.name, component);
});
Vue.use(Loading.directive);
Vue.prototype.$ELEMENT = {
size: opts.size || '',
zIndex: opts.zIndex || 2000
};
Vue.prototype.$loading = Loading.service;
// ...
};
/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
version: '2.7.0',
locale: locale.use,
i18n: locale.i18n,
install,
CollapseTransition,
Loading,
Pagination,
// ... 这里省略大部分组件
TimelineItem
};
复制代码
在组件的开发过程当中若是组件较多,建议使用脚本自动生成构建入口文件。
npm run lint
构建以前使用lint
脚本对构建的源码文件进行eslint
校验:
"lint": "eslint src/**/* test/**/* packages/**/* build/**/* --quiet",
复制代码
Element
对eslint
作了严格控制,一旦eslint
报错那么dist
整体构建脚本执行中止,总体构建失败。这里的eslint
校验可使用eslint-loader进行处理(若是你但愿eslint
校验失败也能够进行构建能够查看Errors and Warning)。
webpack --config build/webpack.conf.js
webpack --config build/webpack.conf.js
脚本用于构建umd总文件,执行该脚本最终会在lib
下生成index.js
文件:
lib
├── index.js # umd 总文件
复制代码
webpack.conf.js
配置以下:
// build/webpack.conf.js
// ...忽略
module.exports = {
mode: 'production',
// 指定入口文件src/index.js,该入口文件由`build:file`脚本自动生成
entry: {
app: ['./src/index.js']
},
output: {
// 在lib文件中生成
path: path.resolve(process.cwd(), './lib'),
// 生成lib/index.js
filename: 'index.js',
// 生成umd模块
libraryTarget: 'umd',
// src/index.js文件采用export default语法抛出,所以须要设置libraryExport
// 不然引入的UI组件库须要使用.default才能引用到抛出的对象
// if your entry has a default export of `MyDefaultModule`
// var MyDefaultModule = _entry_return_.default;
// 这里踩过坑,因此说明一下,不配置的话遇到的问题是引入的UI组件库无法解构
libraryExport: 'default',
},
resolve: {
extensions: ['.js', '.vue', '.json'],
// 'element-ui': path.resolve(__dirname, '../')
// alias中的'element-ui'做为npm包抛出后指向了业务项目node_modules所在的npm包路径
alias: config.alias
},
externals: {
// 构建只排除vue
// umd模块经过CDN形式引入,所以将全部的组件、utils、i18n等构建在内
// umd模块没有按需引入功能
vue: config.vue
},
// ...忽略
};
复制代码
构建文件lib/index.js
主要的功能是用于CDN形式引入项目,而且没法作到按需加载,产生的体积很是大,对于简单的应用可能不适用。
webpack --config build/webpack.common.js
webpack --config build/webpack.common.js
脚本用于构建commonjs2总文件,执行该脚本最终会在lib
下生成element-ui.common.js
文件:
lib
├── element-ui.common.js # commonjs2 总文件
复制代码
因为该文件须要在业务层面再次使用Webpack构建,所以考量的方面较多。在分析Webpack配置以前,再次回顾一下Element
能为咱们作什么:
utils
方法(commonjs2,固然官方没有对外说明)webpack --config build/webpack.common.js
脚本主要用于构建完整引入功能,同时为了能够在业务层面抛出按需引入、支持国际化等功能,构建element-ui.common.js
时须要将UI组件、支持国际化、utils方法的源代码排除。
webpack.common.js
配置以下:
// build/webpack.common.js
// ...忽略
module.exports = {
mode: 'production',
entry: {
app: ['./src/index.js']
},
output: {
path: path.resolve(process.cwd(), './lib'),
publicPath: '/dist/',
filename: 'element-ui.common.js',
chunkFilename: '[id].js',
libraryExport: 'default',
library: 'ELEMENT',
// 生成commonjs2模块
libraryTarget: 'commonjs2'
},
resolve: {
extensions: ['.js', '.vue', '.json'],
// 'element-ui': path.resolve(__dirname, '../')
alias: config.alias,
modules: ['node_modules']
},
// 这里用于排除UI组件、支持国际化、utils方法的源代码,这些源代码须要额外的脚本进行构建
externals: config.externals,
optimization: {
// commonjs2无须压缩处理
minimize: false
},
// ...忽略
};
复制代码
重点须要关注一下config.externals
属性,打印输出该变量的值:
[{
vue: 'vue',
// 排除全部UI组件的源代码
'element-ui/packages/option':'element-ui/lib/option',
// ...
// 排除国际化的源代码
'element-ui/src/locale': 'element-ui/lib/locale',
// 排除utils方法的源代码
'element-ui/src/utils/vue-popper': 'element-ui/lib/utils/vue-popper',
'element-ui/src/mixins/emitter': 'element-ui/lib/mixins/emitter',
'element-ui/src/transitions/collapse-transition': 'element-ui/lib/transitions/collapse-transition'
// ...
},
// var nodeExternals = require('webpack-node-externals');
// nodeExternals()
[Function]
];
复制代码
externals属性能够将一些特定的依赖从输出的bundle中排除,例如在开发态中组件之间有依赖关系,element-ui/packages/pagination
中引入element-ui/packages/option
组件:
pagecages/pagination/src/pagination.js
// pagination组件中须要用到option组件
import ElOption from 'element-ui/packages/option';
// ...
复制代码
Webpack构建后,能够发如今element-ui.common.js
中并无将element-ui/packages/option
组件打包在内,而只是更改了它的引入路径element-ui/lib/option
(在实现按需引入功能时会用webpack --config build/webpack.component.js
脚本构建出该文件)。
// lib/element-ui.common.js
module.exports = require("element-ui/lib/option");
复制代码
所以以上列出的config.externals
属性的key
和value
能够排除UI组件、支持国际化、utils方法功能的代码。
config.externals
属性的最后一个值是[Function]
,是由webpack-node-externals生成的。这里解释一下webpack-node-externals
的做用:
Webpack allows you to define externals - modules that should not be bundled. When bundling with Webpack for the backend - you usually don't want to bundle its node_modules dependencies. This library creates an externals function that ignores node_modules when bundling in Webpack.
例如在Elment
组件库开发中须要依赖deepmerge
,那么Webpack构建的时候不须要将该依赖bundle到element-ui.common.js
中,而是将其添加到Element
组件库(做为npm包发布)的dependencies
,这样经过npm安装Element
的同时也会安装它的依赖deepmerge
,从而使得element-ui.common.js
经过require("deepmerge")
的形式引入该依赖不会报错。
这里列出element-ui.common.js
排除的一些代码:
// 排除utils源码(utils源码会经过`npm run build:utils`脚本构建)
module.exports = require("element-ui/lib/utils/dom");
// 排除vue
module.exports = require("vue");
// 排除国际化源码(国际化源码会经过`npm run build:utils`脚本构建)
module.exports = require("element-ui/lib/locale");
// 须要注意和Vue相关的JSX依赖(Vue CLI3系统构建的包也会有一个该功能的依赖)
module.exports = require("babel-helper-vue-jsx-merge-props");
// 排除一些Elment组件使用的其余依赖
module.exports = require("throttle-debounce/throttle");
// 排除UI组件源码(UI组件源码会经过`webpack --config build/webpack.component.js`脚本构建)
module.exports = require("element-ui/lib/option");
复制代码
须要注意
Element
发布的npm包入口文件就是element-ui.common.js
,能够经过package.json中的main
字段信息查看。
webpack --config build/webpack.component.js
webpack --config build/webpack.component.js
脚本用于构建commonjs2的UI组件(提供按需引入功能),执行该脚本最终会在lib
下生成全部Element
支持的UI组件(同时这些文件也会被element-ui.common.js
总入口文件引用):
lib
├── alert.js # commonjs 组件
├── aside.js
├── button.js
├── ...
复制代码
查看build/webpack.component.js
配置:
// ...忽略
const Components = require('../components.json');
// Components是全部组件的构建入口列表
// {
// "pagination": "./packages/pagination/index.js",
// ...
// "timeline-item": "./packages/timeline-item/index.js"
// }
const webpackConfig = {
mode: 'production',
// 多入口
entry: Components,
output: {
path: path.resolve(process.cwd(), './lib'),
publicPath: '/dist/',
filename: '[name].js',
chunkFilename: '[id].js',
libraryTarget: 'commonjs2'
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: config.alias,
modules: ['node_modules']
},
// 排除其余UI组件、支持国际化、utils的源码,这些源码会额外构建
externals: config.externals,
},
// ...忽略
};
复制代码
构建单个组件和构建整体入口文件element-ui.common.js
的Webpack配置相似,须要将utils
、locale
以及其余一些依赖排除。
npm run build:utils
build:utils
脚本主要用于构建commonjs的utils
(提供国际化以及utils
功能):
"build:utils": "cross-env BABEL_ENV=utils babel src --out-dir lib --ignore src/index.js",
复制代码
能够发现该命令并非经过Webpack进行多文件构建,而是经过Babel直接进行转义处理(Webpack构建会产生额外的Webpack代码,而且配置繁琐,Babel转义处理构建的代码很是干净),将src
目录下除了Webpack构建入口文件src/index.js
之外的全部其余文件进行转义处理。执行该脚本最终会在lib
下生成全部的utils
文件:
lib
├── directives # commonjs 指令
├── locale # commonjs 国际化API和语言包
├── mixins # commonjs 混入
├── transitions # commonjs 过分动画
├── utils # commonjs 工具方法
复制代码
生成的这些工具方法会被lib
下的element-ui.common.js
和各个组件引用,同时在业务层面也能够引用这些工具方法。查看.babelrc
文件的配置信息:
{
"presets": [
[
"env",
{
"loose": true,
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
],
"stage-2"
],
"plugins": ["transform-vue-jsx"],
"env": {
// cross-env BABEL_ENV=utils
"utils": {
"presets": [
[
"env",
{
// 松散模式,更像人手写的ES5代码
"loose": true,
// es6转成commonjs
"modules": "commonjs",
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
],
],
"plugins": [
["module-resolver", {
"root": ["element-ui"],
"alias": {
// 相似于Webpack的externals功能
// 将源代码的引入路径更改为目标代码的引入路径
"element-ui/src": "element-ui/lib"
}
}]
]
},
"test": {
"plugins": ["istanbul"]
}
}
}
复制代码
utils
文件源代码之间互相引用的路径是element-ui/src
,转义成目标代码后互相之间的引用路径是element-ui/lib
,所以须要有相似于Webpack的externals
的功能去更改目标代码的引用路径,进行Babel转义时插件babel-plugin-module-resolver能够实现该功能。
npm run build:theme
build:theme
脚本主要用于构建UI组件的css样式:
"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",
复制代码
这里主要关注 gulp build --gulpfile packages/theme-chalk/gulpfile.js
脚本,该脚本使用Gulp构建工具构建css样式文件,Glup构建多文件样式会很是简单。最终将当前构建的packages/theme-chalk/lib
目录下的内容拷贝到lib/theme-chalk
目录下供外部业务使用:
lib
├── theme-chalk # css 样式文件
│ ├── fonts # icons
│ ├── alert.css # 按需引入的组件样式
│ ├── ... # 按需引入的组件样式
│ └── index.css # 完整引入样式
复制代码
查看gulpfile.js
文件:
'use strict';
const { series, src, dest } = require('gulp');
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const cssmin = require('gulp-cssmin');
function compile() {
return src('./src/*.scss')
// sass转化成css
.pipe(sass.sync())
// Parse CSS and add vendor prefixes to rules by Can I Use
// css浏览器兼容处理
.pipe(autoprefixer({
browsers: ['ie > 9', 'last 2 versions'],
cascade: false
}))
// 压缩css
.pipe(cssmin())
.pipe(dest('./lib'));
}
function copyfont() {
return src('./src/fonts/**')
.pipe(cssmin())
.pipe(dest('./lib/fonts'));
}
exports.build = series(compile, copyfont);
复制代码
构建整个Element
组件库的脚本繁多,构建的代码之间互相还有引用关系,对于开发的引用路径也会产生必定的约束。所以设计相似于Element
的UI框架相对开发者而言须要必定的开发门槛。
这里基于Vue CLI 3的开发/构建目标/库能力以及Lerna工具设计了一个UI框架,这个UI框架集成了如下特色:
PATCH
或MINOR
版本。这里设定业务层面须要进行webpack构建处理,所以能够对UI框架的组件不进行构建处理,固然若是UI组件的设计须要特殊的webpack loader处理除外,不然业务层面须要作额外的webpack配置。固然不构建处理是相对于必定的使用场景的,不构建处理可能也会产生额外的一些问题。
这个UI框架的设计也会有一些缺陷:
为了简化UI框架的webpack配置,这里将Vue CLI 3做为开发的容器引入,借用Vue CLI 3的构建库功能(构建web-components-组件功能应该更合适,这里没有进行验证),几乎能够作到UI组件构建的零配置。经过审查项目的-webpack-配置能力,能够查看Vue CLI 3为咱们预先设置的通用webpack配置(几乎能够知足大部分的UI组件构建)。
这里使用Vue CLI 3的插件和Preset功能开发了几个插件,以便于快速构建起步的UI设计框架,具体的preset.json配置以下:
{
"useConfigFiles": true,
"router": true,
"routerHistoryMode": true,
"vuex": false,
"cssPreprocessor": "less",
"plugins": {
"@vue/cli-plugin-babel": {},
"@vue/cli-plugin-eslint": {
"lintOn": ["save", "commit"]
},
"@ziyi2/vue-cli-plugin-ui-base": {},
"@ziyi2/vue-cli-plugin-ui-cz": {},
"@ziyi2/vue-cli-plugin-ui-lint": {}
}
}
复制代码
这里采用了官方设计的@vue/cli-plugin-babel和@vue/cli-plugin-eslint插件,同时本身设计了额外的三个插件来支持整个新的UI框架的起步:
@ziyi2/vue-cli-plugin-ui-base
:UI框架基础插件,生成Monorepo结构的源码目录(加入Lerna管理工具),生成基础通用的webpack配置(在VUE CLI 3的webpack配置上进行再配置,VUE CLI3提供了vue.config.js
文件供开发者进行webpack再配置),提供了几个基础UI组件的示例(仅参考价值)。@ziyi2/vue-cli-plugin-ui-cz
: UI框架的cz适配器插件,加入了cz-customizable、commitlint、conventional-changelog,用于生成Angular规范的Git提交说明、检测提交说明是否符合规范以及自动生成UI框架的升级日志等。@ziyi2/vue-cli-plugin-ui-lint
:UI框架的lint-staged插件,代码提交前会执行Eslint校验,校验不经过则不容许提交辣鸡代码。这三个插件已经发布在npm的仓库里,若是是已有的Vue CLI 3项目,可直接经过
vue add @ziyi2/ui-cz
等命令进行安装使用,插件源码地址ziyi2/vue-cli3-lerna-ui/plugins,若是想学习设计Vue CLI 3插件,可参考插件开发指南,不过官方文档可能不够详细,建议参考官方设计的插件或者别人设计的优秀插件。
Lerna是一个Monorepo管理工具,使全部的组件(npm包)设计都集成在一个git仓库里,同时能够利用yarn的workspace特性,模拟发布的组件环境,从而使组件的开发和测试变得简单,不须要屡次进行组件的发布测试(这里用Lerna进行Vue CLI插件开发也很是方便)。
同时Lerna还集成了版本发布工具,能够快速的对UI框架进行版本发布。
UI组件各自修复问题或者新增功能能够各自快速发布
PATCH
和MINOR
版本,若是UI组件总体有非兼容性更新,能够利用Lerna进行MAJOR
版本发布,更多关于版本发布规范可查看语义化版本。
利用Vue CLI 3的远程Preset,这里将本身设计的UI框架分享给你们进行实践使用:
// 可能获取会有点慢,你们耐心等待
vue create --preset ziyi2/vue-cli3-lerna-ui my-project --packageManager yarn
复制代码
若是报错
unable to get local issuer certificate
,能够设置git config --global http.sslVerify false
。
若是远程确实获取preset.json失败,能够采用本地的方式,将preset.json配置复制下来,放入新建的preset.json
文件,执行如下命令生成UI框架:
vue create --preset ziyi2/vue-cli3-lerna-ui my-project --packageManager yarn
复制代码
执行后的生成过程以下:
// 启动开发服务
"serve": "vue-cli-service serve",
// 生成静态资源
"build": "vue-cli-service build",
// Eslint校验
"lint": "vue-cli-service lint",
// 安装和连接Lerna repo的依赖
"bootstrap": "lerna bootstrap",
// 更新升级日志
"cz:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
// 构建
"lib": "lerna run lib"
复制代码
若是须要利用GitHub Pages发布静态资源,能够新增命令
"deploy": "npm run build && gh-pages -d dist"
,须要安装gh-page
依赖。
进入项目目录,使用yarn serve
命令启动开发态视图
这里给出了国际化、选择器、警告以及按钮等UI设计示例。
执行lerna run lib
后(构建能够配合npm run lint
校验,校验不经过则构建失败),Lerna工具会对每个npm包执行lib
脚本:
这里分别对utils
、btn
、theme
包进行了构建处理,其中btn
采用了Vue CLI 3默认的构建库配置。
UI框架生成并构建后的Monorepo结构以下:
.
├── packages # workspaces
│ ├── alert # 警告(不构建)
│ │ ├── alert.vue # 组件源码
│ │ ├── index.js # npm包入口文件
│ │ └── package.json # npm包描述文件
│ ├── btn # 按钮
│ │ ├── lib # 目标文件
│ │ │ └── lib.common.js # npm包入口文件
│ │ ├── btn.vue # 组件源码
│ │ ├── index.js # 构建入口文件
│ │ ├── package.json # npm包描述文件(须要vue cli的开发态依赖)
│ │ └── vue.config.js # 构建配置文件
│ ├── locale # 国际化
│ │ ├── lang # 语言包
│ │ │ ├── enjs # 英文
│ │ │ └── zh_CN.js # 中文
│ │ ├── mixins # 各个组件调用的国际化API
│ │ ├── src # 源码
│ │ ├── index.js # npm包入口文件
│ │ ├── alert.vue # 组件源码
│ │ ├── index.js # npm包入口文件
│ │ └── package.json # npm包描述文件
│ ├── select # 选择器(相似于alert)
│ ├── theme # 样式
│ │ ├── lib # 目标文件
│ │ │ ├── alert.css # 警告样式
│ │ │ ├── btn.css # 按钮样式
│ │ │ ├── index.css # 整体样式
│ │ │ └── select.css # 选择器样式
│ │ ├── src # 源文件
│ │ │ ├── utils # 通用方法和变量
│ │ │ ├── alert.less # 警告样式
│ │ │ ├── btn.less # 按钮样式
│ │ │ ├── index.less # 整体样式
│ │ │ └── select.less # 选择器样式
│ │ ├── gulpfile.js # 构建配置文件
│ │ └── package.json # npm包描述文件
│ └── utils # 工具方法
│ ├── lib # 目标文件(这里也能够采用lodash的方式,去掉lib文件夹这一层)
│ ├── src # 源文件
│ ├── babel.config.js # 构建配置文件
│ └── package.json # npm包描述文件
├── public # 公共资源目录
├── src # 开发态目录
├── .browserslistrc # UI框架目标浏览器配置
├── .cz-config.js # cz定制化提交说明配置
├── .gitignore # git忽略配置
├── .lintstagedrc # lint-staged配置
├── babel.config.js # vue cli的babel配置
├── lerna.json # lerna配置
├── package.json # vue cli容器描述文件(容器不是npm包)
├── postcss.config.js # postcss配置
├── README.md # 说明
└── vue.common.js # 通用的组件构建配置文件
复制代码
这里重点说明src
文件,src
文件能够根据开发须要自行选定方案:
.vue
文件形式进行Demo演示,若是想使用.md
文件进行演示,能够采用vue-markdown-loader。发布彻底能够按照语义化版本进行:
npm publish
快速发布MINOR
和PATCH
版本。lerna publish
发布MAJOR
版本。使用Lerna工具发布的npm包建议采用scope的形式发布,UI框架示例没有给出Demo,若是想采用scope形式发布能够查看ziyi2/vue-cli3-lerna-ui,须要在每一个npm包的package.json
中作额外的配置,具体可查看vue-cli3-lerna-ui/plugins/vue-cli-plugin-ui-base/package.json的publishConfig
字段信息。
若是
lerna publish
发布失败,例如报403
错误等,可使用lerna publish from-package
命令发布,具体查看官方说明Lerna/publish/usage。
对比Element的UI框架设计,采用Vue CLI 3 & Lerna的形式能够简化UI框架的配置,使各个UI组件的构建配置互相独立,对于简单的UI组件能够利用Vue CLI 3的默认webpack配置。同时采用Monorepo的设计结构(Why is Babel a monorepo?),配合Lerna工具,可使得UI框架修复问题和发布新功能的响应能力变得更快。
生成UI框架实践项目的github地址是ziyi2/vue-cli3-lerna-ui,包括了preset.json
、本身设计的Vue CLI插件以及本身设计的一系列UI组件(和生成的UI框架示例稍有不一样),若是以为总体结构有不合理的或者考虑不够全面的地方,欢迎你们提issue,这样我也能够对它进行完善。若是你们感兴趣,但愿你们可以Star一下,这里拜谢你们了!