浅谈Vue CLI 3结合Lerna进行UI框架设计
当前大部分ui框架设计的webpack配置都相对复杂,例如 element 、 ant design vue 和muse-ui等vue组件库。例如element,为了实现业务层面的两种引入形式( 完整引入 和 按需引入 ),以及抛出一些可供业务层面通用的 utils
、 i18n
等,webpack配置变得非常复杂。为了简化ui框架的设计难度,这里介绍一种简单的ui框架设计,在此之前先简单介绍一下 element 的构建流程,以便对比新的ui框架设计。
一般组件库的设计者将引入形式设计成 完整引入 和 按需引入 两种形式: 完整引入 的开发相对便利,针对一些大型业务或者对于打包体积不是特别注重的业务, 按需引入 开发的颗粒度相对精细,可以减少业务的打包体积。
设计的ui框架实践项目的github地址是,包括了preset.json、自己设计的vue cli插件以及自己设计的一系列ui组件(和生成的ui框架示例稍有不同),如果觉得整体结构有不合理的或者考虑不够全面的地方,欢迎大家提issue,这样我也可以对它进行完善。如果大家感兴趣,希望大家能够star一下,这里拜谢大家了!
element
首先了解 element
的构建流程,查看 element 2.7.0
版本 package.json
的 :
// 其中的`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的构建脚本,忽略 测试、发布、启动开发态调试页面、构建演示页面 等脚本。
npm run dist
与 element
构建相关的npm脚本繁多,但是 总体构建脚本 是 dist
:
"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"
&&
是继发执行,只有当前任务成功,才能执行下一个任务。
总体构建脚本包含了以下按顺序执行的脚本命令
- 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文档。
执行 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
为我们提供了以下能力:
1、cdn引入(umd 总文件)
2、npm包完整引入(抛出commonjs2总文件)
3、按需引入(抛出commonjs2的所有ui组件)
4、支持国际化
5、提供utils方法(官方文档没有说明,但事实上业务可以使用)
cdn引入的umd总文件一般是全量构建的,不会有依赖问题,但是commonjs2模块的文件需要在业务层面再次使用webpack构建。例如需要在业务层面支持 国际化 和 提供utils 的功能,那么就不能将 国际化 和 提供utils 的代码 bundle 到 commonjs2总文件 或 commonjs2的所有ui组件 中(每一个组件都 bundle utils
的方法或者国际化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
校验失败也可以进行构建可以查看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
能为我们做什么:
1、完整引入(抛出commonjs2总文件)
2、按需引入(抛出commonjs2的所有ui组件)
3、支持国际化(commonjs2)
4、提供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] ];
属性可以将一些特定的依赖从输出的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 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转义时插件可以实现该功能。
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);
vue cli 3 & lerna
构建整个 element
组件库的脚本繁多,构建的代码之间互相还有引用关系,对于开发的引用路径也会产生一定的约束。因此设计类似于 element
的ui框架相对开发者而言需要一定的开发门槛。
这里基于vue cli 3的 开发/构建目标/库 能力以及 lerna 工具设计了一个ui框架,这个ui框架集成了以下特点:
1、 结构特点 :每个ui组件都是一个npm包, 多语言、工具和样式 都是自成体系的npm包,可被业务或ui组件灵活引用,同时天然按需加载。
2、 配置特点 :如果需要进行构建处理,那么每个npm包可单独进行构建配置,配置变得更加简单。结合vue cli3的 构件库 能力,对于简单ui组件的构建几乎可以做到webpack零配置,当然需要特殊的webpack loader除外。
3、 发布特点 :组件库的版本迭代可以更快,不需要进行整体构建,每个组件可单独快速发布 patch
或 minor
版本。
这里设定业务层面需要进行webpack构建处理,因此可以对ui框架的组件不进行构建处理,当然如果ui组件的设计需要特殊的webpack loader处理除外,否则业务层面需要做额外的webpack配置。当然不构建处理是相对于一定的使用场景的,不构建处理可能也会产生额外的一些问题。
这个ui框架的设计也会有一些缺陷:
1、没有完整引入功能(也可以进行整体构建,但是这里不推荐)
2、不提供umd模块
3、业务层面引入繁琐(可以出额外的引入工具,简化业务中的ui组件引入)
vue cli 3
构建库
为了简化ui框架的webpack配置,这里将vue cli 3作为开发的容器引入,借用vue cli 3的功能( 构建web-components-组件 功能应该更合适,这里没有进行验证),几乎可以做到ui组件构建的零配置。通过 能力,可以查看vue cli 3为我们预先设置的通用webpack配置(几乎可以满足大部分的ui组件构建)。
插件体系
这里使用vue cli 3的插件和preset功能开发了几个插件,以便于快速构建起步的ui设计框架,具体的 配置如下:
{ "useconfigfiles": true, "router": true, "routerhistorymode": true, "vuex": false, "csspreprocessor": "less", // mac os x下生效,windows下不生效,具体未深入研究 "packagemanager": "yarn", "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": {} } }
这里采用了官方设计的 和 插件,同时自己设计了额外的三个插件来支持整个新的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 适配器插件,加入了 、 、 ,用于生成angular规范的git提交说明、检测提交说明是否符合规范以及自动生成ui框架的升级日志等。
@ziyi2/vue-cli-plugin-ui-lint
:ui框架的插件,代码提交前会执行eslint校验,校验不通过则不允许提交辣鸡代码。
这三个插件已经发布在npm的仓库里,如果是已有的vue cli 3项目,可直接通过 vue add @ziyi2/ui-cz
等命令进行安装使用,插件源码地址,如果想学习设计vue cli 3插件,可参,不过官方文档可能不够详细,建议参考官方设计的插件或者别人设计的优秀插件。
lerna
lerna是一个monorepo管理工具,使所有的组件(npm包)设计都集成在一个git仓库里,同时可以利用yarn的workspace特性,模拟发布的组件环境,从而使组件的开发和测试变得简单,不需要多次进行组件的发布测试(这里用lerna进行vue cli插件开发也非常方便)。
同时lerna还集成了版本发布工具,可以快速的对ui框架进行版本发布。
ui组件各自修复问题可以各自快速发布 patch
版本,如果ui组件整体有非兼容性更新,可以利用lerna进行 major
版本发布,更多关于版本发布规范可查看语义化版本。
ui框架实践
利用vue cli 3的远程preset,这里将自己设计的ui框架分享给大家进行实践使用:
// 可能获取会有点慢,大家耐心等待 vue create --preset ziyi2/vue-cli3-lerna-ui my-project
如果报错 unable to get local issuer certificate
,可以设置 git config --global http.sslverify false
。
如果远程确实获取preset.json失败,可以采用本地的方式,将配置复制下来,放入新建的 preset.json
文件,执行以下命令生成ui框架:
vue create --preset preset.json my-project
执行后的生成过程如下:
脚本命令
// 启动开发服务 "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
命令启动开发态视图,如果是windows系统,可能会报以下错误:
在windows下 vue create
可能会采用npm进行依赖安装,mac os x下无此问题,此时需要额外使用yarn进行再一次安装操作(这里使用了yarn的workspace特性,因此安装依赖建议都使用yarn进行操作):
lerna bootstrap
执行 yarn serve
:
这里给出了国际化、选择器、警告以及按钮等ui设计示例。
构建
执行 lerna run lib
后(构建可以配合 npm run lint
校验,校验不通过则构建失败),lerna工具会对每一个npm包执行 lib
脚本:
这里分别对 utils
、 btn
、 theme
包进行了构建处理,其中 btn
采用了vue cli 3默认的构建库配置。
monorepo结构
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
文件可以根据开发需要自行选定方案:
1、使用默认的cli服务进行开发和ui框架demo演示,这里ui框架采用原生的 .vue
文件形式进行demo演示,如果想使用 .md
文件进行演示,可以采用vue-markdown-loader 。
2、使用vue 驱动的静态网站生成器vuepress,这个目前不是很稳定。 发布
发布
完全可以按照语义化版本进行:
1、各自npm包可以使用 npm publish
快速发布 minor
和 patch
版本。
2、如果某个npm包有非兼容性更新,那么可以使用 lerna publish
发布 major
版本。
使用lerna工具发布的npm包建议采用scope的形式发布,ui框架示例没有给出demo,如果想采用scope形式发布可以查看 ,需要在每个npm包的 package.json
中做额外的配置,具体可查看 的 publishconfig
字段信息。
总结
对比element的ui框架设计,采用vue cli 3 & lerna的形式可以简化ui框架的配置,使各个ui组件的构建配置互相独立,对于简单的ui组件可以利用vue cli 3的默认webpack配置。同时采用monorepo的设计结构( why is babel a monorepo? ),配合lerna工具,可以使得ui框架修复问题和发布新功能的响应能力变得更快。
生成ui框架实践项目的github地址是 i ,包括了 preset.json
、自己设计的vue cli插件以及自己设计的一系列ui组件(和生成的ui框架示例稍有不同),如果觉得整体结构有不合理的或者考虑不够全面的地方,欢迎大家提issue,这样我也可以对它进行完善。如果大家感兴趣,希望大家能够star一下,这里拜谢大家了!
参考链接
- element - github
- - 阮一峰
- - github
- element官方文档
- - eslint文档
- module definition systems - webpack文档
- - github
- - github
- externals - webpack文档
- - github
- gulp - gulp文档
- vue cli 3/开发/构建目标/库 - vue cli文档
- vue cli 3/开发/webpack相关/审查项目的webpack配置 - vue cli文档
- vue cli 3/基础/插件和preset - vue cli文档
- - vue cli plugin
- - vue cli plugin
- - git提交说明工具
- - cz适配器,自定义说明
- - cz适配器,提交说明检测
- - cz适配器,生成日志
- - 代码提交审核工具
- - vue cli文档
- 语义化版本 - 版本发布规范
- vue cli3/基础/cli服务 - vue cli文档
- why is babel a monorepo?
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。