从零构建一个操作shell的node插件并打包发布

3,061 阅读4分钟

今天我们来从零构建一个简易的node脚本插件,方便操作shell,构建自己的脚本工具,帮助大家理解一些node模块,webpack打包过程及npm发布过程。

child_process.exec

要使用node操作shell,首先要了解node中的child_process.exec,简单的来讲,exec会开启一个shell,并且执行输入的命令,就像是大家使用git bash来执行某些命令,如npm init。介绍完了,show code。

文件结构

首先创建一个结构如下的文件夹,并执行npm init -y

├─src
  └─index.js

插件编写

在index.js文件中,编写主要代码。

首先引入所需要的exec

const util = require('util');
const exec = util.promisify(require('child_process').exec);

一般所需要的即三个参数,执行的命令行(command),执行的目录(cwd),执行的超时时间(timeout),即

exec(command, { cwd: path || null, timeout: timeout || 0 })

执行命令的代码如下所示:

/**
 * @name: 执行命令行
 * @param {Array} cmd/执行命令语句
 * @param {String} path/执行命令的路径
 * @param {Number} timeout/执行命令的超时时间
 * @return: {Boolean} 是否成功
 */
const shell = async (arr) => {
  for (let i = 0; i < arr.length; i++) {
    const { cmd, path, timeout } = arr[i]
    // 组装执行命令
    const command = cmd.reduce((total, item, index) => {
      if (index === 0) {
        return total + item
      } else {
        return total + ` && ${item}`
      }
    }, '')
    const { error, stdout, stderr } = await exec(command, { cwd: path || null, timeout: timeout || 0 });
    if (error) {
      // 打印错误日志
      log(error)
      return false
    }
  }
  console.log("完成")
  return true
}

传入的参数为对象数组arr,对象中的cmd为字符串数组,存放执行的命令行,使用" && "连接每个命令行,path为执行命令的路径,timeout为该次进程的超时时间,且将执行步骤改为同步。

执行过程中可能会出现报错,那么这个时候就需要一个日志来记录错误。

错误日志

引入所需功能

const fs = require('fs');
const path = require('path');

获取当前时间以备用

/**
 * @name: 当前时间
 * @param {String} type/date为日期,time精确到秒
 * @return: {String} 当前时间
 */
const timeStr = (type) => {
  const zeroFill = n => {
    n = n.toString()
    return n[1] ? n : '0' + n
  }
  const date = new Date()
  const year = date.getFullYear()
  const month = zeroFill(date.getMonth() + 1)
  const day = zeroFill(date.getDate())
  const hour = zeroFill(date.getHours())
  const minute = zeroFill(date.getMinutes())
  const second = zeroFill(date.getSeconds())
  if (type === "date") {
    return `${year}-${month}-${day}`
  }
  if (type === "time") {
    return `${year}-${month}-${day} ${hour}:${minute}:${second}`
  }
}
// 当前日期
const date = timeStr("date")
// 当前时间
const time = timeStr("time")

输出错误日志

/**
 * @name: 输出错误日志
 * @param {type} error/错误信息
 * @return: 
 */
const log = error => {
  const logPath = path.join(__dirname, "log")
  const txtPath = path.join(__dirname, "log", `${date}.txt`)
  if (!fs.existsSync(logPath)) {
    // 不存在log目录,则创建
    fs.mkdirSync(logPath)
  }
  if (!fs.existsSync(txtPath)) {
    // 不存在错误日志文件,则创建
    fs.writeFileSync(txtPath, `${time}  ${error}; \n`)
  } else {
    // 存在则追加错误信息
    fs.appendFileSync(txtPath, `${time}  ${error}; \n`)
  }
}

使用fs.existsSync检查是否存在log目录,如果不存在则使用fs.mkdirSync创建目录。

再检查是否有当天的错误日志文件,不存在则使用fs.writeFileSync创建文件,并写入错误信息与时间; 若存在,则对这个错误日志文件使用fs.appendFileSync追加错误信息。

最后通过

module.exports = shell

导出

之后在src目录下创建一个example文件来检测下刚刚的代码是否可以成功运行。

const shell = require("./index")

shell([{ cmd: ["mkdir pikaz-shell"], path: "D:\\" }])

此命令会在D盘创建一个pikaz-shell文件夹

执行

node src/example

当在D盘看到新创建的文件夹时,就说明代码可成功运行了。

代码编写完,就需要打包了,我们使用webpack来打包。

打包

安装webpack

npm install webpack webpack-cli --save-dev

在项目目录下创建webpack.config.js配置文件,内容如下:

const path = require('path');

module.exports = {
  mode: 'production',
  entry: {
    "pikaz-shell": "./src/index.js",
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'lib'),
    libraryTarget: 'umd'
  },
  node: {
    fs: 'empty',
    child_process: 'empty',
  }
};

其中,mode为打包模式,设置为production生产模式,可自动压缩代码。

entry为打包的入口,设置为src目录下的index文件。

output为输出文件,我们设置到lib文件夹下,libraryTarget一般都设置为umd,即可将你的 library 暴露为所有的模块定义下都可运行的方式。它将在 CommonJS, AMD 环境下运行,或将模块导出到 global 下的变量。

node将fs和child_process设置为'empty',因为我们使用的node是计算机安装的全局node,这样设置webpack就不会查找这两个模块,不然会报错在该项目查找不到这两个模块。

最后将打包命令"build": "webpack"添加进package.json的scripts中

发布

发布首先需要一个npm账号,可以自己去https://www.npmjs.com/注册一个。

有账号则继续接下来的操作。 对package.json文件设置如下:

{
  "name": "pikaz-shell",
  "version": "0.1.4",
  "description": "javascript for manipulating the shell",
  "main": "lib/pikaz-shell.js",
  "scripts": {
    "build": "webpack",
    "example": "node src/example"
  },
  "keywords": [
    "node",
    "shell"
  ],
  "files": [
    "lib"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/pikaz-18/pikaz-shell.git"
  },
  "bugs": {
    "url": "https://github.com/pikaz-18/pikaz-shell/issues"
  },
  "author": "pikaz",
  "license": "MIT"
}

name为项目名称,version为项目版本,每一次发布都需要更改版本,description为项目介绍,main为项目的入口地址,我们指定为打包出来的lib目录下的pikaz-shell.js文件,keywords为项目关键词,files为白名单,只有在白名单上的文件或文件夹才会上传至npm,我们只需要上传打包的文件夹lib即可,减少包体积,repository为项目github的地址,bugs为github上issue的地址,author为作者,license为开源协议,一般我们写插件选择MIT即可,这个协议规定最松,如需了解其他协议可自行搜索。

项目地址

github.com/pikaz-18/pi…

本插件也上传至npm了,如有需要,也可以直接使用哦

npm install --save -dev pikaz-shell

最后

下一篇文章会使用此插件来构建一个服务器上的前端自动部署功能,再也不用看后端脸色或者手动更新开发环境项目啦。

如果觉得有收获的话,请点个赞吧,rua