博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Node.js折腾记二:命令行交互
阅读量:6808 次
发布时间:2019-06-26

本文共 8404 字,大约阅读时间需要 28 分钟。

前言

学习node.js生成文件、执行脚本,使用CI持续集成,自动构建工具之后,想要玩玩自己写点东西试试

  • 命令行参数获取使用
  • 命令行交互使用
  • 目录树生成使用

代码:

目录结构:

D:\node-test...├─index.js├─sh| └sh1.js├─scripts|    └generateComponent.js├─components|     ...|     ├─run-sh.js...复制代码
D:\node-test├─ components    ├─ components-dir-tree1.json    ├─ file.2.js    ├─ file.bakeup.js    ├─ file.js    ├─ index.js    ├─ log.js    ├─ node-test-dir-tree.json    ├─ run-sh.js    ├─ test      └─ aa        ├─ bb.js        └─ cc    └─ timeFormat.js├─ index.js├─ json    ├─ a.json    └─ b.json├─ package-lock.json├─ package.json├─ README.md├─ scripts    └─ generateComponent.js└─ sh    └─ sh1.js复制代码

一、生成文件:

npm命令:

package.json:{  ...  "scripts": {    "create:comp": "node scripts/generateComponent --path",  },  ...}复制代码

--path 这个参数的值可以通过下面获取到:

--path 可以自行设置,获取的时候[path]将作为key存到program

const program = require('commander'); // 命令参数处理program  .version('0.0.1')  .option('-l --path [path]', 'list of customers in CSV file')  .parse(process.argv);// node scripts/generateComponents --path inputNameconst inputName = program.path;log('\ninputName: ',inputName);复制代码

命令行交互 inquirer.js 简单使用:

  • name:字段名, 调用then的回调参数值里可以找到匹配的name,
  • message:提示信息,
  • 其他的就是一些选项数据、默认值、过滤规则、校验、配置等

questions数组内一个子对象的type可以是:

(以下摘抄自)

  • confirm: yes/no,type, name, message, [, default] 属性
  • input: 键盘输入,type, name, message, [, default, filter, validate, transformer] 属性.
  • number: type, name, message, [, default, filter, validate] 属性.
  • rawlist: 类似于ol标签,有序列表,type, name, message, choices, [, default, filter] 属性
  • list: 类似于ul标签,无序列表,type, name, message, choices, [, default, filter] 属性
  • checkbox: 多选,type, name, message, choices, [, default, filter, validate] 属性
  • expand: 展开menu,type, name, message, choices, [, default] 属性
  • password: type, name, message, mask, [, default, filter, validate] 属性.
  • editor: type, name, message, mask, [, default, filter, validate] 属性.
const questions = [  {    type: "confirm",    name: "override",    message: "是否覆盖?"  }];inquirer.prompt(questions).then(res => {      if (res.override) {      log('\n文件将被覆盖!');      resolve(path);    } else {      log('\n不覆盖已有文件!');          }  });复制代码

更多的属性:

