1

[Node.js v8.10.0]

I'm drastically simplifying this example for clarity. I have 3 scripts: parent.js, first.js, and second.js

parent.js:

'use strict';

const path = require('path');
const {fork} = require('child_process');

const firstScript = path.resolve('first.js');
const first = fork(firstScript);

const secondScript = path.resolve('second.js');
const second = fork(secondScript);

first.on('message', message => {
  console.log('parent received message from first: ' + message);
  second.send(message);
});

second.on('message', message => {
  console.log('parent received message from second: ' + message);
});

first.send('original message');

first.js:

'use strict';

class First {
}

process.on('message', async (message) => {
  console.log('first received message: ' + message);
  process.send(message);
});

module.exports = {First};

second.js:

'use strict';

const {First} = require('./first.js');

process.on('message', message => {
  console.log('second received message: ' + message);
  process.send(message);
});

Expected output:

first received message: original message

parent received message from first: original message

second received message: original message

parent received message from second: original message

Actual output:

first received message: original message

parent received message first: original message

first received message: original message

second received message: original message

parent received message from second: original message

parent received message from second: original message

In this example, the First class is meaningless. But it illustrates the problem I'm trying to avoid. Specifically, the const {First} = require('./first.js'); line in second.js is wreaking havoc on the IPC (as illustrated by the actual output, compared to the expected output).

Currently, I'm "solving" this problem by moving the First class to a separate file. But I'm wondering if it's possible to keep everything in one file (i.e., still make it possible to export the class in first.js -- but not create IPC-related chaos).

user4487338
  • 78
  • 1
  • 6

1 Answers1

0

The thing is, when you require a script, under the hood, the script is ran and the exports are extracted at the end. What you see is totally logic - basically there are four process instead of one when you run $ node parent.js

  1. Parent, created by $ node parent.js
  2. First, created by fork(firstScript)
  3. Second, created by fork(secondScript)
  4. another First, created by require('./first.js')

Tell me if you need me to add an ascii art process tree displaying the message exchanges and the process creation, or if that's okay!

Ah, that makes sense! But... how can I export a file without executing the parts of the script that create IPC hooks?

It is a common design pattern in JavaScript (node or web) to have only mute files except one. That is, all the files are only importing/exporting classes and constants, but there is only one main file that actually trigger the whole program by referencing all the intelligence elsewhere in the source code. Basically this:

// hello.js
module.exports = () => console.log('hello world');
// main.js
const hello = require('./hello');
hello();

It's always best to factor your code as this to simplify your work, but if you can't, you can always prevent some code to be ran depending on whether the script is required or called, as explained here. In your case, rewriting first.js as the following:

'use strict';

class First {
}

// called only if invoked as script
if (require.main==module) {
  process.on('message', async (message) => {
    console.log('first received message: ' + message);
    process.send(message);
  });
}

module.exports = {First};

Gives the expected output you described upon running node parent.js.

Nino Filiu
  • 16,660
  • 11
  • 54
  • 84
  • No, that makes sense (and I'm assuming "another First" inherits the IPC channel from Second, which is why the parent receives 2 messages on that channel). Like I said, I've already separated everything to avoid this issue -- I was just wondering if it was possible to export the class (in node.js) without actually running the entire script (as you mentioned). – user4487338 Feb 27 '19 at 23:07
  • Yes it is! I'll edit my answer so as to have a formatting ease – Nino Filiu Feb 27 '19 at 23:08
  • Done! Any further questions? – Nino Filiu Feb 27 '19 at 23:23