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

概述

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

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

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

即便有以上这么多缺点吧,大多数项目还是能顺利的迁移过来:

node --experimental-modules main.mjs

但是在生产环境,采用pm2运行代码,就出现了问题.
普通的pm2启动命令:

pm2 start main.js

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

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: …

解决办法

后来参考网上的issue,解决办法如下:

  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

参考链接

pm2 issue

总结

目前来看暂时解决了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