{  /* Preferred way: with promise */  filter() {    return new Promise(/* etc... */);  },  /* Legacy way: with this.async */  validate: function (input) {    // Declare function as asynchronous, and save the done callback    var done = this.async();    // Do async stuff    setTimeout(function() {      if (typeof input !== 'number') {        // Pass the return value in the done callback        done('You need to provide a number');        return;      }      // Pass the return value in the done callback      done(null, true);    }, 3000);  }}复制代码

生成文件 scripts/generateComponent.js:

const fs = require('fs');const path = require('path');const program = require('commander'); // 命令参数处理const inquirer = require('inquirer'); // 选择const chalk = require('chalk');const log = (...text) => console.log(...text);const componentDir = path.resolve(__dirname, '../components');const newComp = `const fs = require('fs');const path = require('path');console.log('这是一个自动生成的component');`;// npm scripts不能接收参数// 下面需要 node 运行传入参数program  .version('0.0.1')  .option('-l --path [path]', 'list of customers in CSV file')  .parse(process.argv);// node scripts/generateComponents --path inputNameconst inputName = program.path;log('\ninputName: ',inputName);const questions = [  {    type: "confirm",    name: "override",    message: "是否覆盖?"  }];mkdir(componentDir + `\\${inputName||'noname'}`).then(path => {  log('\n开始生成文件...');  return new Promise((resolve) => {    fs.writeFile(path+'\\index.js', newComp, 'utf-8', err => {      if (err) throw err;            log(`\n${path}\\index.js 文件创建成功!\n`);      resolve();    });  });}).catch(err => {  throw err;});// 创建目录function mkdir(path) {  return new Promise((resolve) => {    if (fs.existsSync(path)) {      log(`\n${path}: 文件夹已存在`);      // 命令行交互      inquirer.prompt(questions).then(res => {          if (res.override) {          log('\n文件将被覆盖!');          resolve(path);        } else {          log('\n不覆盖已有文件!');                  }      });    } else {      fs.mkdirSync(path);            log('\n文件夹创建成功!');      resolve(path);    }  })}module.export = {  mkdir}复制代码

命令行打印的提示

  • 新文件
$ npm run create:comp aa> test@1.0.0 create:comp D:\node-test> node scripts/generateComponent --path "aa"inputName:  aa文件夹创建成功!开始生成文件...D:\node-test\components\aa\index.js 文件创建成功!复制代码
  • 文件已存在
$ npm run create:comp aa> test@1.0.0 create:comp D:\node-test> node scripts/generateComponent --path "aa"inputName:  aaD:\node-test\components\aa: 文件夹已存在? 是否覆盖? No不覆盖已有文件!复制代码

二、执行脚本:

使用child_process子进程的exec执行脚本

以下内容,摘抄自

默认情况下, stdinstdoutstderr 的管道在父 Node.js 进程和衍生的子进程之间建立。 这些管道具有有限的(和平台特定的)容量。 如果子进程在没有捕获输出的情况下写入超出该限制的 stdout,则子进程将阻塞等待管道缓冲区接受更多的数据。 这与 shell 中的管道的行为相同。 如果不消费输出,则使用 { stdio: 'ignore' } 选项。

child_process.spawn() 方法异步地衍生子进程,且不阻塞 Node.js 事件循环。 child_process.spawnSync() 方法则以同步的方式提供等效功能,但会阻止事件循环直到衍生的进程退出或终止。

为方便起见, child_process 模块提供了 child_process.spawn()child_process.spawnSync() 的一些同步和异步的替代方法。 注意,这些替代方法中的每一个都是基于 child_process.spawn()child_process.spawnSync() 实现的。

  • child_process.exec(): 衍生一个 shell 并在该 shell 中运行命令,当完成时则将 stdoutstderr 传给回调函数。
  • child_process.execFile(): 类似于 child_process.exec(),除了它默认会直接衍生命令且不首先衍生 shell
  • child_process.fork(): 衍生一个新的 Node.js 进程,并通过建立 IPC 通信通道来调用指定的模块,该通道允许在父进程与子进程之间发送消息。
  • child_process.execSync(): child_process.exec() 的同步版本,会阻塞 Node.js 事件循环。
  • child_process.execFileSync(): child_process.execFile() 的同步版本,会阻塞 Node.js 事件循环。 对于某些用例,例如自动化的 shell 脚本,同步的方法可能更方便。 但是在大多数情况下,同步的方法会对性能产生重大影响,因为它会停止事件循环直到衍生的进程完成。

npm命令:

package.json:{  ...  "scripts": {    "sh": "node components/run-sh.js",  },  ...}复制代码
  • 命令生成 sh/sh1.js:

使用npm命令时,需如上所示,在上面package.jsonscripts配置好

const fs = require('fs');const isDir = dir => fs.statSync(dir).isDirectory();/** * 返回相关的shell脚本 */ // 打印指定目录function ls(dir=null) {  if (dir) {    log('dir: ', dir);    return `cd ${dir} && ls`;  }  return "ls";}/** * 构建前端项目 * @param {项目路径} dir  * @param {执行的 npm 命令} cmd  */function buildFE(dir, cmd) {  if (!dir || !isDir(dir) || !cmd) return;  log('build-dir: ', dir);  return `cd ${dir} && ${cmd}`;}module.exports = {  ls,  buildFE}复制代码
  • 执行脚本 components/run-sh.js
// exec 执行shell命令const { exec } = require('child_process');const path = require('path');require('./log');const timeFormat = require('./timeFormat');const { ls, buildFE } = require('../sh/sh1.js');// console.log('sh: ',sh);const shdir = path.resolve(__dirname, '../sh');// 打印指定路径目录//exec(ls('/code/react-t1'), (err, stdout, stderr) => {
// if (err) throw err;// if ( stderr) log('stderr: ', stderr); // // 执行的命令所打印的内容// log('stdout: ', stdout);// let nowTime = timeFormat({timestamp: new Date(), hasTime: true });// log('time: ', nowTime);//})let nowTime = timeFormat({
timestamp: new Date(), hasTime: true });log('start--time: ', nowTime);exec(buildFE('/code/react-t1', 'npm run build'), (err, stdout, stderr) => { if (err) throw err; if ( stderr) log('stderr: ', stderr); // 执行的命令所打印的内容 log('stdout: ', stdout); nowTime = timeFormat({
timestamp: new Date(), hasTime: true }); log('end--time: ', nowTime);})复制代码
  • 命令行打印:
