node child_process not firing message event - node.js

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.

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

Related

Top-level await doesn't work in the latest Node.js

Is top-level await still not supported in Node.js (Jan 2020, Node.js 13.5.0)?
I've tried some tutorials, like this one, but still no luck, always getting the same error:
D:\NodeJS>node --experimental-modules test.js
(node:17724) ExperimentalWarning: The ESM module loader is experimental.
file:///D:/NodeJS/test.js:9
await test();
^^^^^
SyntaxError: Unexpected reserved word
The entire file content:
function test() {
}
await test();
I have tried using "type": "module" in package.json, and renaming file into test.mjs, but still the same error, even with the latest Node.js 13.5.0
What am I doing wrong?
Per this issue tracker and this blog post, top-level await is available in Node v13.3+ behind the flag --harmony-top-level-await. The module flag you're enabling is only for ESM modules and not for top level await.
node --experimental-repl-await
works for the Node REPL
edit: the Node 16 REPL accepts top level await by default, you don't need the experimental flag anymore
I dont know why, but to get the --harmony features like you need to use --eval (-e) or --print (-p) instead of just launching node like
node -e "import('./test.mjs')" --experimental-modules --input-type=module --harmony-top-level-await
file-content:
console.log(await Promise.resolve("test"));
console:
node -e "import('./test.mjs')" --experimental-modules --input-type=module --harmony-top-level-await
(node:9096) ExperimentalWarning: The ESM module loader is experimental.
test
When using node -e:
Note that while top-level await is unflagged in node 14.8.0, when doing node -e (node --eval), the input type defaults to CJS, and top-level await is allowed only in ESM mode.
To tell that the input is ESM, you need a flag:
node --input-type=module -e 'console.log(await Promise.resolve(42))'
> 42
As an alternative, you could wrap your top level code into function mark it as async but don't wait for it's result. And only wait for the result of async action you need to wait.
That way you will have no warning, not work in 100% of situations, because top level code can be in multiple files etc. But for the majority hope could help, w/o need to change node flags, as it's not always easy (for example when you don't run any node commands yourself and need to extract some node/webpack configs)
setupApp()
async function setupApp () {
await action1()
action2()
}

Is there a way to import from this node module with 'import' instead of 'require'?

I'm using this node module 'deep-equal' () and so far the only way I've been able to access the function in it is with var equal = require('deep-equal');, as suggested in the documentation. I usually use import instead of require, and am wondering if it's possible to use import with this module. The main function is exported from the file in this line:
var deepEqual = module.exports = function (actual, expected, opts) {...}
Is it possible to import this function with import, or is it only possible with require?
Thanks!
Yes you actually can.
If you're using nodejs LTS then you'll have to use .mjs extension for the file where you're using import and pass experimental-modules flag while running node process.
// foo.mjs
import equal from 'deep-equal';
node --experimental-modules foo.mjs
As of nodejs 12.3.0 you can simply pass the experimental-modules. From docs
Once enabled, Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code
Also you can specify type as module in your package.json:
// package.json
{
"type": "module"
}
From docs
Files ending with .js or .mjs, or lacking any extension, will be loaded as ES modules when the nearest parent package.json file contains a top-level field "type" with a value of "module"

Importing a zip file and getting individual files in it, using Webpack

I have a standard webpack environment set up, and I am using ES6 imports with npm packages (the usual import name from 'package'). I'm using webpack-dev-server as my dev environment, and the standard webpack build for building the output directory.
I have a zip file in my source containing a large number of XML files, and in my JS program, I want to be able to read that zip file in and be able to extract individual files from it, so I can get the text from those files and process the XML in them.
I am currently using the xmldoc package for transforming XML text to a JSON object for processing, but I have not been able to find a reliable package for reading in a zip file (using the path to the file) and being able to get the individual files in it. In the ones I have tried, I have run into trouble with node's fs module. If I try adding the target: 'node' property to my webpack config file, I receive an error stating require is not defined.
Is there a reliable npm package compatible with ES6 imports that can read a zip file into my program? I realize that means the zip must be included in the build files to be sent to the browser, but that is better than including the hundreds of individual files without zipping them. Thanks!
I think you want browserfs. Here is example code from the readme. You will also need to do some config for webpack (check the readme):
fetch('mydata.zip').then(function(response) {
return response.arrayBuffer();
}).then(function(zipData) {
var Buffer = BrowserFS.BFSRequire('buffer').Buffer;
BrowserFS.configure({
fs: "MountableFileSystem",
options: {
"/zip": {
fs: "ZipFS",
options: {
// Wrap as Buffer object.
zipData: Buffer.from(zipData)
}
},
"/tmp": { fs: "InMemory" },
"/home": { fs: "IndexedDB" }
}
}, function(e) {
if (e) {
// An error occurred.
throw e;
}
// Otherwise, BrowserFS is ready to use!
});
});

