loading...
Cover image for Import Local JSON In Node.js v8.5 Experimental Modules

Import Local JSON In Node.js v8.5 Experimental Modules

geoff profile image Geoff Davis ・2 min read

In case you missed it, Node.js v8.5.0 was released on September 12, bringing a host of new features and fixes.

Among these features, and one I'm quite excited about, is (experimental) support for ES2015+ modules in Node. In order to use "ESModules", one must:

  • Convert all Node files to use the .mjs extension
  • Change all require() and module.exports statements to import and export statements, respectively
  • Run any Node files/applications using these modules under the --experimental-modules flag

This article by Dr. Axel Rauschmayer has more details on the new system, as well as some examples and potential issues to watch for.

That's all good, but what if you're importing local data or information from a package.json file? That won't work if you're using the import statement, since the import does not parse files the same as the require function, and JSON files do not use the necessary .mjs file extension.

You could move all your JSON files over to Javascript object syntax inside .mjs files, or you could use a snippet I wrote to use the fs module to import the data. In this case, you do not need to make any updates to the JSON files that already use require(), as the require function in the snippet has the same result as the Node function.

Here is a sample application before using standard CommonJS modules:

// package.json
{
  // ...
  "version": "1.0.0",
  // ...
}

// logVersion.js
const logVersion = (version) => console.log(`Hello World v${version}`);
module.exports = { logVersion }

// index.js
const { version } = require('./package.json');
const logVersion = require('./logVersion.js');

logVersion(version); // -> Hello World v1.0.0

…And the same application using the Experimental Modules and my require() snippet:

// package.json
{
  // ...
  "version": "1.0.0",
  // ...
}

// logVersion.js
const logVersion = (version) => console.log(`Hello World v${version}`);
export default logVersion

// index.js
import fs from 'fs';
import logVersion from './logVersion';

const require = (filepath, encoding = "utf8") =>
    JSON.parse(fs.readFileSync(filepath, { encoding }));

const { version } = require('./package.json');

logVersion(version); // -> Hello World v1.0.0

Eventually, I would like to create a module, but have run into some issues with resolving paths in modules; if you would like to help debug and/or develop this functionality, feel free to file a pull request or an issue.

My snippet on Github can be found here: geoffdavis92/require.mjs.

Enjoy!

Posted on by:

geoff profile

Geoff Davis

@geoff

Senior UI Developer @ ALSAC/St. Jude // All opinions, articles, and comments convey my views alone.

Discussion

markdown guide
 

I just brought in Babel to let me use this in every file except the first one. I was a bit surprised when import appConfig from './appconfig.json' worked, but then I realized Babel was changing the import to require(), which works as per usual. I'd read the "new in 8.5.0" post, but being relatively inexperienced with JS, I'd missed that part (or, at least, the implications of that lone bullet point).

I appreciate the snippet; I now know what my next commit will include. :) Thanks for the write-up!

 

Glad I could help! I was migrating one of my Node projects over to this new mjs style, and noticed that this could be a problem if people relied on data stored in their package.json or some other JSON file.

 

I'm guessing the new mjs thing is an all-or-nothing thing? I tried just adding the --experimental-modules flag on my existing app, and it didn't like it. However, I've finally had success getting my Vue front-end to send the data to the API, it process it, and return something that makes sense. (woo hoo!)

I'll defer playing with modules for a bit, though I do have an .mjs file there (you can old-style require them, too, if you add the extension) to remind me.

I'm guessing the new mjs thing is an all-or-nothing thing?

I believe that is the case. To be honest I do not know much about how Node works behind-the-scenes, but it appears that switching between --experimental-modules and CommonJS modules would be like using straight ES201* code or sending it through Babel.

... I do have an .mjs file there (you can old-style require them, too, if you add the extension) ...

Good to know! I like it because I don't have to switch headspace anymore when working on frontend and backend code.