一、 Makefile 文件
Make是最常用的构建工具,它的规则配置一般写在 Makefile 文件里。make 的使用有点像 package.json 里的 scripts,把一段长命令用一段短命令来执行。
Makefile文件由一系列规则(rules)构成。每条规则的形式如下。
<target> : <prerequisites> [tab] <commands>
上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。
Element UI 项目里的 Makefile 代码如下:
# Makefile中,.PHONY后面的target表示的也是一个伪造的target, 而不是真实存在的文件target,注意Makefile的target默认是文件。
.PHONY: dist test
# 执行make默认指向help
default: help
# 构建主题
# build all theme
build-theme:
npm run build:theme
# 安装依赖
install:
npm install
# 使用淘宝源安装依赖
install-cn:
npm install --registry=http://registry.npm.taobao.org
# 构建应用
dev:
npm run dev
play:
npm run dev:play
# 新增组件
new:
node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))
# 为网站添加新语言
new-lang:
node build/bin/new-lang.js $(filter-out $@,$(MAKECMDGOALS))
# 打包
dist: install
npm run dist
# 部署
deploy:
@npm run deploy
# 发布
pub:
npm run pub
# 单元测试
test:
npm run test:watch
# 帮助信息
help:
@echo " \033[35mmake\033[0m \033[1m命令使用说明\033[0m"
@echo " \033[35mmake install\033[0m\t\033[0m\t\033[0m\t\033[0m\t--- 安装依赖"
@echo " \033[35mmake new <component-name> [中文名]\033[0m\t--- 创建新组件 package. 例如 'make new button 按钮'"
@echo " \033[35mmake dev\033[0m\t\033[0m\t\033[0m\t\033[0m\t--- 开发模式"
@echo " \033[35mmake dist\033[0m\t\033[0m\t\033[0m\t\033[0m\t--- 编译项目,生成目标文件"
@echo " \033[35mmake deploy\033[0m\t\033[0m\t\033[0m\t\033[0m\t--- 部署 demo"
@echo " \033[35mmake pub\033[0m\t\033[0m\t\033[0m\t\033[0m\t--- 发布到 npm 上"
@echo " \033[35mmake new-lang <lang>\033[0m\t\033[0m\t\033[0m\t--- 为网站添加新语言. 例如 'make new-lang fr'"
除了 make new
和 make new-lang
两个命令外,其他脚本命令都已经分析过了。
make new
node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))
执行该命令可以新增组件。
可以执行 "make new aaa 组件中文名" 或者 "node ./build/bin/new.js aaa
组件中文名" 来生成 aaa
组件,方便快捷多了。
添加新组件 aaa
,优势出来了:
- 在/packages目录下新建组件目录,并完成目录结构的构建/packages/aaa
- 创建组件文档,/examples/docs/{lang}/aaa.md
- 创建组件单元测试文件,/test/unit/specs/aaa.spec.js
- 创建组件样式文件,/packages/theme-chalk/src/aaa.scss
- 创建组件类型声明文件,/types/aaa.d.ts
- 配置: 在 /components.json 文件中配置组件信息, 在 /examples/nav.config.json 中添加该组件的路由配置, 在 /packages/theme-chalk/src/index.scss 文件中自动引入该组件的样式文件, 将类型声明文件在 /types/element-ui.d.ts 中自动引入
make new-lang
node build/bin/new-lang.js $(filter-out $@,$(MAKECMDGOALS))
执行该命令后添加新语言。
二、Element 官网左侧路由
生成路由文件:examples/route.config.js
除了【更新日志】的路由组件在 examples/pages/zh-CN/ 目录下以外,所有组件的路由组件都在 examples/docs/zh-CN/ 目录下,以 .md 形式存在。
还有一个开发时,调试组件用的特殊路由 /play。
三、更新图标字体库
对 Element 二次开发时,我们有时候要添加 Icon 图标。我们怎么来维护这些图标呢?
步骤如下:
- 在 iconfont.cn 新建一个项目用来维护图标库
- 添加、修改图标后,选择“Font class”类型,点击项目设置更改前缀为“el-icon-”,然后点击“下载至本地”
3. 替换 packages/theme-chalk/src/fonts 目录下的字体文件(ttf、woff)
4. 把 packages/theme-chalk/src/icon.scss 最底部的这段代码移到上面来,方便以后更新。
5. 更新 packages/theme-chalk/src/icon.scss 文件(看一下第49行注释)
6. 更新 examples/icon.json
7. 重新打包:npm run dist
四、其他工程化脚本
md-loader
说到 md-loader
,官网的文档展示和 demo
展示多亏了他。
它是一个 loader
,官网组件页面的组件 demo
加文档的模式一大半的功劳都是源自于它。
可以在 /examples/route.config.js
中看到 registerRoute
方法生成组件页面的路由配置时,使用 loadDocs
方法加载 /examples/docs/zh-CN/组件名.md
。
注意,这里加载的是 markdown
文档,而不是 vue
文件,但是却能像 vue
文件一样在页面上渲染成一个 Vue
组件,这是怎么做到的呢?
我们知道,webpack
的理念是一切资源都可以 require
,只需配置相应的 loader
即可。在 /build/webpack.demo.js
文件中的 module.rules
下可以看到对 markdown
规则的处理,先通过 md-loader
处理 markdown
文件,从中解析出 vue
代码,然后交给 vue-loader
,最终生成 vue
单文件组件渲染到页面。这就能看到组件页面的文档和组件 demo
展示效果。
/build/webpack.demo.js
:
{
test: /\.md$/,
use: [
{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
},
{
loader: path.resolve(__dirname, './md-loader/index.js')
}
]
},
至于如何将 markdown
解析成 vue
组件,可以阅读下 Element
团队的:谈谈 Element 文档中的 Markdown 解析
build/config.js
webpack
的公共配置,比如 externals、alias
等。通过 externals
的配置解决了组件库部分代码的冗余问题,比如组件和组件库公共模块的代码,但是组件样式冗余问题没有得到解决;alias
别名配置为开发组件库提供了方便。
// webpack 公共配置,比如 externals、alias
var path = require('path');
var fs = require('fs');
var nodeExternals = require('webpack-node-externals');
var Components = require('../components.json');
Object.keys(Components).forEach(function (key) {
externals[`element-ui/packages/${key}`] = `element-ui/lib/${key}`;
});
// externals 解决组件依赖其它组件并按需引入时代码冗余的问题
// 比如 Table 组件依赖 Checkbox 组件,在项目中如果我同时引入 Table 和 Checkbox 时,会不会产生冗余代码
// 如果没有以下内容的的话,会,这时候你会看到有两份 Checkbox 组件代码。
// 包括 locale、utils、mixins、transitions 这些公共内容,也会出现冗余代码
// 但有了 externals 的设置,就会将告诉 webpack 不需要将这些 import 的包打包到 bundle 中,运行时再从外部去
// 获取这些扩展依赖。这样就可以在打包后 /lib/tables.js 中看到编译后的 table.js 对 Checkbox 组件的依赖引入:
// module.exports = require("element-ui/lib/checkbox")
// 这么处理之后就不会出现冗余的 JS 代码,但是对于 CSS 部分,element-ui 并未处理冗余情况。
// 可以看到 /lib/theme-chalk/table.css 和 /lib/theme-chalk/checkbox.css 中都有 Checkbox 组件的样式
externals['element-ui/src/locale'] = 'element-ui/lib/locale';
utilsList.forEach(function (file) {
file = path.basename(file, '.js');
externals[`element-ui/src/utils/${file}`] = `element-ui/lib/utils/${file}`;
});
mixinsList.forEach(function (file) {
file = path.basename(file, '.js');
externals[`element-ui/src/mixins/${file}`] = `element-ui/lib/mixins/${file}`;
});
transitionList.forEach(function (file) {
file = path.basename(file, '.js');
externals[`element-ui/src/transitions/${file}`] = `element-ui/lib/transitions/${file}`;
});
externals = [Object.assign({
vue: 'vue'
}, externals), nodeExternals()];
exports.externals = externals;
// 设置别名
exports.alias = {
main: path.resolve(__dirname, '../src'),
packages: path.resolve(__dirname, '../packages'),
examples: path.resolve(__dirname, '../examples'),
'element-ui': path.resolve(__dirname, '../')
};
exports.vue = {
root: 'Vue',
commonjs: 'vue',
commonjs2: 'vue',
amd: 'vue'
};
exports.jsexclude = /node_modules|utils\/popper\.js|utils\/date\.js/;
总结
Element
整体架构是真的非常棒,利用脚本实现工程化,值得我们在开发中学习和应用。涉及到添加新组件、添加新语言、构建应用、打包编译应用、发布应用、单元测试等等。比如添加新组件,执行完脚本可以帮助开发者解决创建新组件的目录、四种语言下的文档、配置官网展示文件等。
开发者只需要编写具体组件的逻辑即可,根本不需要每一次新建一个组件改动多个文件,拒绝重复劳动。切记,在项目搭建的过程中,可以使用脚本解决的事情,坚决不要手动解决。