Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS ES6 Modules and "default" export / import

I am trying to use ES6 style modules with NodeJS v13.13 and I am running into conflicting behavior.

Originally my project was transpiled with node-babel, but then I enabled the builtin ES6 module support by adding "type": "module" to my package.json file.

At this point, import statements such as import * as esprima from 'esprima'; stopped working correctly. Upon examination, rather than the import creating the function esprima.parse, it was creating a function esprima.default.parse.

Of course this was all fixable by using something like:

import * as esprimaLoad from 'esprima';
const esprima = esprimaLoad.default;

However, what behavior is correct per the spec? Is babel right to strip out / collapse the default object, and is there a bug in the current node.js behavior which is still labeled as experimental? All of this ES Module vs CommonJS module stuff gives me a headache.

Update:

I still haven't gotten to the bottom of this, but there is more involved. esprima.js, one of the libraries where this was an issue, appears to have been created using webpack and is a UMD (universal module definition) format. It starts with the following:

(function webpackUniversalModuleDefinition(root, factory) {
/* istanbul ignore next */
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if(typeof define === 'function' && define.amd)
        define([], factory);
/* istanbul ignore next */
    else if(typeof exports === 'object')
        exports["esprima"] = factory();
    else
        root["esprima"] = factory();
})(this, function() { ...

I think the webpack UMD format is already meant to work with both import statements in the browser and require statements in node.js. However, when using the experimental modules / babel in node.js it seems like the following does not work at all:

import esprima from 'esprima'

and the following works with babel but not the experimental modules:

import * as esprima from 'esprima'

and the following works with both babel and the experimental modules:

import * as esprimaLoad from 'esprima'
const esprima = esprimaLoad.default?esprimaLoad.default:esprimaLoad;

For modules that don't use this webpack UMD trickery, both the babel and the experimental modules seems to work just fine.

like image 223
bruceceng Avatar asked Apr 15 '20 16:04

bruceceng


Video Answer


1 Answers

If you are exporting default then you don't need to import it in that roundabout fashion.

The simplest version directly imports the default:

import myDefault from '/modules/my-module.js';

It is also possible to use the default syntax with the ones seen above (namespace imports or named imports). In such cases, the default import will have to be declared first. For instance:

import myDefault, * as myModule from '/modules/my-module.js';
// myModule used as a namespace

You can check out more from MDN

So in your case

import esprima from 'esprima';

This should be simplest import statement.

like image 78
Aritra Chakraborty Avatar answered Oct 17 '22 10:10

Aritra Chakraborty