How to import JSON files in ES modules (Node.js) without using assert
A while ago, Node moved from the require statement to an import statement when they adopted ES modules and renamed their prior modules as common JavaScript (cjs). They call the new method modular JavaScript (mjs).
So if you are like me, you find some Node modules that only work with ES and are forced to start writing your code using ES.
What that means is that you go from:
var fs = require('fs');
To:
import fs from 'fs';
And in some cases, you have to write it like this:
import * as fs from 'fs';
That seems pretty straightforward.
And then you run into a require statement that looks like this:
const pkgObj = require('./package.json')
If you change that as we have with the prior statements, you will get an error from Node about needing to add an assertion.
If you do some searching, you will find that the recommendation for that code is:
import * as pkgObj from './package.json' assert { type: "json" }
I have two issues with this.
- This uses an experimental feature of Node as of January 2023. And Node displays a warning when your code is executed if you are writing a Console application. And as an experimental feature, the way it works could change.
- The object structure that is returned is different than what it was before. I used to be able to get the version from my package.json with pkgObj.version. Now we have to use pkgObj.default.version.
There is a workaround for this: if you need to use anything that still uses a require statement, you can put it in a file that ends with .cjs.
My original statement is in my index.js file, so I will need to create a new one. I’ll name it pkgObj.cjs.
module.exports = pkgObj = require('./package.json')
Now that I have that, I can use this line in my index.js file:
import pkgObj from './pkgObj.cjs'
I’m using the ./ only to illustrate that the files can be located wherever you put them, and you must ensure you include the .cjs in the file reference.
Once assert is no longer an experimental feature, that will be the preferred way to use it. I hope they resolve the need for using pkgObj.default before it does.
For now, use a .cjs file.