Reusing require.js modules in Node.js

Using the same code in the browser and in the server is something that every developer dream of. The solution of that problem is known as the Holy Grail of javascript and there are different approaches to trying to get it. Probably we will be much closer to find the Grail when ECMAScript 6 modules are supported by every browser, but until that day, people try to find their ways to reuse as much as possible.

A lot of developers are using the awesome tool Browserify nowadays to make node modules work in the browser. Browserify is great, and I think that the way of requiring modules in a Node way is much cleaner than the one used in the browser by AMD modules. But it needs to 'compile' the node source code to a browser version in order to be used in the client side, so actually it is not the same code that runs in the server.

Currently it is not possible to require scripts in a CommonJS style (node style) in the browser

var module = require('mymodule.js');

because the script execution can't be halted until the module is ready to use it. That is why Browserify needs to transform the code to be used by the client.

On the other hand, browser javascript modules are defined using the AMD notation (for example, the ones used by require.js) and Node.js would be perfectly able to load the modules with a defined in that way.

require('mymodule.js', function(module){
//use your module here
});

 Introducing AMDrequire

AMDrequire is a npm package that makes Node.js able to load AMD modules like if they were native Node modules. Let's say we have the following require.js module in mymodule.js
define([],function(){
  return 10;
});
Using AMDrequire it is possible to load it in your Node.js the way it would be loaded in the browser:
require(['./mymodule.js'], function(ten){
  console.log(ten + 10); //Outputs 20 in the Node.js console.
});
That means that all the modules written for require.js are suddenly available for their use in Node.js. Isn't it great? And the best part of it that there is no need to modify one line of code, the same exact code is being reused by the client and the server.

And what is even better, you can still use Node.js modules as usual, requiring them in a synchronous way.

Notice that AMD modules are loaded using require.js notation, with an array as the first parameter (named define are not supported yet), and Node modules are loaded using standard Node.js notation, with the path or name string as the first parameter.

var module = require('mymodule.js');

How can I use AMDrequire?

AMDrequire is available as NPM package, so, to use it, the first thing to do is add it to your project
npm install amdrequire
Then, make it the first require in your application's entry file
require = require('amdrequire');
Once this is done, it is possible to load AMD modules in any of the application files. Also it is possible to create modules with the define method to be used in the server and the client.

Configuring AMDrequire

To make the configuration easier, AMDrequire can directly receive require.js configuration object to use the same named requires than the client.
require = require('amdrequire');
require.config({
    paths: {
        'world': 'somedir/world'
    }
    basePath: __dirname + '/public/assets/js',
    publicPath: __dirname + '/public'
});
As it is seen in the example, the config method accepts almost the same parameters of require.js one. That method is only available in the require object returned when amdrequire is loaded. There are two different parameters :
  • basePath:  It is equivalent to require.js baseUrl option, so it should point to the local path of that URL. All the relative paths used in AMD's require and define calls, that don't start with ./ or ../ will be relative to this directory. In the example, the world module should be in __dirname + '/public/assets/js/somedir/world.js' .
  • publicPath: Defines the path of the root URL directory. In the browser it is possible to require modules using root routes, they start with a slash /like/route/from/the/root and they are relative to the domain URL. publicPath  tells what is the equivalent to that /  route to AMDrequire, so it can handle that kind of requires.

 Want to collaborate?

AMDrequire is a young module, so any help in its development would be great. In the AMDrequire git page it is possible to find deeper documentation and some suggestions on what to improve, and of course, any comment is really welcome.
© arqex 2023
Someday,
we'll find ourselves
far, far away...
Transitions here have been created using a library of mine:
React interactable.
This awesome hyperspace effect thanks to this codepen from Noah Blon.
Software development can be fun!
Javier Márquez
Software developer