Skip to content

Node Modules Explained

Posted on:December 11, 2022 at 11:11 AM

In Node.js world terms module, module system, package, node modules and npm are related concepts and can be confusing. This article explains node modules and how they work by using code examples. Get hands-on experience by creating a node package from scratch.

Node.js modules

Before Node.js JavaScript did not have a widely adopted module system. Node.js introduced CommonJs module system that allowed treating individual files and folders as a separate modules. CommonJs uses module.exports to expose functionality from a module and require to load other modules. Any file or folder that can loaded using require is considered a module.

Example of a hello-world file module:

// hello-world.js
function greet () { return 'Hello World'; }
module.exports = {  greet };

Node.js also supports treating a folder as a module. Example of a hello-world folder module:

// hello-world/index.js
function greet () { return 'Hello World'; }
module.exports = {  greet };

Any module can now load and use the above file or folder hello-world module:

// client.js
const helloWorldFile = require('./hello-world.js');
console.log(helloWorldFile.greet());

const helloWorldFolder = require('./hello-world');
console.log(helloWorldFolder.greet());

// Output:
// Hello World
// Hello World

node_modules folder

In CommonJs if the path provided to require does not start with /, ./ or ../, and path is not a core node module then Node.js attempts to load that path from the node_modules folder. Example of how Node.js tries to load hello-world.js module:

// /home/gru/project/client.js
const helloWorld = require('hello-world.js');

/* Node.js will attempt to find hello-world in following paths */
/home/gru/project/node_modules/hello-world.js
/home/gru/node_modules/hello-world.js
/home/node_modules/hello-world.js
/node_modules/hello-world.js

package

A package in Node.js is a folder containing a package.json file. The package.json file describes the package name, version and other details. Packages can be distributed on public and private registries. A package is not required to contain any JavaScript files. But in most common usage a package will contain JavaScript modules.

npm

npm is a software registry that allow developers to share and borrow Node.js packages. It supports both public and private packages. npm provides the npm CLI to manage packages from command line.

ECMAScript modules

Node.js now also supports the official standard ES Modules for packaging JavaScript code. Note that ES module can import a CommonJs module but not vice versa. Support for ES modules is improving. But large number of node packages still use CommonJs module system and tooling such as WebPack is lacking support for ES modules. This means that when creating ES module node packages you might still need to transpile them to CommonJs so that they can be imported by other CommonJs modules.

Published node package

Figure: A published node package

Hands-on: Creating a hello-world package

To keep things simple we are going to create a monorepo where we can create npm modules without having to use a software registry. For monorepo we are going to use turborepo. Run following command and pick default options:

npx create-turbo@latest --use-npm node-modules-explained

This will create a node-modules-explained folder. Inside packages folder we are going to create a hello-world folder.

cd node-modules-explained
mkdir packages/hello-world
touch packages/hello-world/index.js
touch packages/hello-world/package.json

Edit packages/hello-world/package.json:

{
    "name": "hello-world",
    "version": "0.0.0",
    "private": true
}

Edit packages/hello-world/index.js:

function greet() {
    return 'Hello World!!!';
}

module.exports = { greet };

Our hello-world package is ready for use. We are going to use it in a Next.js app.

Edit apps/web/package.json and add “hello-world”: ”*” to dependencies section.

{
    "dependencies":
    {
        "next": "13.0.0",
        "react": "^18.2.0",
        "react-dom": "^18.2.0",
        "ui": "*",
        "hello-world": "*"
    }
}

Edit apps/web/pages/index.tsx:

import { greet } from "hello-world";

export default function Web() {
    return (
        <div>
            <h1>Web</h1>
            <button onClick={() => window.alert(greet())}>Greet</button>
        </div>
    );
}

Notice that apps/web is a Next.js app that uses ES Modules.

Start the web app:

npm run dev

Open http://localhost:3000. Click on the Greet button to see our hello-world package in action.

hello-world node module in action

Figure: hello-world Node.js package in action