Understanding and Developing Node Modules

0
139
5 min read

 

Node Web Development

Node Web Development

A practical introduction to Node, the exciting new server-side JavaScript web development stack

        Read more about this book      

(For more resources on Web Development, see here.)

 

What’s a module?

Modules are the basic building block of constructing Node applications. We have already seen modules in action; every JavaScript file we use in Node is itself a module. It’s time to see what they are and how they work.

The following code to pull in the fs module, gives us access to its functions:

var fs = require('fs');

The require function searches for modules, and loads the module definition into the Node runtime, making its functions available. The fs object (in this case) contains the code (and data) exported by the fs module.

Let’s look at a brief example of this before we start diving into the details. Ponder over this module, simple.js:

var count = 0;
exports.next = function() { return count++; }

This defines an exported function and a local variable. Now let’s use it:

Node Web Development

The object returned from require(‘./simple’) is the same object, exports, we assigned a function to inside simple.js. Each call to s.next calls the function next in simple.js, which returns (and increments) the value of the count variable, explaining why s.next returns progressively bigger numbers.

The rule is that, anything (functions, objects) assigned as a field of exports is exported from the module, and objects inside the module but not assigned to exports are not visible to any code outside the module. This is an example of encapsulation.

Now that we’ve got a taste of modules, let’s take a deeper look.

 

Node modules

Node’s module implementation is strongly inspired by, but not identical to, the CommonJS module specification. The differences between them might only be important if you need to share code between Node and other CommonJS systems. A quick scan of the Modules/1.1.1 spec indicates that the differences are minor, and for our purposes it’s enough to just get on with the task of learning to use Node without dwelling too long on the differences.

 

How does Node resolve require(‘module’)?

In Node, modules are stored in files, one module per file. There are several ways to specify module names, and several ways to organize the deployment of modules in the file system. It’s quite flexible, especially when used with npm, the de-facto standard package manager for Node.

Module identifiers and path names

Generally speaking the module name is a path name, but with the file extension removed. That is, when we write require(‘./simple’), Node knows to add .js to the file name and load in simple.js.

Modules whose file names end in .js are of course expected to be written in JavaScript. Node also supports binary code native libraries as Node modules. In this case the file name extension to use is .node. It’s outside our scope to discuss implementation of a native code Node module, but this gives you enough knowledge to recognize them when you come across them.

Some Node modules are not files in the file system, but are baked into the Node executable. These are the Core modules, the ones documented on nodejs.org. Their original existence is as files in the Node source tree but the build process compiles them into the binary Node executable.

There are three types of module identifiers: relative, absolute, and top-level.

Relative module identifiers begin with “./” or “../” and absolute identifiers begin with “/”. These are identical with POSIX file system semantics with path names being relative to the file being executed.

Absolute module identifiers obviously are relative to the root of the file system. Top-level module identifiers do not begin with “.” , “..”, or “/” and instead are simply the module name. These modules are stored in one of several directories, such as a node_modules directory, or those directories listed in the array require.paths, designated by Node to hold these modules.

Local modules within your application

The universe of all possible modules is split neatly into two kinds, those modules that are part of a specific application, and those modules that aren’t. Hopefully the modules that aren’t part of a specific application were written to serve a generalized purpose. Let’s begin with implementation of modules used within your application.

Typically your application will have a directory structure of module files sitting next to each other in the source control system, and then deployed to servers. These modules will know the relative path to their sibling modules within the application, and should use that knowledge to refer to each other using relative module identifiers.

For example, to help us understand this, let’s look at the structure of an existing Node package, the Express web application framework. It includes several modules structured in a hierarchy that the Express developers found to be useful. You can imagine creating a similar hierarchy for applications reaching a certain level of complexity, subdividing the application into chunks larger than a module but smaller than an application. Unfortunately there isn’t a word to describe this, in Node, so we’re left with a clumsy phrase like “subdivide into chunks larger than a module“. Each subdivided chunk would be implemented as a directory with a few modules in it.

Node Web Development

In this example, the most likely relative module reference is to utils.js. Depending on the source file which wants to use utils.js it would use one of the following require statements:

var utils = require('./lib/utils');
var utils = require('./utils');
var utils = require('../utils');

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here