• Stars
    star
    198
  • Rank 196,898 (Top 4 %)
  • Language
    JavaScript
  • Created over 14 years ago
  • Updated over 13 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Asynchronous URL-based CommonJS module loader for Node with automated dependency resolution and module reloading

Nodules is an asynchronous module loader for Node that provides URL/HTTP-based module ids, module hot-reloading, and package based module mapping. Nodules implements the CommonJS package.json mappings proposal and automatically analyzes modules references and downloads any dependencies on first access prior to executing modules. Remotely downloaded modules are retained so they only need to be downloaded once. Nodules supports standard CommonJS modules, and CommonJS module transport format via require, require.ensure, define, and require.define.

To see Nodules in action right away, go into the "example" directory, and you can start the example "package" with:

node ../lib/nodules.js

The first time you run this, Nodules should automatically download the dependency, and then start the application. You can test the module hot-reloading by making a change to sibling.js while it is running.

The most direct way to load a module with nodules is simply to load the module from the command prompt:

node /path/to/nodules.js http://somesite.com/my-module.js

The require provided by nodules is transitive, so all dependencies of my-module will also be able to utilize full URLs. Nodules asynchronously downloads all the deep dependencies of a module prior to execution so that all requires can execute synchronously even though all modules are fetched asynchronously. The modules are all saved/cached locally so that future require calls (in future program executions) can always run locally.

Naturally, it is easier to start nodules with a script, create a script with using the script from example/nodules as a template, and you can simply do:

nodules module-to-load 

Packages

For any type of real development, it is recommended that you use packages rather than unorganized individual modules. Nodules provides an elegant mechanism for working with packages based on package.json mappings. A package is a directory/file structure for a set of modules, module configuration, and other resources. An example can be found in the nodules's "example" directory. If you run nodules from within a package, it will automatically read the "package.json" from the current working directory for module configuration and id mapping, use the "lib" as one of the default paths for looking modules, and execute the "lib/index.js" file if it exists. The package.json's mappings can contain mappings to URIs so that you don't have to use URIs directly in your require calls in your modules. For example, your package.json could define this mapping to map the foo namespace to the modules from a package archive available from somesite.com:

package.json
{
   "name":"my-project",
   "mappings": {
      "foo": "http://somesite.com/foo.zip"
   }
}

We could then define our index.js file using that mapping:

lib/index.js:
var Something = require("foo/bar").Something; // The module from http://somesite.com/foo/lib/bar.js
Something();

Now we can run our package by simply starting nodules from inside this directory (with package.json):

nodules

Mappings

Nodules supports referening package zip file which is the recommended mechanism for referencing packages: For example:

"mappings": {
   "commonjs-utils": "http://github.com/kriszyp/commonjs-utils/zipball/master"
}

When the target ends with a slash, the mapping will only match module ids in require statements where the mapping is the first term in a path, so this would match something of the form:

