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: 1-js/13-modules/01-modules-intro/article.md
+39-32
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,7 @@
1
1
2
2
# Modules, introduction
3
3
4
-
As our application grows bigger, we want to split it into multiple files, so called 'modules'.
5
-
A module usually contains a class or a library of useful functions.
4
+
As our application grows bigger, we want to split it into multiple files, so called "modules". A module usually contains a class or a library of functions.
6
5
7
6
For a long time, JavaScript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple, so there was no need.
8
7
@@ -14,13 +13,15 @@ For instance:
14
13
-[CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.js server.
15
14
-[UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS.
16
15
17
-
Now all these slowly become a part of history, but we still can find them in old scripts. The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js.
16
+
Now all these slowly become a part of history, but we still can find them in old scripts.
17
+
18
+
The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. So we'll study it from now on.
18
19
19
20
## What is a module?
20
21
21
-
A module is just a file, a single script, as simple as that.
22
+
A module is just a file. One script is one module.
22
23
23
-
There are directives `export` and `import` to interchange functionality between modules, call functions of one module from another one:
24
+
Modules can load each other and use special directives `export` and `import` to interchange functionality, call functions of one module from another one:
24
25
25
26
-`export` keyword labels variables and functions that should be accessible from outside the current module.
26
27
-`import` allows to import functionality from other modules.
@@ -44,15 +45,17 @@ alert(sayHi); // function...
44
45
sayHi('John'); // Hello, John!
45
46
```
46
47
47
-
In this tutorial we concentrate on the language itself, but we use browser as the demo environment, so let's see how to use modules in the browser.
48
+
The `import` directive loads the module by path `./sayHi.js` relative the current file and assigns exported function `sayHi` to the corresponding variable.
49
+
50
+
Let's run the example in-browser.
48
51
49
52
As modules support special keywords and features, we must tell the browser that a script should be treated as module, by using the attribute `<script type="module">`.
The browser automatically fetches and evaluates imported modules, and then runs the script.
58
+
The browser automatically fetches and evaluates the imported module (and its imports if needed), and then runs the script.
56
59
57
60
## Core module features
58
61
@@ -70,8 +73,6 @@ Modules always `use strict`, by default. E.g. assigning to an undeclared variabl
70
73
</script>
71
74
```
72
75
73
-
Here we can see it in the browser, but the same is true for any module.
74
-
75
76
### Module-level scope
76
77
77
78
Each module has its own top-level scope. In other words, top-level variables and functions from a module are not seen in other scripts.
@@ -82,7 +83,7 @@ In the example below, two scripts are imported, and `hello.js` tries to use `use
82
83
83
84
Modules are expected to `export` what they want to be accessible from outside and `import` what they need.
84
85
85
-
So we should import `user.js`directly into `hello.js` instead of `index.html`.
86
+
So we should import `user.js` into `hello.js`and get the required functionality from it instead of relying on global variables.
86
87
87
88
That's the correct variant:
88
89
@@ -125,10 +126,10 @@ alert("Module is evaluated!");
125
126
import`./alert.js`; // Module is evaluated!
126
127
127
128
// 📁 2.js
128
-
import`./alert.js`; // (nothing)
129
+
import`./alert.js`; // (shows nothing)
129
130
```
130
131
131
-
In practice, top-level module code is mostly used for initialization. We create data structures, pre-fill them, and if we want something to be reusable -- export it.
132
+
In practice, top-level module code is mostly used for initialization, creation of internal data structures, and if we want something to be reusable -- export it.
132
133
133
134
Now, a more advanced example.
134
135
@@ -160,9 +161,9 @@ alert(admin.name); // Pete
160
161
*/!*
161
162
```
162
163
163
-
So, let's reiterate -- the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other modules will see that.
164
+
So, let's reiterate -- the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other modules will see that.
164
165
165
-
Such behavior is great for modules that require configuration. We can set required properties on the first import, and then in further imports it's ready.
166
+
Such behavior allows to *configure* modules on first import. We can setup its properties once, and then in further imports it's ready.
166
167
167
168
For instance, `admin.js` module may provide certain functionality, but expect the credentials to come into the `admin` object from outside:
168
169
@@ -175,14 +176,16 @@ export function sayHi() {
175
176
}
176
177
```
177
178
178
-
Now, in`init.js`, the first script of our app, we set `admin.name`. Then everyone will see it, including calls made from inside `admin.js` itself:
179
+
In`init.js`, the first script of our app, we set `admin.name`. Then everyone will see it, including calls made from inside `admin.js` itself:
179
180
180
181
```js
181
182
// 📁 init.js
182
183
import {admin} from'./admin.js';
183
184
admin.name="Pete";
184
185
```
185
186
187
+
Another module can also see `admin.name`:
188
+
186
189
```js
187
190
// 📁 other.js
188
191
import {admin, sayHi} from'./admin.js';
@@ -204,11 +207,13 @@ Its content depends on the environment. In the browser, it contains the url of t
204
207
</script>
205
208
```
206
209
207
-
### Top-level "this" is undefined
210
+
### In a module, "this" is undefined
208
211
209
212
That's kind of a minor feature, but for completeness we should mention it.
210
213
211
-
In a module, top-level `this` is undefined, as opposed to a global object in non-module scripts:
214
+
In a module, top-level `this` is undefined.
215
+
216
+
Compare it to non-module scripts, where `this` is a global object:
212
217
213
218
```html run height=0
214
219
<script>
@@ -224,14 +229,14 @@ In a module, top-level `this` is undefined, as opposed to a global object in non
224
229
225
230
There are also several browser-specific differences of scripts with `type="module"` compared to regular ones.
226
231
227
-
You may want skip those for now if you're reading for the first time, or if you don't use JavaScript in a browser.
232
+
You may want skip this section for now if you're reading for the first time, or if you don't use JavaScript in a browser.
228
233
229
234
### Module scripts are deferred
230
235
231
236
Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:script-async-defer)), for both external and inline scripts.
232
237
233
238
In other words:
234
-
- external module scripts `<script type="module" src="...">`don't block HTML processing, they load in parallel with other resources.
239
+
- downloading of external module scripts `<script type="module" src="...">`doesn't block HTML processing, they load in parallel with other resources.
235
240
- module scripts wait until the HTML document is fully ready (even if they are tiny and load faster than HTML), and then run.
236
241
- relative order of scripts is maintained: scripts that go first in the document, execute first.
237
242
@@ -263,11 +268,13 @@ Please note: the second script actually works before the first! So we'll see `un
263
268
264
269
That's because modules are deferred, so way wait for the document to be processed. The regular scripts runs immediately, so we saw its output first.
265
270
266
-
When using modules, we should be aware that HTML-page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put transparent overlays or "loading indicators", or otherwise ensure that the visitor won't be confused by that.
271
+
When using modules, we should be aware that HTML-page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put "loading indicators", or otherwise ensure that the visitor won't be confused by that.
267
272
268
273
### Async works on inline scripts
269
274
270
-
Async attribute `<script async type="module">` is allowed on both inline and external scripts. Async scripts run immediately when imported modules are processed, independently of other scripts or the HTML document.
275
+
For non-module scripts, `async` attribute only works on external scripts. Async scripts run immediately when ready, independently of other scripts or the HTML document.
276
+
277
+
For module scripts, it works on any scripts.
271
278
272
279
For example, the script below has `async`, so it doesn't wait for anyone.
273
280
@@ -287,7 +294,7 @@ That's good for functionality that doesn't depend on anything, like counters, ad
287
294
288
295
### External scripts
289
296
290
-
There are two notable differences of external module scripts:
297
+
External scripts that have `type="module"` are different in two aspects:
291
298
292
299
1. External scripts with same `src` run only once:
293
300
```html
@@ -296,7 +303,7 @@ There are two notable differences of external module scripts:
296
303
<script type="module" src="my.js"></script>
297
304
```
298
305
299
-
2. External scripts that are fetched from another origin (e.g. another site) require [CORS](mdn:Web/HTTP/CORS) headers, as described in the chapter <info:fetch-crossorigin>. In other words, if a module script is fetched from another origin, the remote server must supply a header `Access-Control-Allow-Origin: *` (may use site domain instead of `*`) to indicate that the fetch is allowed.
306
+
2. External scripts that are fetched from another origin (e.g. another site) require [CORS](mdn:Web/HTTP/CORS) headers, as described in the chapter <info:fetch-crossorigin>. In other words, if a module script is fetched from another origin, the remote server must supply a header `Access-Control-Allow-Origin` allowing the fetch.
300
307
```html
301
308
<!-- another-site.com must supply Access-Control-Allow-Origin -->
302
309
<!-- otherwise, the script won't execute -->
@@ -332,13 +339,6 @@ Old browsers do not understand `type="module"`. Scripts of the unknown type are
332
339
</script>
333
340
```
334
341
335
-
If we use bundle tools, then as scripts are bundled together into a single file (or few files), `import/export` statements inside those scripts are replaced by special bundler functions. So the resulting "bundled" script does not contain any `import/export`, it doesn't require `type="module"`, and we can put it into a regular script:
336
-
337
-
```html
338
-
<!-- Assuming we got bundle.js from a tool like Webpack -->
339
-
<script src="bundle.js"></script>
340
-
```
341
-
342
342
## Build tools
343
343
344
344
In real-life, browser modules are rarely used in their "raw" form. Usually, we bundle them together with a special tool such as [Webpack](https://webpack.js.org/) and deploy to the production server.
@@ -357,13 +357,20 @@ Build tools do the following:
357
357
- Modern, bleeding-edge JavaScript syntax may be transformed to older one with similar functionality using [Babel](https://babeljs.io/).
358
358
- The resulting file is minified (spaces removed, variables replaced with shorter named etc).
359
359
360
+
If we use bundle tools, then as scripts are bundled together into a single file (or few files), `import/export` statements inside those scripts are replaced by special bundler functions. So the resulting "bundled" script does not contain any `import/export`, it doesn't require `type="module"`, and we can put it into a regular script:
361
+
362
+
```html
363
+
<!-- Assuming we got bundle.js from a tool like Webpack -->
364
+
<script src="bundle.js"></script>
365
+
```
366
+
360
367
That said, native modules are also usable. So we won't be using Webpack here: you can configure it later.
361
368
362
369
## Summary
363
370
364
371
To summarize, the core concepts are:
365
372
366
-
1. A module is a file. To make `import/export` work, browsers need `<script type="module">`, that implies several differences:
373
+
1. A module is a file. To make `import/export` work, browsers need `<script type="module">`. Modules have several differences:
367
374
- Deferred by default.
368
375
- Async works on inline scripts.
369
376
- To load external scripts from another origin (domain/protocol/port), CORS headers are needed.
@@ -372,7 +379,7 @@ To summarize, the core concepts are:
372
379
3. Modules always `use strict`.
373
380
4. Module code is executed only once. Exports are created once and shared between importers.
374
381
375
-
So, generally, when we use modules, each module implements the functionality and exports it. Then we use `import` to directly import it where it's needed. Browser loads and evaluates the scripts automatically.
382
+
When we use modules, each module implements the functionality and exports it. Then we use `import` to directly import it where it's needed. Browser loads and evaluates the scripts automatically.
376
383
377
384
In production, people often use bundlers such as [Webpack](https://webpack.js.org) to bundle modules together for performance and other reasons.
Copy file name to clipboardExpand all lines: 2-ui/1-document/02-dom-nodes/article.md
+34-19
Original file line number
Diff line number
Diff line change
@@ -8,15 +8,25 @@ libs:
8
8
9
9
The backbone of an HTML document are tags.
10
10
11
-
According to Document Object Model (DOM), every HTML-tag is an object. Nested tags are called "children" of the enclosing one.
11
+
According to Document Object Model (DOM), every HTML-tag is an object. Nested tags are "children" of the enclosing one. The text inside a tag it is an object as well.
12
12
13
-
The text inside a tag it is an object as well.
13
+
All these objects are accessible using JavaScript, we can use them to modify the page.
14
14
15
-
All these objects are accessible using JavaScript.
15
+
For example, `document.body` is the object representing `<body>` tag.
16
+
17
+
Running this code will make the `<body>` red for 3 seconds:
18
+
19
+
```js run
20
+
document.body.style.background='red'; // make the background red
21
+
22
+
setTimeout(() =>document.body.style.background='', 3000); // return back
23
+
```
24
+
25
+
That was just a glimpse of DOM power. Soon we'll learn more ways to manipulate DOM, but first we need to know about its structure.
16
26
17
27
## An example of DOM
18
28
19
-
For instance, let's explore the DOM for this document:
On the picture above, you can click on element nodes and their children will open/collapse.
45
55
```
46
56
47
-
Tags are called *element nodes* (or just elements). Nested tags become children of the enclosing ones. As a result we have a tree of elements: `<html>` is at the root, then `<head>` and `<body>` are its children, etc.
57
+
Every tree node is an object.
58
+
59
+
Tags are *element nodes* (or just elements), they form the tree structure: `<html>` is at the root, then `<head>` and `<body>` are its children, etc.
48
60
49
61
The text inside elements forms *text nodes*, labelled as `#text`. A text node contains only a string. It may not have children and is always a leaf of the tree.
50
62
@@ -55,7 +67,7 @@ Please note the special characters in text nodes:
55
67
- a newline: `↵` (in JavaScript known as `\n`)
56
68
- a space: `␣`
57
69
58
-
Spaces and newlines -- are totally valid characters, they form text nodes and become a part of the DOM. So, for instance, in the example above the `<head>` tag contains some spaces before `<title>`, and that text becomes a `#text` node (it contains a newline and some spaces only).
70
+
Spaces and newlines -- are totally valid characters, like letters and digits. They form text nodes and become a part of the DOM. So, for instance, in the example above the `<head>` tag contains some spaces before `<title>`, and that text becomes a `#text` node (it contains a newline and some spaces only).
59
71
60
72
There are only two top-level exclusions:
61
73
1. Spaces and newlines before `<head>` are ignored for historical reasons,
@@ -78,15 +90,14 @@ let node2 = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,
78
90
drawHtmlTree(node2, 'div.domtree', 690, 210);
79
91
</script>
80
92
81
-
```smart header="Edge spaces and in-between empty text are usually hidden in tools"
93
+
```smart header="Spaces at string start/end and space-only text nodes are usually hidden in tools"
82
94
Browser tools (to be covered soon) that work with DOM usually do not show spaces at the start/end of the text and empty text nodes (line-breaks) between tags.
83
95
84
-
That's because they are mainly used to decorate HTML, and do not affect how it is shown (in most cases).
96
+
Developer tools save screen space this way.
85
97
86
-
On further DOM pictures we'll sometimes omit them where they are irrelevant, to keep things short.
98
+
On further DOM pictures we'll sometimes omit them when they are irrelevant. Such spaces usually do not affect how the document is displayed.
87
99
```
88
100
89
-
90
101
## Autocorrection
91
102
92
103
If the browser encounters malformed HTML, it automatically corrects it when making DOM.
@@ -148,7 +159,9 @@ You see? The `<tbody>` appeared out of nowhere. You should keep this in mind whi
148
159
149
160
## Other node types
150
161
151
-
Let's add more tags and a comment to the page:
162
+
There are some other node types besides elements and text nodes.
163
+
164
+
For example, comments:
152
165
153
166
```html
154
167
<!DOCTYPE HTML>
@@ -174,7 +187,7 @@ let node6 = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,
174
187
drawHtmlTree(node6, 'div.domtree', 690, 500);
175
188
</script>
176
189
177
-
Here we see a new tree node type -- *comment node*, labeled as `#comment`.
190
+
We can see here a new tree node type -- *comment node*, labeled as `#comment`, between two text nodes.
178
191
179
192
We may think -- why is a comment added to the DOM? It doesn't affect the visual representation in any way. But there's a rule -- if something's in HTML, then it also must be in the DOM tree.
180
193
@@ -195,8 +208,6 @@ There are [12 node types](https://dom.spec.whatwg.org/#node). In practice we usu
195
208
196
209
To see the DOM structure in real-time, try [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Just type in the document, and it will show up DOM at an instant.
197
210
198
-
## In the browser inspector
199
-
200
211
Another way to explore the DOM is to use the browser developer tools. Actually, that's what we use when developing.
201
212
202
213
To do so, open the web-page [elks.html](elks.html), turn on the browser developer tools and switch to the Elements tab.
@@ -225,20 +236,24 @@ The best way to study them is to click around. Most values are editable in-place
225
236
226
237
## Interaction with console
227
238
228
-
As we explore the DOM, we also may want to apply JavaScript to it. Like: get a node and run some code to modify it, to see the result. Here are few tips to travel between the Elements tab and the console.
239
+
As we work the DOM, we also may want to apply JavaScript to it. Like: get a node and run some code to modify it, to see the result. Here are few tips to travel between the Elements tab and the console.
229
240
230
-
- Select the first `<li>` in the Elements tab.
231
-
- Press `key:Esc` -- it will open console right below the Elements tab.
241
+
For the start:
242
+
243
+
1. Select the first `<li>` in the Elements tab.
244
+
2. Press `key:Esc` -- it will open console right below the Elements tab.
232
245
233
246
Now the last selected element is available as `$0`, the previously selected is `$1` etc.
234
247
235
248
We can run commands on them. For instance, `$0.style.background = 'red'` makes the selected list item red, like this:
236
249
237
250

238
251
239
-
From the other side, if we're in console and have a variable referencing a DOM node, then we can use the command `inspect(node)` to see it in the Elements pane.
252
+
That's how to get a node from Elements in Console.
253
+
254
+
There's also a road back. If there's a variable referencing a DOM node, then we can use the command `inspect(node)` in Console to see it in the Elements pane.
240
255
241
-
Or we can just output it in the console and explore "at-place", like `document.body` below:
256
+
Or we can just output DOM-node in the console and explore "at-place", like `document.body` below:
0 commit comments