# ES module

[JS](..) ⟩ [module]() ⟩ ES module&#x20;

{% hint style="success" %}
[es6](../feature/es6 "mention")

<mark style="color:purple;">**ES modues**</mark> are supported by [browser](../../browser "mention")s and <mark style="color:orange;">**servers**</mark>, with a bit of <mark style="color:yellow;">**configuration**</mark>：

```markup
<!-- ⭐️ HTML (browser, client-side JS) -->
<!--    ╭──── ⭐️ ───╮ (module mode)    -->
<script type="module" src="script.js"></script>
```

```javascript
// ⭐️ (Node.js, server-side JS)
// - add this line to "package.json" file
"type": "module",
```
{% endhint %}

{% tabs %}
{% tab title="🔴 主題" %}
* [default](es/export/default "mention")
* [browser](browser "mention")
{% endtab %}

{% tab title="⭐️ 重點" %}
{% hint style="warning" %}
* ES module [**imports**](es/import) happen <mark style="color:red;">**before**</mark> a module’s <mark style="color:yellow;">**script starts running**</mark>.&#x20;
* [**import**](es/import) declarations <mark style="color:yellow;">**may**</mark>**&#x20;**<mark style="color:red;">**not**</mark> appear <mark style="color:yellow;">**inside**</mark> [**functions**](../val/func) or [**blocks**](../grammar/statement/other/block):exclamation:&#x20;
* <mark style="color:yellow;">**names**</mark> of <mark style="color:yellow;">**dependencies**</mark> <mark style="color:red;">**must**</mark>**&#x20;**<mark style="color:yellow;">**be**</mark> <mark style="color:orange;">**quoted strings**</mark>, <mark style="color:red;">**not**</mark>**&#x20;arbitrary** [**expressions**](../grammar/statement/expr):exclamation:
{% endhint %}

{% hint style="success" %}
<mark style="color:purple;">**ES module**</mark>

* allows you to have <mark style="color:red;">**both**</mark> [**default export**](es/export/default) and [**named exports**](es/export/named) in one module, <mark style="color:red;">**unlike**</mark> [commonjs](commonjs "mention").
* works only via <mark style="color:green;">**`http(s)://`**</mark>, <mark style="color:red;">**not**</mark> <mark style="color:yellow;">**locally**</mark> (<mark style="color:red;">**`file://`**</mark>)❗️
* <mark style="color:red;">**always**</mark> works in [strict-mode](../concept/env/js-engine/mode/strict-mode "mention")❗️
* has its <mark style="color:yellow;">**own**</mark> [top-level](../scope/top-level "mention"), <mark style="color:yellow;">**top-level variables**</mark> and <mark style="color:yellow;">**functions**</mark> from a <mark style="color:purple;">**module**</mark> are <mark style="color:red;">**not seen**</mark> in <mark style="color:yellow;">**other scripts**</mark>❗️
* should **export** what they want to be accessible from outside and **import** what they need.
* can make **global variables** by explicitly assigning them to **window**, e.g. **`window.user = "John"`** (not recommended❗️) (👉🏻 compare with **next** point❗️)
* If the **same module** is imported **multiple times**, its code is executed **only once**, upon the **first import**❗️(⭐️ **exports** are generated & **shared** between importers)
{% endhint %}

{% hint style="danger" %}
<mark style="color:purple;">**bare modules**</mark>

modules <mark style="color:red;">**without any path**</mark> are called “<mark style="color:yellow;">**bare**</mark>” modules.&#x20;

* such modules are <mark style="color:red;">**not allowed**</mark> in <mark style="color:yellow;">**import**</mark>.&#x20;
* **references** of <mark style="color:yellow;">**imported**</mark> JS files <mark style="color:red;">**must start with**</mark>**:** "<mark style="color:blue;">`/`</mark>", "<mark style="color:blue;">`./`</mark>", or "<mark style="color:blue;">`../`</mark>"❗️
{% endhint %}

{% hint style="info" %}
**Note:** _module scripts_ usually use the "**.mjs**" extension to signal that it’s a **module** rather than a regular script. **On the web**, file **extensions don’t really matter**, as long as the files are served with the **correct MIME type** (e.g. **text/javascript** for JS files) in the **Content-Type** HTTP header.

