Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 242 lines (166 sloc) 13.073 kb
2a420a7 @tj No longer gitignoring html
tj authored
1 <div class='mp'>
2 <h1>CommonJS Module System</h1>
3 <p><a href="http://commonjs.org">CommonJS</a> is a community driven effort to standardize packaging of JavaScript libraries, known as <em>modules</em>. Modules written which comply to this standard provide portability between other compliant frameworks such as narwhal, and in some cases even browsers.</p>
4
5 <p>Although this is ideal, in practice modules are often not portable due to relying on apis that are currently only provided by, or are tailored to node specifically. As the framework matures, and additional standards emerge our modules will become more portable.</p>
6
7 <h2 id="Creating-Modules">Creating Modules</h2>
8
fa384c9 @tj Regenerated book
tj authored
9 <p>Let's create a utility module named <em>utils</em>, which will contain a <code>merge()</code> function to copy the properties of one object to another. Typically in a browser, or environment without CommonJS module support, this may look similar to below, where <code>utils</code> is a global variable.</p>
2a420a7 @tj No longer gitignoring html
tj authored
10
11 <pre><code>var utils = {};
12 utils.merge = function(obj, other) {};
13 </code></pre>
14
15 <p>Although namespacing can lower the chance of collisions, it can still become an issue, and when further namespacing is applied it can look flat-out silly. CommonJS modules aid in removing this issue by "wrapping" the contents of a JavaScript file with a closure similar to what is shown below, however more pseudo globals are available to the module in addition to <code>exports</code>, <code>require</code>, and <code>module</code>. The <code>exports</code> object is then returned when a user invokes <code>require('utils')</code>.</p>
16
17 <pre><code>var module = { exports: {}};
18 (function(module, exports){
19 function merge(){};
20 exports.merge = merge;
21 })(module, module.exports);
22 </code></pre>
23
24 <p>First create the file <em>./utils.js</em>, and define the <code>merge()</code> function as seen below. The implied anonymous wrapper function shown above allows us to seemingly define globals, however these are not accessible until exported.</p>
25
26 <pre><code> function merge(obj, other) {
27 var keys = Object.keys(other);
28 for (var i = 0, len = keys.length; i &lt; len; ++i) {
29 var key = keys[i];
30 obj[key] = other[key];
31 }
32 return obj;
33 };
34
35 exports.merge = merge;
36 </code></pre>
37
38 <p>The typical pattern for public properties is to simply define them
39 on the <code>exports</code> object like so:</p>
40
41 <pre><code>exports.merge = function(obj, other) {
42 var keys = Object.keys(other);
43 for (var i = 0, len = keys.length; i &lt; len; ++i) {
44 var key = keys[i];
45 obj[key] = other[key];
46 }
47 return obj;
48 };
49 </code></pre>
50
51 <p>Next we will look at utilizing out new module in other libraries.</p>
52
53 <h2 id="Requiring-Modules">Requiring Modules</h2>
54
55 <p>There are four main ways to require a module in node, first is the <em>synchronous</em> method, which simply returns the module's exports, second is the <em>asynchronous</em> method which accepts a callback, third is the <em>asynchronous http</em> method which can load remote modules, and lastly is requiring of shared libraries or "node addons" which we will cover later.</p>
56
57 <p>To get started create a second file named <em>./app.js</em> with the code shown below. The first line <code>require('./utils')</code> fetches the contents of <em>./utils.js</em> and returns the <code>exports</code> of which we later utilize our <code>merge()</code> method and display the results of our merged object using <code>console.dir()</code>.</p>
58
59 <pre><code>var utils = require('./utils');
60
61 var a = { one: 1 };
62 var b = { two: 2 };
63 utils.merge(a, b);
64 console.dir(a);
65 </code></pre>
66
67 <p>Core modules such as the <em>sys</em> which are bundled with node can be required without a path, such as <code>require('sys')</code>, however 3rd-party modules will iterate the <code>require.paths</code> array in search of a module matching the given path. By default <code>require.paths</code> includes <em>~/.node_libraries</em>, so if <em>~/.node_libraries</em>/utils.js_ exists we may simply <code>require('utils')</code>, instead of our relative example <code>require('./utils')</code> shown above.</p>
68
69 <p>Node also supports the concept of <em>index</em> JavaScript files. To illustrate this example lets create a <em>math</em> module that will provide the <code>math.add()</code>, and <code>math.sub()</code> methods. For organizational purposes we will keep each method in their respective <em>./math/add.js</em> and <em>./math/sub.js</em> files. So where does <em>index.js</em> come into play? we can populate <em>./math/index.js</em> with the code shown below, which is used when <code>require('./math')</code> is invoked, which is conceptually identical to invoking <code>require('./math/index')</code>.</p>
70
71 <pre><code>module.exports = {
72 add: require('./add'),
73 sub: require('./sub')
74 };
75 </code></pre>
76
77 <p>The contents of <em>./math/add.js</em> show us a new technique, here we use <code>module.exports</code> instead of <code>exports</code>. Previously mentioned was the fact that <code>exports</code> is not the only object exposed to the module file when evaluated, we also have access to <code>__dirname</code>, <code>__filename</code>, and <code>module</code> which represents the current module. Here we simply define the module export object to a new object, which happens to be a function.</p>
78
79 <pre><code>module.exports = function add(a, b){
80 return a + b;
81 };
82 </code></pre>
83
84 <p>This technique is usually only helpful when your module has one aspect that it wishes to expose, be it a single function, constructor, string, etc. Below is an example of how we could provide the <code>Animal</code> constructor:</p>
85
86 <pre><code>exports.Animal = function Animal(){};
87 </code></pre>
88
89 <p>which can then be utilized as shown:</p>
90
91 <pre><code>var Animal = require('./animal').Animal;
92 </code></pre>
93
94 <p>if we change our module slightly, we can remove <code>.Animal</code>:</p>
95
96 <pre><code>module.exports = function Animal(){};
97 </code></pre>
98
99 <p>which can now be used without the property:</p>
100
101 <pre><code>var Animal = require('./animal');
102 </code></pre>
103
104 <h2 id="Require-Paths">Require Paths</h2>
105
106 <p>We talked about <code>require.paths</code>, the <code>Array</code> utilized by node's module system in order to discover modules. By default node checks the following directories for modules:</p>
107
108 <ul>
109 <li><code>&lt;node binary></code>/../../lib/node</li>
110 <li><strong>$HOME</strong>/.node_libraries</li>
111 <li><strong>$NODE_PATH</strong></li>
112 </ul>
113
114
115 <p>The <strong>NODE_PATH</strong> environment variable is much like <strong>PATH</strong>, as it allows several paths delimited by the colon (<code>:</code>) character.</p>
116
117 <h3 id="Runtime-Manipulation">Runtime Manipulation</h3>
118
119 <p>Since <code>require.paths</code> is just an array, we can manipulate it at runtime in order to expose libraries. In our previous example we defined the libraries <em>./math/{add,sub}.js</em>, in which we would typically <code>require('./math')</code> or <code>require('./math/add')</code> etc. Another approach is to prepend or "unshift" a directory onto <code>require.paths</code> as shown below, after which we can simply <code>require('add')</code> since node will iterate the paths in order to try and locate the module.</p>
120
121 <pre><code>require.paths.unshift(__dirname + '/math');
122
123 var add = require('add'),
124 sub = require('sub');
125
126 console.log(add(1,2));
127 console.log(sub(1,2));
128 </code></pre>
129
130 <h2 id="Pseudo-Globals">Pseudo Globals</h2>
131
132 <p>As mentioned above, modules have several pseudo globals available to them, these are as follows:</p>
133
134 <ul>
135 <li><code>require</code> the require function itself</li>
136 <li><code>module</code> the current <code>Module</code> instance</li>
137 <li><code>exports</code> the current module's exported properties</li>
138 <li><code>__filename</code> absolute path to the current module's file</li>
139 <li><code>__dirname</code> absolute path to the current module's directory</li>
140 </ul>
141
142
143 <h3 id="require-">require()</h3>
144
145 <p>Although not obvious at first glance, the <code>require()</code> function is actually
146 re-defined for the current module, and calls an internal function <code>loadModule</code> with a reference to the current <code>Module</code> to resolve relative paths and to populate <code>module.parent</code>.</p>
147
148 <h3 id="module">module</h3>
149
150 <p>When we <code>require()</code> a module, typically we only deal with the module's <code>exports</code>, however the <code>module</code> variable references the current module's <code>Module</code> instance. This is why the following is valid, as we may re-assign the module's <code>exports</code> to any object, even something trivial like a string:</p>
151
152 <pre><code>// css.js
153 module.exports = 'body { background: blue; }';
154 </code></pre>
155
156 <p>To obtain this string we would simply <code>require('./css')</code>. The <code>module</code> object also contains these useful properties:</p>
157
158 <ul>
159 <li><code>id</code> the module's id, consisting of a path. Ex: <code>./app</code></li>
160 <li><code>parent</code> the parent <code>Module</code> (which required this one) or <code>undefined</code></li>
161 <li><code>filename</code> absolute path to the module</li>
162 <li><code>moduleCache</code> an object containing references to all cached modules</li>
163 </ul>
164
165
166 <h2 id="Asynchronous-Require">Asynchronous Require</h2>
167
168 <p>Node provides us with an asynchronous version of <code>require()</code>, aptly named <code>require.async()</code>. Below is the sample example previously shown for our <em>utils</em> module, however non blocking. <code>require.async()</code> accepts a callback of which the first parameter <code>err</code> is <code>null</code> or an instanceof <code>Error</code>, and then the module exports. Passing the error (if there is one) as the first argument is an extremely common idiom in node for async routines.</p>
169
170 <pre><code>require.async('./utils', function(err, utils){
171 console.dir(utils.merge({ foo: 'bar' }, { bar: 'baz' }));
172 });
173 </code></pre>
174
175 <h2 id="Requiring-Over-HTTP">Requiring Over HTTP</h2>
176
177 <p>Asynchronous requires in node also have the added bonus of allowing module loading via <strong>HTTP</strong> and <strong>HTTPS</strong>.
178 To require a module via http all we have to do is pass a valid url as shown in the <em>sass</em> to <em>css</em> compilation example below:</p>
179
180 <pre><code>var sassUrl = 'http://github.com/visionmedia/sass.js/raw/master/lib/sass.js',
181 sassStr = ''
182 + 'body\n'
183 + ' a\n'
184 + ' :color #eee';
185
186 require.async(sassUrl, function(err, sass){
187 var str = sass.render(sassStr);
188 console.log(str);
189 });
190 </code></pre>
191
192 <p>Outputs:</p>
193
194 <pre><code>body a {
195 color: #eee;}
196 </code></pre>
197
198 <h2 id="Registering-Module-Compilers">Registering Module Compilers</h2>
199
fa384c9 @tj Regenerated book
tj authored
200 <p>Another cool feature that node provides us is the ability to register compilers for a specific file extension. A good example of this is the CoffeeScript language, which is a ruby/python inspired language compiling to vanilla JavaScript. By using <code>require.registerExtension()</code> we can have node compile CoffeeScript to JavaScript in an automated fashion.</p>
2a420a7 @tj No longer gitignoring html
tj authored
201
fa384c9 @tj Regenerated book
tj authored
202 <p>To illustrate its usage, let's create a small (and useless) Extended JavaScript language, or "ejs" for our example which will live at <em>./compiler/example.ejs</em>, its syntax will look like this:</p>
2a420a7 @tj No longer gitignoring html
tj authored
203
204 <pre><code>::min(a, b) a &lt; b ? a : b
205 ::max(a, b) a &gt; b ? a : b
206 </code></pre>
207
208 <p>which will be compiled to:</p>
209
210 <pre><code>exports.min = function min(a, b) { return a &lt; b ? a : b }
211 exports.max = function max(a, b) { return a &gt; b ? a : b }
212 </code></pre>
213
fa384c9 @tj Regenerated book
tj authored
214 <p>First let's create the module that will actually be doing the ejs to JavaScript compilation. In this example it is located at <em>./compiler/extended.js</em>, and exports a single method named <code>compile()</code>. This method accepts a string, which is the raw contents of what node is requiring, transformed to vanilla JavaScript via regular expressions.</p>
2a420a7 @tj No longer gitignoring html
tj authored
215
216 <pre><code>exports.compile = function(str){
217 return str
218 .replace(/(\w+)\(/g, '$1 = function $1(')
219 .replace(/\)(.+?)\n/g, '){ return $1 }\n')
220 .replace(/::/g, 'exports.');
221 };
222 </code></pre>
223
224 <p>Next we have to "register" the extension to assign out compiler. As previously mentioned our compiler lives at <em>./compiler/extended.js</em> so we are requiring it in, and passing the <code>compile()</code> method to <code>require.registerExtension()</code> which simply expects a function accepting a string, and returning a string of JavaScript.</p>
225
226 <pre><code>require.registerExtension('.ejs', require('./compiler/extended').compile);
227 </code></pre>
228
229 <p>Now when we require our example, the ".ejs" extension is detected, and will pass the contents through our compiler, and everything works as expected.</p>
230
231 <pre><code>var example = require('./compiler/example');
232 console.dir(example)
233 console.log(example.min(2, 3));
234 console.log(example.max(10, 8));
235
236 // =&gt; { min: [Function], max: [Function] }
237 // =&gt; 2
238 // =&gt; 10
239 </code></pre>
240
241 </div>
Something went wrong with that request. Please try again.