Modules in Node.js
When programming in Node.js, it’s important to understand the basics of the module system, such as scope, exports, and how that allows you to do some caching.
Scope
Every file (module!) in Node.js is wrapped in the following function [1]:
(function (exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
Therefore, variables are not by default put in the global scope. Things are only exposed when you edit module.exports
.
exports vs. module.exports
In JS, objects and arrays are assigned by reference. module.exports
is simply an object that the require function returns when called with module’s name as its input.
exports
, on the other hand, is a reference to module.exports
, nothing more. Here’s how to not abuse it:
// Don't do this!
// in ./a.js
exports = { name: 'Alex' }
// in index.js
const a = require('./a') // {}
Since exports
is a reference, you can’t overwrite it. module.exports
will not get updated.
// Both of these are fine
// in a.js
module.exports = { name: 'Alex' }
// in a.js
module.exports.name = 'Alex'
Caching
The first time modules are read, they are cached in require.cache
. This is a classic example of memoization.
const filename = 'a.js'
const a = require(`./${filename}`)
a === require
.cache[`${__dirname}/${filename}`]
.exports // true
Summary
- Variables in a file (a module) are constrained to that scope. This is why you see so much top-level variable declaration in Node.
module.exports
is an object that therequire
function returns when it receives the module’s name as an input.exports
is a reference to that object.- Modules are cached the first time they’re read.