Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

与脚手架大战:回合2 #47

Open
youngwind opened this issue Mar 20, 2016 · 0 comments
Open

与脚手架大战:回合2 #47

youngwind opened this issue Mar 20, 2016 · 0 comments

Comments

@youngwind
Copy link
Owner

再接再厉

继回合1 #46 之后,开始准备回合2。这次我重新整理了一下思路。

  1. 我要实现的是一个简单的脚手架生成器,它只需要能够生成我指定的那两三种项目。
  2. 生成的方式与上一次思考的相同,也就是(拷贝文件→装包→构建→启动服务),而非大量地写文件。
  3. 终端交互采取inquirer,获取到参数之后传递给生成模块去处理
  4. 这次需要重点解决的问题有。
  5. 如何让shell认识我定义的命令?
  6. 如何优雅地调用shell的命令?

寻找方案

针对第一个难点,经人指点,我知道应该在package.json的bin字段中定义我这个命令。其实平常我们输入cd,ls这些命令,shell之所以认识,是因为它们在环境变量$path中能找到。但是全局安装的npm module并不在$path中啊。npm的解决方案是,对于全局安装的,有bin字段的包,**在安装的时候会主动建立一个链接,从$path指向该module的某个可执行文件。**就像如图所示的第二行箭头那样。
2016-03-20 11 34 47
其实这个bin字段还可以配置多个命令,详细的可以参考这里。ok,第一个难题可以解决了。
针对第二个难点,我搜索到了shell.js,关于shell.js,可以参考阮一峰老师的教程

开始敲代码

ok,解决方案敲定之后就开始撸起袖子敲代码了。
先写终端交互的cli.js,主要涉及inquirer.js

#!/usr/bin/env node
'use strict';

var inquirer = require("inquirer");
var lazySmart = require("./lazy-smart");
var shell = require("shelljs");

var questions = [

  // 项目名称
  {
    type: "input",
    name: "name",
    message: "input your project name",
    validate: function (value) {

      if (!value) {
        return "project name can not be null"
      }

      // 检查文件夹是否已存在
      var ls = shell.ls();
      if (ls.indexOf(value) !== -1) {
        return "File exists, please select another project name.."
      } else {
        return true;
      }
    }
  },

  // 选择项目架构类型
  {
    type: "list",
    name: "architecture",
    message: "select your project architecture",
    choices: ["ejs+gulp", "ejs+webpack"]
  },

  // git仓库名称
  {
    type: "input",
    name: "gitName",
    message: "input the repository name of git project.(make sure the repository is created and empty)",
    default: function (answer) {
      return answer.name;
    }
  },

  // git仓库所有者名称
  {
    type: "input",
    name: "gitOwner",
    message: "input the owner of git project.",
    default: function () {
      var userName = shell.exec('git config --global --get user.name').output;
      userName = userName.substring(0, userName.length - 1);
      return userName;
    }
  }
];

inquirer.prompt(questions, function (answers) {
  //把用户输入的参数传递给生成模块
  lazySmart.init(answers);
});

然后编写生成模块lazy-smart.js

// 调用执行命令行
var shell = require("shelljs");

// 支持在脚本中直接执行命令
require('shelljs/global');

// 解析获取命令行参数
var argv = require('yargs').argv;
// 初始化
exports.init = function (options) {

  exports.copy(options);
  exports.initGit(options);
  exports.install(options);
  exports.build(options);
  exports.run(options);
};
....

把功能模块划分好之后,剩下函数的编写就不难了,完整的代码在这里

至此,已经完成了第一套项目脚手架的搭建,之后第二,第三套就跟脚手架没啥关系了。通过这次自己手动写脚手架,主要有两个收获。

  1. 通过分析问题找准解决方案之后,敲代码才能效率高。
  2. 跟终端交互还是很有趣的。

遗留问题点:

  1. npm包的本地调试和发布流程不是非常顺畅,而且有个极其坑爹的.gitignore变成.npmignore的问题还不知道为啥。暂时找到的参考资料在这里
  2. shell.js的exce是串行执行的,当我想在在一个js文件调用多个不会结束自动结束的进程的时候容易出问题,比如先后开启npm run start 和gulp watch这些。有什么办法能够直接打开新终端窗口吗?或者结合child_process?这个可是每个都是并行执行的。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant