使用yeoman-generator 构建自己的脚手架

yeoman-generator

 yeoman-generator是一个构建脚手架的工具,如果你还不了解你自行google到官网看下,这里只简单介绍一下,它是一个脚手架生成工具,比如在之前写 ASP.NET MVC 的时候,Visual Studio 会给你选模板,然后生成一个项目的基本结构(脚手架),这对提升开发体验是很有帮助的,节省了重复劳动。然而前端没有什么 IDE(WebStorm?或许吧),没有一个固定的开发模式,可能你喜欢 jshint,我想用 eslint,你觉得 angular 顺手,我觉得 vue 更合适,这时就可以使用 Yeoman 这个工具,生成一个适合自己技术栈的脚手架,需要的一些文件都预先生成好,给自己省点事

yeoman-generator的开发配置

环境准备

安装或者更新一下你的node和npm

npm install -g n  //首先安装n模块

n stable  //升级node.js到最新稳定版

n 5.0.0  //或者指定版本升级

node -v  //检查更新是否成功

然后安装yeoman

npm install -g yo

创建目录

新建一个名为generator-xxx(yeoman脚手架命名规范)的文件夹,我这里叫generator-vue-webpack。然后在目录下执行npm init创建package.json文件。修改为

{

     "name":"generator-vue-webpack",

      "version":"1.0.0",

     "description":"vue2+webpack2脚手架",

       "main":"generators/index.js",

"scripts": {

        "test":"echo \"Error: no test specified\" && exit 1"

},

"files": [

       "generators"

],

"repository": {

            "type":"git",

            "url":"git+https://github.com/xiaoxinghug/generator-vuepackage.git"

},

"keywords": [

          "yeoman-generator"

],

"dependencies": {

        "deep-extend":"^0.4.1",

          "generator-license":"^3.1.1",

              "yeoman-generator":"^0.22.0",

           "chalk":"^1.1.3",

         "yosay":"^1.2.1",

          "lodash":"^4.11.1",

           "mkdirp":"^0.5.1"

},

"author":"chenxiaoxing",

"license":"ISC",

"bugs": {

          "url":"https://github.com/xiaoxinghug/generator-vuepackage/issues"

},

"homepage":"https://github.com/xiaoxinghug/generator-vuepackage#readme",

"license":"Apache-2.0"

}

然后在此目录下新建generators->app->index.js,generators-app-templates,如下图所示:



generator-reactpackage是整个npm包的项目文件夹

templates目录里面就是我们最后要用到的项目模版文件,里面的内容是一个完整的前端项目,可以自定义。

index.js是开发脚手架的主要逻辑文件。

开始开发

然后编辑index.js文件:

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

cons tpath=require('path');

const fs=require('fs');

const chalk=require('chalk');

const yosay=require('yosay');

const _=require('lodash');

const extend=require('deep-extend');

const utils=require('./utils/misc');

const CONFIG=require('./templates/config');

const boilerplatesMap=CONFIG.boilerplatesMap;