The "**.mjs**" extension is especially **useful** on other platforms such as [Node.js](https://nodejs.org/api/esm.html#esm_enabling) and [d8](https://v8.dev/docs/d8), where there’s **no** concept of **MIME types** or other mandatory hooks such as **type="module"** to determine whether something is a **module** or a **regular** script.\
📗 V8.dev ⟩ [Dynamic import()](https://v8.dev/features/dynamic-import)
{% endhint %}
{% endtab %}

{% tab title="👥 相關" %}
* :shield: <mark style="color:purple;">**ES module**</mark> <mark style="color:red;">**always**</mark> <mark style="color:yellow;">**works**</mark> in [strict-mode](../concept/env/js-engine/mode/strict-mode "mention").
* [CSS import](../../css/import)
* [shorthand](../val/obj/prop/shorthand "mention")
{% endtab %}

{% tab title="💈 範例" %}
```javascript
// ⭐️ import         ╭── ⭐️ ───╮
import {sayHi} from './sayHi.js';   // ⭐️ must start with: "/", "./", or "../"

// ⭐️ import all the exports
import * as moduleObj from './module.js'

// ⭐️ export
export { a, b };        // ⭐️ export { ... }
export { a as a2, b };  // ⭐️ export { A as B, ... }

// ⭐️ export default
export default obj;
import obj from "./module.js";    // ⭐️ without `{}`, not `{obj}`❗️
import defaultExport, {otherExport, ...} from "./module.js";
```

* replit ⟩&#x20;
  * [ES modules](https://replit.com/@pegasusroe/ES-Module#main.js)
  * [module in browser](https://replit.com/@pegasusroe/modules-in-browser#script.js)
{% endtab %}

{% tab title="📗 參考" %}
* [ ] JS.info ⟩&#x20;
  * [ ] [Modules](https://javascript.info/modules-intro)
  * [ ] [Export and Import](https://javascript.info/import-export)
  * [ ] [Dynamic imports](https://javascript.info/modules-dynamic-imports)
* [ ] V8.dev ⟩ [Dynamic import()](https://v8.dev/features/dynamic-import) ⭐️⭐️⭐️
* [ ] web.dev ⟩ [Using CSS Module Scripts to import stylesheets](https://web.dev/css-module-scripts/) ⭐️
* [ ] Kyle ⟩ [JS ES6 Modules](https://youtu.be/cRHQNNcYf6s) ⭐️
* [ ] MakeUseOf ⟩ [How to Import and Export Functions in JavaScript](https://www.makeuseof.com/how-to-import-and-export-functions-in-javascript/)
* [ ] [ydkjs-scope-and-closures-v.2](../../master/ref/book/you-dont-know-js-series-v.2/ydkjs-scope-and-closures-v.2 "mention") > Ch. 8 > [Modern ES Modules](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch8.md#modern-es-modules-esm)
{% endtab %}

{% tab title="📘 手冊" %}
* MDN ⟩&#x20;
  * import.[meta](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import.meta)
  * [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) statement
  * [\<script>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script) ⟩ [async](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-async) attribute
{% endtab %}
{% endtabs %}

## async scripts

{% hint style="info" %}
* **async** scripts **run immediately when ready**, **independently** of **other scripts** or the HTML **document**.
* **async** has **no effect** on **inline normal scripts**. For **module** scripts, it works on **inline** scripts **as well**. (👉🏻 See: tab 2️⃣ above)
{% endhint %}

## Cross-Origin Scripts

{% hint style="warning" %}
**Scripts** fetched from another origin (e.g. **another site**) require [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) headers, as described in the chapter [Fetch: Cross-Origin Requests](https://javascript.info/fetch-crossorigin).\
📗 JS.info ⟩ [External scripts](https://javascript.info/modules-intro#external-scripts)
{% endhint %}

```markup
<!-- another-site.com must supply Access-Control-Allow-Origin -->
<!-- otherwise, the script won't execute -->
<script type="module" src="http://another-site.com/their.js"></script>
```

##
