Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trick Node.js to load .js files as ES6 modules?

Node.JS 10 added experimental support for loading ES6 modules, which already work in browsers. That would mean that we could finally use exactly the same files for Node.JS and browsers without any transpiling or polyfills.

Except we can't. Node.js requires .mjs extension for files to be loaded as modules. I tried tricking node by using a symlink, but node got around it:

D:\web\lines>node --experimental-modules ES6test.mjs
(node:7464) ExperimentalWarning: The ESM module loader is experimental.
D:\web\lines\ES6test.js:6
import myLibrary from "./MyFile.mjs";
       ^^^^^^^^^^^^^^^

I can't think of any other workaround to make this work - which really renders the whole ES6 module support useless.

Can anybody else think of some trick to make Node.js ignore the extension?

like image 719
Tomáš Zato - Reinstate Monica Avatar asked Jun 13 '18 20:06

Tomáš Zato - Reinstate Monica


2 Answers

You can now import .js file in node v12.x, in 2 steps:

  • Add the following line in your package.json file:
// package.json
{
  "type": "module"
}
  • Add --experimental-modules flag before the script:
node --experimental-modules index.js

Reference: https://nodejs.org/api/esm.html

like image 157
Toan Avatar answered Sep 19 '22 08:09

Toan


Node.js requires all ES modules should have .mjs extension. Since Node.js support of ES modules is experimental, this is subject to change. A proposal and open pull request are expected to address this problem with package.json esm flag and --mode option.

Currently this can be solved with custom ES module loader that hooks into default module resolver and changes module type for some modules:

custom-loader.mjs

import path from 'path';

const ESM_WITH_JS_EXT = './MyFile.js'; // relative to loader path
const ESM_WITH_JS_EXT_URL = new URL(path.dirname(import.meta.url) + `/${ESM_WITH_JS_EXT}`).href;

export function resolve(specifier, parentModuleURL, defaultResolver) {
    const resolvedModule = defaultResolver(specifier, parentModuleURL);

    if (resolvedModule.url === ESM_WITH_JS_EXT_URL)
        resolvedModule.format = 'esm';

    return resolvedModule;
}

It is used as:

node --experimental-modules --loader ./custom-loader.mjs ./index.mjs

Since there are fundamental differences in how ES and CommonJS modules are evaluated, the changes should be limited to modules that need them.

like image 29
Estus Flask Avatar answered Sep 21 '22 08:09

Estus Flask