You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: chapters/ch09.asciidoc
+23-11Lines changed: 23 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ A while later, the RequireJS library was born. It provided a way of defining the
7
7
8
8
Other complexity management mechanisms exist, such as the dependency injection mechanism in AngularJS, where you define named components using functions where you can, in turn, specify other named component dependencies. AngularJS carries the load of dependency injection on your behalf, so you only have to name components and specify dependencies.
9
9
10
-
CommonJS surfaced as an alternative to RequireJS, and it was swiftly popularized by Node.js soon afterwards. In this chapter we'll take a look at CommonJS, which is still heavily in use today. We'll then cover the module system introduced to native JavaScript in ES6, and lastly we'll explore interoperability between CommonJS and native JavaScript modules -- also known as "ES modules".
10
+
CommonJS (CJS) surfaced as an alternative to RequireJS, and it was swiftly popularized by Node.js soon afterwards. In this chapter we'll take a look at CommonJS, which is still heavily in use today. We'll then cover the module system introduced to native JavaScript in ES6, and lastly we'll explore interoperability between CommonJS and native JavaScript modules -- also known as ECMAScript modules (ESM).
11
11
12
12
=== 9.1 CommonJS
13
13
@@ -49,7 +49,7 @@ node app
49
49
# [1, 2]
50
50
----
51
51
52
-
The +require+ function in CommonJS modules can be treated dynamically, just like any other JavaScript function. This aspect of +require+ is sometimes leveraged to dynamically +require+ different modules that conform to one interface. As an example, let's conjure up a +templates+ directory with a number of view template functions. Our templates will take a model and return an HTML string.
52
+
The +require+ function in CJS can be treated dynamically, just like any other JavaScript function. This aspect of +require+ is sometimes leveraged to dynamically +require+ different modules that conform to one interface. As an example, let's conjure up a +templates+ directory with a number of view template functions. Our templates will take a model and return an HTML string.
53
53
54
54
The template found in the following code snippet renders an item of a grocery shopping list by reading its attributes from a +model+ object.
55
55
@@ -145,7 +145,7 @@ console.log(render(`list`, [{
145
145
146
146
image::../images/c09g03-dynamic-render.png["Printing different views through a normalized render function."]
147
147
148
-
Moving on, you'll notice that ES6 modules are heavily influenced by CommonJS. In the next few sections we'll look at +export+ and +import+ statements, and learn how ES6 modules are compatible with CommonJS.
148
+
Moving on, you'll notice that ES6 modules are heavily influenced by CommonJS. In the next few sections we'll look at +export+ and +import+ statements, and learn how ESM is compatible with CJS.
ES6 modules are files that may expose an API through +export+ statements. Declarations in ES6 modules are scoped to that module, just like we observed about CommonJS. Any variables declared inside a module aren't available to other modules unless they're explicitly exported as part of that module's API and then imported in the module that wants to access them.
200
+
ES6 modules are files that may expose an API through +export+ statements. Declarations in ESM are scoped to the local module, just like we observed about CommonJS. Any variables declared inside a module aren't available to other modules unless they're explicitly exported as part of that module's API and then imported in the module that wants to access them.
201
201
202
202
===== Exporting a Default Binding
203
203
@@ -233,7 +233,7 @@ function initialize () {
233
233
initialize()
234
234
----
235
235
236
-
In contrast with CommonJS, +export+ statements in ES6 modules can only be placed at the top level. "Top-level only" +export+ statements is a good constraint to have, as there aren't many good reasons to dynamically define and expose an API based on method calls. This limitation also helps compilers and static analysis tools parse ES6 modules.
236
+
In contrast with CJS, +export+ statements in ESM can only be placed at the top level. "Top-level only" +export+ statements is a good constraint to have, as there aren't many good reasons to dynamically define and expose an API based on method calls. This limitation also helps compilers and static analysis tools parse ES6 modules.
237
237
238
238
[source,javascript]
239
239
----
@@ -243,19 +243,19 @@ function initialize () {
243
243
initialize()
244
244
----
245
245
246
-
There are a few other ways of exposing an API in ES6 modules, besides +export default+ statements.
246
+
There are a few other ways of exposing an API in ESM, besides +export default+ statements.
247
247
248
248
===== Named Exports
249
249
250
-
In CommonJS modules, when you want to expose multiple values, you don't necessarily need to explicitly export an object containing every one of those values. You could simply add properties onto the implicit +module.exports+ object. There's still a single binding being exported, containing all properties the +module.exports+ object ends up holding. While the following example exports two individual values, both are exposed as properties on the exported object.
250
+
When you want to expose multiple values from CJS modules you don't necessarily need to explicitly export an object containing every one of those values. You could simply add properties onto the implicit +module.exports+ object. There's still a single binding being exported, containing all properties the +module.exports+ object ends up holding. While the following example exports two individual values, both are exposed as properties on the exported object.
251
251
252
252
[source,javascript]
253
253
----
254
254
module.exports.counter = 0
255
255
module.exports.count = () => counter++
256
256
----
257
257
258
-
We can replicate this behavior in ES6 modules by using the named exports syntax. Instead of assigning properties to an implicit +module.exports+ object like with CommonJS, in ES6 you declare the bindings you want to +export+, as shown in the following code snippet.
258
+
We can replicate this behavior in ESM by using the named exports syntax. Instead of assigning properties to an implicit +module.exports+ object like with CommonJS, in ES6 you declare the bindings you want to +export+, as shown in the following code snippet.
259
259
260
260
[source,javascript]
261
261
----
@@ -273,7 +273,7 @@ export counter // SyntaxError
273
273
export count
274
274
----
275
275
276
-
By being rigid in how its declarative module syntax works, ES6 modules favor static analysis once again at the expense of flexibility. Flexibility inevitably comes at the cost of added complexity, which is a good reason not to offer flexible interfaces.
276
+
By being rigid in how its declarative module syntax works, ESM favors static analysis, once again at the expense of flexibility. Flexibility inevitably comes at the cost of added complexity, which is a good reason not to offer flexible interfaces.
277
277
278
278
===== Exporting Lists
279
279
@@ -348,7 +348,7 @@ You can give aliases to named exports, as they pass through your module. If the
348
348
export { increment as add } from './counter'
349
349
----
350
350
351
-
Our modules could also expose every single named export found in another module by using a wildcard, as shown in the next snippet. Note that this wouldn't include the default binding exported by the +counter+ module.
351
+
An ESM module could also expose every single named export found in another module by using a wildcard, as shown in the next snippet. Note that this wouldn't include the default binding exported by the +counter+ module.
352
352
353
353
[source,javascript]
354
354
----
@@ -446,7 +446,19 @@ You can also explicitly name the +default+ binding, which needs an alias.
446
446
import { default as counter, increment } from './counter'
447
447
----
448
448
449
-
We also have namespace imports.
449
+
The following example demonstrates how ESM semantics differ from those of CJS. Remember: we're exporting and importing bindings, and not direct references. For practical purposes, you can think of the +counter+ binding found in the next example as a property getter that reaches into the +counter+ module and returns its local +counter+ variable.
0 commit comments