You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
'use strict';const{ series, src, dest }=require('gulp');constsass=require('gulp-sass');constautoprefixer=require('gulp-autoprefixer');constcssmin=require('gulp-cssmin');functioncompile(){returnsrc('./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'));}functioncopyfont(){returnsrc('./src/fonts/**').pipe(cssmin()).pipe(dest('./lib/fonts'));}exports.build=series(compile,copyfont);
第一次在掘金发文章,有点啰里啰嗦,大家见谅。
当前大部分UI框架设计的Webpack配置都相对复杂,例如Element、Ant Design Vue和Muse-UI等Vue组件库。例如Element,为了实现业务层面的两种引入形式(完整引入和按需引入),以及抛出一些可供业务层面通用的
utils
、i18n
等,Webpack配置变得非常复杂。为了简化UI框架的设计难度,这里介绍一种简单的UI框架设计,在此之前先简单介绍一下Element的构建流程,以便对比新的UI框架设计。设计的UI框架实践项目的github地址是ziyi2/vue-cli3-lerna-ui,包括了
preset.json
、自己设计的Vue CLI插件以及自己设计的一系列UI组件(和生成的UI框架示例稍有不同),如果觉得整体结构有不合理的或者考虑不够全面的地方,欢迎大家提issue,这样我也可以对它进行完善。如果大家感兴趣,希望大家能够Star一下,这里拜谢大家了!Element
首先了解
Element
的构建流程,查看Element2.7.0
版本package.json
的npm 脚本:npm run dist
与
Element
构建相关的npm脚本繁多,但是总体构建脚本是dist
:总体构建脚本包含了以下按顺序执行的脚本命令
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样式执行
npm run dist
后会在当前根目录生成新的lib
文件夹,包含以下构建内容:从Element官方文档的使用指南结合
lib
可以看出,Element
为我们提供了以下能力:utils
方法(官方文档没有说明,但事实上业务可以使用)CDN引入的umd总文件一般是全量构建的,不会有依赖问题,但是commonjs2模块的文件需要在业务层面再次使用Webpack构建。例如需要在业务层面支持国际化和提供utils的功能,那么就不能将国际化和提供utils的代码bundle到commonjs2总文件或commonjs2的所有UI组件中(每一个组件都bundle
utils
的方法或者国际化API显然是不合理的),如果需要在业务层面支持按需引入的功能,那么不建议将所有UI组件的源码bundle到commonjs2总文件中,这样便可以实现层层引用,对外抛出功能的同时在业务层面可以防止Webpack二次打包,从而导致引入两遍甚至多遍相同的代码的问题。接下来分析一下各个脚本的构建功能。
npm run build:file
build:file
脚本是自动生成一些源码文件的脚本:其中与构建相关的脚本是
node build/bin/build-entry.js
,主要用于生成Webpack构建的入口源文件src/index.js
:npm run lint
构建之前使用
lint
脚本对构建的源码文件进行eslint
校验:webpack --config build/webpack.conf.js
webpack --config build/webpack.conf.js
脚本用于构建umd总文件,执行该脚本最终会在lib
下生成index.js
文件:webpack.conf.js
配置如下:构建文件
lib/index.js
主要的功能是用于CDN形式引入项目,并且无法做到按需加载,产生的体积非常大,对于简单的应用可能不适用。webpack --config build/webpack.common.js
webpack --config build/webpack.common.js
脚本用于构建commonjs2总文件,执行该脚本最终会在lib
下生成element-ui.common.js
文件:由于该文件需要在业务层面再次使用Webpack构建,因此考量的方面较多。在分析Webpack配置之前,再次回顾一下
Element
能为我们做什么:utils
方法(commonjs2,当然官方没有对外说明)webpack --config build/webpack.common.js
脚本主要用于构建完整引入功能,同时为了可以在业务层面抛出按需引入、支持国际化等功能,构建element-ui.common.js
时需要将UI组件、支持国际化、utils方法的源代码排除。webpack.common.js
配置如下:重点需要关注一下
config.externals
属性,打印输出该变量的值:externals属性可以将一些特定的依赖从输出的bundle中排除,例如在开发态中组件之间有依赖关系,
element-ui/packages/pagination
中引入element-ui/packages/option
组件:pagecages/pagination/src/pagination.js
Webpack构建后,可以发现在
element-ui.common.js
中并没有将element-ui/packages/option
组件打包在内,而只是更改了它的引入路径element-ui/lib/option
(在实现按需引入功能时会用webpack --config build/webpack.component.js
脚本构建出该文件)。因此以上列出的
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
排除的一些代码:webpack --config build/webpack.component.js
webpack --config build/webpack.component.js
脚本用于构建commonjs2的UI组件(提供按需引入功能),执行该脚本最终会在lib
下生成所有Element
支持的UI组件(同时这些文件也会被element-ui.common.js
总入口文件引用):查看
build/webpack.component.js
配置:构建单个组件和构建总体入口文件
element-ui.common.js
的Webpack配置类似,需要将utils
、locale
以及其他一些依赖排除。npm run build:utils
build:utils
脚本主要用于构建commonjs的utils
(提供国际化以及utils
功能):可以发现该命令并不是通过Webpack进行多文件构建,而是通过Babel直接进行转义处理(Webpack构建会产生额外的Webpack代码,并且配置繁琐,Babel转义处理构建的代码非常干净),将
src
目录下除了Webpack构建入口文件src/index.js
以外的所有其他文件进行转义处理。执行该脚本最终会在lib
下生成所有的utils
文件:生成的这些工具方法会被
lib
下的element-ui.common.js
和各个组件引用,同时在业务层面也可以引用这些工具方法。查看.babelrc
文件的配置信息:npm run build:theme
build:theme
脚本主要用于构建UI组件的css样式:这里主要关注
gulp build --gulpfile packages/theme-chalk/gulpfile.js
脚本,该脚本使用Gulp构建工具构建css样式文件,Glup构建多文件样式会非常简单。最终将当前构建的packages/theme-chalk/lib
目录下的内容拷贝到lib/theme-chalk
目录下供外部业务使用:查看
gulpfile.js
文件:Vue CLI 3 & Lerna
构建整个
Element
组件库的脚本繁多,构建的代码之间互相还有引用关系,对于开发的引用路径也会产生一定的约束。因此设计类似于Element
的UI框架相对开发者而言需要一定的开发门槛。这里基于Vue CLI 3的开发/构建目标/库能力以及Lerna工具设计了一个UI框架,这个UI框架集成了以下特点:
PATCH
或MINOR
版本。这个UI框架的设计也会有一些缺陷:
Vue CLI 3
构建库
为了简化UI框架的webpack配置,这里将Vue CLI 3作为开发的容器引入,借用Vue CLI 3的构建库功能(构建web-components-组件功能应该更合适,这里没有进行验证),几乎可以做到UI组件构建的零配置。通过审查项目的-webpack-配置能力,可以查看Vue CLI 3为我们预先设置的通用webpack配置(几乎可以满足大部分的UI组件构建)。
插件体系
这里使用Vue CLI 3的插件和Preset功能开发了几个插件,以便于快速构建起步的UI设计框架,具体的preset.json配置如下:
这里采用了官方设计的@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校验,校验不通过则不允许提交辣鸡代码。Lerna
Lerna是一个Monorepo管理工具,使所有的组件(npm包)设计都集成在一个git仓库里,同时可以利用yarn的workspace特性,模拟发布的组件环境,从而使组件的开发和测试变得简单,不需要多次进行组件的发布测试(这里用Lerna进行Vue CLI插件开发也非常方便)。
同时Lerna还集成了版本发布工具,可以快速的对UI框架进行版本发布。
UI框架实践
利用Vue CLI 3的远程Preset,这里将自己设计的UI框架分享给大家进行实践使用:
如果远程确实获取preset.json失败,可以采用本地的方式,将preset.json配置复制下来,放入新建的
preset.json
文件,执行以下命令生成UI框架:执行后的生成过程如下:
脚本命令
启动
进入项目目录,使用
yarn serve
命令启动开发态视图这里给出了国际化、选择器、警告以及按钮等UI设计示例。
构建
执行
lerna run lib
后(构建可以配合npm run lint
校验,校验不通过则构建失败),Lerna工具会对每一个npm包执行lib
脚本:这里分别对
utils
、btn
、theme
包进行了构建处理,其中btn
采用了Vue CLI 3默认的构建库配置。Monorepo结构
UI框架生成并构建后的Monorepo结构如下:
这里重点说明
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
字段信息。总结
对比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一下,这里拜谢大家了!参考链接
The text was updated successfully, but these errors were encountered: