资讯专栏INFORMATION COLUMN

yeoman-generator 入门教程

caiyongji / 957人阅读

摘要:上下文路径为了方便文件流的输入输出,使用两种位置环境。目标上下文目标上下文定义为当前工作目录或含文件最接近的父文件夹。这确保了用户行为的一致。帮助用户严重需要覆盖的内容。

摘要

随着 Web 2.0 和 HTML 5 的流行,现在的 Web 应用所能提供的功能和交互能力比之前传统的 Web 应用要强大很多。应用的很多实现逻辑被转移到了浏览器端来实现。浏览器不再只提供单一的数据接收和展现功能,而是提供更多的用户交互能力。浏览器端所包含的 HTML、CSS 和 JavaScript 代码也变得更加复杂。对于日益复杂的前端代码,需要有更好的流程和工具来管理开发的各个方面,包括初始的代码结构、开发流程和自动化测试等。yeoman 是一个新兴的工具。它结合了 Yo、Grunt 和 Bower 等工具,组成了一个完整的工具集合,提供各种 Web 应用开发中所需的实用功能。

正文 1. yeoman

Yeoman可以帮助我们创建新的开发项目,为我们提供更好的工具来使我们的项目更多样化。

2. yeoman-generator

Generators是yeoman生态系统的积木,是通过yo命令运行而为终端用户生产文件的插件。

3. 构建创建自己的generator 1. 创建 node module

在你需要创建generator的地方创建一个目录,目录要以generator-name命名(name替换成你要创建的generator名称)。命名规则很重要,因为yeoman会通过文件系统来查找可以使用的generator。
在上面创建的目录下创建一个package.json文件,该文件是一个Node.js项目的的模块清单.相关介绍请看官网。你可以通过在命令行运行 npm init 来构建package.json文件,当然你也可以手动填充这个文件:

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

其中 name 属性必须以generator-前缀。keywords 属性必须包含"yeoman-generator" 并且repo必须有一个引用 generators page索引的描述。

你必须保证引用了最新版本的yeoman-generator 模块作为依赖.可以通过 npm install --save yeoman-generator来实现。

files属性必须是一个在你的generator里面用到的文件和目录的数组。

2.目录树

yeoman是深度依赖你组织的文件目录文件系统,每一个子generator都有自己的文件夹。

generator默认把app作为默认的子generator,当你使用yo name 调用的是app子generator。因此你的generator必须包含app/目录。你可以通过yo name:subcommand命令来调用子generator,他会调用与subcommand完全一样的文件夹即子generator。

下面是示例项目的文件夹结构

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

通过命令 yo nameyo name:router 可以显示出来generator。

如果你不想把所有的文件都放在根目录下面,很幸运的是yeoman支持两种不同的目录结构 ./ generators/ ,yeoman会从他们当中注册可用的generators。

所以前一个示例的结构也可用定义成如下:

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

如果你使用这种目录结构,请确保package.json 文件内的 files 属性定义了子generator在generators目录下:

     {
       "files": [
         "generators/app",
         "generators/router"
       ]
     }
3. 扩展generator

当到了这一步你就可用去实现generator的具体内容了

yeoman提供了一个基础的generator让我们扩展使用以实现自己的目标.基础的generator提供了大部分的功能来缓解你的任务量。

下面是扩展基础generator的方法:

    var generators = require("yeoman-generator");
    module.exports = generators.Base.extend();

extend 允许你在基础的class上扩展新的自己想要的prototype规范.他的功能是通过Class-extend模块得来的。如果你用过backbone,你会觉得他很熟悉。在生态系统中,我们指定扩展的generator使用module.export来让其有效,就像在nodeJs使用export module一样

4. 重写constructor方法

有些generator方法只有定义在构造方法内才能被调用到.这些特殊的方法可以做的一些重要的操作等,而这些操作可能在构造之外无法正常运行。

    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
      }
    });
5. 添加自定义方法

当generator被调用时,通常情况下里面定义的方法会按照顺序执行,但是我们将在下一节中看到的,一些特殊的方法名称将触发特定的运行秩序。

下面的一段代码是创建两个自定义的方法

    module.exports = generators.Base.extend({
      method1: function () {
        console.log("method 1 just ran");
      },
      method2: function () {
        console.log("method 2 just ran");
      }
    });

当运行generator 你会看到会用log打印出来。

6. 运行generator

当在本地目录内完成上面的创建后,generator还不能被当做全局的npm module ,我们可以通过在 generator-name/目录下运行 npm link 来实现generator的全局化。

7.找到工程根目录

当使用yo命令来运行generator的生活,yeoman会把 .yo-rc.json 文件所在的目录作为工程的根目录,之后Yeoman将当前文件目录跳转到根目录下运行请求的生成器。当我们使用this.config.save()的时候,storage模块会创建它。如果.yo-rc.json 不在当前的工作目录,请确保他也不在其他的项目目录里。

4. 完善generator 1.创建用户交互

我们推荐在prompting 方法内来定义prompt与用户交互,定义方法如下:

   module.exports = generators.Base.extend({
     prompting: function () {
       return this.prompt([{
         type    : "input",
         name    : "name",
         message : "Your project name",
         default : this.appname // Default to current folder name
       }, {
         type    : "confirm",
         name    : "cool",
         message : "Would you like to enable the Cool feature?"
       }]).then(function (answers) {
         this.log("app name", answers.name);
         this.log("cool feature", answers.cool);
       }.bind(this));
     }
   })
2. 运行上下文

在generator内,所有的静态方法都会被作为action而自定执行,当然generator也提供了可以声明不自动执行的辅助函数,generator提供了三种可以创建辅助函数的方法.

1 通过下划线开头定义函数,如:CopyFiles

2 使用实例函数声明:

    generators.Base.extend({
        constructor: function () {
          this.helperMethod = function () {
            console.log("won"t be called automatically");
          };
        }
      });

3 继承一个父级generator:

      var MyBase = generators.Base.extend({
        helper: function () {
          console.log("methods on the parent generator won"t be called automatically");
        }
      });

      module.exports = MyBase.extend({
        exec: function () {
          this.helper();
        }
      });
3.运行顺序

运行顺序

Yeoman是按照优先级顺序依次执行所定义的方法。当你定义的函数名字是Yeoman定义的优先级函数名时,会自动将该函数列入到所在优先级队列中,否则就会列入到 default 优先层级队列中。

基本上执行的顺序如下:

initializing

prompting

configuring

default

writing

conflicts

install

end

4.generator Arguments

Arguments是在命令行中直接传递的。 如:yo webapp my-project,接受键值对的条件。

desc:描述argument

required:定义是否必须

optional:是否可选择的

type:参数类型,支持的类型有String Number Array Object

defaults: argument默认值

banner:字符串显示的使用说明(这是默认提供)

注意:参数必须的定义在construct函数内,否则当你使用generator调用命令(如:yo webapp --help)的时候,不能够输出相关的帮助信息。

示例:

    var _ = require("lodash");

    module.exports = generators.Base.extend({
      // note: arguments and options should be defined in the constructor.
      constructor: function () {
        generators.Base.apply(this, arguments);

        // This makes `appname` a required argument.
        this.argument("appname", { type: String, required: true });
        // And you can then access it later on this way; e.g. CamelCased
        this.appname = _.camelCase(this.appname);
      }
    });
5. Options

option和argument很相似,但是option是作为命令行标识使用的,如yo webapp --coffee

我们可可以通过generator.option()添加option。

示例:

 module.exports = generators.Base.extend({
   // note: arguments and options should be defined in the constructor.
   constructor: function () {
     generators.Base.apply(this, arguments);

     // This method adds support for a `--coffee` flag
     this.option("coffee");
     // And you can then access it later on this way; e.g.
     this.scriptSuffix = (this.options.coffee ? ".coffee": ".js");
   }
 });
6. 输出消息

输出消息是通过generator.log模块来处理实现的。不建议使用console.log输出命令。

示例:

    module.exports = generators.Base.extend({
      myAction: function () {
        this.log("Something has gone wrong!");
      }
    });
7. 处理依赖关系

一般当你运行你的generator的时候,你经常需要通过 npm 和 Bower来安装一些generator用到的依赖模块。而这些任务是非常繁琐的,为了方便,yeoman将这部分任务抽离了出来。

npm

你只需要调用generator.npmInstall() 命令就可以执行npm安装命令,yeoman确保了npm install只执行了一次,即使他被多个generator调用。

例如你想安装lodash作为dev dependency:

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

上面代码等同于调用了npm install lodash --save-dev命令。

Bower

你只需要调用generator.bowerInstall()即可启动安装命令。yeoman确保了bower install只执行了一次,即使他被多个generator调用。

npm && Bower

调用enerator.installDependencies()即可同时运行npm 和 bower。

其他tools

yeoman抽离了spawn命令,这个抽离保证了我们可以在Linux ,mac 以及windows系统上可以很好的运行。

假如你是一个PHP狂热爱好者,你想运行composer命令,你可以这样做:

    generators.Base.extend({
      install: function () {
        this.spawnCommand("composer", ["install"]);
      }
    });

请确保面spawn命令在install队列里。因为您的用户不愿意等待在那儿直到安装命令完成。

8. 上下文路径

为了方便文件流的输入输出,Yeoman使用两种位置环境。

1. 目标上下文

目标上下文定义为当前工作目录或含.yo-rc.json文件最接近的父文件夹。该.yo-rc.json文件定义了一个generator项目的根目录。该文件允许用户在子目录中运行命令,并让他们在项目中可以运行。这确保了用户行为的一致。

你可以通过generator.destinationRoot()命令获取目标路径,也可以通过generator.destinationPath("sub/path")来拼一个路径:

    // Given destination root is ~/projects
    generators.Base.extend({
      paths: function () {
        this.destinationRoot();
        // returns "~/projects"

        this.destinationPath("index.js");
        // returns "~/projects/index.js"
      }
    });
2. 模板上下文

模板上下文是你保存模板文件的目录,他一般是你要读取和复制的目录。模板上下文一般是默认是定义在 ./templates/目录的.你可以通过generator.sourceRoot("new/template/path")命令来重写。你可以通过generator.sourceRoot()或者generator.templatePath("app/index.js").来获取路径。

    generators.Base.extend({
      paths: function () {
        this.sourceRoot();
        // returns "./templates"

        this.templatePath("index.js");
        // returns "./templates/index.js"
      }
});
3. “内存”文件系统

当涉及到覆盖用户的文件的时候,yeoman非常的谨慎,基本上,每一个write动作都是一个为已经存在的文件解决冲突的过程。帮助用户严重需要覆盖的内容。

4. 文件工具

generator的this.fs暴露出所有的文件方法,通过mem-fs editor .

其他相关介绍请看官网

9.完整示例
    "use strict";

    var generators = require("yeoman-generator");
    var mkdirp = require("mkdirp");
    var yosay = require("yosay");
    var chalk = require("chalk");
    module.exports = generators.Base.extend({

        constructor: function() {
            generators.Base.apply(this, arguments);
            this.option("coffee");
            this.scriptSuffix = (this.options.coffee ? ".coffee": ".js");
        },

        initializing: function() {
            var message = chalk.bgBlack.bold("
Welcome to webApp
") + chalk.underline("webApp.github.io
");
            this.log(yosay(message));
        },

        prompting: function() {
             var prompts = [{
                type:"input",
                name: "appName",
                message: "input app name .",
                default: "webApp"
            }];
            this.prompt(prompts, function (answers) {
                this.log(answers);
            }.bind(this));
        },

        configuring: function() {
            this.config.save();
        },

        selfFunction: function () {
            this.log("执行了自定义方法");
        },

        writing: function() {
           this.fs.copyTpl(
             this.templatePath("index.html"),
             this.destinationPath("public/index.html"),
             { title: "Templating with Yeoman" }
           );
        },

    });
作者信息

原文链接:http://yeoman.io/authoring/
翻译自力谱宿云 LeapCloud 团队_UX成员:Jerry Zhang
力谱宿云 LeapCloud 团队首发:https://blog.maxleap.cn/archi...

欢迎关注微信订阅号:从移动到云端
欢迎加入我们的力谱宿云 LeapCloud 活动QQ群:555973817,我们将不定期做技术分享活动。
若有转载需要,请转发时注意自带作者信息一栏并本自媒体公号:力谱宿云,尊重原创作者及译者的劳动成果~ 谢谢配合~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79828.html

相关文章

  • 引言 下面是一个使用脚手架来初始化项目的典型例子。 showImg(https://segmentfault.com/img/remote/1460000019219651?w=1312&h=533); 随着前端工程化的理念不断深入,越来越多的人选择使用脚手架来从零到一搭建自己的项目。其中大家最熟悉的就是create-react-app和vue-cli,它们可以帮助我们初始化配置、生成项目结构、自...

    AnthonyHan 评论0 收藏0
  • 如何快速开发一个自己的项目脚手架?

    摘要:开发一个自己的脚手架了解了一些脚手架的工作方式与的基本概念,咱们就可以来创建一个属于自己的脚手架。引言 下面是一个使用脚手架来初始化项目的典型例子。   showImg(https://user-gold-cdn.xitu.io/2019/5/16/16ac081750971790);     随着前端工程化的理念不断深入,越来越多的人选择使用脚手架来从零到一...

    alighters 评论0 收藏0
  • 从零开始做Vue前端架构(9)

    摘要:那该怎么管理这两个不同的项目呢解决子模块用的的同学肯定一下子就想到子模块的知识了。最后,也希望有想法的同学还有大佬多多留言,给点建议原文地址从零开始做前端架构脚手架参考资料官方文档使用定制前端脚手架别人写的脚手架文件操作相关文档子模块 前言 相信很多人都用过vue-cli或create-react-app或者类似的脚手架。脚手架方便我们复制,粘贴,或者clone代码库,而且还可以更具用...

    Vicky 评论0 收藏0
  • W3School 教程整理

    摘要:离线版大部分整理自,少部分整理自,由本人整理。感谢站长的无私奉献。由于本人精力有限,此处的列表不一定能够及时更新,最新版本请到本人博客查看。 离线版大部分整理自 w3cschool ,少部分整理自 w3school ,由本人整理。 感谢 w3cschool 站长的无私奉献。 由于本人精力有限,此处的列表不一定能够及时更新,最新版本请到本人博客查看。 AngularJS教程 最后更...

    douzifly 评论0 收藏0
  • W3School 教程整理

    摘要:离线版大部分整理自,少部分整理自,由本人整理。感谢站长的无私奉献。由于本人精力有限,此处的列表不一定能够及时更新,最新版本请到本人博客查看。 离线版大部分整理自 w3cschool ,少部分整理自 w3school ,由本人整理。 感谢 w3cschool 站长的无私奉献。 由于本人精力有限,此处的列表不一定能够及时更新,最新版本请到本人博客查看。 AngularJS教程 最后更...

    CoffeX 评论0 收藏0

发表评论

0条评论

caiyongji

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<