nature book bug burger costumes doctors hospital office shoes skull rocket

使用 Yeoman Generators 制作自己的脚手架

前端开发环境日益复杂,通过 Yeoman 我们能够快速的搭起环境。但是网上教程多过时,于是决定自己整理一篇。

前言

Generators 类似于开发环境的构建模板,包括构建开发环境所需的文件和配置,以及 Yeoman 的运行脚本等。

制作 Generators 依赖于 yeoman 官方提供的 yeoman-generator 模块,介于技术容易过时,特别说明本文编写时采用 v1.1.1 版,是官方最新版本。在此版本下,所有的代码都是可以正常工作。(新版 API 变化,故而网上旧的教程基本无法使用)

通过本文尝试用最新最简的方式实现目标,通过本文的学习,大家可以初步学会创建和使用自己的 Generators。

Yeoman LOGO

准备

Generators 必须要发布到 npmjs,并且有开放的 git 托管地址。符合官方规范的会出现在 Yeoman 官方 上,一定要这样才能使用并且共享。

为此,我们需要拥有

  1. npmjs.com 账号
  2. github.com 账号
  3. 本地装 NodeJS 环境
  4. 本地装 Git Shell

没有账号的朋友,建议先到官网注册账号。


然后,在 github 上创建我们的公共项目。

  1. 名字必须以 “generator-” 开头,例如我的 “generator-reactweb”
  2. 写一些自己看得懂的项目描述
  3. 开源协议可以选:“MIT”
  4. 其他请随意

如果本地未配置 git 环境,请先配置好。(我是 MacOS 系统,使用默认 Shell)

开始

命令行切换到项目目录(cd 命令),通过 git clone [项目地址] 的方式,把 github 上的项目 clone 到本地。
(PS:这一步也可以基于 Git图形化工具 完成,但是之后的操作,我们都需要直接在命令行里完成)

现在确保命令行在项目文件夹根目录,我们在这里创建 ‘package.json’:

npm init -y #自应答模式

命令执行后,会根据默认选择生成一个 ‘package.json’ 文件。然后安装必须的依赖:

sudo npm i yeoman-generator -S #制作 Yeoman Generator 必须依赖此模块

等待一口茶功夫,就完成……

提示:

  1. 这里如果您使用 Windows,可以不必加 ‘sudo’。
  2. 大陆的朋友建议把 NPM 换成国内阿里的镜像。

现在我们可以使用喜欢的编辑器打开 ‘package.json’,编辑它让它尽可能完整,否则可能无法被 Yeoman 官网收录。

以下是我的 ‘package.json’ 文件内容:

{
  "name": "generator-reactweb",
  "version": "1.1.0",
  "description": "React WEB 项目包含基本:react15 + react-router + webpack2 + ES2015",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/wwh447/generator-reactweb.git"
  },
  "homepage": "https://github.com/wwh447/generator-reactweb",
  "bugs": {
    "url": "https://github.com/wwh447/generator-reactweb/issues"
  },
  "files": [
    "generators"
  ],
  "keywords": [
    "yeoman-generator"
  ],
  "author": "Eded.Wang",
  "license": "MIT",
  "dependencies": {
    "yeoman-generator": "^1.1.1"
  }
}

请依次在项目根目录下,创建这样的目录 /generators/app/template/ 结构。我们构建项目的模板文件将放在 template 里,出此之外,还需要一个 Yeoman 的配置文件协助完成构建。所以,我们在 /generators/app/ 目录下创建 ‘index.js’ 文件。

首先,下图是我项目目录结构:

目录结构

在 ‘template’ 中,我放入构建 ‘React Web’ 项目所需的文件。其中以 ‘_tmpl’ 结尾的文件,原名是前面带 ‘.’ 的隐藏文件,为了方便 NodeJS 文件系统处理,故而如此命名。


让我们来编辑 ‘index.js’ 文件,以下是我的代码:

// /generators/app/index.js

// 创建 yeoman generator 的核心功能模块.
const Generator = require('yeoman-generator');

// 文件读写模块.
const fs = require('fs');
// 路径模块
const path = require('path');

// PS: fs 和 path 是 NodeJS 的核心模块,无需安装.

/**
 * Base generator.
 */
