编写一个简易的Cli工具

前置准备

  1. 开发环境

    Node 环境 (必须)
    VS Code 开发工具 (非必须,你可以使用你喜欢的开发工具)

  2. 注册 NPM 账号

    访问 NPM 官网 ,点击 Sign up 字样,输入邮箱用户名密码就可以完成创建了,注意这里的 Username 和 Password 将用于后续登录和发布包。Public Email 用于接收推送邮件。

开发

  1. 创建 NPM 项目

    新建一个空文件夹
    运行命令行,切换到你想存放文件的目录,执行新建文件。如:

    1
    2
    3
    4
    C:> cd D:/
    D:> mkdir gitchat-oni
    D:> cd gitchat-oni
    D:\gitchat-oni>

    新建一个 NPM 项目

    在刚刚的目录下执行 npm init ,输入项目的一下信息

  2. 配置程序入口

    打开 package.json 做一点点的修改:

    1
    2
    3
    4
    "main": "index.js",
    "bin": {
    "new": "./bin/new.js"
    }

    如果是插件的话,入口文件就是 main 所定义的;如果是工具的话,入口文件就是 bin 所定义的。

  3. 创建入口文件

    在项目中新建一个bin目录,在bin目录新建一个new.js的文件

  4. 编写入口文件

    安装工具所需要的依赖:

    1
    2
    3
    4
    5
    6
    D:\new>npm i commander --save
    npm notice created a lockfile as package-lock.json. You should commit this file.
    npm WARN gitchat-oni@1.0.0 No repository field.

    + commander@2.15.1
    added 1 package in 2.184s

    commander 是 Node.js 命令行接口的完整解决方案,打开 new.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/usr/bin/env node
    //这里需要声明文件运行环境,特别重要!!
    const program = require('commander');
    program
    .version(require('../package').version)
    .on('--help', printHelp)
    .usage('<command> [options]')
    .parse(process.argv)
    //process模块用来与当前进程互动,可以通过全局变量process访问,
    //不必使用require命令加载。它是一个EventEmitter对象的实例。

    function printHelp (){
    console.log("gitchat help");
    }

    这里其实我们的工具已经编写完毕了,它的功能就是打印出它自己的版本号,还有执行 –help 的时候,打印一段文字。

  5. 将工具上传到 NPM 上,或者使用 npm link 命令安装到本地

    首先要先登录到 NPM,使用刚刚注册的账号密码,这里的邮箱是用于接收推送邮件的。

    1
    2
    3
    4
    5
    D:\new>npm login
    Username: hc
    Password:
    Email: (this IS public) xxxx@qq.com
    Logged in as xiaohuoni on https://registry.npmjs.org/.

    然后执行推送 npm publish:

    上传成功,同时你可以查看邮箱,有一封来自 NPM 官方的邮件。

  6. 将自己的工具安装到电脑上

    1
    npm i new -g
  7. 定义 new-cli

    其实原理就是当你执行 new 之后,将一份脚手架代码,复制到你当前的目录下面。
    先定义命令。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    program
    .command('new')
    .description('新建一个项目')
    .action(function(name,other){
    console.log("执行了new")
    console.log("新建一个项目")
    console.log("执行拷贝")
    });
    program.parse(process.argv);
  8. 完善 new-cli 功能

    因为我们的 new 功能是执行拷贝,所以这里先安装几个插件:

    npm i path vinyl-fs through2 –save

    修改 new.js

    1
    2
    3
    .action(function(name,other){
    require('../lib/new.js').run(name,other)
    });

    新建 new.js 文件 (注意上面的引用的是 lib 目录下,我们创建的是 src 目录下,后面会转译):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    import { join } from "path";
    import vfs from "vinyl-fs";
    import through from "through2";

    exports.run = function(name, other) {
    const cwd = join(__dirname, "../template");//从template目录下拷贝
    const dest = process.cwd();//当前执行命令的目录
    console.log(`新建一个项目在: ${dest}.`);
    vfs
    .src(["**/*", "!node_modules/**/*"], { cwd: cwd, cwdbase: true, dot: true })
    .pipe(template(dest, cwd))
    .pipe(vfs.dest(dest))
    .on("end", function() {
    console.log("新建项目完成");
    })
    .resume();
    /**
    * 执行拷贝
    */
    function template(dest, cwd) {
    return through.obj(function(file, enc, cb) {
    if (!file.stat.isFile()) {
    return cb();
    }
    console.log(file.path.replace(cwd + "/", ""));
    this.push(file);
    cb();
    });
    }
    };
  9. 使用 babel 转译代码

    开发中我们可能偏向于使用 es2016、es2017,或者 react、vue 等语法。比如我们的 new.js 中使用了 import,所以我们在项目中添加 babel 来转译代码,使得所有的语法都是 es2015 的修改 package.json(在最后面增加)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      "devDependencies": {
    "babel-cli": "^6.10.1",
    "babel-plugin-add-module-exports": "^0.2.1",
    "babel-plugin-transform-runtime": "^6.9.0",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-stage-0": "~6.5.0",
    "babel-runtime": "^6.9.2"
    },
    "babel": {
    "presets": ["es2015", "stage-0"],
    "plugins": ["add-module-exports", "transform-runtime"]
    }

    修改package.json

    1
    2
    3
    4
      "scripts": {
    "test":"xxxxxx"
    "build": "rm -rf lib && babel src --out-dir lib"
    },
  10. 添加模板文件

新建 D:\newtemplate,并在该目录下随意放入文件,最终会全部拷贝到我们的初始化项目中。

你可以将你设计的框架脚手架什么的放到这里面。

  1. 编译之后上传 NPM
1
2
npm run build
npm publish