0

When I'm sending a message from parent.js to child.js in commonJs syntax then it works. In parent.js I have

//parent.js
const cp = require('child_process');

let child = cp.fork('./child.js');

child.on('message', (message) =>{
    console.log('Parent got message: '+message);
});

// parent sends a message
child.send('Parent sends message');

in child.js I have:

// child.js
process.on('message', (m) => {
    console.log('child got message:', m);

    process.send('child sends message');
});

everything works and in console I'm getting:

child got message: Parent sends message
Parent got message: child sends message

but it stops working when I use ES6 import syntax:

import * as cp from 'child_process';

Do I'm doing something wrong, or this is a nodejs bug?

My node version is 16.13.2 Under not working I mean cursor in terminal is blinking, but I'm not getting any message and I'm not getting any error.

Arto Avag
  • 97
  • 2
  • 8

1 Answers1

1

The import foo from 'foo' syntax is only supported in ECMAScript Modules. The ECMAScript Modules (or ESM for short) have been supported (without experimental flag) from Node v12 onwards. However, NodeJS has traditionally used CommonJS (CJS) module format (const foo = require('foo');). To support both formats and ensure interoperability between both of them, NodeJS requires you (the developer) to explicitly identify which of the two formats your file is in.

To indicate to NodeJS that your file is in ESM format, you can use one of the following options:

  1. Name your file with .mjs extension instead of .js. By default, NodeJS treats all .js files as CJS modules, only files named .mjs are considered to be ES Modules. The files with import ... in your above example should be named parent.mjs & child.mjs respectively.
  2. Add "type": "module" in your package.json. This will make NodeJS consider all .js files in your project as ES modules. Use this if all (or almost all) files in your project use import ... syntax. If you need to use require('foo'); syntax in any file, it must be named with .cjs extension instead.
  3. Run node process with --input-type=module flag passing the code from STDIN. This option is impractical in most scenarios. Though you could use it by running: node --input-type="module" < parent.js, note that file is not passed as argument here, only its contents are redirected to STDIN of node process.
d_shiv
  • 1,670
  • 10
  • 8
  • thank your for the answer. In my package.json I had already set type: module, but as you have suggested I have changed file extensions from .js to .mjs as well, and run with the given option the parent.mjs file, but this did not helped either, Im still getting nothing in my console without any error. Im just seeing blinking cursor nothing more after running the parent.mjs. my node version is: v16.13.2. – Arto Avag Feb 16 '22 at 11:04
  • 1
    Oh I see. Okay, remove the `type: module` from `package.json`, rename parent to `parent.mjs`, and leave child named as `child.js` ensuring that `child.js` is run as CJS module. And in this setup it will all work out fine. The issue is caused by the way ESM modules are loaded. When the `child.send` call is made from parent, the child.js is still loading, and `process.on` has not been executed yet. The message is just lost, and the sequence never triggers. – d_shiv Feb 16 '22 at 11:28
  • 1
    You can also fix this by leaving `type: module` in package.json, but renaming child to `child.cjs`. OR, by running `child.send` with a few milli-seconds delay in parent. The best approach in my opinion, however, would be to trigger the sequence from child. The parent is definitely running of course, so whenever the child process comes online, it sends a message to parent, and that triggers the sequence. – d_shiv Feb 16 '22 at 11:32
  • just putting the code under setTimeout solved the problem, thank you d_shiv! – Arto Avag Feb 16 '22 at 12:48