I regularly work with a Node project at work where functionality in a certain file is imported in other files using the require
keyword, and exported to be used in other files using the module.exports
keyword. More recently, I started working on a side project using create-react-app, where files are imported using the import
keyword and exported using the export
keyword. Although both projects use the same programming language, I never questioned this difference until now.
What is a module?
To make code more DRY, we're often told to extract code that is used in many places to a separate function that is imported in all the files that need it. For example, a date parsing function that is used application-wide. In JavaScript speak, this function would be called a module. A module, however, isn't always necessarily a function, but can also be a number of related functions, a class or even a single variable.
Node's solution
Node's module management system is called CommonJS, and it uses the aforementioned require
keyword. For example, here's a very simple function that checks token validity on a fetch request. The last line allows us to export this module to be used in other places:
// utils/isTokenValid.js
const isTokenValid = (err) => {
if (err.status === 401) return false;
return true;
};
module.exports = isTokenValid;
And this is how we'd use it in another file:
// index.js
const isTokenValid = require('../utils/isTokenValid');
const response = await fetch('/');
if (!isTokenValid(response))
throw new Error('Authentication error');
And then came ES6
With this revision of the language, a native module management system was introduced. Now, we can rewrite the above example in this way:
// utils/isTokenValid.js
const isTokenValid = (err) => {
if (err.status === 401) return false;
return true;
};
export default isTokenValid;
// index.js
import isTokenValid from '../utils/isTokenValid';
const response = await fetch('/');
if (!isTokenValid(response))
throw new Error('Authentication error');
This example uses a default export for isTokenValid
. Alternatively, it can be rewritten as export { isTokenValid }
then imported in index.js
as import { isTokenValid } from '../utils/isTokenValid'
.
Using import/export
in Node
Now does that mean we have to remember where to use each of these two syntaxes if we're building a full stack JavaScript application? Thankfully, Node is already on it and has started to offer support to ES6 import/export syntax. At the moment, the support is experimental and unstable and therefore not recommended to be used in production. Using it is not straightforward either, as you have to change each file from a .js
to a .mjs
along with changes in your package.json
.
The other way to get started using import/export in your Node app is to install Babel which can take care of transpiling all your ES6 code to ES5. Personally, I opted to keep using CommonJS syntax in my backend and ES6 syntax in my frontend, now that I understand the difference between them.
Thanks for reading. Until next time 👋
Cover photo by Danny Lines on Unsplash
Top comments (0)