Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
require(ESM)とECMAScript仕様
Search
uhyo
April 25, 2024
Technology
7
2.1k
require(ESM)とECMAScript仕様
Meguro.es #27 @ oRo
uhyo
April 25, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
React 19 + Jotaiを試して気づいた注意点
uhyo
9
2.6k
TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論
uhyo
3
2.1k
tsconfig.jsonの最近の新機能 ファイルパス編
uhyo
7
3k
非同期処理を活用しながらRust製wasmとJSを連携する方法(wasm-bindgenを使いたくない人向け)
uhyo
4
4k
tsconfig.jsonの設定を見直そう!フロントエンド向け 2024夏
uhyo
26
9.8k
React 19を概念から理解する
uhyo
22
10k
TypeScript Quiz (Encraft #12 Frontend Quiz Night)
uhyo
8
1.7k
Shadow DOMとCSSの現状
uhyo
11
7.6k
TypeScriptってどんな言語? 言語そのものを知る面白さ
uhyo
16
9k
Other Decks in Technology
See All in Technology
Oracle Exadata Database Service(Dedicated Infrastructure):サービス概要のご紹介
oracle4engineer
PRO
0
12k
My small contributions - Fujiwara Tech Conference 2025
ijin
0
1.5k
Docker Desktop で Docker を始めよう
zembutsu
PRO
1
210
EMConf JP の楽しみ方 / How to enjoy EMConf JP
pauli
2
160
Building Scalable Backend Services with Firebase
wisdommatt
0
110
dbtを中心にして組織のアジリティとガバナンスのトレードオンを考えてみた
gappy50
0
350
re:Invent2024 KeynoteのAmazon Q Developer考察
yusukeshimizu
1
170
LLM活用の現在とこれから:LayerXにおける事例とともに 2025/1 ver. / layerx-llm-202501
yuya4
3
180
WantedlyでのKotlin Multiplatformの導入と課題 / Kotlin Multiplatform Implementation and Challenges at Wantedly
kubode
0
260
Oracle Base Database Service:サービス概要のご紹介
oracle4engineer
PRO
1
16k
20250116_自部署内でAmazon Nova体験会をやってみた話
riz3f7
1
130
AWSマルチアカウント統制環境のすゝめ / 20250115 Mitsutoshi Matsuo
shift_evolve
0
120
Featured
See All Featured
Building Your Own Lightsaber
phodgson
104
6.2k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
3k
Documentation Writing (for coders)
carmenintech
67
4.5k
Rails Girls Zürich Keynote
gr2m
94
13k
Designing Experiences People Love
moore
139
23k
4 Signs Your Business is Dying
shpigford
182
22k
Building Flexible Design Systems
yeseniaperezcruz
328
38k
We Have a Design System, Now What?
morganepeng
51
7.3k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
Automating Front-end Workflow
addyosmani
1366
200k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.3k
Transcript
require(ESM)とECMAScript仕様 2024-04-25 Meguro.es #27 @ oRo
発表者紹介 uhyo 株式会社カオナビ フロントエンドエンジニア 普段はTypeScriptとかReactをやっている。 好きな⾔語機能はジェネレータ関数。
JavaScriptの最近のニュース Node.jsが require(ESM) のサポートを追加。 require先がtop-level awaitを含まない ESモジュール (sync ESM) であれば、
CJSファイルからrequireできる。
This Talk require(ESM) って、ECMAScript仕様の視点で ⾒るとどういうことなんだっけ? を解説します
CJSとかESMの復習
ScriptとModule ECMAScript仕様上、JavaScriptプログラムは 2種類に分類される。 •Script: 昔からあるやつ •Module: import/exportが使えるやつ 両者は構⽂レベルで異なる。 (importなどをScriptで使うのは構⽂エラー)
ScriptとModule ScriptかModuleかは外的要因によって決まる (ことが多い) HTML <script> // Scriptとしてパースされる </script> <script type=“module”>
// Moduleとしてパースされる </script> Node.js foo.cjs // Scriptとしてパースされる bar.mjs // Moduleとしてパースされる
ESモジュールグラフ import/exportでつながるモジュールグラフが形成 される。
モジュールの種類 モジュールはJavaScriptファイルとは限らない。 .js .js .mjs .js .js .js .html .json
.wasm .css
モジュールの種類 ECMAScriptでは3種類に分類される。 (下は上の部分クラス) (Abstract) Module Record … 全てのモジュール Cyclic Module
Record … 他のモジュールをimport可能 Source Text Module Record … JavaScriptで書かれた モジュール ※ 厳密に⾔えばAbstract Module Recordも他のモジュールに依存可能だが、ES仕様で扱う依存グラフには表れない
モジュールの種類 .js .js .mjs .js .js .js .html .json .wasm
.css
Node.jsのCJSとESMの関係は? CommonJSのモジュールはECMAScriptモジュー ルではない。ECMAScript側から⾒たらどういう 扱いなのか? .mjs .cjs 特にこうやってESMからCJSをimportする場合
Node.jsのCJSとESMの関係は? 多分CommonJSモジュールはESMから⾒たら Abstract Module Recordに相当する。 .mjs .cjs
モジュールの種類と仕様 (Abstract) Module Record … 全部ホスト依存 Cyclic Module Record …
モジュールグラフの探索周り は仕様で明記 Source Text Module Record … 全部仕様で明記 この仕様により、JS以外のモジュールを扱うことができ る。JS以外のモジュールの挙動は、⼀部または全部が ホスト依存となる。 ※ ESモジュールのホストの例: Node.js、HTML仕様、webpackなど
Node.jsのCJS Abstract Module Recordの挙動は、仕様で 決められた制約を守ればホスト環境の⾃由。 つまり、.cjsから何がexportされるのかとか、 同期的に実⾏されるといった詳細はNode.jsが ⾃由に決められる。 .mjs .cjs
本題
require(ESM)の仕様上の解釈 require(“./module.mjs”)のようにすると、 module.mjsが同期的に実⾏される。 このことをES仕様に沿って記述できるか? ES仕様と⽭盾する処理にはならないのか? が気になる
既存の類例 ⾮モジュールからモジュールを実⾏する機能と して、import()がすでに存在する。 この構⽂であれば、ScriptからでもModuleを 実⾏できる。もちろんNode.jsのCJSからでも。 import(“module”).then(mod => …) “module”をモジュール解決して実⾏し、モジュール名前空間オ ブジェクトに解決されるPromiseを返す
import()の仕様レベルの挙動
import()の仕様レベルの挙動 import(“module”) HostLoadImportedModule … モジュール解決してModule Recordを取得 module.LoadRequestedModules() … 依存モジュール読み込み module.Link()
… Environment Recordを初期化 module.Evaluate() … モジュールグラフに従って実⾏ ざっくりこの4段階でモジュールを実⾏できる。
HTML仕様の例 HTML仕様でも、モジュールを実⾏することはEvaluate()で表現 (LoadRequestedModulesとLinkは別のところで呼んでる)
ES仕様におけるモジュールの実⾏ module.Evaluate()を呼び出すことでモジュールが実 ⾏される。Evaluateには次の制約がある。 •Promiseを返す。モジュールの実⾏が完了すると fulfillする • Evaluateを呼ぶ前にLinkの呼び出しが成功して いる必要がある
ES仕様におけるモジュールの実⾏ module.Link()はモジュールの実⾏の準備をする。 Linkには次の制約がある。 • Linkを呼ぶ前にLoadRequestedModulesの 呼び出しが成功している必要がある
ES仕様におけるモジュールの実⾏ module.LoadRequestedModules()はモジュールの 依存先を全部読み込む。Promiseを返す。 LoadRequestedModulesはホスト定義の HostLoadImportedModuleを利⽤して実際の 読み込みを⾏う。 (HostLoadImportedModule⾃体は同期的にも⾮同期的にも 動作可能と定義されている)
ES仕様におけるモジュールの実⾏ 仕様上の制約として、この順に実⾏する必要がある。 HostLoadImportedModule ↑利⽤ module.LoadRequestedModules() ↑前提 module.Link() ↑前提 module.Evaluate()
ES仕様におけるモジュールの実⾏ require(ESM)の処理をES仕様で記述する場合も制約を守る必要がある。 HostLoadImportedModule ↑利⽤ module.LoadRequestedModules() ↑前提 module.Link() ↑前提 module.Evaluate()
ES仕様におけるモジュールの実⾏ HostLoadImportedModule 同期実⾏可能 ↑利⽤ module.LoadRequestedModules() Promiseを返す ↑前提 module.Link() 同期実⾏ ↑前提
module.Evaluate() Promiseを返す
ES仕様におけるモジュールの実⾏ HostLoadImportedModule 同期実⾏可能 ↑利⽤ module.LoadRequestedModules() Promiseを返す ↑前提 module.Link() 同期実⾏ ↑前提
module.Evaluate() Promiseを返す
Evaluate()の同期実⾏ 実はsync ESMのみをサポートする前例が Service Workerに存在する。 モジュールをService Workerとして登録する場合、 TLAを含むモジュールを登録することはできない。
Service Workerの仕様を⾒る 登録されたモジュールを実⾏するところの仕様
Service Workerの仕様を⾒る module.Evaluate()の結果のPromise 最初から解決済
Sync ESMのEvaluate() 実はES仕様では、TLAを持たないSource Text Module RecordのEvaluate()は、最初から 解決済みのPromiseを返すことが保証されている。 (=TLAを含まないモジュールグラフは仕様上同期的に 実⾏できる) Evaluate()が返したPromiseをもらった瞬間に
捨てればOK。
ES仕様におけるモジュールの実⾏ HostLoadImportedModule 同期実⾏可能 ↑利⽤ module.LoadRequestedModules() Promiseを返す ↑前提 module.Link() 同期実⾏ ↑前提
module.Evaluate() Promiseを返す
LoadRequestedModules()の定義を⾒る
ES仕様におけるモジュールの実⾏ 詳細は省くが、HostLoadImportedModule()が同期的に動く 環境であれば、 LoadRequestedModules()が返すPromiseも 最初から解決されている。 こちらも同期的に実⾏可能。 (返ってきたPromiseはやはり捨てる)
補⾜: エラー処理について どちらも返ってきたPromiseを捨てることで同期的に 処理可能だが、エラーの場合の対応は必要。 そこは処理系特権でPromiseの中⾝を同期的に確認し、 エラー処理を⾏う。
まとめ
まとめ Node.jsが新たに実装したrequire(ESM)は、 実装されてもECMAScript仕様とは⽭盾しないことが 分かった。 (仕様上Promiseの中⾝を同期的に⾒るというずるが必要になるが、 多分実装でカバーできる) 安⼼して使おう!