module.exports=yeoman.Base.extend({

info:function() { 

            this.log(chalk.green('I am going to build your app!'));

},

initializing:function() {

           this.props={};

},

prompting:function() {

             vardone=this.async();

             letallBoilerplates=_.keys(boilerplatesMap);

varprompts=[     

 {

                       name:'boilerplate',

                      type:'list',

                      choices:allBoilerplates,

                      default:allBoilerplates[0],

                      message:'boilerplate'

}, {

                    name:'name',

                    message:'Your project name',

                   default:path.basename(process.cwd())// Default to current folder name

}, {

                  name:'version',

                 default:'0.1.0',

                 message:'version'

},

{

             name:'description',

            default:'vue project',

             message:'description'

},

{

               name:'repo',

            default:utils.getGitOrigin(),

            message:'git repository'

},

{

            name:'keywords', 

          default:'vue',

          message:'keywords',

 filter:function(words) {

          returnwords.split(/\s*,\s*/g);

}

},

{

            name:'author',

         default:this.user.git.name(),

       message:'author'

},

{

         name:'email', 

       default:this.user.git.email(),

       message:'E-Mail'

}

];

this.prompt(prompts,function(props) {

          this.props=props;

// To access props later use this.props.someAnswer;

            done();

}.bind(this));

},

/*

* 生成 LICENSE

*

* */

default:function() {

     this.composeWith('license', { 

options:{

          name:this.props.author,

         email:this.props.email,

           website:''

}

}, {

local:require.resolve('generator-license/app')

});

},

writing:{

"init":function() {

           this.currentDir=boilerplatesMap[this.props.boilerplate]||_.keys(boilerplatesMap)[0];

},

/*

* 生成 package.json

*

* */

"package_json":function() {

             varcurrentPkg=this.fs.readJSON(this.destinationPath('package.json'), {});

          varpkg_json={

                 "webpack2+vue2+router2":{

                   devDependencies:{

                           "autoprefixer":"^6.7.2",

                            "babel-core":"^6.22.1",

                            "babel-loader":"^6.2.10",

                              "babel-plugin-transform-runtime":"^6.22.0",

                              "babel-preset-env":"^1.3.2",

                               "babel-preset-stage-2":"^6.22.0",

                               "babel-register":"^6.22.0",

                               "chalk":"^1.1.3",

                              "compression-webpack-plugin":"^0.4.0",

                               "connect-history-api-fallback":"^1.3.0",

                             "copy-webpack-plugin":"^4.0.1",

                              "css-loader":"^0.28.0",

                             "eventsource-polyfill":"^0.9.6",

                             "express":"^4.14.1",

                            "extract-text-webpack-plugin":"^2.0.0",

                        "file-loader":"^0.11.1",

                       "friendly-errors-webpack-plugin":"^1.1.3",

                        "html-webpack-plugin":"^2.28.0",

                         "http-proxy-middleware":"^0.17.3",

                           "isomorphic-fetch":"^2.2.1",

                      "less":"^2.7.2",

                     "less-loader":"^4.0.3",

"opn":"^4.0.2",

"optimize-css-assets-webpack-plugin":"^1.3.0",

"ora":"^1.2.0",

"rimraf":"^2.6.0",

"semver":"^5.3.0",

"shelljs":"^0.7.6",

"url-loader":"^0.5.8",

"vue-datepicker":"^1.3.0",

"vue-datepicker-simple":"^1.5.1",

"vue-loader":"^11.3.4",

"vue-style-loader":"^2.0.5",

"vue-template-compiler":"^2.2.6",

"vuex":"^2.3.1",

"webpack":"^2.3.3",

"webpack-bundle-analyzer":"^2.2.1",

"webpack-dev-middleware":"^1.10.0",

"webpack-hot-middleware":"^2.18.0",

"webpack-merge":"^4.1.0"

},

dependencies:{


},

scripts:{

"dev":"node build/dev-server.js",

"start":"node build/dev-server.js",

"build":"node build/build.js"

}

}


author:{

name:this.props.author,

email:this.props.email

},

keywords:[],

"dependencies":pkg_json.dependencies||{},

"devDependencies":pkg_json.devDependencies||{},

"scripts":pkg_json.scripts||{},

"bugs":{

"url":"http://"+utils.getHomeUrl(this.props.repo)+"/issues"

},

"homepage":"http://"+utils.getHomeUrl(this.props.repo)

},currentPkg);

// Combine the keywords

if(this.props.keywords) {

this.pkg.keywords=_.uniq(this.props.keywords.concat(this.pkg.keywords));

}

// Let's extend package.json so we're not overwriting user previous fields

this.fs.writeJSON(this.destinationPath('package.json'),this.pkg);

},

/*

* 生成 README.md

*

* */

"directories":function() {

this.fs.copy(this.templatePath('./'+this.currentDir+'/static')+"/gitignore",this.destinationPath('./.gitignore'));

this.fs.copy(this.templatePath('./'+this.currentDir+'/static')+"/babelrc",this.destinationPath('./.babelrc'));

this.fs.copy(this.templatePath('./'+this.currentDir+'/static')+"/**/*.*",this.destinationPath('./'));

// this.fs.copyTpl(this.templatePath('./' + this.currentDir + '/tpl') + "/**/*.*", this.destinationPath('./'), {AppName: this.pkg.name});

}

},

install(){//安装依赖

letopt={

cwd:this.destinationPath('./')

};

switch(this.props.boilerplate) {

case'webpack2+vue2':

this.spawnCommandSync('yarn', ['install'],opt);

// this.spawnCommandSync('webpack',[],opt);

this.spawnCommandSync('npm',['start'],opt);

break;

case'webpack2+vue2+router2':

this.spawnCommandSync('yarn', ['install'],opt);

// this.spawnCommandSync('webpack',[],opt);

this.spawnCommandSync('npm',['start'],opt);

break;

default:

break;

}

}

});

更多详细配置你转到 generator-vuepackage 或者加我qq咨询1083590865

yeoman-generator的使用

> npm install -g yo

> npm install -g generator的包名。使用yeoman-generator的脚手架包名需要以 generator-取名字,比如说你发布的npm包名是generator-angular就可以直接

> yo angular

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容