使用Yeoman generator來規範工程的初始化

前言

隨着開發團隊不斷髮展壯大,在人員增長的同時也帶來了協做成本的增長;業務項目愈來愈多,類型也各不相同。常見的類型有基礎組件、業務組件、基於React的業務項目、基於Vue的業務項目等等。若是想要對每一個項目進行一些規範上的約束好比Git提交規範、Javascript規範簡直難於登天。全部的這些,只是由於還欠缺一個好用的工程化工具,在項目建立的初期自動的將這些目錄結構和文件生成、而且集成工程常見的規範來進行約束。javascript

本文分爲兩部分,首先會談談目前團隊的痛點以及基於yeoman generator的設計思路;而後會詳細介紹如何實現定製的generator,過程當中遇到的問題和解決辦法。html

痛點一:工程建立不智能

  • 代碼目錄文件手工拷貝
  • 不一樣場景的工程對目錄結構的要求不盡相同

痛點二:規範約束難以統一集成

  • 難以在新的工程項目中集成新的規範,須要手動加hook
  • 缺乏增量機制對舊項目集成

基於Yeoman generator的設計思路

咱們須要給每一個工程類型的項目建立一個generator。按照目前前端技術棧的發展狀況來看,一個團隊通常會有3~5個generator。把這些generator當作一個個的插件,經過工具上層的CLI命令來暴露給開發者使用。前端

在generator之下,須要開發一系列服務和集成規範。包括和Git倉庫打通,也就是經過腳手架初始化目錄時,先對開發者鑑權。以後根據開發者輸入的項目名稱在遠程Git倉庫裏面建立倉庫而且授予開發者權限。後期功能完善以後,能夠作一些錦上添花的工做,好比進行數據統計,分析各個業務倉庫使用的generator版本信息,是否集成了最新的feature等等。java

總體系統架構以下:git

下面我準備開發一個適用於Now直播活動類搭建的腳手架了,名字是generator-now-activitygithub

自定義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 實例自己,調用的順序以下:shell

  • initializing - 初始化一些狀態之類的,一般是和用戶輸入的 options 或者 arguments 打交道,這個後面說。
  • prompting - 和用戶交互的時候(命令行問答之類的)調用。
  • configuring - 保存配置文件(如 .babelrc 等)。
  • default - 其餘方法都會在這裏按順序統一調用。
  • writing - 在這裏寫一些模板文件。
  • conflicts - 處理文件衝突,好比當前目錄下已經有了同名文件。
  • install - 安裝依賴
  • end - 結束部分

與用戶交互

Yeoman提供了API來讓generator和用戶進行交互,直接經過this.prompts函數,它的內部實現是使用了Inquire.js。npm

/**
   * 提示用戶輸入配置項
   * @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的拷貝方式進行區分。json

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

參考資料

相關文章
相關標籤/搜索