前言

随着开发团队不断发展壮大,在人员增加的同时也带来了协作成本的增加;业务项目越来越多,类型也各不相同。常见的类型有基础组件、业务组件、基于React的业务项目、基于Vue的业务项目等等。如果想要对每个项目进行一些规范上的约束比如Git提交规范、Javascript规范简直难于登天。所有的这些,只是因为还欠缺一个好用的工程化工具,在项目创建的初期自动的将这些目录结构和文件生成、并且集成工程常见的规范来进行约束。

本文分为两部分,首先会谈谈目前团队的痛点以及基于yeoman generator的设计思路;然后会详细介绍如何实现定制的generator,过程中遇到的问题和解决办法。

痛点一:工程创建不智能

  • 代码目录文件手工拷贝
  • 不同场景的工程对目录结构的要求不尽相同

痛点二:规范约束难以统一集成

  • 难以在新的工程项目中集成新的规范,需要手动加hook
  • 缺少增量机制对旧项目集成

基于Yeoman generator的设计思路

我们需要给每个工程类型的项目创建一个generator。按照目前前端技术栈的发展情况来看,一个团队一般会有3~5个generator。把这些generator看成一个个的插件,通过工具上层的CLI命令来暴露给开发者使用。

在generator之下,需要开发一系列服务和集成规范。包括和Git仓库打通,也就是通过脚手架初始化目录时,先对开发者鉴权。之后根据开发者输入的项目名称在远程Git仓库里面创建仓库并且授予开发者权限。后期功能完善之后,可以做一些锦上添花的工作,比如进行数据统计,分析各个业务仓库使用的generator版本信息,是否集成了最新的feature等等。

整体系统架构如下:

下面我准备开发一个适用于Now直播活动类搭建的脚手架了,名字是generator-now-activity

自定义generator的目录结构

├───package.json
└───generators/
├───app/
| ├───templates/
| | ├─── src/
| | |─── _cilintrc.js
| | |─── _eslintrc.js
| | |─── _fis-conf.js
| | |─── _package.json
| | |─── _project.js
| | |─── _README.md
| | |─── editorconfig
| | |─── gitignore
| | └─── vcmrc
│ └───index.js
└───utils.js

扩展generator

在generator的外层index.js文件里,通过继承yeoman-generator来扩展我们自己的generator,然后模块暴露给外部。

const Generator = require('yeoman-generator');

module.exports = class extends Generator {

}

Yeoman的运行周期

一个 Yeoman Generator 被创建后(构造函数必然是最先被调用的),会依次调用它原型上的方法,且每一个方法中的 this 都被绑定为 Generator 实例本身,调用的顺序如下:

  • initializing - 初始化一些状态之类的,通常是和用户输入的 options 或者 arguments 打交道,这个后面说。
  • prompting - 和用户交互的时候(命令行问答之类的)调用。
  • configuring - 保存配置文件(如 .babelrc 等)。
  • default - 其他方法都会在这里按顺序统一调用。
  • writing - 在这里写一些模板文件。
  • conflicts - 处理文件冲突,比如当前目录下已经有了同名文件。
  • install - 安装依赖
  • end - 结束部分

与用户交互

Yeoman提供了API来让generator和用户进行交互,直接通过this.prompts函数,它的内部实现是使用了Inquire.js。

  /**
* 提示用户输入配置项
* @returns {Promise.<TResult>}
*/
prompting() { return this.prompt([{
type: 'input',
name: 'projectName',
message: '请输入活动的名称 (now-activity):',
default: 'now-activity-default'
}]).then((answers) => {
this.log('活动名称', answers.projectName);
this.props = answers;
}); }

模板拷贝策略

对于工程src目录部分直接通过深度优先算法拷贝写入。对于工程的规范类、配置的文件需要单独写入,这一类可能需要接受用户的输入,同时需要集中进行维护,因此需要和src的拷贝方式进行区分。

src深度优先拷贝代码如下:

const fs = require('fs');
const path = require('path'); function read(root, filter, files, prefix) {
prefix = prefix || '';
files = files || [];
filter = filter || noDotFiles; const dir = path.join(root, prefix);
if (!fs.existsSync(dir)) return files;
if (fs.statSync(dir).isDirectory())
fs.readdirSync(dir)
.filter(filter)
.forEach(function (name) {
read(root, filter, files, path.join(prefix, name));
});
else
files.push(prefix); return files
} function noDotFiles(x) {
return x[0] !== '.';
} module.exports = {
read
};

在外层通过Yeoman提供的API this.fs.copy()方法来进行文件拷贝

    /**
* 源代码模板
*/
const sourceCode = () => {
const sourceDir = path.join(this.templatePath(), './src/');
const filePaths = utils.read(sourceDir);
_.each(filePaths, (filePath) => {
this.fs.copy(
this.templatePath('./src/' + filePath),
this.destinationPath('./src/' + filePath)
);
});
};

开发完generator之后,就可以通过yo now-activity来进行使用了。

generator和其它工具如CLI集成

前面提到的yo now-activity的方式使用可能存在一些问题,因为这种方式要求代码必须上传到github上。对于公司内部的工具,不走正常的开源流程显然是不被允许的。那么,有没有什么方法,不添加generator到Yeoman的generator列表里就能够使用呢?

幸运的是,Yeoman提供了yeoman-environment来帮助我们在其它工具中集成编写好的generator,yo其实也只是yeoman-environment暴露到上层的一个命令而已。

const yeoman = require('yeoman-environment');
const yeomanEnv = yeoman.createEnv(); /**
* Lookup方法会在本地查找已经安装过的generator
*/
yeomanEnv.lookup(() => {
yeomanEnv.run('@tencent/now-activity', {'skip-install': true}, err => {
console.log('done');
});
});

