Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support "type": "module" (esm for node 13) #4540

Open
siric opened this issue Dec 5, 2019 · 72 comments
Open

support "type": "module" (esm for node 13) #4540

siric opened this issue Dec 5, 2019 · 72 comments

Comments

@siric
Copy link

siric commented Dec 5, 2019

esm is no longer experimental in node 13, however pm2 does not read out "type": "module" from package.json, which means that esm imports/exports can not be used with pm2:

import { foo } from './foo.js';
       ^

SyntaxError: Unexpected token {
@siric siric changed the title support "type": "module" in node 13 support "type": "module" (esm for node 13) Dec 5, 2019
@r3gisc
Copy link

r3gisc commented Dec 7, 2019

Some investigations: (node v13.3.0, pm2 4.2.0, MacOs 10.14.6)

  • With "type":"module" in package.json
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)
  • With .mjs extension
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)
  • Without neither .mjs or "type":"module" :
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//issues/4385]

NB: There is absolutely no require() in the code

@bradocchs
Copy link

Same here. I'm using .mjs and node 13, but esm workaround not even working for me. App runs fine using systemd daemon.

@NeonCreativeStudios
Copy link

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

@r3gisc
Copy link

r3gisc commented Dec 19, 2019

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)

  • pm2.start(pm2Options)
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
  • loader.js
const moduleFile = process.cwd() + '/' + process.argv[2]
process.argv.splice(2, 2)
import (moduleFile)

@Unitech
Copy link
Owner

Unitech commented Dec 19, 2019

Thanks for this report and suggestion, will dig this

@AlbertMarashi
Copy link

Is this seriously not working?

@AlbertMarashi
Copy link

@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)

@AlbertMarashi
Copy link

@Unitech Plz comment, this has been out for some time now and it has not been addressed

@Unitech
Copy link
Owner

Unitech commented Jan 9, 2020

Will work on it by the next 7 days

@AlbertMarashi
Copy link

Thanks, I've had to resort to using forever, but keen to switch back to pm2 once it's ready

Unitech added a commit that referenced this issue Jan 13, 2020
@Unitech
Copy link
Owner

Unitech commented Jan 13, 2020

Ok I landed the ES module support

@Unitech
Copy link
Owner

Unitech commented Jan 13, 2020

Can anyone try it out please?

npm install Unitech/pm2#development -g
pm2 update
pm2 start app.mjs

Thank you!

@vitalets
Copy link

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')

@AlbertMarashi
Copy link

@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

@Unitech
Copy link
Owner

Unitech commented Jan 20, 2020

Release on pm2 4.2.2

npm install pm2@latest -g
pm2 update

@Unitech Unitech closed this as completed Jan 20, 2020
@r3gisc
Copy link

r3gisc commented Jan 21, 2020

It works ! thanks a lot

@r3gisc
Copy link

r3gisc commented Jan 21, 2020

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.

@vitaliytv
Copy link

with ESM on windows my success only with:

pm2 start node -- src/index.js

@chrisstone07
Copy link

chrisstone07 commented Jun 24, 2020

@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?

@iot-resister
Copy link

iot-resister commented Jul 1, 2020

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" ]

@AlbertMarashi
Copy link

Having issues with this again

@pmikolajek
Copy link

@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.

@ckcr4lyf
Copy link

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!

@EskelCz
Copy link

EskelCz commented Sep 9, 2021

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

@bentaber
Copy link

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

@CallumWalterWhite
Copy link

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!

@muhammedkamel
Copy link

muhammedkamel commented Oct 19, 2021

@Unitech Any updates with node 14 I am using pm2 v5 and still have the same problem.

I changed the config name to ecosystem.config.cjs then

pm2 start ecosystem.config.cjs

@ciarans
Copy link

ciarans commented Oct 20, 2021

module.exports = {
  apps : [{
    name   : "API",
    script : "./src/Admin/API/Index.js"
  }]
}

Throws the same error - Ive had to go back to nodemon :(

@mreinstein
Copy link

esm is natively supported, stable in all active LTS distributions. Is this not something pm2 ever plans to support?

@fvilar
Copy link

fvilar commented Dec 10, 2021

Working for me with a package.json inside the route.
if you have modules/app.js, just add a modules/package.json

package.json

{
  "version": "1.0.0",
  "type": "module"
}

@jrs320
Copy link

jrs320 commented Jan 6, 2022

@Unitech Any updates with node 14 I am using pm2 v5 and still have the same problem.

I changed the config name to ecosystem.config.cjs then

pm2 start ecosystem.config.cjs

Has the problem been solved?

@DenProgMan
Copy link

DenProgMan commented Jan 6, 2022 via email

@jaclas
Copy link

jaclas commented Jan 28, 2022

I still get many errors, I use node 17.3, pm2 5.1.2 and ESM...

@Diferno
Copy link

Diferno commented Feb 22, 2022

Yup, same here.
After many years working with pm2 and commonjs, changing to ESM and bumping into this is really frustrating.

EDIT: solved using exosystem.config file with CJS extension as mentioned in some posts above
pm2 start ecosystem.config.cjs

@roeniss
Copy link

roeniss commented Mar 11, 2022

I think this comment should get a prize:

really simple "workaround" is to just write your config file in YAML

Thank you so much, @adamhl8 !

@bryce-mullican
Copy link

bryce-mullican commented Mar 17, 2022

Like others I was frustrated with having issues with pm2. After reading:

Tried to start a script in children folder and it still works:
image

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 > works
  • pm2 start modules/app.js > works
  • pm2 start modules/api/app.js > not working

as well as:

Working for me with a package.json inside the route. if you have modules/app.js, just add a modules/package.json

package.json

{
  "version": "1.0.0",
  "type": "module"
}

I was able to work around the problem by creating a "package.json" file 1 level away from the script I was calling in the "ecosystem.config.cjs" and that worked for me.

/root
 |_ ecosystem.config.cjs
 |_ /src
    |_ package.json
    |_ /services
        |_ SCRIPT_NAME.js <- this is what ecosys is calling

So it appears the issue is that it won't traverse more than one level if you are using ESM. Just my two cents FWIW.

Thanks @HRK44, @fvilar.

os: Ubuntu
node: v16.3.0
pm2: 5.2.0

This was referenced Apr 4, 2022
@Firsh
Copy link

Firsh commented May 16, 2022

Ok, so "type": "module", is given. In the docs you need to read very closely to notice the mention of being able to use a json config file. And you need to go right to the ecosystem config file examples to reveal that even yaml is supported.

This ecosystem.config.js doesn't work in this case, yet it's all you see in the docs:

module.exports = {
  apps: [{
    name: "app1",
    script: "./index.js"
  }]
}

But this ecosystem.config.json works:

{
  "apps": [{
    "name": "app1",
    "script": "./index.js"
  }]
}

Also this ecosystem.config.yaml works:

apps:
  - name : 'app1'
    script: './index.js'

If you really want to stick with a JS file, this ecosystem.config.es6.js works as well:

export default {
  apps: [{
    name: "app1",
    script: "./index.js"
  }]
}

I'm not saying the docs are bad, but they certainly don't cover every new kind of possibility.

Bonus:

{
  "name": "app1",
  "script": "./index.js"
}

Probably the easisest json config if you only have 1 app to config and have managed by pm2.

@dzek69
Copy link

dzek69 commented Jun 3, 2022

2 and a half year with no luck? That's a shame :(

Anyway, the simplest solution is the one from @nickpharrison

Near your index.js or whatever create entry.mjs file with import "./index.js" and run it instead. It just works, the .mjs extension is what forces node into ESM mode.

@FbN
Copy link

FbN commented Jun 3, 2022 via email

@mreinstein
Copy link

was starting to think that pm2 is superfluous. You can better manage

100% agreed, pm2 (and other service wrappers) aren't needed in 2022.

@rhwinter
Copy link

rhwinter commented Dec 19, 2022

Things get even weirder if one is trying to use pm2 deploy, so I'll add this comment for future reference.

Unlike what @Firsh mentions, the json variant of the ecosystem file can't be named ecosystem.config.json, but ecosystem.json; if only a ecosystem.config.json file is present, it will be skipped and package.json will be used.

Also, using an ecosystem.config.es6.js or an ecosystem.config.cjs file doesn't seem to work when issuing pm2 deploy. Indeed, checking the deploy code, one can find:

var defaultConfigNames = ['ecosystem.config.js', 'ecosystem.json', 'ecosystem.json5', 'package.json'];

So, clearly, those are the only file names allowed.

Also, any of them will by parsed (by calling Common.parseConfig()) and end up being required, which is, needless to say, very frustrating if your entire project is using ES6 modules — in other words, as far as I can tell, the only way to use deploy in that case is to have a ecosystem.json file or to explicitly declare the config file, like so:

$ pm2 deploy ecosystem.config.cjs production

where production is the environment set in the file itself.

It would be nice if pm2 caught that automatically, which, it now occurs to me, would just require adding ecosystem.config.cjs to the deploy code:

@@ -67,7 +67,7 @@ module.exports = function(CLI) {
     // Find ecosystem file by default
     if (!Common.isConfigFile(file)) {
       env = args[0];
-      var defaultConfigNames = ['ecosystem.config.js', 'ecosystem.json', 'ecosystem.json5', 'package.json'];
+      var defaultConfigNames = ['ecosystem.config.js', 'ecosystem.config.cjs', 'ecosystem.json', 'ecosystem.json5', 'package.json'];
       file = Utility.whichFileExists(defaultConfigNames);
 
       if (!file) {

@GimpMaster
Copy link

@rhwinter - Agreed, it would be nice if they added ecosystem.config.cjs. I had this exact same issue a week ago and like you said you have to manually specify ecosystem.config.cjs on the command line. It sure would be nice if they added cjs as well. Can you create a pull request?

@mmxhello
Copy link

mmxhello commented Jan 9, 2023

Wow, I couldn't solve this for 2 weeks, but now it's done.
The problem was that node version on my server was 12, but the latest for now is 19.
I checked it with:
node --version
Then installed a package to update node:
sudo npm install -g n
And, to update:
sudo n latest
Rebooted server
sudo reboot
And it works!

@uritz
Copy link

uritz commented Jan 17, 2023

If you are here scratching your head and pulling whatever hairs you have left there... :)
Here is one more thing to check, which I've learned in the hard way (2 working days).
If you're running pm2 in sudo, make sure to check the node version of your sudo. My "regular" node version was 18.x while my sudo version was 12.x so whatever I did from the above, didn't help...
Once upgraded, I had to do NOTHING. Worked like a charm.
🤦‍♂️

@PlebeiusGaragicus
Copy link

Searching for this issue brought me here. Trying to run pm2 on a Debian 11 Linode instance - ran into issues. I had installed node with apt install and it gave me v12.12.something. Uninstalled that and used the snap store instead and I got version v18.15.0 - problem solved. I am very much a beginner and was starting to lose hope.

@virtuallyunknown
Copy link

There is an example above illustrated by @Firsh that uses a ecosystem.config.es6.js file. Unfortunately this doesn't appear to be working as intended. If you issue the pm2 start ecosystem.config.es6.js command, it will treat it as a program rather than a configuration file, which is obviously not what you want.

export default {
    apps: [
        {
            name: 'foo',
            script: 'node foo.js',
        },
        {
            name: 'bar',
            script: 'node bar.js',
        }
    ]
};

console.log("hello");

image

The ~/.pm2/logs/ecosystem.config.es6-out.log file will just contain a bunch of hellos.

@GimpMaster
Copy link

It looks like in 5.3.1 this issue was solved for ecosystem.config.cjs

Here is the commit c810b9f

If that is the case i think you can use ecosystem.config.cjs and type: module in your node project.

We could probably close this issue?

@Veffica
Copy link

Veffica commented Feb 26, 2024

If you are here scratching your head and pulling whatever hairs you have left there... :) Here is one more thing to check, which I've learned in the hard way (2 working days). If you're running pm2 in sudo, make sure to check the node version of your sudo. My "regular" node version was 18.x while my sudo version was 12.x so whatever I did from the above, didn't help... Once upgraded, I had to do NOTHING. Worked like a charm. 🤦‍♂️

This was the solution to my problem!! Thank you Uritz!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests