UDN-企业互联网技术人气社区

板块导航

浏览  : 696
回复  : 2

[原生js] 上手 yeoman generator

[复制链接]
芭芭拉的头像 楼主
发表于 2017-1-8 15:20:48 | 显示全部楼层 |阅读模式
  最近折腾脚手架相关的一些事情。说到脚手架,不得不谈的就是 yeoman 了。

  是什么

  yeoman 是一个脚手架生成工具。

  yeoman generator 则是 yeoman 的精髓所在。

  从我的理解来看。 yeoman 就是一个工具外壳,它定制了如何调用 generator ,给 generator 提供了运行环境。 yeoman generator 则是解耦出来的核心部分,负责完成一个脚手架应该做的事。

  线上已经有很多 generator ,可以满足我们一大波需求。不过要做到真正灵活,完全符合自己的需求、业务中的需要就要自己自定义 generator 了。

  怎么做

  yeoman 的强大之处在于它提供了一套非常强大的编写自定义 generator 的 API ,而且上手非常容易。只要按照特定的约束,很快就可以定制一套自己的 generator 。话不多说,马上一起来看看怎么做。

  目录结构
  1. |- app
  2.     |- index.js
  3.     |- template
  4.         |- 模板文件
  5. |- package.json (主入口为app/index.js)
复制代码

  初始化一个npm包,定制目录结构如上,这样就简单完成 generator 的目录结构啦。当然你可以用 generator-generator 生成符合规范的 generator ,这样更加快捷。

  index.js结构示例

  package.json 不多说,注意主入口写好就行。index.js 也是按照具体的约束,一个简单的示例:
  1. var generators = require('yeoman-generator')

  2. module.exports = generators.Base.extend({  
  3.   constructor: function () {
  4.     generators.Base.apply(this, arguments)
  5.   }

  6.   // 方法A

  7.   // 方法B
  8. })
复制代码

  一个 Yeoman Generator 被创建后,会依次调用它原型上的方法,调用的顺序如下:

  • initializing - 初始化一些状态之类的,通常是和用户输入的 options 或者 arguments 打交道,这个后面说。
  • prompting - 和用户交互的时候(命令行问答之类的)调用。
  • configuring - 保存配置文件(如 .babelrc 等)。
  • default - 其他方法都会在这里按顺序统一调用。
  • writing - 在这里写一些模板文件。
  • conflicts - 处理文件冲突,比如当前目录下已经有了同名文件。
  • install - 开始安装依赖。

  也可以自定义方法,比如demo里方法A会先于方法B执行。下面具体介绍下每个方法的一些作用。

  prompting

  用于做命令行的交互,这个应该是最常用的一个功能。用于在命令行和用户交互,用户提一些问题,我们的 generator 收集问题的结果。一个简单的例子:
  1. prompting: function () {
  2.         let models = [{
  3.             name: 'eslint',
  4.             checked: true
  5.         }, {
  6.             name: 'sass-lint',
  7.             checked: true
  8.         }];

  9.         const prompts = [{
  10.             type: 'checkbox',
  11.             name: 'enable',
  12.             message: '开启哪些功能?',
  13.             choices: models
  14.         }, {
  15.             type: 'confirm',
  16.             name: 'installDependencies',
  17.             message: '安装相关依赖?',
  18.             when: (props) => {
  19.                 return props.enable.length;
  20.             }
  21.         }, {
  22.             type: 'list',
  23.             name: 'tool',
  24.             message: '使用npm/tnpm?',
  25.             choices: [
  26.                 CFG.CHOICE.TOOL.NPM,
  27.                 CFG.CHOICE.TOOL.TNPM
  28.             ],
  29.             when: (props) => {
  30.                 return props.installDependencies;
  31.             }
  32.         }];

  33.         return this.prompt(prompts).then((options) => {
  34.             this.userOptions = options;
  35.         });
  36.     },
复制代码

  这里不对代码细解释,只需要知道这里可以做用户命令行交互,具体每个参数有什么意义, github 上搜索一下 Inquirer.js 就很清晰了。

  writing 

  这里用于文件拷贝,读文件,写文件。一个简单的例子:
  1. writing: function () {
  2.         const options = this.userOptions;
  3.         const imlintrcPath = this.cfg.imPath;
  4.         const imlintrcJson = {
  5.             config: options
  6.         };
  7.         const enableModules = options.enable || [];
  8.         const MODULES = CFG.MODULES;
  9.         const pkgPath = this.cfg.pkgPath;
  10.         let pkgJson;

  11.         /** 1. 复制基础样板文件 */
  12.         this.cfg.files.forEach((item) => {
  13.             this.fs.copy(
  14.                 this.templatePath(item),
  15.                 this.destinationPath(item)
  16.             );
  17.         });

  18.         /** 2. 创建imlintrc文件 */
  19.         this.fs.writeJSON(imlintrcPath, imlintrcJson);

  20.         /** 3. 修改package.json scripts配置 */
  21.         try {
  22.             pkgJson = this.fs.readJSON(pkgPath);
  23.         } catch (ex) {
  24.             console.log('imlint: package.json不合法');
  25.             process.exit();
  26.         }

  27.         pkgJson.devDependencies = pkgJson.devDependencies || {};
  28.         pkgJson.scripts = pkgJson.scripts || {};
  29.         Object.assign(pkgJson.scripts, this.cfg.scripts || {});

  30.         /** 4. 部署对应模块,包括:1. 迁移文件 2. 修改package.json devDependencies配置 */
  31.         enableModules.forEach((item) => {
  32.             const cur = MODULES[item];

  33.             if (!cur) {
  34.                 return;
  35.             }

  36.             Object.assign(pkgJson.devDependencies, cur.pkgs);

  37.             if (cur.files) {
  38.                 cur.files.forEach((file) => {
  39.                     this.fs.copy(
  40.                         this.templatePath(file),
  41.                         this.destinationPath(file)
  42.                     );
  43.                 });
  44.             }
  45.         });

  46.         /** 5. 写package.json文件 */
  47.         this.fs.writeJSON(pkgPath, pkgJson);
  48.     },
复制代码

  具体文件API的意义可参见 mem-fs-editor 这个库

  install 

  用于安装依赖,比如npm install一个lodash
  1. install() {
  2.     this.npmInstall(['lodash'], { 'save-dev': true });
  3. }
复制代码

  发布

  index.js 写完,一个简单的 generator 就ok了。上面这个 DEMO 具体的详细例子,可以看 generator-imlint-init

  将上面这个 npm 包发布后,就可以按如下方法安装使用了~~
  1. npm install -g yo
  2. npm install -g generator-imlint-init

  3. yo imlint-init
复制代码

  小结

  例子比较简单,方法也只说了下 generator 最常用的三个方法。

相关帖子

发表于 2017-1-8 15:21:17 | 显示全部楼层
占坑编辑ing
使用道具 举报

回复

发表于 2017-1-9 20:19:54 来自手机 | 显示全部楼层
回帖支持下楼主,请眼熟我,我叫“金色的骷髅“
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部