NodeJS modules

Require or import modules

In the REPL all node modules are already present so you do not have to explicitly require() them first. But when you write your own files you can must choose between one of two options:

// file.js
const http = require('http');

or use ES6-style, but you have to use .mjs file extension.

// file.mjs
import http from 'http';

Node Modules

There are a number of steps involved whenever you require('something'):

  1. Resolving
  2. Loading
  3. Wrapping
  4. Evaluating
  5. Caching

The difference between require('something') and require('./something') is that the first will search for the module in a folder node_modules starting from the file location and – if not found – goes all the way up to the root. Whereas the second invocation will look up for a file in the current folder.

require('something') looks for files in this order: something.js, something.json and something.node. You can check their corresponding functions with require.extensions.

If you require() a module the underlying file gets loaded. You can use require.resolve() without loading the module, which you might want to do to check if an optional package is installed or not.

If a folder is specified as a module (instead of a file) the package.json‘s "main" property of this folder/package is looked up and the associated file is loaded (or index.js if "main" is not specified).

Node wraps your code in a (hidden) function, that means that you can access this function’s arguments:

// function(exports, module, require, __filename, __dirname) {
console.log(arguments);
module.exports.a = 42;
// }

Now you know that require or exports for example are not a global variables, but instead are passed in by a hidden function. Also any variable defined inside that function is not global.

The hidden function also returns module.exports by default for every file. So when you call

// a.js
const bVar = require('b');

then bVar actually points to module.exports from file b.js.

Be aware that there is a difference between

exports = { hello: 'there' } // will not export the object
// and
module.exports = { hello: 'there' } // will work

In the first case we are simply reassining a variable to an object. In the second case we are changing the reference to a new object, what is what we usually want.

To test if a module is run as script from command line or required:

// myFile.js
const someFunction = () => {
  console.log("I do something");
}

if(require.main === module) {
  // run as script from command line. Read in command line arguments
  print(process.argv[2], process.argv[3]);
} else {
  // being required
  module.exports = someFunction;
}

Now myFile.js can be required or run as a script.

Modules Caching

Modules are cached, which means if you require them twice or more than they will only get required once. You can verify that by checking require.cache. which holds an array of all cached modules. One way to prevent caching might be to just remove the file entry from that array. But a better way is to simply export the functionality of the module as a function:

// myFile.js
module.exports = () => {
  console.log("I was called");
}

Now you can call it twice and it will also console.log twice:

require('myFile.js')();
require('myFile.js')();

About Author

Mathias Bothe Contact me

I am Mathias, born 38 years ago in Heidelberg, Germany. Today I am living in Munich and Stockholm. I am a passionate IT freelancer with more than 14 years experience in programming, especially in developing web based applications for companies that range from small startups to the big players out there. I am founder of bosy.com, creator of the security service platform BosyProtect© and initiator of several other software projects.