Open siric opened 4 years ago
Some investigations: (node v13.3.0, pm2 4.2.0, MacOs 10.14.6)
7|xxxx | (node:24598) Warning: require() of ES modules is not supported.
7|xxxx | require() of xxxx.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
7|xxxx | Instead rename loader-scanner.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from xxxxx/package.json.
7|xxxx | Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: xxxx.js
7|xxxx | at Object.Module._extensions..js (internal/modules/cjs/loader.js:1163:13)
9|xxxx | Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: xxxxx.mjs
9|xxxx | at Module.load (internal/modules/cjs/loader.js:981:11)
9|xxxx | at Function.Module._load (internal/modules/cjs/loader.js:891:14)
8|xxxx | (node:24843) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
8|xxxx | xxxxx.js:10
8|xxxx | import { Run } from 'xxxxxxx';
8|xxxx | ^^^^^^
8|xxxx | SyntaxError: Cannot use import statement outside a module
8|xxxx | at wrapSafe (internal/modules/cjs/loader.js:1050:16)
8|xxxx | at Module._compile (internal/modules/cjs/loader.js:1098:27)
8|xxxx | at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:10)
The only workaround I've found so far is to keep esm is to use ESM loader with node args:
-r esm
(https://www.npmjs.com/package/esm)
But it's really slow compared to native node 13 loader
related to [https://github.com/Unitech/pm2/issues/4385]
NB: There is absolutely no require() in the code
Same here. I'm using .mjs and node 13, but esm workaround not even working for me. App runs fine using systemd daemon.
This is my first time using pm2 and I thought I was going insane! Have been googling about this for hours. I hope there will be a fix soon
A quick and dirty fix for pm2/lib/ProcessContainerFork.js : @Unitech
26 if (process.env.pm_exec_path)
27 // require('module')._load(process.env.pm_exec_path, null, true); //REPLACE
27 import(process.env.pm_exec_path); // (we don't use await here) //BY
Workaround: I'm using a 'custom loader' which is faster than esm-loader and use Node 13 native one. Its goal is to bypass ProcessContainerFork.js
We need to use node interpreter args: (here as api, but can be done using command line/ecosystem file)
pm2Options.interpreterArgs = '-- path/to/loader.js index.mjs'
// "--" is mandatory because we don't want node to parse our custom args.
// they will be placed before pm2's (ProcessContainerFork.js)
//
// index.mjs is our ES6 target script
// we should need "type":"module" in package.json if .mjs extension is not used
const moduleFile = process.cwd() + '/' + process.argv[2]
process.argv.splice(2, 2)
import (moduleFile)
Thanks for this report and suggestion, will dig this
Is this seriously not working?
@Unitech how can I help? This is pretty critical for my team as we're using modules in production.
It's been enabled officially by node, although still experimental (it works great on my end)
@Unitech Plz comment, this has been out for some time now and it has not been addressed
Will work on it by the next 7 days
Thanks, I've had to resort to using forever
, but keen to switch back to pm2 once it's ready
Ok I landed the ES module support
Can anyone try it out please?
npm install Unitech/pm2#development -g
pm2 update
pm2 start app.mjs
Thank you!
I've checked:
pm2 start app.mjs
- ok (package.type missing) pm2 start app.js
- ok (package.type = 'module')pm2 start src/app.mjs
- ok (package.type missing) pm2 start src/app.js
- ERR_REQUIRE_ESM (package.type = 'module')@Unitech
Works for me, but I had an error with this applying to saved processes.
I had to delete the process from pm2 and then reinstall it for it to work. Not a huge deal, but it might affect users wanting to move over to ESM
Release on pm2 4.2.2
npm install pm2@latest -g
pm2 update
It works ! thanks a lot
Just a detail: according to Node.js doc: https://nodejs.org/api/esm.html
The nearest parent package.json is defined as the first package.json found when searching in the current folder, that folder’s parent, and so on up until the root of the volume is reached.
Here pm2 is checking package.json in the current folder and it's first parent. In my case js is transpiled from src to a/deeper/folder then I have to copy project root's package.json to deployment folder, but it's not a big deal.
with ESM on windows my success only with:
pm2 start node -- src/index.js
@vitalets @r3gisc With node 12.18 and pm2 4.4.0 pm2 all combinations that you mentioned fails with ERR_REQUIRE_ESM error, which version of node did you use to verify that it's working?
This does not work with the docker pm2-runtime
.
RUN yarn global add pm2@4.2.2
COPY . .
EXPOSE 8080
CMD [ "pm2-runtime", "index.js" ]
Gives:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /usr/src/app/index.js
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1154:13)
at Module.load (internal/modules/cjs/loader.js:986:32)
adding pm2 update
doesn't fix either.
Per @vitaliytv suggestion I chcnged the following.
CMD [ "pm2-runtime", " node -- index.js" ]
Having issues with this again
@Unitech I'm getting Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
on pm2 4.4.0 with node 12.18.2.
I don't understand why need to switch to .mjs
extension.
I don't understand why after I add "type": "module"
it still not working.
I don't understand why need esm
at the first place.
I don't understand after install esm
, alias in .babelrc
totally not working.
pm2
doesn't seems fix the problem but create more problem.
Can we reopen this issue. pm2 4.4.0 have the same problem again
why folks above said it works with v4.2.2. ? I have v4.4.1 installed but it still doesn't work
This test: https://github.com/Unitech/pm2/blob/0d44c41b07193bb793420ea23c476e020f8e99d5/test/e2e/esmodule.sh is passing
What is wrong with these tests? Let me know so I can fix whatever is missing
@Unitech I figured out what is wrong.
In pm2/lib/ProcessUtils.js
:
try {
data = JSON.parse(fs.readFileSync(path.join(path.dirname(exec_path), 'package.json')))
if (data.type === 'module')
return true
else
return false
} catch(e) {
}
In my use case, index.js
is in a subdirectory, such as app/lib/index.js
. The issue is that path.join(path.dirname(exec_path)
looks for package.json
in the same directory as index.js
, silently fails, and then can't find it.
Can you modify this to look for package.json
at the root of the directory?
Something like this would do the trick.
I think the problem is that ESModules support is disabled for version below 13 (current LTS is 12.18.4) See here
@Unitech if pm2 calls the user scripts with require('userscript.js')
in an wrapper rather than with process.fork('userscript.js')
directly, this issue technically cannot be fixed, because node v13+ forbids require()
on es module with type: module
, which has nothing to do with whether the function require
is hooked by -r esm
.
it's needed to make a big change about how pm2 calls user scripts. it should be:
process.fork
directlyimport()
in a wrapper@Unitech it's still not working with "type": "module" in the package.json file, like in the picture below
I can confirm that the "type": "module"
in package.json does not work properly on NodeJS LTS
I don't know why this isn't getting any priority, I literally can't use PM2 with ESM modules. Just discovered I also can't use the ecosystem file when type: "module"
is enabled in package.json because it tries to import the file using require
and errors out.
This is the reason ESM modules is erroring, changing this code resolves it for me:
https://github.com/Unitech/pm2/issues/4540#issuecomment-692296125
use babel
to build file and run with pm2
Best workaround I've found for this is to change the name of the entry script from ending in ".js" to ending in ".mjs", not exactly an ideal solution, but it gets the job done as a temporary fix until this actually gets some attention
Using an Ecosystem file still doesn't work with ESM. pm2 needs to use import
syntax or it could simply try to look for an Ecosystem file ending in .cjs
.
For anyone having this issue, a really simple "workaround" is to just write your config file in YAML (see here). i.e. ecosystem.config.yaml
and point your scripts to it.
Same feeling as @dhtree, pm2 is blocking our migration to ESM. It's frustrating.
If it can help someone, I found the following workaround :
pm2 start "node -- /path/to/app.js"
For this configuration:
pm2: 4.1.2 node: 14.16.1 (using n) package.json: has "type": "module" file extension: js os: centOS
With pm2#development:
app.js
// app.mjs
import { addTwo } from './addTwo.js';
// Prints: 6
console.log(addTwo(4));
addTwo.js
// addTwo.mjs
function addTwo(num) {
return num + 2;
}
export { addTwo };
package.json:
{
"name": "esm",
"version": "1.0.0",
"description": "",
"main": "addTwo.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
❯ node -v
v15.12.0
Then when I start:
pm2 start app.js
It works:
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
PM2 | App [app:4] exited with code [0] via signal [SIGINT]
PM2 | App [app:4] starting in -fork mode-
PM2 | App [app:4] online
4|app | 6
This is fantastic!
It works if the app.js file is at the root of the project, if it's deeper, doesn't work
Tried to start a script in children folder and it still works:
For anyone that wants another workaround, I have found that creating a separate entry script for the ecosystem file with extension .mjs
works well, which then just imports the "real" entry script. ie having a file called entry.mjs
which just contains:
import * as entry from './app.js';
Tried to start a script in children folder and it still works:
Try one level deeper... esm/deep/app.js I just tried and 1 level deep seems to work, 2 levels deep doesn't work :
pm2 start app.js
root > workspm2 start modules/app.js
> workspm2 start modules/api/app.js
> not workingnode version : 14.16.0
start script in package.json - cross-env NODE_ENV=development nodemon --es-module-specifier-resolution=node --experimental-modules --no-warnings src/common/bin/app.js
getting below error on running pm2 start npm -- run start
0|npm | Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/Programs/npm' is not supported resolving ES modules imported from /home/dhruv/.nvm/versions/node/v14.16.0/lib/node_modules/pm2/lib/ProcessContainerFork.js
0|npm | at finalizeResolution (internal/modules/esm/resolve.js:272:17)
0|npm | at moduleResolve (internal/modules/esm/resolve.js:699:10)
0|npm | at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
0|npm | at Loader.resolve (internal/modules/esm/loader.js:86:40)
0|npm | at Loader.getModuleJob (internal/modules/esm/loader.js:230:28)
0|npm | at Loader.import (internal/modules/esm/loader.js:165:28)
0|npm | at importModuleDynamically (internal/modules/cjs/loader.js:1006:27)
0|npm | at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:30:14)
0|npm | at Object.<anonymous> (/home/dhruv/.nvm/versions/node/v14.16.0/lib/node_modules/pm2/lib/ProcessContainerFork.js:30:16)
0|npm | at Module._compile (internal/modules/cjs/loader.js:1063:30) {
0|npm | code: 'ERR_UNSUPPORTED_DIR_IMPORT',
0|npm | url: 'file://Programs/npm'
0|npm | }
pm2 start "node -- index.js"
and pm2 start index.js
seems to cause less error
If it can help someone, I found the following workaround :
pm2 start "node -- /path/to/app.js"
For this configuration:
pm2: 4.1.2 node: 14.16.1 (using n) package.json: has "type": "module" file extension: js os: centOS
This is what worked for me, since the app.js
file was not in the root. many thanks!
What worked for me to make it run with ecosystem config was naming it ecosystem.config.cjs, and starting with pm2 start ecosystem.config.cjs
I'll echo @EskelCz in that renaming your ecoystem file to end with .cjs
, and of course using common js module syntax inside of that file for requires and exports, seems to be working
If it can help someone, I found the following workaround :
pm2 start "node -- /path/to/app.js"
For this configuration:
pm2: 4.1.2 node: 14.16.1 (using n) package.json: has "type": "module" file extension: js os: centOS
This worked for me, thank you so much!
esm is no longer experimental in node 13, however pm2 does not read out
"type": "module"
frompackage.json
, which means that esm imports/exports can not be used with pm2: