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()
andmodule.exports
statements toimport
andexport
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!
Top comments (4)
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 theimport
torequire()
, 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-stylerequire
them, too, if you add the extension) to remind me.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.Good to know! I like it because I don't have to switch headspace anymore when working on frontend and backend code.