How to import content from a JSON within an ESM (Ecmascript modules) module in Node.js?

Asked

Viewed 95 times

3

It is common for me to see online courses, articles and tutorials over the internet, Node.js codes that can import local JSON files into code to be manipulated, used, tested, etc... In these examples, they use Commonjs to import JSON, using the require(). Something like (for example):

Folder structure:

|
 \_ test.json
|
 \_ index.js

Content of the JSON:

{
  "foo": "baz"
}

Node.js code:

const json = require('./test.json');

// exibe: { foo: 'baz' }
console.log(json);

The problem is that this methodology does not work when using ESM (Ecmascript modules). The code below will return an error:

For those who don’t know, in recent versions of Node.js you can use ESM by configuring the package json. defining "type": "module".

import json from './test.json';

console.log(json);

Error:

node:internal/process/esm_loader:74
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /home/cmt-cardeal/<path-irrelevante>/test.json
    at new NodeError (node:internal/errors:363:5)
    ....
}

If I try to interoperate Commonjs with ESM, ie use the require within a file defined as ESM, I have another error in the terminal:

file:///home/cmt-cardeal/<path-irrelevante>/index.js:3
const json = require('./test.json');
             ^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/home/cmt-cardeal/<path-irrelevante>/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
...

Explained this, I wanted to know:

  • How to import JSON content into a file defined as ESM unused FS and without having to rename the file to the extension .cjs?

My version of Node.js when preparing this question: v16.0.0

Recalling: Javascript: Differences between import and require

  • LEIA-ME: If you find that this question is duplicated, please feel free to signal, because I found nothing similar. :)

  • DICA: If anyone wants to propose an answer, the tip is to use the createRequire of core module module. I am trying to contribute questions with relevant information to help the community and if no one has an answer, in the future I put my answer. :)

  • I would question that part: "without using FS". Why?

  • @Luizfelipe commented in his reply

1 answer

3


The new Ecmascript Modules (ESM) syntax has been stabilized in recent versions of Node.js to replace Commonjs, non-standard by language specification.

Although the "goal" of ESM and CJS are the same, there are some differences. Among them, one can mention, in the case of this question, the fact that, so far, the syntax of ES Modules does not support the import of JSON.

Therefore, a way (recommended by the documentation itself of Node.js) to import JSON is to use the API of file system. Thus:

import { readFile } from 'fs/promises';
const json = JSON.parse(await readFile('./test.json', 'utf8'));

Another way is to "recreate" the require for use in the context of Ecmascript Modules. However, I would question the use of this alternative.

Recreate the require, using the aforementioned createRequire, seems like a overhead very large for simple file reading and subsequent parse. The require is extremely complex and goes far beyond simple imports of JSON. It is not worth it.

Just to ensure the completeness of this answer, I would give to do so:

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const json = require('./test.json');

But I must reiterate: the createRequire nay should be used for this since it is a overhead extremely large for simple file reading. Ideally the createRequire should be used only in cases where a codebase makes use of both ESM and CJS, being necessary to create a "bridge" to interlink them. Use createRequire to read JSON is, in most cases, absurd.


In the future, when the proposal to import assertions is stabilized, I suppose it will be possible to import JSON with ES Modules. Until then, it is possible to use flag --experimental-json-modules - not stabilised as it is experimental.

  • The idea was just this, to talk about the createRequire to import JSON. O require is really complex, but the idea was to do something a little out of the ordinary that is to use fs since I imagine that there must be several solutions that use it. The question is intended to inform an alternative.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.