一些细节

  • 为了方便本地调试看效果,在generator根目录下运行 tnpm link
  • 使用Yeoman提供的API this.log来打印信息,而不要使用console.log
  • 如果是内部工具,运行的时候命令为:yo @tencent/now-activity

最后

安装示例(限内部)

$ tnpm install -g yo generator-generator @tencent/feflow-cli
$ feflow init

参考资料

使用Yeoman generator来规范工程的初始化的更多相关文章

  1. Yeoman generator

    使用Yeoman generator来规范工程的初始化 前言 随着开发团队不断发展壮大,在人员增加的同时也带来了协作成本的增加:业务项目越来越多,类型也各不相同.常见的类型有基础组件.业务组件.基于R ...

  2. node命令行工具之实现项目工程自动初始化的标准流程

    一.目的 传统的前端项目初始流程一般是这样: 可以看出,传统的初始化步骤,花费的时间并不少.而且,人工操作的情况下,总有改漏的情况出现.这个缺点有时很致命. 甚至有马大哈,没有更新项目仓库地址,导致提 ...

  3. 与你相遇好幸运,制作自己的Yeoman Generator

    使用别人写好的生成器: npm install -g yonpm install -g generator-angularyo angular 如何自己制作符合自己心仪的生成器呢: https://g ...

  4. 使用MeanJS Yeoman Generator

    1.首先全局安装该生成器 sudo npm install -g generator-meanjs 2.为项目创建一个路径 mkdir xmen && cd xmen 3.创建app ...

  5. 编写自定义Yeoman生成器

    转载自JSCON-简时空:<自定义Yeoman生成器> 1.Getting Started 1.1.设置Node模块 Yeoman提供了generator-generator方便快速编写自 ...

  6. 前端工程化系列[06]-Yeoman脚手架核心机制

    在前端工程化系列[05] Yeoman脚手架使用入门这边文章中,对Yeoman的使用做了简单的入门介绍,这篇文章我们将接着探讨Yeoman这个脚手架工具内部的核心机制,主要包括以下内容 ❏ Yeoma ...

  7. 基于Yeoman实现自定义脚手架

    什么是脚手架? Yeoman是什么? 实现自定义脚手架 基于Yeoman实现Vue-cli 一.什么是脚手架? 手脚架从功能上来讲就是创建项目初始文件,这其中包括生成功能模块配置.自动安装依赖.自动生 ...

  8. 为什么选择 Yeoman 及 Yeoman 的安装

    今天向您介绍一个我刚接触到的比较新的网络前端开发工具: Yeoman . 什么是Yeoman? Yeoman是Google的团队和外部贡献者团队合作开发的一个项目.通过内部三个工具(yo,grunt, ...

  9. 前端工程化系列[05] Yeoman脚手架使用入门

    Yeoman是一款流行的前端的脚手架工具. 脚手架工具可以用来快速的自动生成项目的必要文件和基础文件结构.Yeoman使用的内建命令为yo,同时它自己也是一个包管理工具和自动化任务工具,它基于特定的模 ...

随机推荐

  1. Kafka 0.10 Producer网络流程简述

    1.Producer 网络请求 1.1 Producer Client角度 KafkaProducer主要靠Sender来发送数据给Broker. Sender: 该线程handles the sen ...

  2. ionic,Angular 开发实践

    1.实践参考 http://www.jianshu.com/p/ea0dcf1d31c9 原文思路搭建 2. 环境搭建步骤 : a. 安装node b.安装 cordova      sudo   n ...

  3. Linux编程之ICMP洪水攻击

    我的上一篇文章<Linux编程之PING的实现>里使用ICMP协议实现了PING的程序,ICMP除了实现这么一个PING程序,还有哪些不为人知或者好玩的用途?这里我将介绍ICMP另一个很有 ...

  4. Codeforces 719B Anatoly and Cockroaches

    B. Anatoly and Cockroaches time limit per test:1 second memory limit per test:256 megabytes input:st ...

  5. eclipse设置统一编码

    1.Window-->Preferences-->General-->Workspace->Text file encoding->Other->UTF-8. 2. ...

  6. HR从业者的下一个十年该怎么做?

    众所周知,目前我们所处的以互联网为代表的新经济时代,有两个重要的特征一是客户价值至上,二是人力资本主权.围绕这两个基本特征,我们需要重新架构我们的商业模式和创新人力资源管理思维.模式.工具和方法. 人 ...

  7. android学习3——长宽的单位问题dp,px,dpi

    android设备的单位px,pt,dp,sp 分辨率 先通俗说下分辨率的概念.可以把屏幕想想成一个个正方形格子组成的.如果横向有1280个格子,竖向有720个格子.那么分辨率就是1280*720.这 ...

  8. 编程思想之——"人是活的,程序是死的"

    "人是活的,程序是死的"这句话我时常提起,可能很多人不是很理解我为什么会这样说,下面我就简单来谈谈我对这句话的理解. 1.不要因为技术而技术,技术选型的初衷是需求. 现在很多人在做 ...

  9. Dapper C# 访问SQLite

    1.以操作SQLite为例.先下载Dapper,项目引用添加Dapper.dll,然后入下 SQLiteConnectionStringBuilder sb = new SQLiteConnectio ...

  10. VUE2.0实现购物车和地址选配功能学习第四节

    第四节 v-on实现金额动态计算 用¥金额 进行格式处理,可以使用原生js进行转换,但是在vuei,使用filter过滤器更加方便 注: 1.es6语法=>和import等 好处在于res参数后 ...