使用YEOMAN建立屬於本身的前端工做流

背景

前幾天看了一篇文章大受啓發:我理想中的前端工做流,如今工做中一直在使用gulp和webpack作自動化,在單獨項目中效果很不錯。可是隨着項目逐漸怎多,是須要使用一個工具來幫你快速建立和規範項目。javascript

Yeoman是什麼

Yeoman是一個腳手架,能夠快速生成一個項目的骨架。官網上有不少你們已經寫好的腳手架,也能夠本身寫一個適合本身的,接下來我會翻譯下官網的教程,學習的同時把經驗分享給你們。css

Yeoman能作什麼

Yeoman只是幫咱們生成項目的骨架是遠遠不夠的,官網上介紹,Yeoman是由三部分組成的:腳手架工具 - Yo、構建工具 - Grunt or Gulp、包管理工具 - Bower or npm。html

建立Yeoman

翻譯yeoman官網Creating a generator流程

(一)Getting started 快速開始
(二)Running Context 生命週期
(三)User Interactions 和使用者互動
(四)composability 組合
(五)Managing Dependencies 依賴管理
(六)Interacting with the file system 文件操做前端


(一)快速開始

原文地址:http://yeoman.io/authoring/index.htmlvue

1.1 創建一個node模塊

1.首先要創建一個文件夾,在這個文件夾內寫你的generator,這個文件夾的名字 必須 被命名爲generator-name,name爲你generator的名字,假如我想寫一個vue的腳手架,我能夠命名爲:generator-vue,這個很關鍵,Yeoman文件系統只會信任這種規範的generator。java

mkdir generator-vue

2.創建node模塊,首先要必備文件 package.json ,這個文件能夠經過執行 npm init 指令來生成,前提是須要安裝 node 及 npm。node

{
  "name": "generator-vue",
  "version": "0.1.0",
  "description": "",
  "files": [
    "app",
    "router"
  ],
  "keywords": ["yeoman-generator"],
  "dependencies": {
    "yeoman-generator": "^0.20.2"
  }
}

幾點要求:webpack

