pm2模块es6支持
2019年03月17日 22:56:03

概述

import/export是ES6中对模块操作的新语法,最早在nodejs6中得到了支持,根据ECMAScript标准的定义,以后会使用import/export进行模块的相关操作,而nodejs现存的require功能仅仅是一个内置方法.所以为了尽早熟悉这种语法模式和相关部署,就尽早迁移了过来.

随着ES6规范的普及,有关import/export的支持问题也发生了变化,相应的pm2模块的支持也有了新的变化。就目前使用的系统环境来看,node稳定版是node12,nodejs13已经发布了。

针对各个版本对ES6功能的支持情况,可以参考我的上一篇短文介绍。nodejs对import的支持

操作流程

针对import/export目前发现的问题:

  1. 需要nodejs 6.0+
  2. 文件扩展名必须是.mjs
  3. require方法互斥,不能同时使用
  4. 该功能的实现还是实验性的,node需要--experimental-modules参数,才可以启用(node6至node12)
node --experimental-modules main.mjs
  1. 该功能引入的模块,需要在代码的最顶层,无法嵌套
  2. 该功能只支持静态调用,动态调用需要import()方法(需要nodejs v10)
  3. 代码错误跟踪变得更模糊,希望能在后续改进

针对现在的不同node版本,使用pm2模块操作还是有一些区别的

node v6

pm2 start main.js

pm2的操作说明里,提到可以使用node_args参数,启用ES6支持的办法行不通:

# error
pm2 start main.mjs --node-args="--experimental-modules"

或者使用config文件:

// cat app.config.js
module.exports = {
    apps: [{
        name: 'webauthn',
        script: 'main.mjs',
        node_args: '--experimental-modules',
        instances: 1,
        exec_mode: "fork",
        wait_ready: false,
        watch: false,
        listen_timeout: 8000,
        kill_timeout: 3000
    }]
}

但是都会提示如下错误:

# pm2 logs <NAME>
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: …

可以采用安装esm模块的办法:

  1. 安装esm模块
npm i esm --save
  1. 修改入口文件扩展名
mv main.mjs main.js
  1. 修改pm2启动命令
pm2 start main.js --node-args="-r esm"

或者使用config文件:

// cat app.config.js
module.exports = {
    apps: [{
        name: 'ProjectName',
        script: 'main.js',
        node_args: '-r esm',
        instances: 1,
        exec_mode: "fork",
        wait_ready: false,
        watch: false,
        listen_timeout: 8000,
        kill_timeout: 3000
    }]
}
  1. 运行项目程序:
pm2 start app.config.js

node v12

在node12版本中已经不能使用esm模块实现ES6支持了,对pm2的调用需要修改package.json文件,增加{"type":"module"},然后使用命令行执行:

pm2 -s stop ProjectName;NODE_ENV=xxx pm2 -i 1 start node --name ProjectName -- --experimental-modules main.mjs

中间的--参数让后面的--experimental-modules参数能够传递给node程序

node v13

由于node13版本中已经去掉了--experimental-modules参数,所以在命令行参数上,可以忽略这个参数:

pm2 -s stop ProjectName;NODE_ENV=xxx pm2 -i 1 start node --name ProjectName -- main.mjs

参考链接

pm2 issue
pm2 --experimental-modules 标记被忽略
pm2 mjs支持

总结

目前来看暂时解决了pm2对es6语法的支持,但是最近的更新中,服务端更新到node v11.x版本,无法再使用-r esm的方式运行,所以暂时使用nvm对node进行了降级.
另外发现在stackoverflow中有提到新版本node对es6的支持.

Update 3: Since Node 13, you can use either the .mjs extension, or set “type”: “module” in your package.json. You don’t need to use the --experimental-modules flag.
Update 2: Since Node 12, you can use either the .mjs extension, or set “type”: “module” in your package.json. And you need to run node with the --experimental-modules flag.
Update: In Node 9, it is enabled behind a flag, and uses the .mjs extension.
node --experimental-modules my-app.mjs