本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
1. 前言
1.1 这个库,是干啥的
每次新增一个页面的时候,你是怎么操作的?每次新增页面复制粘贴?今天我们从 element-ui 中学习一下如何初始化新的组件。
1.2 你能学到
element-ui如何初始化新的组件- 学以致用应用到自己开发的项目中,比如新增页面等~
2. 准备
2.1 环境准备
2.1.1 在线环境
通过 github1s 在线 vscode 打开:new.js
2.1.2 git clone
# 克隆官方项目git clone https://github.com/ElemeFE/element.git# npm i -g yarncd element && npm run dev
3 看看 源码
3.1 经典三部曲
3.1.1 经典README
README 中好像没什么,只要安装方式和快速上手和其他的一些目前用不到的东西,但是里面有个贡献指南。我们等会进去看看~
3.1.2 经典package.json
先看看是怎么启动项目的
从 package.json 中即可得知
"script": {"bootstrap": "yarn || npm i","build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js","dev": "npm run bootstrap && npm run build:file && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.demo.js & node build/bin/template.js",},
3.1.3 贡献指南
贡献指南中提到本文关键
组件开发规范
- 通过
**make new**创建组件目录结构,包含测试代码、入口文件、文档- 如果包含父子组件,需要更改目录结构,参考 Button
- 组件内如果依赖了其他组件,需要在当前组件内引入,参考 Select
make命令
这个make new命令是啥?怎么在 package.json 中 script 模块没看到嘞?
我是真第一次见哇😶然后搜索了一下找到了阮一峰老师的这篇文章~
Make这个词,英语的意思是”制作”。Make命令直接用了这个意思,就是要做出某个文件。并且需要有人告诉它,如何调用其他命令完成这个目标。
而这个人就是 Makefile文件~
MakeFile
我们去到 MakeFile 里看看,就能找到对应的new命令
# element/Makefilenew:node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))
这行命令又指向了一个地方 build/bin/new.js 看来这里就是关键岛屿了~
3.3 理解源码
在 new.js 设置断点后,命令行输入make new zhou 舟测试,zhou 是 组件名字,也是后面路径什么的所用的,后面那个则是组件中文名。然后就跟着调试就好了~
3.3.1 命令初始判断 L1-L11
'use strict';console.log();process.on('exit', () => {console.log();});if (!process.argv[2]) {console.error('[组件名]必填 - Please enter new component name');process.exit(1);}
process.on
process对象部署了EventEmitter接口,可以使用on方法监听各种事件,并指定回调函数。
这里监听了 exit 事件,退出时输出一个空行来使得终端显示更为美观
process.argv
process.argv属性返回一个数组,由命令行执行脚本时的各个参数组成。它的第一个成员总是node,第二个成员是脚本文件名,其余成员是脚本文件的参数。
这里对参数进行判断,如果没有传入必填的参数——即组件名,就会报错并 exit
3.3.2 引入相关依赖 L13-L20
// 路径模块const path = require('path');// 文件模块const fs = require('fs');// 保存文件const fileSave = require('file-save');// 转驼峰const uppercamelcase = require('uppercamelcase');// 第一个参数 组件名const componentname = process.argv[2]; //*// 第二个参数 组件中文名const chineseName = process.argv[3] || componentname;// 转驼峰const ComponentName = uppercamelcase(componentname);// package 路径const PackagePath = path.resolve(__dirname, '../../packages', componentname);
file-save
file-save模块会为文件建立一个写入流,如果目录不存在需要创建,则自动创建目录。
后面添加文件配置就用到了这个
3.3.3 文件模板 L21-L95
定义了多个文件模板方便分情况进行使用
const Files = [{filename: 'index.js',content: `import ${ComponentName} from './src/main';/* istanbul ignore next */${ComponentName}.install = function(Vue) {Vue.component(${ComponentName}.name, ${ComponentName});};//...]
3.3.4 添加配置到对应文件中 L97-L130
把 componentname添加到 components.json
// 添加到 components.jsonconst componentsFile = require('../../components.json');if (componentsFile[componentname]) { //判断zhou是否已经存在console.error(`${componentname} 已存在.`);process.exit(1);}componentsFile[componentname] = `./packages/${componentname}/index.js`; //设置为对应的字符串//建立对应文件fileSave(path.join(__dirname, '../../components.json')).write(JSON.stringify(componentsFile, null, ' '), 'utf8').end('\n');
把 componentname.scss 添加到 index.scss
// 添加到 index.scssconst sassPath = path.join(__dirname, '../../packages/theme-chalk/src/index.scss');const sassImportText = `${fs.readFileSync(sassPath)}@import "./${componentname}.scss";`;fileSave(sassPath).write(sassImportText, 'utf8').end('\n
把 componentname.d.ts 添加到 element-ui.d.ts
// 添加到 element-ui.d.tsconst elementTsPath = path.join(__dirname, '../../types/element-ui.d.ts');let elementTsText = `${fs.readFileSync(elementTsPath)}/** ${ComponentName} Component */export class ${ComponentName} extends El${ComponentName} {}`;const index = elementTsText.indexOf('export') - 1;const importString = `import { El${ComponentName} } from './${componentname}'`;elementTsText = elementTsText.slice(0, index) + importString + '\n' + elementTsText.slice(index);fileSave(elementTsPath).write(elementTsText, 'utf8').end('\n');
3.3.5 创建 package L131-L136
// 创建 packageFiles.forEach(file => {fileSave(path.join(PackagePath, file.filename)).write(file.content, 'utf8').end('\n');});
forEach遍历前面的文件模板,并写入 packages 文件夹路径下对应文件,新增 element/packages/zhou/index.js``element/packages/zhou/src/main.vue等文件
3.3.6 把新增的组件添加到 nav.config.json L138-L155
// 添加到 nav.config.jsonconst navConfigFile = require('../../examples/nav.config.json');Object.keys(navConfigFile).forEach(lang => {let groups = navConfigFile[lang][4].groups;groups[groups.length - 1].list.push({path: `/${componentname}`,title: lang === 'zh-CN' && componentname !== chineseName? `${ComponentName} ${chineseName}`: ComponentName});});fileSave(path.join(__dirname, '../../examples/nav.config.json')).write(JSON.stringify(navConfigFile, null, ' '), 'utf8').end('\n');console.log('DONE!');
修改json文件中对应的配置,如添加
{"path": "/zhou","title": Zhou"}
4. 学习资源
- 阮一峰老师:make 命令
- 阮一峰老师:process
-
5. 总结 & 收获
5.1 总结 new.js 流程
5.2 知识点
process相关知识点- npm file-save 库
- 本来繁琐的操作,如何通过总结与规范让一行代码减去大量重复的工作
5.3 React相关的
我技术栈主要是React,没用过vue,所以本来想看看antd系列有没有类似的东西,但是并没有找到…当然本文的知识点基本都还是原生JS
但我还是想看看🤣如果你有看到 Re``act 技术栈有用到类似东西的话,欢迎评论区留言,让我去瞅瞅😛🌊如果有所帮助,欢迎点赞关注,一起进步⛵
