Yeoman,教你快速打造自己的腳手架

yeoman.png

不造大家在實(shí)際開(kāi)發(fā)項(xiàng)目中,有沒(méi)有這樣的困惑,就是每次起一個(gè)新的項(xiàng)目,腳手架都要從舊有的項(xiàng)目copy,然后改名、刪除內(nèi)容,留下基本框架,最后還有npm install,安裝包。并且,經(jīng)常會(huì)因?yàn)椴寮陌姹締?wèn)題,導(dǎo)致運(yùn)行出錯(cuò)(當(dāng)然,如果你所在的小組有一套完整的工具流,可以忽略我)。

身為程序媛的我,怎么可以忍受這種不高bigger的項(xiàng)目腳手架搭建方式呢?

還好,有Yeoman來(lái)相助。

搭建腳手架必備工具

  • yeoman
  • 腳手架模板

起始準(zhǔn)備

  • 確定你安裝了node和npm,node的版本要求在4.0以上,npm要求與node相匹配的版本。
    版本號(hào)可以通過(guò)以下方式查看:
node-version.png
  • 全局安裝yeoman
sudo npm install -g yo
  • 查看版本
yo-version.png

創(chuàng)建屬于你自己的generator

創(chuàng)建文件目錄

  • 創(chuàng)建文件夾,文件夾名為generator-namename是你創(chuàng)建的generator的名字。這里我以generator-gulp為例,創(chuàng)建以gulp為構(gòu)建工具的腳手架

  • 創(chuàng)建package.json

npm init
  • 創(chuàng)建文件夾app、templates,文件index.js

  • 現(xiàn)在的文件目錄如下:

  - generator-gulp
    - app
      - templates  // 存放腳手架目錄
      - index.js     // 對(duì)腳手架進(jìn)行操作的代碼
    - package.json

修改package.json

{
    "name": "generator-gulp",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [
        "yeoman-generator"
    ],
    "author": "huangxiaoyan",
    "license": "ISC",
    "dependencies": {
        "del": "^2.2.0",
        "yeoman-generator": "^0.23.3"
    }
}

安裝插件

執(zhí)行npm install,安裝yeoman-generator和del這兩個(gè)插件

npm install

創(chuàng)建腳手架模板

我以基于gulp的腳手架為例。分為pc端和移動(dòng)端這兩種模板,創(chuàng)建后的目錄如下:

  - templates
    - mobile
      - html
      - js
      - sass
      -images
    - pc
     - html
      - js
      - sass
      -images
    - gulpfile.js
    - package.json

編寫(xiě)index.js

這是最重要最關(guān)鍵的一步。

Yeoman提供了多個(gè)方法來(lái)搭建你自己的腳手架。具體的可以去看看官方文檔,在這里,我只抽取里面主要的方法來(lái)完成腳手架的搭建。

先上框架版的index.js

var generators = require('yeoman-generator'),
    _ = require('yeoman-generator/node_modules/lodash'),
    glob = require('yeoman-generator/node_modules/glob'),
    chalk = require('yeoman-generator/node_modules/chalk'),
    log = console.log,
    fs = require('fs'),
    path = require('path'),
    del = require('del'),
    generatorName = 'gulp';  // 記住這個(gè)名字,下面會(huì)有用

 // 導(dǎo)出模塊,使得yo xxx能夠運(yùn)行
module.exports = yeoman.generators.Base.extend({
    constructor: function () {
        // 默認(rèn)會(huì)添加的構(gòu)造函數(shù)
        yeoman.generators.Base.apply(this, arguments);
    },
    prompting: function () {
         // 詢(xún)問(wèn)用戶(hù)
    },
    writing: {
        // 拷貝文件,搭建腳手架
    },
    end: {
        // 搭建完執(zhí)行的操作
    }
})

constructor

在這個(gè)階段,檢查腳手架是否已經(jīng)存在,如果存在,則退出。

  constructor: function(){
        generators.Base.apply(this, arguments);

        // 檢查腳手架是否已經(jīng)存在
        var dirs = glob.sync('+(src)');
        //now _.contains has been abandoned by lodash,use _.includes
        if(_.includes(dirs, 'src')){
            // 如果已經(jīng)存在腳手架,則退出
            log(chalk.bold.green('資源已經(jīng)初始化,退出...'));
            setTimeout(function(){
                process.exit(1);
            }, 200);
        }
    },

