1. 前言

大家好,我是若川。最近组织了源码共读活动,感兴趣的可以点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。已进行三个月了,很多小伙伴表示收获颇丰。

想学源码,极力推荐之前我写的《学习源码整体架构系列》 包含20余篇源码文章。

本文仓库 element-analysis,求个star^_^[1]

最近组织了源码共读活动,大家一起学习源码,每周学习200行左右的源码,已进行到13期。于是搜寻各种值得我们学习,且代码行数不多的源码。

其中 element-ui[2]新建组件的源码[3]100多行,非常值得我们学习。

可以通过 github1s.com 在线 VSCode 打开:https://github1s.com/ElemeFE/element/blob/dev/build/bin/new.js

阅读本文,你将学到:

1. 学会调试学习源码
2. element-ui 如何初始化新的组件
3. 可以学以致用应用到自己开发的项目中,比如新增页面等
4. 等等

2. 环境准备

2.1 克隆

# 推荐克隆我的项目,保证与文章同步
git clone https://github.com/lxchuan12/element-analysis.git
# npm i -g yarn
cd element-analysis/element && npm run dev# 或者克隆官方项目
git clone https://github.com/ElemeFE/element.git
# npm i -g yarn
cd element && npm run dev

2.2 看开源项目的 README 和贡献文档等

看开源项目,我们一般先看README,README.md[4] 中一般有贡献指南[5]

开发环境搭建

首先你需要 Node.js 4+,yarn 和 npm 3+。注意:我们使用 yarn 进行依赖版本的锁定,所以请不要使用 npm install 安装依赖。

git clone git@github.com:ElemeFE/element.git
npm run dev# open http://localhost:8085

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",},
}

npm run dev 时是先执行了 npm run bootstrap => yarn || npm i 命令,安装好了依赖。

npm run build:file 应该留着下一篇文章讲述。

组件开发规范

通过 make new 创建组件目录结构,包含测试代码、入口文件、文档 如果包含父子组件,需要更改目录结构,参考 Button组件内如果依赖了其他组件,需要在当前组件内引入,参考 Select

make 命令的配置对应根目录 Makefile

# element/Makefile
new:node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))

通过查看 Makefile 文件我们知道了make new命令对应的是:node build/bin.new.js

接着我们来调试源码。

2.3 调试源码

在最新版的 VSCode 中,auto attach 功能,默认支持智能调试,如果发现不支持,可以通过快捷键 ctrl + shift + p 查看是否启用。