1. name:必須格式爲 `generator-你項目的名字`。
2. keywords:數組中必須有 `yeoman-generator`,這樣你的項目纔會被[Yeoman官方的generators列表](http://yeoman.io/generators/)所收錄。 
3. 若是須要添加其餘的屬性能夠去[npm官網文檔](https://docs.npmjs.com/files/package.json#files)中查看。

1.2 文檔結構

經過1.1步驟已經有了package.json,下一步在新建兩個文件夾分別叫app和router,結構以下。git

├───package.json
├───app/
│   └───index.js
└───router/
    └───index.js
1.2.1 默認項目

當你執行Yeoman指令 yo vue(上面你已經創建的項目名字)的時候,他會默認執行你根目錄下app/index.js的內容,因此一個新項目,app/ 目錄是必須的。github

1.2.2 子項目

router/做爲子項目,能夠經過 yo vue:router 來執行。

1.2.3 更改文件目錄
├───package.json
└───generators/
    ├───app/
    │   └───index.js
    └───router/
        └───index.js

若是不喜歡把全部項目都放在根目錄下,Yeoman還容許把項目放在 generators/ 下面,改寫上面的例子:

├───package.json
└───generators/
    ├───app/
    │   └───index.js
    └───router/
        └───index.js

若是更改了文件目錄,要同步修改 package.json 中對應文件的目錄結構:

{
  "files": [
    "generators/app",
    "generators/router"
  ]
}

1.3 擴展generator

1.3.1 重寫構造函數
module.exports = generators.Base.extend({
  // The name `constructor` is important here
  constructor: function () {
    // Calling the super constructor is important so our generator is correctly set up
    generators.Base.apply(this, arguments);

    // Next, add your custom code
    this.option('coffee'); // This method adds support for a `--coffee` flag
  }
});
1.3.2 添加本身的方法
module.exports = generators.Base.extend({
  method1: function () {
    console.log('method 1 just ran');
  },
  method2: function () {
    console.log('method 2 just ran');
  }
});

下一步的時候當你運行generator的時候,會看到這兩句console輸出在控制檯。

1.4 運行generator

1.4.1 安裝全局generator

在項目跟路徑下 generator-name(vue)/ 執行指令:

npm link

過程當中,將會安裝node模塊依賴,和建立軟鏈接指向你當前項目。

//1.到本地全局node模塊路徑下
cd /usr/local/lib/node_modules 

//2.查看列表
ll 

//3.會看到已經安裝了一個全局的geneator-vue模塊
npm
geneator-vue -> /Users/lvjinlong/generator-vue
gulp
..  

//4.此時在任意新建的項目文件夾中yo項目的名字,會看到上面實例中的console打印出來的結果。
yo vue
1.4.2 尋找根目錄

安裝geneator的時候,Yeoman會搜索你的文件夾,會把包含 .yo-rc.json 文件的文件夾做爲你的根目錄來初始化項目。

問:那麼, .yo-rc.json 是個什麼東西呢?
答:當你 第一次 調用 this.config.save() 的時候,系統會生成這個文件。

問:那麼,this.config.save() 這個方法的做用是什麼呢?
答:官網 這篇文章會有講解,大致意思是會利用 .yo-rc.json 來存儲或是讀取用戶相關信息。

因此當你初始化一個項目的時候,別忘記清除掉以前系統生成的.yo-rc.json


(二)生命週期

原文地址:http://yeoman.io/authoring/running-context.html

2.1 Prototype methods as actions

每一個方法會直接附加在generator原型上做爲一個action,每一個action按照必定的循序執行在Yeoman的生命週期中。

這些方法至關於直接執行了 Object.getPrototypeOf(generator)
全部方法都會 自動執行 。若是不想都自動執行,請往下看。

2.1.1 私有方法

只有私有方法在Yeoman中才不會自動執行,下面有三種辦法幫你建立一個私有方法。

1. 在方法名前面加下劃線(例如:_method
2. 使用實例方法
generators.Base.extend({
  init: function () {
    this.helperMethod = function () {
      console.log('won\'t be called automatically');
    };
  };
});
3.繼承父generator
var MyBase = generators.Base.extend({
    helper: function () {
      console.log('won\'t be called automatically');
    }
  });

  module.exports = MyBase.extend({
    exec: function () {
      this.helper();
    }
  });

2.2 生命週期

Yeoman中的定義了生命週期鉤子,和這些鉤子命名相同的會按照順序執行,若是和這些鉤子名稱不同則默認爲 default

這些生命週期鉤子 按順 序爲:

  1. initializing:初始化方法(檢驗當前項目狀態、獲取configs、等)
  2. prompting:獲取用戶選項
  3. configuring:保存配置(建立 .editorconfig 文件)
  4. default:若是函數名稱如生命週期鉤子不同,則會被放進這個組
  5. writing:寫generator特殊的文件(路由、控制器、等)
  6. conflicts:衝突後處理辦法
  7. install:正在安裝(npm、bower)
  8. end:安裝結束、清除文件、設置good bye文案、等

(三)和用戶互動

原文地址:http://yeoman.io/authoring/user-interactions.html

Yeoman默認在終端中執行,可是也支持在多種不一樣工具中執行。這時候咱們使用 console.log() 或是 process.stdout.write() 用戶就可能看不到,Yeoman中使用 generator.log() 來統一打印輸出結果。

3.1和用戶互動

3.1.1 Prompts - 提示框

提示框是Yeoman主要和用戶交流的手段,是經過Inquirer模塊來實現的,全部的API及參數能夠看這裏,執行如下實例看下效果:

module.exports = generators.Base.extend({
  prompting: function () {
    var done = this.async();
    this.prompt({
      type    : 'input',
      name    : 'name',
      message : 'Your project name',
      default : this.appname // Default to current folder name
    }, function (answers) {
      this.log(answers.name);
      done();
    }.bind(this));
  }
})
3.1.2 Remembering user preferences 記錄用戶預設參數

一個肯定的答案,好比賬號,用戶可能屢次提交同一個答案,這時候能夠用Yeoman提供 store 來存儲這些答案。

this.prompt({
  type    : 'input',
  name    : 'username',
  message : 'What\'s your Github username',
  store   : true
}, callback);

這時候會在跟路徑下生成一個.yo-rc.json文件,裏面會存儲name信息。能夠參考官網storage這一節

3.1.3 Arguments - 參數

參數直接經過命令行傳遞,例如:

yo webapp my-project

這個例子中,my-project 是第一個參數。

通知系統咱們須要參數,咱們使用 generator.argument() 方法,這個方法接受兩種形式:

  1. name(String) -- generator['name']
  2. hash(key-value) -- 哈希值的形式,接受如下參數做爲key值

    • desc -> 參數描述
    • required -> 是否爲必須傳遞 [ ture | false ]
    • optional -> 是否可選 [ ture | false ]
    • type -> 參數類型 [ String | Number | Array | Object]
var _ = require('lodash'); //須要提早安裝lodash模塊,提供一些經常使用方法
module.exports = generators.Base.extend({
  //注: arguments和options必須在constructor中定義.
  constructor: function () {
    generators.Base.apply(this, arguments);
    //appname爲一個必須的參數
    this.argument('appname', { type: String, required: true });
    //用駝峯式把這個參數保存起來
    this.appname = _.camelCase(this.appname);
  }
});
3.1.4 Options - 選項

Options(選項)看起來像是Arguments(參數),可是他們是在命令行中的標誌。

實例:舉一個官網團隊的腳手架demo - webapp - 15行

module.exports = generators.Base.extend({
  constructor: function () {
    generators.Base.apply(this, arguments);
    this.option('skip-welcome-message', {
      desc: 'Skips the welcome message',
      type: Boolean
    });
  }
})

用法:
webapp - options

yo webapp --skip-install

3.2 輸出信息

輸出信息使用 generator.log 模塊,和js的 console.log() 基本一致。

module.exports = generators.Base.extend({
  myAction: function () {
    this.log('Something has gone wrong!');
  }
});

傳值的方式同Arguments(參數),字符串或hash。區別是參數:

* desc:描述
* alias:簡寫(--version 簡寫爲 -v)
* type:[ Boolean | String | Number ]
* defaults:默認值
* hide :[ Boolean ] 是否隱藏幫助信息

(四)組合

原文地址:http://yeoman.io/authoring/composability.html

頗有趣的是,官網的第一個demo居然是一個變形金剛組合的gif,可見他們是多麼想表達各個小功能組合起來後的yeoman是有多強大。

能夠經過如下兩種方式開始組合:

  1. 依賴另一個generator(例如:generator-backbone 使用 generator-mocha)。
  2. 使用者,根據本身的需求在初始化項目的時候選擇配置。(例如:sass 或者 less來搭配 webpack 或是 gulp

4.1 generator.composeWith()

composeWith 方法容許你的generator來組合別人的generator,可是一旦組合成功,不要忘記第二章的內容 <(二)Running Context 生命週期>,全部被組合的generator都遵循Yeoman的生命週期規則來順序執行,不一樣的generator執行順序,取決於composeWith調用他們的順序,看下面的API及執行順序實例。

4.1.1 API

composeWith接收三個參數:

  1. namespace:聲明generator和誰組合。[ String ]
  2. options:調用generator的時候須要接收的參數。[ Object | Array ]
  3. settings:你的generator用這些配置來決定若是運行其餘的generators。[ Object ]

    • settings.local:須要在 dependencies中配置,使用dependencies安裝的模塊至關於本地模塊,這裏使用 require.resolve來返回一個本地模塊的路徑,如:node_modules/generator-name [ String ]
    • settings.linkweak or strong [ String ]

      • week link:在初始化的時候不運行,好比後端運行的,frameworks或css的預處理。
      • strong link:一直運行。

當須要用 peerDependencies 來組合generator

this.composeWith('backbone:route', { options: {
  rjs: true
}});

當須要用 dependencies 來組合generator

this.composeWith('backbone:route', {}, {
  local: require.resolve('generator-bootstrap')
});

//注:require.resolve()將返回node.js須要的模塊路徑。

接下來4.2中會解釋 peerDependenciesdependencies的區別。

4.1.2 執行順序實例

// In my-generator/generators/turbo/index.js
module.exports = require('yeoman-generator').Base.extend({
  'prompting' : function () {
    console.log('prompting - turbo');
  },

  'writing' : function () {
    console.log('writing - turbo');
  }
});

// In my-generator/generators/electric/index.js
module.exports = require('yeoman-generator').Base.extend({
  'prompting' : function () {
    console.log('prompting - zap');
  },

  'writing' : function () {
    console.log('writing - zap');
  }
});

// In my-generator/generators/app/index.js
module.exports = require('yeoman-generator').Base.extend({
  'initializing' : function () {
    this.composeWith('my-generator:turbo');
    this.composeWith('my-generator:electric');
  }
});

來分析下上面這段腳本:

  1. 以上這段腳本在初始化的時候執行了兩個 composeWith 方法 turbo 和 electric。
  2. 分別執行了他們目錄下的index.js。
  3. 加載順序判斷:turbo 優先於 electric。
  4. 生命週期問題:prompting 優先於 writing。

因此執行後的結果以下:

prompting - turbo
prompting - zap
writing - turbo
writing - zap

4.2 peerDependenciesdependencies的區別

npm容許如下三種dependencies(依賴):

  1. dependencies:使用依賴,本身或是別人使用你的generator所必備的依賴模塊。這些模塊被generator視爲本地模塊。
  2. peerDependencies:看下面的 注: npm@3後,peerDependencies不會再被自動安裝,須要手動。
  3. devDependencies:開發依賴,做爲開發或者是測試須要用的模塊,若是別人安裝你的generator,這些模塊不該該被安裝。

當使用 peerDependencies 別的模塊也要依賴當前這個模塊,當心不要建立版本致使衝突,Yeoman推薦使用(>=) 或 (*) 來安裝可用的版本,如:

{
  "peerDependencies": {
    "generator-gruntfile": "*",
    "generator-bootstrap": ">=1.0.0"
  }
}

注:npm@3之後,peerDependencies不會再被自動安裝,安裝他們必須執行以下:

npm install generator-yourgenerator generator-gruntfile generator-bootstrap@">=1.0.0"

(五)依賴管理

原文地址:http://yeoman.io/authoring/dependencies.html

Yeoman提供如下幾種形式來安裝依賴。

5.1 npm

使用 generator.npmInstall() 來安裝npm包,若是你在多個generators調用了 npm install Yeoman保證只會執行一次。

例如:你須要安裝 lodash 這個模塊做爲發開依賴。

generators.Base.extend({
  installingLodash: function() {
    this.npmInstall(['lodash'], { 'saveDev': true });
  }
});

效果等同於直接在終端輸入:

npm install lodash --save-dev

5.2 Bower

使用 generator.bowerInstall() 來安裝依賴。實例:同npm。

5.3 Both npm & Bower

使用 generator.installDependencies() 來同時安裝npm 和 bower。實例:同npm。

5.4 Using other tools

可使用 spawnCommand 來安裝其餘工具。好比:PHP的composer。

(六)文件操做

原文地址:http://yeoman.io/authoring/file-system.html

6.1 根路徑

Yeoman會在這個根路徑中建立你項目的腳手架。

根路徑會以如下兩種方式定義:

  1. 當前工做路徑
  2. 最近一級中包含 .yo-rc.json 的路徑

你能夠經過Yeoman提供的 generator.destinationRoot() 方法來獲取根路徑,這個方法接收一個參數 generator.destinationPath('sub/path') 來獲取子目錄的路徑。

例如:

查看當前路徑

$ pwd
~/projects
//跟路徑是 ~/projects
generators.Base.extend({
  paths: function () {
    this.destinationRoot();
    // returns '~/projects'

    this.destinationPath('/sub/index.js');
    // returns '~/projects/sub/index.js'
  }
});

6.2 經常使用工做路徑

原文是Template context,其實我感受直譯不太好,換作叫經常使用工做路徑會更好。

這個路徑的默認取你當前目錄 ./templates/ , 能夠手動覆蓋這個路徑 generator.sourceRoot('new/template/path')

例如:

generators.Base.extend({
  paths: function () {
    this.sourceRoot(); //設置經常使用工做路徑
    // returns './templates'

    this.templatePath('index.js'); //讀取經常使用工做路徑
    // returns './templates/index.js'
  }
});

6.3 文件操做

全部文件相關的方法都會經過 this.fs 暴露出來。這裏有全部文件操做相關方法,包括下面的copyTpl 方法。

實例: 把一個 經常使用工做路徑 的文件複製到 根路徑 下,並傳一個參數。

1.經常使用工做路徑下的 ./templates/index.html 內容是:
<html>
  <head>
    <title><%= title %></title>
  </head>
</html>
2.咱們用 copyTpl 方法把來複制文件,該方法使用ejs模板語法
generators.Base.extend({
  writing: function () {
    this.fs.copyTpl(
      this.templatePath('index.html'),//第一個參數:from
      this.destinationPath('public/index.html'),//第二個參數:to
      { title: 'Templating with Yeoman' }//第三個參數:options
    );
  }
});
3.來看複製後的 public/index.html
<html>
  <head>
    <title>Templating with Yeoman</title>
  </head>
</html>

6.4 經過「流」來改變文件

Yeoman提供 registerTransformStream() 方法,使用gulp的來操做文件。

例如:

var beautify = require('gulp-beautify');
this.registerTransformStream(beautify({indentSize: 2 }));

6.5 修改已經存在文件的內容

Yeoman介紹了幾個比較流行的解析器:

1.Cheerio for parsing HTML,基本實現流程以下
var cheerio = require('cheerio'),
    $ = cheerio.load('<h2 class="title">Hello world</h2>');

$('h2.title').text('Hello there!');
$('h2').addClass('welcome');

$.html();
//=> <h2 class="title welcome">Hello there!</h2>
2. Esprima for parsing JavaScript
3. For JSON files 可使用JSON原生的方法
本次只翻譯了前六章,後續會翻譯後六章、本身若是寫一個generator以及遇到的坑和問題。都會更新在個人github的Yeoman-article中。

github:https://github.com/tonyljl526/yeoman

相關文章
相關標籤/搜索