prompting

詢(xún)問(wèn)用戶(hù),根據(jù)答案生成不同模板的腳手架

  prompting: function(){
        var questions = [
            {
                name: 'projectAssets',
                type: 'list',
                message: '請(qǐng)選擇模板:',
                choices: [
                    {
                        name: 'PC模板',
                        value: 'pc',
                        checked: true   // 默認(rèn)選中
                    },{
                        name: 'Mobile模板',
                        value: 'mobile'
                    }
                ]
            },
            {
                type: 'input',
                name: 'projectName',
                message: '輸入項(xiàng)目名稱(chēng)',
                default: this.appname
            },
            {
                type: 'input',
                name: 'projectAuthor',
                message: '項(xiàng)目開(kāi)發(fā)者',
                store: true,   // 記住用戶(hù)的選擇
                default: 'huangxiaoyan'
            },{
                type: 'input',
                name: 'projectVersion',
                message: '項(xiàng)目版本號(hào)',
                default: '0.0.1'
            }
        ]
        return this.prompt(questions).then(
            function(answers){
                for(var item in answers){
                    // 把a(bǔ)nswers里的內(nèi)容綁定到外層的this,便于后面的調(diào)用
                    answers.hasOwnProperty(item) && (this[item] = answers[item]);
                }
            }.bind(this));
    }

writing

copy文件到指定目錄,生成腳手架。

writing: function(){
        /**
        * 可以在prompting階段讓用戶(hù)輸入
        * 也可以指定,完全根據(jù)個(gè)人習(xí)慣
        **/
        this.projectOutput = './dist';
        //拷貝文件
        this.directory(this.projectAssets,'src');
        this.copy('gulpfile.js', 'gulpfile.js');
        this.copy('package.json', 'package.json');
    }

end

生成腳手架后,進(jìn)行的一些處理。

end: function(){
          /**
          * 刪除一些多余的文件
          * 由于無(wú)法復(fù)制空文件到指定目錄,因此,如果想要復(fù)制空目錄的話
          * 只能在空文件夾下建一個(gè)過(guò)渡文件,構(gòu)建完后將其刪除
        **/
        del(['src/**/.gitignore','src/**/.npmignore']);
        var dirs = glob.sync('+(node_modules)');
        if(!_.includes(dirs, 'node_modules')){
            // 將你項(xiàng)目的node_modules和根目錄下common-packages的node_modules進(jìn)行軟連接
            // 為什么要這樣做,大家可以先想想
            this.spawnCommand('ln', ['-s', '/usr/local/lib/node_modules/common-packages/'+generatorName+'/node_modules', 'node_modules']);
        }
    }

最后一步

generator-gulp目錄下執(zhí)行

npm link

這一步將generator-gulp軟連接到你的usr/local/lib/node_modules/generator-gulp
這樣運(yùn)行yo時(shí),就可以找到這個(gè)generator-gulp

未解決的問(wèn)題

最后還有一個(gè)問(wèn)題,就是為什么在end階段要對(duì)node_modules進(jìn)行軟連接呢?

因?yàn)檫@樣每次構(gòu)建腳手架的時(shí)候,不需要每次都去安裝插件,不需要每次都去執(zhí)行npm install,并且可以保證包的版本號(hào)一致。

common-packages

我們可以創(chuàng)建這樣的一個(gè)目錄,專(zhuān)門(mén)存放需要的node_modulescommon-packages就是這樣的一個(gè)功能。
目錄結(jié)構(gòu)如下:

- common-packages
  - gulp
    - package.json
    - node_modules

其中,gulp這個(gè)文件名是跟你的generatorName是一致的。
剛剛上面說(shuō)了,這個(gè)文件是在根目錄下的,但是,由于我們可能以后會(huì)對(duì)這個(gè)目錄進(jìn)行修改添加,所以放在根目錄不是很合適。
所以我們可以這樣做,將common-package同樣軟連接到根目錄。

進(jìn)入common-packages,執(zhí)行

npm link

至此,腳手架模板打造完成。

新建項(xiàng)目文件,打開(kāi)終端,執(zhí)行yo,可以看到:

腳手架搭建.png

恭喜恭喜,您已經(jīng)成功了!

完整的項(xiàng)目代碼可以到我的github上查看。
github項(xiàng)目地址:https://github.com/SunnySnail/yo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378

推薦閱讀更多精彩內(nèi)容