使用 npm scripts 统一操作接口

任何一个 Node.js 应用都会有一些基本的操作,如

  • 启动服务

    ./start.sh 或 systemctl start <service> 或 pm2 start app.json …

  • 停止服务

    ./stop.sh 或 systemctl stop <service> 或 pm2 stop app.json …

  • 重启服务

    ./restart.sh 或 systemctl restart <service> 或 pm2 restart app.json …

  • 执行任务脚本

    node ./tools/qps.js 或 ./tools/qps.sh

我们可能会使用 pm2 来管理服务,使用 node 来执行脚本,服务往往会依赖一些环境变量的正确定义,如:

  • PATH

    同一机器可能跑了多个服务,而每个服务使用不同的 node.js 版本,通过设置 PATH 环境变量来决定使用哪个版本的 node.js。

  • NODE_ENV

    值为 production 表示运行在产品环境。

    值为 development 表示运行在开发环境。

    如果忘记设置 NODE_ENV 而导致在线上机器使用开发环境运行服务,后果会很严重。

  • PM2_HOME

    pm2 会在 PM2_HOME (默认为当前用户的 HOME 目录) 目录下存放元数据,服务总是以特定的帐号(如:root)运行,线上机器往往会有多个帐号,当我们以非服务帐号登录系统,并使用 pm2 管理我们的服务进程时,就可能以错误的帐号重复运行我们的服务。

  • NODE_CONFIG_DIR

    config 模块用于指定配置文件存放路径,同时它也会使用 NODE_ENV 环境变量来决定载入哪些配置文件。

所以我们可能会写一大堆脚本,如:

  • .bashrc

    设置环境变量,由于一台机器上可能跑多个服务,而每个服务的环境设置会不一样,所以我们不好直接放置在用户根目录下的 .bashrc 中。

  • .bashrc.$HOSTNAME

    机器特定的环境变量,用于覆盖默认设置

  • start.sh

    会先载入 .bashrc 中定义的环境变量,再使用 pm2 start <app> 启动服务

  • stop.sh

    会先载入 .bashrc 中定义的环境变量,再使用 pm2 stop <app> 停止服务

  • restart.sh

    会先载入 .bashrc 中定义的环境变量,再使用 pm2 restart <app> 重启服务

  • pm2.sh

    会先载入 .bashrc 中定义的环境变量,再使用用户传入的参数执行 pm2

  • node.sh

    会先载入 .bashrc 中定义的环境变量,再使用用户传入的参数执行 node

还有一堆 js 任务脚本,你得决定要不要提供配套的 bash 脚本(确保载入 .bashrc),或者祈祷运行前操作人员会记得先载入 .bashrc

npm scripts 相关文章

npm scripts 使用的是 shell 命令,npm scripts 的强大其实是 shell scripts 的强大,npm scripts 只是约定了统一的入口也就是操作界面。

npm scripts 示例如下:

"scripts": {
  "node": "export NODE_ENV=${NODE_ENV:-production}; node",
  "pm2": "export NODE_ENV=${NODE_ENV:-production}; PM2=pm2; PM2_USER=${PM2_USER:-root}; [[ $HOME != `echo ~$PM2_USER` ]] && PM2=\"sudo -u $PM2_USER pm2\"; $PM2",
  "ps": "npm run pm2 -- list $npm_package_name",
  "prestart": "STARTED=`npm -s run pm2 -- jlist | json -a -c \"this.name == '$npm_package_name' && ['errored', 'stopped'].indexOf(this.pm2_env.status) == -1\" pm2_env.pm_id | wc -l`; [[ $STARTED > 0 ]] && echo $STARTED process already running; exit $STARTED",
  "start": "PM2_FILE=./process.json; [[ -f ./process.${HOSTNAME}.json ]] && PM2_FILE=./process.${HOSTNAME}.json; npm run pm2 -- start $PM2_FILE",
  "stop": "PM2_FILE=./process.json; [[ -f ./process.${HOSTNAME}.json ]] && PM2_FILE=./process.${HOSTNAME}.json; npm run pm2 -- stop $PM2_FILE",
  "restart": "PM2_FILE=./process.json; [[ -f ./process.${HOSTNAME}.json ]] && PM2_FILE=./process.${HOSTNAME}.json; npm run pm2 -- startOrGracefulReload $PM2_FILE"
}

运行 npm scripts:

  • npm run

    列出所有脚本。

  • npm run pm2 -- list

    执行 pm2 list ,会确保正确设置环境变量,并且必要时切换到 pm2 帐号。

  • npm start

    执行 pm2 start ,会确保正确设置环境变量,并且必要时切换到 pm2 帐号,通过 prestart 预先检查进程是否已启动,避免重启服务。

  • npm run node -- tools/qps.js

    执行 node tools/qps.js ,会确保正确设置环境变量。

npm scripts 会自动将 ./node_modules/.bin 添加到 $PATH 环境变量,将 package.json 的内容暴露成环境变量供脚本引用,通过 prepost 钩子自动执行前置/后置附带任务,通过在脚本中调用其它 npm scripts 脚本也可以简化脚本的开发。

现在我们只有 npm scripts,所有的一切操作都从 npm run 开始,整个世界清净了。


node