ctrl + 快捷键打开终端。输入如下命令,即可调试build/bin/new.js`。

make new ruochuan 若川组件
# Ubuntu 和 Mac 支持 make 命令
# 不支持可以用 node
node build/bin/new.js ruochuan 若川组件

调试截图

更多调试细节可以看我的这篇文章:新手向:前端程序员必学基本技能——调试JS代码

接着我们按调试来看主流程。

3. 主流程

我看完 build/bin/new.js 源码画了一张流程图。毕竟俗话说得好,一图胜千言。

流程图

同时执行完命令后也新增和修改了若干文件,git diff 如下图所示。

所有修改的文件

接着我们来看 build/bin/new.js 文件。

3.1 文件开头判断

'use strict';console.log();
process.on('exit', () => {console.log();
});// 第一个参数没传递报错,退出进程
if (!process.argv[2]) {console.error('[组件名]必填 - Please enter new component name');process.exit(1);
}

关于 process 对象可以查看 阮一峰老师 process 对象[6]

process.argv 属性返回一个数组,由命令行执行脚本时的各个参数组成。它的第一个成员总是 node,第二个成员是脚本文件名,其余成员是脚本文件的参数。

接着我们来看,引用的依赖等。

3.2 引用依赖等

// 路径模块
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);
// const Files = [];

其中 file-save[7] 依赖,顾名思义,且非常关键。我们可以在 node_module/file-save 查看一些信息。也可以在 https://npmjs.com 搜索其信息。

接着,我们来看文件模板。定义了若干文件模板,方便写入到项目中。

3.3 文件模板 Files

const Files = [{filename: 'index.js',content: `import ${ComponentName} from './src/main';/* istanbul ignore next */
${ComponentName}.install = function(Vue) {Vue.component(${ComponentName}.name, ${ComponentName});
};export default ${ComponentName};`},{filename: 'src/main.vue',content: `<template><div class="el-${componentname}"></div>
</template><script>
export default {name: 'El${ComponentName}'
};
</script>`},
//   省略其他
];

接着我们继续看添加对应的路径到组件 json 配置中。

3.4 把 componentname 添加到 components.json

// 添加到 components.json
const componentsFile = require('../../components.json');
if (componentsFile[componentname]) {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');

添加到 components.json

3.5 把 componentname.scss 添加到 index.scss

// 添加到 index.scss
const 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');

3.6 把 componentname.d.ts 添加到 element-ui.d.ts

// 添加到 element-ui.d.ts
const 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.7 创建 package

// const PackagePath = path.resolve(__dirname, '../../packages', componentname);
// 创建 package
Files.forEach(file => {fileSave(path.join(PackagePath, file.filename)).write(file.content, 'utf8').end('\n');
});

创建的文件

3.8 把新增的组件添加到 nav.config.json

const 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!');

nav

nav.config.json 的修改,新增的组件显示在导航这里。其中有四次修改是对应四种语言。

nav 导航网站显示

4. 总结

再次放出开头的流程图。

流程图

通过看 element-ui[8]新建组件的源码[9] 流程,我们学到了 file-save[10] 这么方便的写入文件的库等。

同时给我们启发:公司项目新建页面时,或者组件库新增组件时,是不是可以类似做到的,一条命令省去一些繁杂重复的操作。

建议读者克隆我的仓库[11]动手实践调试源码学习。

后续也可以查看 file-save[12] 源码实现等。

最后可以持续关注我@若川。欢迎加我微信 ruochuan12 交流,参与 源码共读 活动,大家一起学习源码,共同进步。

参考资料

[1]

本文仓库 element-analysis,求个star^_^: https://github.com/lxchuan12/element-analysis.git

[2]

更多点击阅读原文查看

最近组建了一个湖南人的前端交流群,如果你是湖南人可以加我微信 ruochuan12 私信 湖南 拉你进群。

推荐阅读

1个月,200+人,一起读了4周源码
我历时3年才写了10余篇源码文章,但收获了100w+阅读

老姚浅谈:怎么学JavaScript?

我在阿里招前端,该怎么帮你(可进面试群)

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》10余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,最近组织了源码共读活动,帮助1000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

识别方二维码加我微信、拉你进源码共读

今日话题

略。分享、收藏、点赞、在看我的文章就是对我最大的支持~

每次新增页面复制粘贴?100多行源码的 element-ui 的新增组件功能教你解愁相关推荐

  1. 【vim】系统剪切板、vim寄存器之间的复制粘贴操作命令?系统剪切板中的内容复制粘贴到命令行?vim文本中复制粘贴到命令行

    一.系统剪切板和文本内容的复制粘贴 1.1 从系统剪切板复制粘贴到文本中 需要操作3次: 分别是英文双引号.一个加号或梅花号,最后是一个p 也即"+p 或者直接使用组合键[Shift + i ...

  2. C++官方自带可持久化平衡树rope的3000行源码

    C++官方rope3000行源码 // SGI's rope class -*- C++ -*-// Copyright (C) 2001-2015 Free Software Foundation, ...

  3. H5类似易企秀/编辑器/页面制作/开发/生成工具/软件/源码/授权

    代码地址如下: http://www.demodashi.com/demo/14960.html 项目简介 H5DS (HTML5 Design software) 这是一款基于WEB的 H5制作工具 ...

  4. HTML5期末考核大作业: 网站——美丽家乡 云南民族文化(8页面) ~ 学生DW网页设计作业源码

    HTML5期末考核大作业: 网站--美丽家乡 云南民族文化(8页面) ~ 学生DW网页设计作业源码 临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大?HTML网页作业无从下手?网页 ...

  5. HTML5期末考核大作业: 网站——美丽家乡 云南民族文化(8页面) ~ 学生DW网页设计作业源码...

    HTML5期末考核大作业: 网站--美丽家乡 云南民族文化(8页面) ~ 学生DW网页设计作业源码 临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大?HTML网页作业无从下手?网页 ...

  6. 小京东V4.2甜心100分销版本-源码分享

    小京东V4.2甜心100分销版本-源码分享 在这里插入图片描述 源码地址: 链接:https://pan.baidu.com/s/1D0z6cEKMxwkU_CokKPbY1A?pwd=znuh 提取 ...

  7. 分享100个PHP源码,总有一款适合您

    链接:https://pan.baidu.com/s/1izHMH9GY5_TEAWbsPFm-3g?pwd=z14r  提取码:z14r PHP源码 分享100个PHP源码,总有一款适合您 page ...

  8. 怎样复制粘贴windows命令行中的内容

    windows是图形化界面和鼠标点击操作的操作系统,但类DOS的命令行(简称CMD)依然存在,它还可以方便快捷的来维护管理电脑,有时候还是必须运行环境.但在命令行下想复制/粘贴某些东西就没有我们常用的 ...

  9. 每次启动项目的服务,电脑竟然乖乖的帮我打开了浏览器,100行源码揭秘!

    1. 前言 大家好,我是若川.最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 参与,已进行三个月了,大家一起交流学习,共同进步. 想学源码,极力推荐之前我写的<学习源码整体架 ...

最新文章

  1. error C1004 发现意外的文件尾
  2. 章节七、4-Sets
  3. iOS开发能用mysql吗_iOS开发之数据库的简单使用
  4. linux下查看tomcat的启动日志
  5. 从后端获取数据然后在页面处理技巧
  6. 小猿学python_小猿圈python入门之转行零基础该如何学Python?
  7. c语言 交互式电子白板案例,交互式电子白板教学案例
  8. Batch Normalization论文笔记
  9. 计算机实用基础试题答案,《计算机实用基础》试题卷(b).doc
  10. 软考笔记——2.1进程管理、同步互斥、死锁、线程
  11. Verilog实现的格雷码与二进制码的互相转换
  12. matlab离散信号z变换,离散信号与系统的Z变换分析
  13. 分式求二阶导数_第12讲 典型例题与练习参考解答:导数的基本运算法则与高阶导数...
  14. 罗振宇2021跨年演讲6:山村小学的豆腐课到底在玩啥?
  15. php游戏传奇,GitHub - esons/pmir2: php,swoole,mirserver,mir2,传奇2,服务器,游戏服务器
  16. LittleVGL入门
  17. 刘宇凡:莫沉浮华,归于平凡
  18. 全文检索服务 _ ElasticSearch
  19. 用html语言制作表白动画,抖音很火的卡通做我女朋友表白html源码
  20. Qt向MySQL中插入图片

热门文章

  1. python导入pyecharts错误没有pyecharts_python报No module named 'pyecharts'的错误怎么办?
  2. extjs中元数据_Extjs中Store小总结
  3. 《算法导论》——MergeSort
  4. vue中的适配:px2rem
  5. 畅通工程 HDU - 1863
  6. python天蝎座-day1笔记
  7. HTML - 超文本标记语言 (Hyper Text Markup Language)
  8. Swift基本语法学习笔记
  9. UML入门之类图教程
  10. C# 获取配置文件节点值