$ npm run sh> test@1.0.0 sh D:\node-test> node components/run-sh.js==log== start--time:  2019-05-08 16:29:24==log== build-dir:  /code/react-t1==log== stdout:> react-t1@0.1.0 build D:\code\react-t1> node scripts/build.jsCreating an optimized production build...Compiled successfully.File sizes after gzip:  62.73 KB  docs\static\js\4.1fe71077.chunk.js  48.9 KB   docs\static\js\7.70929cf8.chunk.js  14.3 KB   docs\static\js\3.fe3cf9bc.chunk.js  13.3 KB   docs\static\js\0.e70acbb7.chunk.js  3.22 KB   docs\static\js\1.6f7cac0f.chunk.js  3.05 KB   docs\static\js\2.ba0e413c.chunk.js  1.94 KB   docs\static\js\main.eb84215c.chunk.js  1.48 KB   docs\static\js\runtime~main.ff53614d.js  634 B     docs\static\css\main.fde90119.chunk.css  592 B     docs\static\js\8.d5307ac7.chunk.js  438 B     docs\static\js\9.1544082f.chunk.js  434 B     docs\static\css\0.451ae571.chunk.cssThe project was built assuming it is hosted at ./.You can control this with the homepage field in your package.json.The docs folder is ready to be deployed.Find out more about deployment here:  https://bit.ly/CRA-deploy==log== end--time:  2019-05-08 16:29:31==log== stderr:  { parser: "babylon" } is deprecated; we now treat it as { parser: "babel" }.复制代码

转载于:https://juejin.im/post/5cc2d63ee51d456e781f2059

你可能感兴趣的文章
亮风台AR眼镜震撼发布 HiAR 产品全面升级
查看>>
WPF Binding学习(三)
查看>>
File API文件操作之FileReader二
查看>>
java基础学习_GUI_如何让Netbeans的东西Eclipse能访问、GUI(图形用户接口)_day25总结...
查看>>
从零开始学 Web 之 CSS(三)链接伪类、背景、行高、盒子模型、浮动
查看>>
java多线程--信号量Semaphore的使用
查看>>
中国存储芯片进入战略关键期
查看>>
市场上的视觉图像采集卡软硬功能对比
查看>>
阿里专家与你分享:你必须了解的Java多线程技术
查看>>
张高兴的 Windows 10 IoT 开发笔记:三轴数字罗盘 HMC5883L
查看>>
rocketmq 同步双写
查看>>
细数国内无人机的江湖门派
查看>>
张高兴的 Windows 10 IoT 开发笔记:部署 ASP.NET Core 2 应用
查看>>
Waymo已经开始绘制亚特兰大地图数据,自动驾驶汽车路测地点又添新城
查看>>
ARM 和 RISC-V 公然开撕,GNOME 之父指责 ARM
查看>>
日本将推出“隐形列车”,你要去体验一番吗?
查看>>
Maven查看依赖树
查看>>
装饰器
查看>>
《物联网框架ServerSuperIO教程》-19.设备驱动和OPC Client支持mysql、oracle、sqlite、sqlserver的持久化。v3.6.4版本发布...
查看>>
Forrester告诫CIO们:谨慎应用区块链网络
查看>>