一、目的

传统的前端项目初始流程一般是这样:

node命令行工具之实现项目工程自动初始化的标准流程

可以看出,传统的初始化步骤,花费的时间并不少。而且,人工操作的情况下,总有改漏的情况出现。这个缺点有时很致命。

甚至有马大哈,没有更新项目仓库地址,导致提交代码到旧仓库,这就很尴尬了。。。
基于这些情况,编写命令行工具(CLI)的目的就很明确:

用于新项目工程的初始化利用工具进行初始化,可以节省项目初期的准备时间避免出现改漏的情况杜绝未更新项目版本仓库地址的问题

以下是新的流程示意图:

node命令行工具之实现项目工程自动初始化的标准流程

二、自动化流程分析

以下是自动化流程图:

node命令行工具之实现项目工程自动初始化的标准流程

从流程图可以得出两个重要的信息:

配置信息模板文件

命令行工具的角色,是负责将两个信息进行融合,提供一个交互平台给用户。

三、工具准备

3.1 配置信息工具

配置信息的获得,需要靠和用户进行交互。由于程序员一般是用终端输入命令进行项目操作。所以,这里选择了两个工具进行支撑。

commander

借鉴Ruby commander理念实现的命令行执行补全解决方案

commander可以接收命令行传入的参数

例子:

npg-cli --help
"htmlcode">
npg-cli
"color: #ff0000">四、实现

以下按我做的开源项目——npm-package-cli的创作过程进行分拆、讲解。

4.1 初始化

新建项目文件夹npm-package-cli,并在该文件夹下运行npm init,生成package.json
项目结构如下:

 npm-package-cli
  |-- package.json

4.2 生成全局指令

这里要生成的全局指令是npg-cli

4.2.1 新建执行文件

新建文件夹bin,并在文件夹下新建名称为cli的shell脚本文件(注意:不能有后缀名)。
clishell脚本文件内容如下:

#!/usr/bin/env node
console.log('hello world');

其中,#!/usr/bin/env node是告诉编译器,以node的方式,运行代码。

并在package.json加入以下内容:

"bin": {
 "npg-cli": "bin/cli"
}

此时,项目结构如下:

 npm-package-cli
  |-- bin
   |-- cli
  |-- package.json

4.2.2 链接指令到全局

链接指令有两种方式:

npm link

npm install -g

两种方式,都需要在npm-package-cli文件夹下运行,才能生效。
作用是把npg-cli指令,指向全局的bin文件下,实现软链。

4.2.3 运行

在任意文件夹下运行命令:

npg-cli

# 输出
hello world

到这里,一个基本的指令就算完成了,接下来是指令的工作内容细化。

4.3 初始化操作类Creation

Creation的作用是整合所有操作,并提供接口给指令文件cli
Creation的结构如下:

class Creation{
 constructor(){
 // code
 }
 do(){
  // code
 }
 // other function
}

其中do方法暴露给脚本文件cli调用。

Creation类放在src/index.js中。

此时,项目结构如下:

 npm-package-cli
  |-- bin
   |-- cli
  |-- src
   |-- index.js
  |-- package.json

4.4 修改cli文件

#!/usr/bin/env node
const Creator = require('../src/index.js');
const project = new Creator();
project.do();

这样,只要实现好do方法,就可以完成npg-cli指令的运行了。

4.5 实现命令行参数读取

实现npg-cli --help,需要借助上文提到的工具commander
新建src/command.js文件,文件内容如下:

const commander = require('commander');
const chalk = require('chalk');
const packageJson = require('../package.json');
const log = console.log;
function initCommand(){
 commander.version(packageJson.version)
  .on('--help', ()=>{
   log(chalk.green(' run testcli and edit the setting.'));
  })
  .parse(process.argv);
}
module.exports = initCommand;

此时,项目结构如下:

 npm-package-cli
  |-- bin
   |-- cli
  |-- src
   |-- command.js
   |-- index.js
  |-- package.json

然后在Creation.do方法内执行initCommand()即可生效。

// src/index.js Creation
const initCommand = require('./command');

class Creation{
 // other code
 do(){
  initCommand();
 }
}

此时,运行npg-cli --help指令,就可以看到:

Usage: npg-cli [options]

Options:
 -V, --version output the version number
 -h, --help  output usage information
 run testcli and edit the setting.

4.6 获取用户输入配置信息

要获取用户输入的信息,需要借助工具inquirer
新建src/setting.js文件,文件内容如下:

const inquirer = require('inquirer');
const fse = require('fs-extra');

function initSetting(){
 let prompt = [
  {
   type: 'input',
   name: 'projectName',
   message: 'project name',
   validate(input){
    if(!input){
     return 'project name is required.'
    }
    if(fse.existsSync(input)){
     return 'project name of folder is exist.'
    }
    return true;
   }
  },
  // other prompt
 ];

 return inquirer.prompt(prompt);
}