module.exports = class extends Generator {

  /** 构造函数 */
  constructor(args, opts) {
    // 继承必须.
    super(args, opts);

    // 获取 AppName,使用路径尾.
    this.appName = path.basename(process.cwd());
    // 设置 Author.
    this.appAuthor = "Eded.Wang";
  }

  /**
   * 初始化方法.
   */
  initializing() {
    this.log("开始构建项目...");
  }

  /**
   * 写入配置
   */
  configuring() {

    // 获取 package 配置模板.
    let defaultSettings = this.fs.readJSON( this.templatePath('package.json') );
    // 做新 package 配置文件.
    let packageSettings = {
      name: this.appName,
      private: true,
      version: '0.0.1',
      description: `${this.appName} - Generated by generator-reactweb`,
      main: 'index.js',
      scripts: defaultSettings.scripts,
      repository: defaultSettings.repository,
      keywords: [],
      author: this.appAuthor,
      devDependencies: defaultSettings.devDependencies,
      dependencies: defaultSettings.dependencies
    };

    // 写入 package.json.
    this.fs.writeJSON(this.destinationPath('package.json'), packageSettings);
  }

  /**
   * 写入文件
   */
  writing() {

    // 创建 dist 空目录.
    fs.mkdirSync('dist');
    // 拷贝入口页.
    // copyTpl 允许使用 EJS 模板引擎替换内容
    this.fs.copyTpl(
      this.templatePath('public/index.html'),
      this.destinationPath('public/index.html'),
      { title: 'Templating with Yeoman' }
    );

    /* 拷贝所需的文件. */

    this.fs.copy(
      this.templatePath("src"),
      this.destinationPath("src")
    );
    this.fs.copy(
      this.templatePath("babelrc_tmpl"),
      this.destinationPath(".babelrc")
    );
    this.fs.copy(
      this.templatePath("eslintrc_tmpl"),
      this.destinationPath(".eslintrc")
    );
    this.fs.copy(
      this.templatePath("gitignore_tmpl"),
      this.destinationPath(".gitignore")
    );
    this.fs.copy(
      this.templatePath("webpack.config.js"),
      this.destinationPath("webpack.config.js")
    );

  }

  /**
   * 安装方法
   */
  install() {
    // 安装 package 安装.
    this.installDependencies({ bower: false });
  }

};

这段代码采用官方推荐的 ES6 方式编写。其中用到 Yeoman API 的方法主要有三个:

  • ‘this.log’
  • ‘this.installDependencies’
  • ‘this.fs.*‘

class Generator 里的所有方法,会在项目构建时依次按顺序执行。(官方有 API 可修改执行顺序)

现在简单介绍一下这三个重要的 API:

  • ‘this.log’ 像 ‘console.log’,只不过文字会在构建时,从命令行输出。
  • ‘this.installDependencies’ 会执行 npm 和 bower 的安装命令,并且完成时冒句提示。本文我们不需要 bower,故而参数设为 false。
  • ‘this.fs’ 是 NodeJS mem-fs-editor 模块的封装,有一些子方法做简便的文件读写操作。

所以,’index.js’ 是重要的,他做的工作是代替人工的创建和复制项目所需的基础文件,并且自动安装 NPM 模块。

还有一些常用的 API,比如 ‘this.option’ 可以创建命令选项,像 ‘–version’ 这样…
还可以做一些问答之类的。更多的请参考 官方文档(英文)

提交

现在我们把代码先提交到 github,除了 ‘node_modules’ 目录不应该被提交,其他全部提交。
(小提示:建议在项目根目录下创建 ‘.gitignore’ 文件,维护用于排除 Git 控制的文件,一行一个)

Git 提交参考如下代码:

git add .  #如果正确配置了 .gitignore,则可以使用 '.' 通配符全部添加到暂存区
git commit -m "我自己的脚手架"  #写一句提交描述
git push  #推送 master 分支

假如已经完成提交,会在 Github 项目主页看到变化。

发布

首先用 npmjs.com 的账号在命令行登录:

npm login  #要求输入注册时的 用户名、密码、邮箱

登录成功之后,在项目根目录下运行:

npm publish --access=public

发布成功,会看到自己的版本号。


如果我们的代码符合 Yeoman 的 Generators 规范,它将会出现在 Yeoman 首页的 Generators 清单里。比如输入我的 ‘reactweb’ 就会搜索到,这真是激动人心的事。

要是你暂时没有在“清单”里找到自己的项目,那么也不用沮丧!因为这可能是由于 Yeoman Generators List 程序缓存,他每小时重置一次,你可以稍后再回来看看。

(重要提示:这并不影响我们使用)

使用

首先 全局安装 自己的 Generators,比如我的叫 ‘generator-reactweb’,所以:

sudo npm i generator-reactweb -g

然后创建一个新的目录,在命令行里切到这个目录,并且执行 ‘yo reactweb’ 运行脚手架程序。(注意把 reactweb 换成自己的脚手架名字)

好,一盏茶功夫就跑完,就是这样喵~

到目前为止的代码,我托管在 码云 的免费项目主页(由于 github 上我正在用,难免调整)。感兴趣的朋友,可以前往检阅。传送门

升级

我们很难一次做到满意,所以难免反复调试和升级脚手架程序。

我遵从这个流程来更新本地脚手架工具:

  1. 修改 generator-reactweb 项目代码,并且推进 package.json 里的 version(版本号)。如 ‘1.0.0’ 改为 ‘1.0.1’ 等……
  2. 命令行登录 npmjs npm login,并重新发布 npm publish --access=public
  3. 重新全局安装最新的 generator-reactweb 脚手架 sudo npm i generator-reactweb@1.0.1 -g,请注意版本号
  4. 在空的欲构建文件夹里,执行构建命令 yo reactweb

参考资料