require(""commonjs-utils/lazy-array");

You can also map directly to individual modules by specifying the full URL with an extension (and Nodules support the jar: scheme). For example:

"lazy-array": "jar:http://github.com/kriszyp/commonjs-utils/zipball/master!/lib/lazy-array.js"

This will only match the exact module id of require("lazy-array") (not require("lazy-array/...")).

Module Reloading

Another critical aspect of productive development is module reloading so you don't have to constantly restart your VM. To use reloading, you can wrap your reloadable code in a require.reloadable function. This function takes a callback that is called whenever any loaded modules change (including when it is first called). For example:

require.reloadable(function(){
	// Load the app and assign to "app" when started and for each reload
	app = require("./my-app.js");
});
// Don't re-execute http server initiation for each reload, should only load once 
http.createServer(function(request, response){
	app(request, response);
}).listen(80);

Nodules does intelligent dependency tracking so that when a file changes, the appropriate modules are reloaded. All the modules that depend on the modified module are reloaded to ensure correct references, but modules without depedency on the modified module are not reloaded. This enabled optimal reloading performance while ensuring the proper references to objects are flushed for consistent behavior.

Module return values

Nodules also supports modules that return a value or switch the exports. This very useful for situations where it is desirable for a module to provide a single function or constructor. One can create a module that returns a function like this: return function(){ ... };

Or exports = function(){ ... };

Using Nodules Programmatically

You can still use nodules programmatically without having to start Node with nodules as the starting script. You can use Nodules's ensure function to asynchronously load an Nodules's entry module:

require("nodules").ensure("http://somesite.com/foo", function(require){
  require("./foo");
});

Where foo.js could have:

var someModule = require("http://othersite.com/path/to/module");

For "normal" top-level ids, require will default to the system's require implementation, so modules can still do:

var fs = require("fs");

Nodules Local Cache

Nodules downloads any necessary dependencies and stores them locally. By default these files will be downloaded to a directory structure rooted in the current working directory (under "downloaded-modules"). However, the location of the local directory of downloaded packages/modules can be defined with the NODULES_PATH environment variable. It is generally recommended that you define the NODULES_PATH variable (to an absolute path) so that the same set of cached/downloaded packages/modules can be reused from different working directories.

It is perfectly valid and reasonable to edit files from the locally downloaded file set within this path. By default URLs are mapped to the file system by converting each part of the URL to a path, but this makes heavily nested paths. To make it easier to edit and work with your own packages, you can define a paths.json file in the NODULES_PATH directory that defines how URLs are mapped to the local file system. For example, this makes a good paths.json for directing your git projects to your own projects directory:

{
  "(jar:)?http://github.com/my-name/([^\/]+)/zipball/[^\/]+!?" : "/projects/$2"
}

(URLs that don't match will be saved using the default mapping mechanism.)

More package.json Configurations

Engine Specific Overlay

CommonJS packages provides a means for creating engine-specific overlays to define alternate configurations for other engines. For example, one could define an overlay in package.json: { "overlay":{ "node": { "file": "fs" } } }

Compiler

We can also define a compiler to be used on sources prior to execution. This is more efficient than using a global extension matching like registerExtension since it only applies to the package that defines the compiler rather than being global. In your package.json you can define a compiler to use (this is how you would use CoffeeScript):

{
   "compiler": {
         "module": "jar:http://github.com/jashkenas/coffee-script/zipball/master!/lib/coffee-script.js",
         "function": "compile"
   },
   "extension": ".coffee",
   ...
}

The "module" property is required, and the "function" property is optional and defaults to "compile".

Proxy Settings

If your machine is behind a proxy, Nodules will need to go through the proxy for HTTP downloads. Nodules will read the "http_proxy" environmental variable to determine what proxy it needs to route requests through.

Nodules provided top level modules

Nodules provides several top level modules for modules loaded with Nodules, including "promise" (promise library), "system" (based on CommonJS module), "fs-promise" (promise based fs module), and "nodules" (the nodules module itself).

Larger Example

You can download and run the Persevere example wiki application with Nodules to see a more complex use of dependencies.

License

Copyright (c) 2010, The Dojo Foundation All Rights Reserved. Nodules is a sub-project of Persevere (www.persvr.org) and is thus available under either the terms of the modified BSD license or the Academic Free License version 2.1. As a recipient of nodules, you may choose which license to receive this code under.

Dev Progress

Currently alpha level, issues: URI redirection needs to properly change module ids More unit tests

More Repositories

1

json-schema

JSON Schema specifications, reference schemas, and a CommonJS implementation
JavaScript
505
star
2

multi-node

Multi-node provides launching of multiple NodeJS processes for TCP/HTTP serving
JavaScript
491
star
3

node-promise

Promise utilities for Node
JavaScript
399
star
4

lmdb-js

Simple, efficient, ultra-fast, scalable data store wrapper for LMDB
JavaScript
358
star
5

msgpackr

Ultra-fast MessagePack implementation with extension for record and structural cloning / msgpack.org[JavaScript/NodeJS]
JavaScript
339
star
6

put-selector

A high-performance, lightweight function for creating and manipulating DOM elements with succinct, elegant, familiar CSS selector-based syntax
JavaScript
290
star
7

promised-io

Promise-based IO for JavaScript.
JavaScript
237
star
8

cbor-x

Ultra-fast CBOR encoder/decoder with extensions for records and structural cloning
JavaScript
176
star
9

alkali

Alkali is library for functional reactive data flows that drive native-based UI elements
JavaScript
162
star
10

compose

ComposeJS is a lightweight JavaScript library for object composition
JavaScript
127
star
11

xstyle

A declarative, reactive framework that extends CSS
JavaScript
98
star
12

cpm

CommonJS Package Manager
JavaScript
95
star
13

commonjs-utils

Utility modules for CommonJS
JavaScript
89
star
14

transporter

Transporter is JSGI application that serves modules to the browser with dependencies included and packaged in the CommonJS module transport format.
JavaScript
40
star
15

dbind

Data bindings for Dojo
JavaScript
29
star
16

weak-lru-cache

A cache using LRU and weak references to cache data in a way that works in harmony with garbage collection
JavaScript
28
star
17

persevere

The Persevere server features a secure RESTful JSON interface for data interaction and storage of dynamic data, JSONQuery/JSONPath querying, Comet-based real-time data notification through Rest Channels and Bayeux support, class-based based object-oriented business logic with data integrity and validation through JSON Schema in its server-side JavaScript environment.
JavaScript
21
star
18

patr

Promise-based asynchronous test runner for JavaScript
JavaScript
16
star
19

lmdbx-js

Wrapper for libmdbx
C++
15
star
20

ua-optimized

AMD plugin for UA-based optimization of feature-detection-has.js based modules
JavaScript
13
star
21

alkali-todo

TodoMVC written with Alkali
JavaScript
12
star
22

each

Multi-purpose iteration function
JavaScript
9
star
23

eslint-plugin-auto-import

ESLint plugin for automatically importing modules
JavaScript
9
star
24

commonjs-package-template

A template for packages in the Dojo foundation package repository
JavaScript
8
star
25

cpr

CommonJS Package Repository with Git integration
JavaScript
7
star
26

bindr

Bindr is a declarative functional reactive binding language
JavaScript
7
star
27

cobase

Composable data stores from reactive JavaScript Join, Transform, Index, and Reduce functions, built on Alkali & LevelDB
TypeScript
7
star
28

babel-plugin-transform-safely

A Babel plugin for transforming expressions with safe property access and modifications, checking parent existence
JavaScript
7
star
29

litmus

An viewer/editor for exploring Alkali variable data flow/dependencies, and their connection to visual DOM elements on a page
JavaScript
7
star
30

cbor-records

Registration for CBOR tag for records
6
star
31

json-tools

CommonJS tools for interaction with JSON and JSON-style structured data
JavaScript
5
star
32

ordered-binary

Representation of JavaScript primitives as a Buffer such that binary order matches natural order of primitives
JavaScript
5
star
33

caesium

Caesium is a collection of CSS tools, including an AMD CSS loader and builder.
JavaScript
4
star
34

node-commonjs

Modules implementing CommonJS specifications on top of Node
JavaScript
4
star
35

babel-plugin-transform-alkali

Babel plugin to transform reactive expressions using alkali.
JavaScript
3
star
36

splinterdb-js

Initial exploration of JS library for SplinterDB
JavaScript
3
star
37

msgpackr-extract

Node addon for string extraction for msgpackr
C++
3
star
38

jss

JSON Stylesheets
JavaScript
2
star
39

coffeetoes6

A very simple coffeescript to ES6 converter with minimal code modification without extra syntactic requirements (you will need to make fixes afterwards)
JavaScript
2
star
40

window-name

Cross-domain browser communication using the window.name transport
JavaScript
2
star
41

literally-typed

A literate form of TypeScript for embedding type information in documentation
JavaScript
2
star
42

xstyle-todo

TodoMVC on xstyle (and dstore)
JavaScript
2
star
43

cbor-extract

C++
2
star
44

persvr-org

Code/contents of persvr.org
JavaScript
1
star
45

backtrace-c

Print C/C++ level backtraces in NodeJS
1
star
46

mysql-store

A MySQL object store implementation for NodeJS
1
star
47

ddoc

dgrid based documentation
JavaScript
1
star
48

db-benchmark

JavaScript
1
star
49

presly

Why am I using Keynote and Powerpoint when I could use dojo.gfx?
JavaScript
1
star