forked from serjIII/threejsSDK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
10_modules.html
375 lines (227 loc) · 56.1 KB
/
10_modules.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
<!doctype html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Modules :: Eloquent JavaScript</title>
<link rel=stylesheet href="js/node_modules/codemirror/lib/codemirror.css">
<script src="js/acorn_codemirror.js"></script>
<link rel=stylesheet href="css/ejs.css">
<script src="js/sandbox.js"></script>
<script src="js/ejs.js"></script><script>var chapNum = 10;var sandboxLoadFiles = ["code/packages_chapter_10.js","code/chapter/07_robot.js"];</script></head>
<article>
<nav><a href="09_regexp.html" title="previous chapter">◀</a> <a href="index.html" title="cover">◆</a> <a href="11_async.html" title="next chapter">▶</a></nav>
<h1><span class=chap_num>Chapter 10</span>Modules</h1>
<blockquote>
<p><a class="p_ident" id="p_OwlHMaRbBt" href="#p_OwlHMaRbBt" tabindex="-1" role="presentation"></a>Write code that is easy to delete, not easy to extend.</p>
<footer>Tef, <cite>Programming is Terrible</cite></footer>
</blockquote><figure class="chapter framed"><img src="img/chapter_picture_10.jpg" alt="Picture of a building built from modular pieces"></figure>
<p><a class="p_ident" id="p_lt7t/NZub8" href="#p_lt7t/NZub8" tabindex="-1" role="presentation"></a>The ideal program has a crystal-clear structure. The way it works is easy to explain, and each part plays a well-defined role.</p>
<p><a class="p_ident" id="p_HLTCewyOYT" href="#p_HLTCewyOYT" tabindex="-1" role="presentation"></a>A typical real program grows organically. New pieces of functionality are added as new needs come up. Structuring—and preserving structure—is additional work. It’s work that will pay off only in the future, the <em>next</em> time someone works on the program. So it is tempting to neglect it and allow the parts of the program to become deeply entangled.</p>
<p><a class="p_ident" id="p_Ph53LAfIAv" href="#p_Ph53LAfIAv" tabindex="-1" role="presentation"></a>This causes two practical issues. First, understanding such a system is hard. If everything can touch everything else, it is difficult to look at any given piece in isolation. You are forced to build up a holistic understanding of the entire thing. Second, if you want to use any of the functionality from such a program in another situation, rewriting it may be easier than trying to disentangle it from its context.</p>
<p><a class="p_ident" id="p_pzOEW37Kfc" href="#p_pzOEW37Kfc" tabindex="-1" role="presentation"></a>The phrase “big ball of mud” is often used for such large, structureless programs. Everything sticks together, and when you try to pick out a piece, the whole thing comes apart, and your hands get dirty.</p>
<h2><a class="h_ident" id="h_BOlGLA/wK7" href="#h_BOlGLA/wK7" tabindex="-1" role="presentation"></a>Modules</h2>
<p><a class="p_ident" id="p_LoWZBZ2Vpv" href="#p_LoWZBZ2Vpv" tabindex="-1" role="presentation"></a><em>Modules</em> are an attempt to avoid these problems. A module is a piece of program that specifies which other pieces it relies on and which functionality it provides for other modules to use (its <em>interface</em>).</p>
<p><a class="p_ident" id="p_kjhUrZ1SF0" href="#p_kjhUrZ1SF0" tabindex="-1" role="presentation"></a>Module interfaces have a lot in common with object interfaces, as we saw them in <a href="06_object.html#interface">Chapter 6</a>. They make part of the module available to the outside world and keep the rest private. By restricting the ways in which modules interact with each other, the system becomes more like LEGO, where pieces interact through well-defined connectors, and less like mud, where everything mixes with everything.</p>
<p><a class="p_ident" id="p_l+1k6bprY2" href="#p_l+1k6bprY2" tabindex="-1" role="presentation"></a>The relations between modules are called <em>dependencies</em>. When a module needs a piece from another module, it is said to depend on that module. When this fact is clearly specified in the module itself, it can be used to figure out which other modules need to be present to be able to use a given module and to automatically load dependencies.</p>
<p><a class="p_ident" id="p_4WkC7snvFx" href="#p_4WkC7snvFx" tabindex="-1" role="presentation"></a>To separate modules in that way, each needs its own private scope.</p>
<p><a class="p_ident" id="p_bgQuCetNwq" href="#p_bgQuCetNwq" tabindex="-1" role="presentation"></a>Just putting your JavaScript code into different files does not satisfy these requirements. The files still share the same global namespace. They can, intentionally or accidentally, interfere with each other’s bindings. And the dependency structure remains unclear. We can do better, as we’ll see later in the chapter.</p>
<p><a class="p_ident" id="p_uf1CU70zfG" href="#p_uf1CU70zfG" tabindex="-1" role="presentation"></a>Designing a fitting module structure for a program can be difficult. In the phase where you are still exploring the problem, trying different things to see what works, you might want to not worry about it too much since it can be a big distraction. Once you have something that feels solid, that’s a good time to take a step back and organize it.</p>
<h2><a class="h_ident" id="h_CpmQEv+4ez" href="#h_CpmQEv+4ez" tabindex="-1" role="presentation"></a>Packages</h2>
<p><a class="p_ident" id="p_g7o14y8ONd" href="#p_g7o14y8ONd" tabindex="-1" role="presentation"></a>One of the advantages of building a program out of separate pieces, and being actually able to run those pieces on their own, is that you might be able to apply the same piece in different programs.</p>
<p><a class="p_ident" id="p_iBvlR95Pda" href="#p_iBvlR95Pda" tabindex="-1" role="presentation"></a>But how do you set this up? Say I want to use the <code>parseINI</code> function from <a href="09_regexp.html#ini">Chapter 9</a> in another program. If it is clear what the function depends on (in this case, nothing), I can just copy all the necessary code into my new project and use it. But then, if I find a mistake in that code, I’ll probably fix it in whichever program I’m working with at the time and forget to also fix it in the other program.</p>
<p><a class="p_ident" id="p_TA/SfLJ50i" href="#p_TA/SfLJ50i" tabindex="-1" role="presentation"></a>Once you start duplicating code, you’ll quickly find yourself wasting time and energy moving copies around and keeping them up-to-date.</p>
<p><a class="p_ident" id="p_CNI2vOkPJp" href="#p_CNI2vOkPJp" tabindex="-1" role="presentation"></a>That’s where <em>packages</em> come in. A package is a chunk of code that can be distributed (copied and installed). It may contain one or more modules and has information about which other packages it depends on. A package also usually comes with documentation explaining what it does so that people who didn’t write it might still be able to use it.</p>
<p><a class="p_ident" id="p_sZgcoPgtEe" href="#p_sZgcoPgtEe" tabindex="-1" role="presentation"></a>When a problem is found in a package or a new feature is added, the package is updated. Now the programs that depend on it (which may also be packages) can upgrade to the new version.</p>
<p id="modules_npm"><a class="p_ident" id="p_oiLHr3lvbw" href="#p_oiLHr3lvbw" tabindex="-1" role="presentation"></a>Working in this way requires infrastructure. We need a place to store and find packages and a convenient way to install and upgrade them. In the JavaScript world, this infrastructure is provided by NPM (<a href="https://npmjs.org"><em>https://npmjs.org</em></a>).</p>
<p><a class="p_ident" id="p_WUPNc5b7D2" href="#p_WUPNc5b7D2" tabindex="-1" role="presentation"></a>NPM is two things: an online service where one can download (and upload) packages and a program (bundled with Node.js) that helps you install and manage them.</p>
<p><a class="p_ident" id="p_kcXuOxm8Rl" href="#p_kcXuOxm8Rl" tabindex="-1" role="presentation"></a>At the time of writing, there are more than half a million different packages available on NPM. A large portion of those are rubbish, I should mention, but almost every useful, publicly available package can be found on there. For example, an INI file parser, similar to the one we built in <a href="09_regexp.html">Chapter 9</a>, is available under the package name <code>ini</code>.</p>
<p><a class="p_ident" id="p_irXmhzBaaT" href="#p_irXmhzBaaT" tabindex="-1" role="presentation"></a><a href="20_node.html">Chapter 20</a> will show how to install such packages locally using the <code>npm</code> command line program.</p>
<p><a class="p_ident" id="p_D/2FJ7Crwg" href="#p_D/2FJ7Crwg" tabindex="-1" role="presentation"></a>Having quality packages available for download is extremely valuable. It means that we can often avoid reinventing a program that 100 people have written before and get a solid, well-tested implementation at the press of a few keys.</p>
<p><a class="p_ident" id="p_4hMCknNFh+" href="#p_4hMCknNFh+" tabindex="-1" role="presentation"></a>Software is cheap to copy, so once someone has written it, distributing it to other people is an efficient process. But writing it in the first place <em>is</em> work, and responding to people who have found problems in the code, or who want to propose new features, is even more work.</p>
<p><a class="p_ident" id="p_K/LevaOaUV" href="#p_K/LevaOaUV" tabindex="-1" role="presentation"></a>By default, you own the copyright to the code you write, and other people may use it only with your permission. But because some people are just nice and because publishing good software can help make you a little bit famous among programmers, many packages are published under a license that explicitly allows other people to use it.</p>
<p><a class="p_ident" id="p_sWMlqqRmbd" href="#p_sWMlqqRmbd" tabindex="-1" role="presentation"></a>Most code on NPM is licensed this way. Some licenses require you to also publish code that you build on top of the package under the same license. Others are less demanding, just requiring that you keep the license with the code as you distribute it. The JavaScript community mostly uses the latter type of license. When using other people’s packages, make sure you are aware of their license.</p>
<h2><a class="h_ident" id="h_QQ/m+TRmqd" href="#h_QQ/m+TRmqd" tabindex="-1" role="presentation"></a>Improvised modules</h2>
<p><a class="p_ident" id="p_VhfSheFY3t" href="#p_VhfSheFY3t" tabindex="-1" role="presentation"></a>Until 2015, the JavaScript language had no built-in module system. Yet people had been building large systems in JavaScript for more than a decade, and they <em>needed</em> modules.</p>
<p><a class="p_ident" id="p_EThAZWj4TA" href="#p_EThAZWj4TA" tabindex="-1" role="presentation"></a>So they designed their own module systems on top of the language. You can use JavaScript functions to create local scopes and objects to represent module interfaces.</p>
<p><a class="p_ident" id="p_3jjByT+Dg0" href="#p_3jjByT+Dg0" tabindex="-1" role="presentation"></a>This is a module for going between day names and numbers (as returned by <code>Date</code>’s <code>getDay</code> method). Its interface consists of <code>weekDay.name</code> and <code>weekDay.number</code>, and it hides its local binding <code>names</code> inside the scope of a function expression that is immediately invoked.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_m+yRMF5NXw" href="#c_m+yRMF5NXw" tabindex="-1" role="presentation"></a><span class="cm-keyword">const</span> <span class="cm-def">weekDay</span> <span class="cm-operator">=</span> <span class="cm-keyword">function</span>() {
<span class="cm-keyword">const</span> <span class="cm-def">names</span> <span class="cm-operator">=</span> [<span class="cm-string">"Sunday"</span>, <span class="cm-string">"Monday"</span>, <span class="cm-string">"Tuesday"</span>, <span class="cm-string">"Wednesday"</span>,
<span class="cm-string">"Thursday"</span>, <span class="cm-string">"Friday"</span>, <span class="cm-string">"Saturday"</span>];
<span class="cm-keyword">return</span> {
<span class="cm-property">name</span>(<span class="cm-def">number</span>) { <span class="cm-keyword">return</span> <span class="cm-variable-2">names</span>[<span class="cm-variable-2">number</span>]; },
<span class="cm-property">number</span>(<span class="cm-def">name</span>) { <span class="cm-keyword">return</span> <span class="cm-variable-2">names</span>.<span class="cm-property">indexOf</span>(<span class="cm-variable-2">name</span>); }
};
}();
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">weekDay</span>.<span class="cm-property">name</span>(<span class="cm-variable">weekDay</span>.<span class="cm-property">number</span>(<span class="cm-string">"Sunday"</span>)));
<span class="cm-comment">// → Sunday</span></pre>
<p><a class="p_ident" id="p_uv8xnuw95L" href="#p_uv8xnuw95L" tabindex="-1" role="presentation"></a>This style of modules provides isolation, to a certain degree, but it does not declare dependencies. Instead, it just puts its interface into the global scope and expects its dependencies, if any, to do the same. For a long time this was the main approach used in web programming, but it is mostly obsolete now.</p>
<p><a class="p_ident" id="p_i8xxHMuJw+" href="#p_i8xxHMuJw+" tabindex="-1" role="presentation"></a>If we want to make dependency relations part of the code, we’ll have to take control of loading dependencies. Doing that requires being able to execute strings as code. JavaScript can do this.</p>
<h2 id="eval"><a class="h_ident" id="h_oeOkEDaadU" href="#h_oeOkEDaadU" tabindex="-1" role="presentation"></a>Evaluating data as code</h2>
<p><a class="p_ident" id="p_jvij1au4eP" href="#p_jvij1au4eP" tabindex="-1" role="presentation"></a>There are several ways to take data (a string of code) and run it as part of the current program.</p>
<p><a class="p_ident" id="p_8T3Py6Zkwc" href="#p_8T3Py6Zkwc" tabindex="-1" role="presentation"></a>The most obvious way is the special operator <code>eval</code>, which will execute a string in the <em>current</em> scope. This is usually a bad idea because it breaks some of the properties that scopes normally have, such as it being easily predictable which binding a given name refers to.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_14x3bOXX9G" href="#c_14x3bOXX9G" tabindex="-1" role="presentation"></a><span class="cm-keyword">const</span> <span class="cm-def">x</span> <span class="cm-operator">=</span> <span class="cm-number">1</span>;
<span class="cm-keyword">function</span> <span class="cm-def">evalAndReturnX</span>(<span class="cm-def">code</span>) {
<span class="cm-variable">eval</span>(<span class="cm-variable-2">code</span>);
<span class="cm-keyword">return</span> <span class="cm-variable">x</span>;
}
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">evalAndReturnX</span>(<span class="cm-string">"var x = 2"</span>));
<span class="cm-comment">// → 2</span>
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">x</span>);
<span class="cm-comment">// → 1</span></pre>
<p><a class="p_ident" id="p_wzjzmC3uLa" href="#p_wzjzmC3uLa" tabindex="-1" role="presentation"></a>A less scary way of interpreting data as code is to use the <code>Function</code> constructor. It takes two arguments: a string containing a comma-separated list of argument names and a string containing the function body. It wraps the code in a function value so that it gets its own scope and won’t do odd things with other scopes.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_Mc9BAi4AVK" href="#c_Mc9BAi4AVK" tabindex="-1" role="presentation"></a><span class="cm-keyword">let</span> <span class="cm-def">plusOne</span> <span class="cm-operator">=</span> <span class="cm-variable">Function</span>(<span class="cm-string">"n"</span>, <span class="cm-string">"return n + 1;"</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">plusOne</span>(<span class="cm-number">4</span>));
<span class="cm-comment">// → 5</span></pre>
<p><a class="p_ident" id="p_vgKeYBfC4h" href="#p_vgKeYBfC4h" tabindex="-1" role="presentation"></a>This is precisely what we need for a module system. We can wrap the module’s code in a function and use that function’s scope as module scope.</p>
<h2><a class="h_ident" id="h_N33QHgUxbG" href="#h_N33QHgUxbG" tabindex="-1" role="presentation"></a>CommonJS</h2>
<p id="commonjs"><a class="p_ident" id="p_kAtCGxNjIq" href="#p_kAtCGxNjIq" tabindex="-1" role="presentation"></a>The most widely used approach to bolted-on JavaScript modules is called <em>CommonJS modules</em>. Node.js uses it and is the system used by most packages on NPM.</p>
<p><a class="p_ident" id="p_NM2zfHqLcE" href="#p_NM2zfHqLcE" tabindex="-1" role="presentation"></a>The main concept in CommonJS modules is a function called <code>require</code>. When you call this with the module name of a dependency, it makes sure the module is loaded and returns its interface.</p>
<p><a class="p_ident" id="p_CNeZtts3Cz" href="#p_CNeZtts3Cz" tabindex="-1" role="presentation"></a>Because the loader wraps the module code in a function, modules automatically get their own local scope. All they have to do is call <code>require</code> to access their dependencies and put their interface in the object bound to <code>exports</code>.</p>
<p><a class="p_ident" id="p_ew2dDAURuM" href="#p_ew2dDAURuM" tabindex="-1" role="presentation"></a>This example module provides a date-formatting function. It uses two packages from NPM—<code>ordinal</code> to convert numbers to strings like <code>"1st"</code> and <code>"2nd"</code>, and <code>date-names</code> to get the English names for weekdays and months. It exports a single function, <code>formatDate</code>, which takes a <code>Date</code> object and a template string.</p>
<p><a class="p_ident" id="p_fH0b3BN1Fp" href="#p_fH0b3BN1Fp" tabindex="-1" role="presentation"></a>The template string may contain codes that direct the format, such as <code>YYYY</code> for the full year and <code>Do</code> for the ordinal day of the month. You could give it a string like <code>"MMMM Do YYYY"</code> to get output like “November 22nd 2017”.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_hEFnba6fud" href="#c_hEFnba6fud" tabindex="-1" role="presentation"></a><span class="cm-keyword">const</span> <span class="cm-def">ordinal</span> <span class="cm-operator">=</span> <span class="cm-variable">require</span>(<span class="cm-string">"ordinal"</span>);
<span class="cm-keyword">const</span> {<span class="cm-def">days</span>, <span class="cm-def">months</span>} <span class="cm-operator">=</span> <span class="cm-variable">require</span>(<span class="cm-string">"date-names"</span>);
<span class="cm-variable">exports</span>.<span class="cm-property">formatDate</span> <span class="cm-operator">=</span> <span class="cm-keyword">function</span>(<span class="cm-def">date</span>, <span class="cm-def">format</span>) {
<span class="cm-keyword">return</span> <span class="cm-variable-2">format</span>.<span class="cm-property">replace</span>(<span class="cm-string-2">/YYYY|M(MMM)?|Do?|dddd/g</span>, <span class="cm-def">tag</span> <span class="cm-operator">=></span> {
<span class="cm-keyword">if</span> (<span class="cm-variable-2">tag</span> <span class="cm-operator">==</span> <span class="cm-string">"YYYY"</span>) <span class="cm-keyword">return</span> <span class="cm-variable-2">date</span>.<span class="cm-property">getFullYear</span>();
<span class="cm-keyword">if</span> (<span class="cm-variable-2">tag</span> <span class="cm-operator">==</span> <span class="cm-string">"M"</span>) <span class="cm-keyword">return</span> <span class="cm-variable-2">date</span>.<span class="cm-property">getMonth</span>();
<span class="cm-keyword">if</span> (<span class="cm-variable-2">tag</span> <span class="cm-operator">==</span> <span class="cm-string">"MMMM"</span>) <span class="cm-keyword">return</span> <span class="cm-variable">months</span>[<span class="cm-variable-2">date</span>.<span class="cm-property">getMonth</span>()];
<span class="cm-keyword">if</span> (<span class="cm-variable-2">tag</span> <span class="cm-operator">==</span> <span class="cm-string">"D"</span>) <span class="cm-keyword">return</span> <span class="cm-variable-2">date</span>.<span class="cm-property">getDate</span>();
<span class="cm-keyword">if</span> (<span class="cm-variable-2">tag</span> <span class="cm-operator">==</span> <span class="cm-string">"Do"</span>) <span class="cm-keyword">return</span> <span class="cm-variable">ordinal</span>(<span class="cm-variable-2">date</span>.<span class="cm-property">getDate</span>());
<span class="cm-keyword">if</span> (<span class="cm-variable-2">tag</span> <span class="cm-operator">==</span> <span class="cm-string">"dddd"</span>) <span class="cm-keyword">return</span> <span class="cm-variable">days</span>[<span class="cm-variable-2">date</span>.<span class="cm-property">getDay</span>()];
});
};</pre>
<p><a class="p_ident" id="p_jvrgfRxGB4" href="#p_jvrgfRxGB4" tabindex="-1" role="presentation"></a>The interface of <code>ordinal</code> is a single function, whereas <code>date-names</code> exports an object containing multiple things—<code>days</code> and <code>months</code> are arrays of names. Destructuring is very convenient when creating bindings for imported interfaces.</p>
<p><a class="p_ident" id="p_cHv4rZkvfj" href="#p_cHv4rZkvfj" tabindex="-1" role="presentation"></a>The module adds its interface function to <code>exports</code> so that modules that depend on it get access to it. We could use the module like this:</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_pWURcHuHTt" href="#c_pWURcHuHTt" tabindex="-1" role="presentation"></a><span class="cm-keyword">const</span> {<span class="cm-def">formatDate</span>} <span class="cm-operator">=</span> <span class="cm-variable">require</span>(<span class="cm-string">"./format-date"</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">formatDate</span>(<span class="cm-keyword">new</span> <span class="cm-variable">Date</span>(<span class="cm-number">2017</span>, <span class="cm-number">9</span>, <span class="cm-number">13</span>),
<span class="cm-string">"dddd the Do"</span>));
<span class="cm-comment">// → Friday the 13th</span></pre>
<p id="require"><a class="p_ident" id="p_vmJrDleGRH" href="#p_vmJrDleGRH" tabindex="-1" role="presentation"></a>We can define <code>require</code>, in its most minimal form, like this:</p>
<pre class="snippet cm-s-default" data-language="javascript" data-sandbox="require"><a class="c_ident" id="c_CSMfqoYOzp" href="#c_CSMfqoYOzp" tabindex="-1" role="presentation"></a><span class="cm-variable">require</span>.<span class="cm-property">cache</span> <span class="cm-operator">=</span> <span class="cm-variable">Object</span>.<span class="cm-property">create</span>(<span class="cm-atom">null</span>);
<span class="cm-keyword">function</span> <span class="cm-def">require</span>(<span class="cm-def">name</span>) {
<span class="cm-keyword">if</span> (<span class="cm-operator">!</span>(<span class="cm-variable-2">name</span> <span class="cm-keyword">in</span> <span class="cm-variable">require</span>.<span class="cm-property">cache</span>)) {
<span class="cm-keyword">let</span> <span class="cm-def">code</span> <span class="cm-operator">=</span> <span class="cm-variable">readFile</span>(<span class="cm-variable-2">name</span>);
<span class="cm-keyword">let</span> <span class="cm-def">module</span> <span class="cm-operator">=</span> {<span class="cm-property">exports</span>: {}};
<span class="cm-variable">require</span>.<span class="cm-property">cache</span>[<span class="cm-variable-2">name</span>] <span class="cm-operator">=</span> <span class="cm-variable-2">module</span>;
<span class="cm-keyword">let</span> <span class="cm-def">wrapper</span> <span class="cm-operator">=</span> <span class="cm-variable">Function</span>(<span class="cm-string">"require, exports, module"</span>, <span class="cm-variable-2">code</span>);
<span class="cm-variable-2">wrapper</span>(<span class="cm-variable">require</span>, <span class="cm-variable-2">module</span>.<span class="cm-property">exports</span>, <span class="cm-variable-2">module</span>);
}
<span class="cm-keyword">return</span> <span class="cm-variable">require</span>.<span class="cm-property">cache</span>[<span class="cm-variable-2">name</span>].<span class="cm-property">exports</span>;
}</pre>
<p><a class="p_ident" id="p_sc1VEkBDCY" href="#p_sc1VEkBDCY" tabindex="-1" role="presentation"></a>In this code, <code>readFile</code> is a made-up function that reads a file and returns its contents as a string. Standard JavaScript provides no such functionality—but different JavaScript environments, such as the browser and Node.js, provide their own ways of accessing files. The example just pretends that <code>readFile</code> exists.</p>
<p><a class="p_ident" id="p_DxNIETFONd" href="#p_DxNIETFONd" tabindex="-1" role="presentation"></a>To avoid loading the same module multiple times, <code>require</code> keeps a store (cache) of already loaded modules. When called, it first checks if the requested module has been loaded and, if not, loads it. This involves reading the module’s code, wrapping it in a function, and calling it.</p>
<p><a class="p_ident" id="p_tI7DzFSLjM" href="#p_tI7DzFSLjM" tabindex="-1" role="presentation"></a>The interface of the <code>ordinal</code> package we saw before is not an object but a function. A quirk of the CommonJS modules is that, though the module system will create an empty interface object for you (bound to <code>exports</code>), you can replace that with any value by overwriting <code>module.exports</code>. This is done by many modules to export a single value instead of an interface object.</p>
<p><a class="p_ident" id="p_1en0vUqbeI" href="#p_1en0vUqbeI" tabindex="-1" role="presentation"></a>By defining <code>require</code>, <code>exports</code>, and <code>module</code> as parameters for the generated wrapper function (and passing the appropriate values when calling it), the loader makes sure that these bindings are available in the module’s scope.</p>
<p><a class="p_ident" id="p_xriS0EN27o" href="#p_xriS0EN27o" tabindex="-1" role="presentation"></a>The way the string given to <code>require</code> is translated to an actual filename or web address differs in different systems. When it starts with <code>"./"</code> or <code>"../"</code>, it is generally interpreted as relative to the current module’s filename. So <code>"./<wbr>format-date"</code> would be the file named <code>format-date.js</code> in the same directory.</p>
<p><a class="p_ident" id="p_L5+LG67XHa" href="#p_L5+LG67XHa" tabindex="-1" role="presentation"></a>When the name isn’t relative, Node.js will look for an installed package by that name. In the example code in this chapter, we’ll interpret such names as referring to NPM packages. We’ll go into more detail on how to install and use NPM modules in <a href="20_node.html">Chapter 20</a>.</p>
<p id="modules_ini"><a class="p_ident" id="p_B5bzWP/zEC" href="#p_B5bzWP/zEC" tabindex="-1" role="presentation"></a>Now, instead of writing our own INI file parser, we can use one from NPM.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_LfcCXOMZGr" href="#c_LfcCXOMZGr" tabindex="-1" role="presentation"></a><span class="cm-keyword">const</span> {<span class="cm-def">parse</span>} <span class="cm-operator">=</span> <span class="cm-variable">require</span>(<span class="cm-string">"ini"</span>);
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">parse</span>(<span class="cm-string">"x = 10\ny = 20"</span>));
<span class="cm-comment">// → {x: "10", y: "20"}</span></pre>
<h2><a class="h_ident" id="h_hF2FmOVxw7" href="#h_hF2FmOVxw7" tabindex="-1" role="presentation"></a>ECMAScript modules</h2>
<p><a class="p_ident" id="p_ZB3AF/XP4y" href="#p_ZB3AF/XP4y" tabindex="-1" role="presentation"></a>CommonJS modules work quite well and, in combination with NPM, have allowed the JavaScript community to start sharing code on a large scale.</p>
<p><a class="p_ident" id="p_yy6++k1U8b" href="#p_yy6++k1U8b" tabindex="-1" role="presentation"></a>But they remain a bit of a duct-tape hack. The notation is slightly awkward—the things you add to <code>exports</code> are not available in the local scope, for example. And because <code>require</code> is a normal function call taking any kind of argument, not just a string literal, it can be hard to determine the dependencies of a module without running its code.</p>
<p id="es"><a class="p_ident" id="p_fGE1JkAJHH" href="#p_fGE1JkAJHH" tabindex="-1" role="presentation"></a>This is why the JavaScript standard from 2015 introduces its own, different module system. It is usually called <em>ES modules</em>, where <em>ES</em> stands for ECMAScript. The main concepts of dependencies and interfaces remain the same, but the details differ. For one thing, the notation is now integrated into the language. Instead of calling a function to access a dependency, you use a special <code>import</code> keyword.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_EpiH8qOAcJ" href="#c_EpiH8qOAcJ" tabindex="-1" role="presentation"></a><span class="cm-keyword">import</span> <span class="cm-def">ordinal</span> <span class="cm-keyword">from</span> <span class="cm-string">"ordinal"</span>;
<span class="cm-keyword">import</span> {<span class="cm-def">days</span>, <span class="cm-def">months</span>} <span class="cm-keyword">from</span> <span class="cm-string">"date-names"</span>;
<span class="cm-keyword">export</span> <span class="cm-keyword">function</span> <span class="cm-def">formatDate</span>(<span class="cm-def">date</span>, <span class="cm-def">format</span>) { <span class="cm-comment">/* ... */</span> }</pre>
<p><a class="p_ident" id="p_Md0hUIO/t1" href="#p_Md0hUIO/t1" tabindex="-1" role="presentation"></a>Similarly, the <code>export</code> keyword is used to export things. It may appear in front of a function, class, or binding definition (<code>let</code>, <code>const</code>, or <code>var</code>).</p>
<p><a class="p_ident" id="p_2XcNI5i8RP" href="#p_2XcNI5i8RP" tabindex="-1" role="presentation"></a>An ES module’s interface is not a single value but a set of named bindings. The preceding module binds <code>formatDate</code> to a function. When you import from another module, you import the <em>binding</em>, not the value, which means an exporting module may change the value of the binding at any time, and the modules that import it will see its new value.</p>
<p><a class="p_ident" id="p_H96aQvDt7C" href="#p_H96aQvDt7C" tabindex="-1" role="presentation"></a>When there is a binding named <code>default</code>, it is treated as the module’s main exported value. If you import a module like <code>ordinal</code> in the example, without braces around the binding name, you get its <code>default</code> binding. Such modules can still export other bindings under different names alongside their <code>default</code> export.</p>
<p><a class="p_ident" id="p_C4XHB0ByrT" href="#p_C4XHB0ByrT" tabindex="-1" role="presentation"></a>To create a default export, you write <code>export default</code> before an expression, a function declaration, or a class declaration.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_Y6Wnu9X+/W" href="#c_Y6Wnu9X+/W" tabindex="-1" role="presentation"></a><span class="cm-keyword">export</span> <span class="cm-keyword">default</span> [<span class="cm-string">"Winter"</span>, <span class="cm-string">"Spring"</span>, <span class="cm-string">"Summer"</span>, <span class="cm-string">"Autumn"</span>];</pre>
<p><a class="p_ident" id="p_XbHIrV+nuJ" href="#p_XbHIrV+nuJ" tabindex="-1" role="presentation"></a>It is possible to rename imported bindings using the word <code>as</code>.</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_I7jPaQvsXj" href="#c_I7jPaQvsXj" tabindex="-1" role="presentation"></a><span class="cm-keyword">import</span> {<span class="cm-def">days</span> <span class="cm-keyword">as</span> <span class="cm-def">dayNames</span>} <span class="cm-keyword">from</span> <span class="cm-string">"date-names"</span>;
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">dayNames</span>.<span class="cm-property">length</span>);
<span class="cm-comment">// → 7</span></pre>
<p><a class="p_ident" id="p_oqym70c7ZR" href="#p_oqym70c7ZR" tabindex="-1" role="presentation"></a>Another important difference is that ES module imports happen before a module’s script starts running. That means <code>import</code> declarations may not appear inside functions or blocks, and the names of dependencies must be quoted strings, not arbitrary expressions.</p>
<p><a class="p_ident" id="p_+UaRV7zy4m" href="#p_+UaRV7zy4m" tabindex="-1" role="presentation"></a>At the time of writing, the JavaScript community is in the process of adopting this module style. But it has been a slow process. It took a few years, after the format was specified, for browsers and Node.js to start supporting it. And though they mostly support it now, this support still has issues, and the discussion on how such modules should be distributed through NPM is still ongoing.</p>
<p><a class="p_ident" id="p_UEipP/dEjR" href="#p_UEipP/dEjR" tabindex="-1" role="presentation"></a>Many projects are written using ES modules and then automatically converted to some other format when published. We are in a transitional period in which two different module systems are used side by side, and it is useful to be able to read and write code in either of them.</p>
<h2><a class="h_ident" id="h_zWTXAU93DC" href="#h_zWTXAU93DC" tabindex="-1" role="presentation"></a>Building and bundling</h2>
<p><a class="p_ident" id="p_Si0Uy8W7Rk" href="#p_Si0Uy8W7Rk" tabindex="-1" role="presentation"></a>In fact, many JavaScript projects aren’t even, technically, written in JavaScript. There are extensions, such as the type checking dialect mentioned in <a href="08_error.html#typing">Chapter 8</a>, that are widely used. People also often start using planned extensions to the language long before they have been added to the platforms that actually run JavaScript.</p>
<p><a class="p_ident" id="p_8YI40LC/+x" href="#p_8YI40LC/+x" tabindex="-1" role="presentation"></a>To make this possible, they <em>compile</em> their code, translating it from their chosen JavaScript dialect to plain old JavaScript—or even to a past version of JavaScript—so that old browsers can run it.</p>
<p><a class="p_ident" id="p_xCwSgQaAdq" href="#p_xCwSgQaAdq" tabindex="-1" role="presentation"></a>Including a modular program that consists of 200 different files in a web page produces its own problems. If fetching a single file over the network takes 50 milliseconds, loading the whole program takes 10 seconds, or maybe half that if you can load several files simultaneously. That’s a lot of wasted time. Because fetching a single big file tends to be faster than fetching a lot of tiny ones, web programmers have started using tools that roll their programs (which they painstakingly split into modules) back into a single big file before they publish it to the Web. Such tools are called <em>bundlers</em>.</p>
<p><a class="p_ident" id="p_F5bhvXPahh" href="#p_F5bhvXPahh" tabindex="-1" role="presentation"></a>And we can go further. Apart from the number of files, the <em>size</em> of the files also determines how fast they can be transferred over the network. Thus, the JavaScript community has invented <em>minifiers</em>. These are tools that take a JavaScript program and make it smaller by automatically removing comments and whitespace, renaming bindings, and replacing pieces of code with equivalent code that take up less space.</p>
<p><a class="p_ident" id="p_0kzBnsBjVM" href="#p_0kzBnsBjVM" tabindex="-1" role="presentation"></a>So it is not uncommon for the code that you find in an NPM package or that runs on a web page to have gone through <em>multiple</em> stages of transformation—converted from modern JavaScript to historic JavaScript, from ES module format to CommonJS, bundled, and minified. We won’t go into the details of these tools in this book since they tend to be boring and change rapidly. Just be aware that the JavaScript code you run is often not the code as it was written.</p>
<h2><a class="h_ident" id="h_P8pyzbI9vO" href="#h_P8pyzbI9vO" tabindex="-1" role="presentation"></a>Module design</h2>
<p><a class="p_ident" id="p_8K2T8s7itK" href="#p_8K2T8s7itK" tabindex="-1" role="presentation"></a>Structuring programs is one of the subtler aspects of programming. Any nontrivial piece of functionality can be modeled in various ways.</p>
<p><a class="p_ident" id="p_98c2qP5s8p" href="#p_98c2qP5s8p" tabindex="-1" role="presentation"></a>Good program design is subjective—there are trade-offs involved and matters of taste. The best way to learn the value of well-structured design is to read or work on a lot of programs and notice what works and what doesn’t. Don’t assume that a painful mess is “just the way it is”. You can improve the structure of almost everything by putting more thought into it.</p>
<p><a class="p_ident" id="p_AF7qUrMoR4" href="#p_AF7qUrMoR4" tabindex="-1" role="presentation"></a>One aspect of module design is ease of use. If you are designing something that is intended to be used by multiple people—or even by yourself, in three months when you no longer remember the specifics of what you did—it is helpful if your interface is simple and predictable.</p>
<p><a class="p_ident" id="p_hHDSnM2Orb" href="#p_hHDSnM2Orb" tabindex="-1" role="presentation"></a>That may mean following existing conventions. A good example is the <code>ini</code> package. This module imitates the standard <code>JSON</code> object by providing <code>parse</code> and <code>stringify</code> (to write an INI file) functions, and, like <code>JSON</code>, converts between strings and plain objects. So the interface is small and familiar, and after you’ve worked with it once, you’re likely to remember how to use it.</p>
<p><a class="p_ident" id="p_uS+as91Giv" href="#p_uS+as91Giv" tabindex="-1" role="presentation"></a>Even if there’s no standard function or widely used package to imitate, you can keep your modules predictable by using simple data
structures and doing a single, focused thing. Many of the INI-file parsing modules on NPM provide a function that directly reads such a file from the hard disk and parses it, for example. This makes it impossible to use such modules in the browser, where we don’t have direct file system access, and adds complexity that would have been better addressed by <em>composing</em> the module with some file-reading function.</p>
<p><a class="p_ident" id="p_JYcq/PgjlO" href="#p_JYcq/PgjlO" tabindex="-1" role="presentation"></a>This points to another helpful aspect of module design—the ease with which something can be composed with other code. Focused modules that compute values are applicable in a wider range of programs than bigger modules that perform complicated actions with side effects. An INI file reader that insists on reading the file from disk is useless in a scenario where the file’s content comes from some other source.</p>
<p><a class="p_ident" id="p_6cqySeVoki" href="#p_6cqySeVoki" tabindex="-1" role="presentation"></a>Relatedly, stateful objects are sometimes useful or even necessary, but if something can be done with a function, use a function. Several of the INI file readers on NPM provide an interface style that requires you to first create an object, then load the file into your object, and finally use specialized methods to get at the results. This type of thing is common in the object-oriented tradition, and it’s terrible. Instead of making a single function call and moving on, you have to perform the ritual of moving your object through various states. And because the data is now wrapped in a specialized object type, all code that interacts with it has to know about that type, creating unnecessary interdependencies.</p>
<p><a class="p_ident" id="p_uR7iWbgBIy" href="#p_uR7iWbgBIy" tabindex="-1" role="presentation"></a>Often defining new data structures can’t be avoided—only a few basic ones are provided by the language standard, and many types of data have to be more complex than an array or a map. But when an array suffices, use an array.</p>
<p><a class="p_ident" id="p_gE7WoNX7+Z" href="#p_gE7WoNX7+Z" tabindex="-1" role="presentation"></a>An example of a slightly more complex data structure is the graph from <a href="07_robot.html">Chapter 7</a>. There is no single obvious way to represent a graph in JavaScript. In that chapter, we used an object whose properties hold arrays of strings—the other nodes reachable from that node.</p>
<p><a class="p_ident" id="p_17Fkotj+nV" href="#p_17Fkotj+nV" tabindex="-1" role="presentation"></a>There are several different pathfinding packages on NPM, but none of them uses this graph format. They usually allow the graph’s edges to have a weight, which is the cost or distance associated with it. That isn’t possible in our representation.</p>
<p><a class="p_ident" id="p_d3wpFXYEjN" href="#p_d3wpFXYEjN" tabindex="-1" role="presentation"></a>For example, there’s the <code>dijkstrajs</code> package. A well-known approach to pathfinding, quite similar to our <code>findRoute</code> function, is called <em>Dijkstra’s algorithm</em>, after Edsger Dijkstra, who first wrote it down. The <code>js</code> suffix is often added to package names to indicate the fact that they are written in JavaScript. This <code>dijkstrajs</code> package uses a graph format similar to ours, but instead of arrays, it uses objects whose property values are numbers—the weights of the edges.</p>
<p><a class="p_ident" id="p_3iug1e4kQG" href="#p_3iug1e4kQG" tabindex="-1" role="presentation"></a>So if we wanted to use that package, we’d have to make sure that our graph was stored in the format it expects. All edges get the same weight since our simplified model treats each road as having the same cost (one turn).</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_NyRXVpwPYN" href="#c_NyRXVpwPYN" tabindex="-1" role="presentation"></a><span class="cm-keyword">const</span> {<span class="cm-def">find_path</span>} <span class="cm-operator">=</span> <span class="cm-variable">require</span>(<span class="cm-string">"dijkstrajs"</span>);
<span class="cm-keyword">let</span> <span class="cm-def">graph</span> <span class="cm-operator">=</span> {};
<span class="cm-keyword">for</span> (<span class="cm-keyword">let</span> <span class="cm-def">node</span> <span class="cm-keyword">of</span> <span class="cm-variable">Object</span>.<span class="cm-property">keys</span>(<span class="cm-variable">roadGraph</span>)) {
<span class="cm-keyword">let</span> <span class="cm-def">edges</span> <span class="cm-operator">=</span> <span class="cm-variable">graph</span>[<span class="cm-variable">node</span>] <span class="cm-operator">=</span> {};
<span class="cm-keyword">for</span> (<span class="cm-keyword">let</span> <span class="cm-def">dest</span> <span class="cm-keyword">of</span> <span class="cm-variable">roadGraph</span>[<span class="cm-variable">node</span>]) {
<span class="cm-variable">edges</span>[<span class="cm-variable">dest</span>] <span class="cm-operator">=</span> <span class="cm-number">1</span>;
}
}
<span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-variable">find_path</span>(<span class="cm-variable">graph</span>, <span class="cm-string">"Post Office"</span>, <span class="cm-string">"Cabin"</span>));
<span class="cm-comment">// → ["Post Office", "Alice's House", "Cabin"]</span></pre>
<p><a class="p_ident" id="p_X8Ulb726ZC" href="#p_X8Ulb726ZC" tabindex="-1" role="presentation"></a>This can be a barrier to composition—when various packages are using different data structures to describe similar things, combining them is difficult. Therefore, if you want to design for composability, find out what data structures other people are using and, when possible, follow their example.</p>
<h2><a class="h_ident" id="h_ErccPg/l98" href="#h_ErccPg/l98" tabindex="-1" role="presentation"></a>Summary</h2>
<p><a class="p_ident" id="p_OX2jY0nGFw" href="#p_OX2jY0nGFw" tabindex="-1" role="presentation"></a>Modules provide structure to bigger programs by separating the code into pieces with clear interfaces and dependencies. The interface is the part of the module that’s visible from other modules, and the dependencies are the other modules that it makes use of.</p>
<p><a class="p_ident" id="p_sYCJxIhCEI" href="#p_sYCJxIhCEI" tabindex="-1" role="presentation"></a>Because JavaScript historically did not provide a module system, the CommonJS system was built on top of it. Then at some point it <em>did</em> get a built-in system, which now coexists uneasily with the CommonJS system.</p>
<p><a class="p_ident" id="p_wDM2Q8HBcB" href="#p_wDM2Q8HBcB" tabindex="-1" role="presentation"></a>A package is a chunk of code that can be distributed on its own. NPM is a repository of JavaScript packages. You can download all kinds of useful (and useless) packages from it.</p>
<h2><a class="h_ident" id="h_TcUD2vzyMe" href="#h_TcUD2vzyMe" tabindex="-1" role="presentation"></a>Exercises</h2>
<h3><a class="i_ident" id="i_CJKk6NIC0T" href="#i_CJKk6NIC0T" tabindex="-1" role="presentation"></a>A modular robot</h3>
<p id="modular_robot"><a class="p_ident" id="p_nPAEnO4pep" href="#p_nPAEnO4pep" tabindex="-1" role="presentation"></a>These are the bindings that the project from <a href="07_robot.html">Chapter 7</a> creates:</p>
<pre class="snippet cm-s-default" data-language="text/plain" ><a class="c_ident" id="c_/nxTd1W0Sy" href="#c_/nxTd1W0Sy" tabindex="-1" role="presentation"></a>roads
buildGraph
roadGraph
VillageState
runRobot
randomPick
randomRobot
mailRoute
routeRobot
findRoute
goalOrientedRobot</pre>
<p><a class="p_ident" id="p_0LdymcLoV8" href="#p_0LdymcLoV8" tabindex="-1" role="presentation"></a>If you were to write that project as a modular program, what modules would you create? Which module would depend on which other module, and what would their interfaces look like?</p>
<p><a class="p_ident" id="p_hU/u/IPER+" href="#p_hU/u/IPER+" tabindex="-1" role="presentation"></a>Which pieces are likely to be available prewritten on NPM? Would you prefer to use an NPM package or write them yourself?</p>
<div class="solution"><div class="solution-text">
<p><a class="p_ident" id="p_o3MT4wM7DB" href="#p_o3MT4wM7DB" tabindex="-1" role="presentation"></a>Here’s what I would have done (but again, there is no single <em>right</em> way to design a given module):</p>
<p><a class="p_ident" id="p_56/CQgKTat" href="#p_56/CQgKTat" tabindex="-1" role="presentation"></a>The code used to build the road graph lives in the <code>graph</code> module. Because I’d rather use <code>dijkstrajs</code> from NPM than our own pathfinding code, we’ll make this build the kind of graph data that <code>dijkstrajs</code> expects. This module exports a single function, <code>buildGraph</code>. I’d have <code>buildGraph</code> accept an array of two-element arrays, rather than strings containing hyphens, to make the module less dependent on the input format.</p>
<p><a class="p_ident" id="p_B6Z6VXRXv9" href="#p_B6Z6VXRXv9" tabindex="-1" role="presentation"></a>The <code>roads</code> module contains the raw road data (the <code>roads</code> array) and the <code>roadGraph</code> binding. This module depends on <code>./graph</code> and exports the road graph.</p>
<p><a class="p_ident" id="p_JLwefzFde0" href="#p_JLwefzFde0" tabindex="-1" role="presentation"></a>The <code>VillageState</code> class lives in the <code>state</code> module. It depends on the <code>./roads</code> module because it needs to be able to verify that a given road exists. It also needs <code>randomPick</code>. Since that is a three-line function, we could just put it into the <code>state</code> module as an internal helper function. But <code>randomRobot</code> needs it too. So we’d have to either duplicate it or put it into its own module. Since this function happens to exist on NPM in the <code>random-item</code> package, a good solution is to just make both modules depend on that. We can add the <code>runRobot</code> function to this module as well, since it’s small and closely related to state management. The module exports both the <code>VillageState</code> class and the <code>runRobot</code> function.</p>
<p><a class="p_ident" id="p_wJDmndPhIc" href="#p_wJDmndPhIc" tabindex="-1" role="presentation"></a>Finally, the robots, along with the values they depend on such as <code>mailRoute</code>, could go into an <code>example-robots</code> module, which depends on <code>./roads</code> and exports the robot functions. To make it possible for <code>goalOrientedRobot</code> to do route-finding, this module also depends on <code>dijkstrajs</code>.</p>
<p><a class="p_ident" id="p_jU189+mtkS" href="#p_jU189+mtkS" tabindex="-1" role="presentation"></a>By offloading some work to NPM modules, the code became a little smaller. Each individual module does something rather simple and can be read on its own. Dividing code into modules also often suggests further improvements to the program’s design. In this case, it seems a little odd that the <code>VillageState</code> and the robots depend on a specific road graph. It might be a better idea to make the graph an argument to the state’s constructor and make the robots read it from the state object—this reduces dependencies (which is always good) and makes it possible to run simulations on different maps (which is even better).</p>
<p><a class="p_ident" id="p_rfGj5/gdUx" href="#p_rfGj5/gdUx" tabindex="-1" role="presentation"></a>Is it a good idea to use NPM modules for things that we could have written ourselves? In principle, yes—for nontrivial things like the pathfinding function you are likely to make mistakes and waste time writing them yourself. For tiny functions like <code>random-item</code>, writing them yourself is easy enough. But adding them wherever you need them does tend to clutter your modules.</p>
<p><a class="p_ident" id="p_shhnxYPdPj" href="#p_shhnxYPdPj" tabindex="-1" role="presentation"></a>However, you should also not underestimate the work involved in <em>finding</em> an appropriate NPM package. And even if you find one, it might not work well or may be missing some feature you need. On top of that, depending on NPM packages means you have to make sure they are installed, you have to distribute them with your program, and you might have to periodically upgrade them.</p>
<p><a class="p_ident" id="p_UgTNT3/2gd" href="#p_UgTNT3/2gd" tabindex="-1" role="presentation"></a>So again, this is a trade-off, and you can decide either way depending on how much the packages help you.</p>
</div></div>
<h3><a class="i_ident" id="i_+pU//gQmZ8" href="#i_+pU//gQmZ8" tabindex="-1" role="presentation"></a>Roads module</h3>
<p><a class="p_ident" id="p_U88wPDSl2i" href="#p_U88wPDSl2i" tabindex="-1" role="presentation"></a>Write a CommonJS module, based on the example from <a href="07_robot.html">Chapter 7</a>, that contains the array of roads and exports the graph data structure representing them as <code>roadGraph</code>. It should depend on a module <code>./graph</code>, which exports a function <code>buildGraph</code> that is used to build the graph. This function expects an array of two-element arrays (the start and end points of the roads).</p>
<pre class="snippet cm-s-default" data-language="javascript" ><a class="c_ident" id="c_FPEwj7xDOs" href="#c_FPEwj7xDOs" tabindex="-1" role="presentation"></a><span class="cm-comment">// Add dependencies and exports</span>
<span class="cm-keyword">const</span> <span class="cm-def">roads</span> <span class="cm-operator">=</span> [
<span class="cm-string">"Alice's House-Bob's House"</span>, <span class="cm-string">"Alice's House-Cabin"</span>,
<span class="cm-string">"Alice's House-Post Office"</span>, <span class="cm-string">"Bob's House-Town Hall"</span>,
<span class="cm-string">"Daria's House-Ernie's House"</span>, <span class="cm-string">"Daria's House-Town Hall"</span>,
<span class="cm-string">"Ernie's House-Grete's House"</span>, <span class="cm-string">"Grete's House-Farm"</span>,
<span class="cm-string">"Grete's House-Shop"</span>, <span class="cm-string">"Marketplace-Farm"</span>,
<span class="cm-string">"Marketplace-Post Office"</span>, <span class="cm-string">"Marketplace-Shop"</span>,
<span class="cm-string">"Marketplace-Town Hall"</span>, <span class="cm-string">"Shop-Town Hall"</span>
];</pre>
<div class="solution"><div class="solution-text">
<p><a class="p_ident" id="p_KWk09Gyhem" href="#p_KWk09Gyhem" tabindex="-1" role="presentation"></a>Since this is a CommonJS module, you have to use <code>require</code> to import the graph module. That was described as exporting a <code>buildGraph</code> function, which you can pick out of its interface object with a destructuring <code>const</code> declaration.</p>
<p><a class="p_ident" id="p_zdT6jLwIjp" href="#p_zdT6jLwIjp" tabindex="-1" role="presentation"></a>To export <code>roadGraph</code>, you add a property to the <code>exports</code> object. Because <code>buildGraph</code> takes a data structure that doesn’t precisely match <code>roads</code>, the splitting of the road strings must happen in your module.</p>
</div></div>
<h3><a class="i_ident" id="i_E/zWqBFdy8" href="#i_E/zWqBFdy8" tabindex="-1" role="presentation"></a>Circular dependencies</h3>
<p><a class="p_ident" id="p_fl2MZMonQV" href="#p_fl2MZMonQV" tabindex="-1" role="presentation"></a>A circular dependency is a situation where module A depends on B, and B also, directly or indirectly, depends on A. Many module systems simply forbid this because whichever order you choose for loading such modules, you cannot make sure that each module’s dependencies have been loaded before it runs.</p>
<p><a class="p_ident" id="p_b5sTJIUt38" href="#p_b5sTJIUt38" tabindex="-1" role="presentation"></a>CommonJS modules allow a limited form of cyclic dependencies. As long as the modules do not replace their default <code>exports</code> object and don’t access each other’s interface until after they finish loading, cyclic dependencies are okay.</p>
<p><a class="p_ident" id="p_s/oDnu78Ko" href="#p_s/oDnu78Ko" tabindex="-1" role="presentation"></a>The <code>require</code> function given <a href="10_modules.html#require">earlier in this chapter</a> supports this type of dependency cycle. Can you see how it handles cycles? What would go wrong when a module in a cycle <em>does</em> replace its default <code>exports</code> object?</p>
<div class="solution"><div class="solution-text">
<p><a class="p_ident" id="p_nf2U1lY9dq" href="#p_nf2U1lY9dq" tabindex="-1" role="presentation"></a>The trick is that <code>require</code> adds modules to its cache <em>before</em> it starts loading the module. That way, if any <code>require</code> call made while it is running tries to load it, it is already known, and the current interface will be returned, rather than starting to load the module once more (which would eventually overflow the stack).</p>
<p><a class="p_ident" id="p_QAZLbqVKnV" href="#p_QAZLbqVKnV" tabindex="-1" role="presentation"></a>If a module overwrites its <code>module.exports</code> value, any other module that has received its interface value before it finished loading will have gotten hold of the default interface object (which is likely empty), rather than the intended interface value.</p>
</div></div><nav><a href="09_regexp.html" title="previous chapter">◀</a> <a href="index.html" title="cover">◆</a> <a href="11_async.html" title="next chapter">▶</a></nav>
</article>