how to use node module with es6 import syntax in typescript

I have a typescript project which has uses one of our node modules which normally runs in our front-end. We are now looking to use this module in node on our server.
The module uses es6 import syntax import { props } from 'module/file'
When I include a ref in typescript using either of the following methods
import { props } from 'module/file';
var props = require('module/file');
I get the following error from typescript
unexpected token 'import'
(function (exports, require, module, __filename, __dirname) { import
It's a big job to re-write the module, and I've tried using babel with babel-plugin-dynamic-import-node, as well as SystemJS.
The problem with these systems is that they are all asynchronous, so I can't import the module in the standard fashion, so I would need to do a whole bunch of re-write when we get to the point that I can use import natively in node.js.
I can't be the first person to have this issue, but I can't seem to find a working solution.
--------------- update with set-up -------------
In response to #DanielKhoroshko's response. The original module I am trying to import is normally packaged by webpack in order to use on the front-end. I am now trying to use this same module both server-side and in the front-end (via webpack on the front-end) without re-writing the imports to use require and without running webpack to bundle the js to use on the server.
To be clear, the original module is written in JS, our service which is trying to use this module is written in typescript and transpiled. When the typescript tries to require the old module which uses import, it is at this point that we are running into the issue.
------------------ some progress ---------------------------
I've made some progress by creating a file in my imported module which uses babel in node.js to transpile the es6 code into commonJS modules.
I've done this via
var babel = require("babel-core")
var store = babel.transformFileSync(__dirname + '/store.js', {
plugins: ["transform-es2015-modules-commonjs"]
});
module.exports = {
store: store.code
}
I can now get the store in my new node.js project. However, the submodules within the store.js file are not included in the export.
So where in my module, it says
import activities from './reducers/activities';
I now get an error
Cannot find module './reducers/activities'
How can I get babel to do a deep traversal to include the sub-directories?
unexpected token 'import' means you are running es-modules code in environment that doesn't support import/export commands. If you are writing you code in TypeScript it's important to transpile it first before building for the browser or use ts-node to run it server-side.
If you are using webpack there are loaders ts-loader and awesome-typescript-loader
What is your setup?
To describe the module you would need to create an activities.d.ts file in the same folder where the js-version (I understood it is called activities.js and containers a reducer) resides with the following (approx.):
import { Reducer } from 'redux';
export const activities: Reducer<any>;
#Daniel Khoroshko was right in many ways, I ended up finding #std/esm which lets you import es6 modules and worked find for fetching the included imports as well.
var babel = require('babel-register')({
presets: ["env"]
});
require = require('#std/esm')(module);
var store = require('ayvri-viewer/src/store');
exports.default = {
store: store
}
I had to run babel to get a consistent build from es6 to node compatible es5

Node 'resolve' with file watching and reloading

Let's assume the module I am requiring has no dependencies. For example, a json file, or a webpack compiled file.
Is there a built in method (or an npm package) that allows you to resolve live instances of files in node?
For example:
foo.js
module.exports = function() {
return 'test!';
}
implementation.js
var liveFoo = require("live-monitor")("foo");
console.log(liveFoo.instance()); // this will auto update when saving foo.js.
I'd imagine this hypothetical node module live-monitor would internally use fs.watch to update the instance export as the file foo.js is changed.
So, anything built in to node? Any package out there that does this already?

Resources