module.exports = initSetting;

此时,项目结构如下:

 npm-package-cli
  |-- bin
   |-- cli
  |-- src
   |-- command.js
   |-- index.js
   |-- setting.js
  |-- package.json

然后在Creation.do方法内执行initSetting()即可生效。

// src/index.js Creation
const initCommand = require('./command');
const initSetting = require('./setting');

class Creation{
 // other code
 do(){
  initCommand();
  initSetting().then(setting => {
   // 用户输入完成后,会得到全部输入信息的json数据 setting
  });
 }
}

这里,inquirer.prompt方法装载好要收集的问题后,返回的是Promise对象。收集完成之后,要在then方法内拿到配置信息,以便进行下一步模板替换的操作。

4.7 模板文件替换输出

模板文件替换,要用到工具mem-fsmem-fs-editor
文件操作,要用到工具shelljs

新建src/output.js文件,文件内容如下(删除了部分代码,以下只是示例,完整项目看最后分享链接):

 

const chalk = require('chalk');
const fse = require('fs-extra');
const path = require('path');
const log = console.log;

function output(creation){
 return new Promise((resolve, reject)=>{
  // 拿到配置信息
  const setting = creation._setting;
  const {
   projectName
  } = setting;
  // 获取当前命令行执行环境所在文件夹
  const cwd = process.cwd();

  // 初始化文件夹path
  const projectPath = path.join(cwd, projectName);
  const projectResolve = getProjectResolve(projectPath);
  
  // 新建项目文件夹
  fse.mkdirSync(projectPath);

  // copy文件夹
  creation.copy('src', projectResolve('src'));
  // 根据配置信息,替换文件内容
  creation.copyTpl('package.json', projectResolve('package.json'), setting);

  // 将内存中的文件,输出到硬盘上
  creation._mfs.commit(() => {
   resolve(); 
  });
 });
}

module.exports = output;

output方法的作用:

  • 新建项目文件夹
  • 把模板文件读取出来,根据配置信息,进行替换(调用的是mem-fs-editor的copyTpl方法)
  • 拷贝其他文件
  • 输出最终文件到硬盘上

这里最重要的一步,是调用mem-fs-editor的方法后,要执行mem-fs-editorcommit方法,输出内存中的文件到硬盘上。

在Creation.do方法中,调用output方法即可输出新项目文件。
打开src/index.js文件,文件内容增加如下方法:

// src/index.js Creation
const initCommand = require('./command');
const initSetting = require('./setting');
const output = require('./output');

class Creation{
 // other code
 do(){
  initCommand();
  initSetting().then(setting => {
   // 用户输入完成后,会得到全部输入信息的json数据 setting
   this._setting = Object.assign({}, this._setting, setting);
   // 输出文件
   output(this).then(res => {
    // 项目输出完成
   });
  });
 }
}

4.8 阶段小结

自动初始化一个项目的流程不外乎以下三点:

  • 读取用户配置
  • 读取模板文件
  • 根据配置,编译模板文件,输出最终文件

命令行工具,是对这三点的有效整合,串连成一个规范的流程。

五、发布npm包的注意点

命令行工具中,使用的第三方工具包,都需要用--save的方式安装。
体现在package.json的表现是dependencies字段:

"dependencies": {
 "chalk": "^2.4.2",
 "commander": "^3.0.0",
 "fs-extra": "^8.1.0",
 "inquirer": "^6.5.0",
 "mem-fs": "^1.1.3",
 "mem-fs-editor": "^6.0.0",
 "shelljs": "^0.8.3"
},

这样,其他用户在安装你发布的CLI工具时,才会自动安装这些依赖。

六、项目开源

我创作的npm-package-cli,是专门用于生成个人npm package项目的CLI工具。
生成的项目,囊括以下功能点:

  • 支持TypeScrpt
  • mocha+chai自动化测试,支持使用TypeScript编写测试用例支持测试覆盖率
  • coverage支持eslint,包括对TypeScript的lint检查
  • Git commit规范提交
  • Git版本自动打标签(standard-version),更新CHANGELOG.md
  • 输出的npm包

支持各种模块规范(AMD、CMD、CommonJS、ESModule)

CLI工具安装方式:

npm install -g npm-package-cli

开源仓库地址:https://github.com/wall-wxk/npm-package-cli

如果对你有所帮助,麻烦给个Star,你的肯定是我前进的动力~

总结

以上所述是小编给大家介绍的node命令行工具之实现项目工程自动初始化的标准流程,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

华山资源网 Design By www.eoogi.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
华山资源网 Design By www.eoogi.com

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。