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
3.1k
require(ESM)とECMAScript仕様
Meguro.es #27 @ oRo
uhyo
April 25, 2024
Tweet
Share
More Decks by uhyo
See All by uhyo
タグ付きユニオン型を便利に使うテクニックとその注意点
uhyo
2
930
ECMAScript仕様の最新動向: プロセスの変化と仕様のトレンド
uhyo
3
760
TypeScript 6.0で非推奨化されるオプションたち
uhyo
17
6.8k
Claude Code 10連ガチャ
uhyo
5
1k
AI時代、“平均値”ではいられない
uhyo
8
3.7k
意外と難しいGraphQLのスカラー型
uhyo
5
1k
RSCの時代にReactとフレームワークの境界を探る
uhyo
13
4.8k
知られざるprops命名の慣習 アクション編
uhyo
12
3.4k
libsyncrpcってなに?
uhyo
0
790
Other Decks in Technology
See All in Technology
M&A 後の統合をどう進めるか ─ ナレッジワーク × Poetics が実践した組織とシステムの融合
kworkdev
PRO
1
430
生成AI時代にこそ求められるSRE / SRE for Gen AI era
ymotongpoo
5
3.2k
ZOZOにおけるAI活用の現在 ~開発組織全体での取り組みと試行錯誤~
zozotech
PRO
5
5.4k
Context Engineeringの取り組み
nutslove
0
340
セキュリティについて学ぶ会 / 2026 01 25 Takamatsu WordPress Meetup
rocketmartue
1
300
AzureでのIaC - Bicep? Terraform? それ早く言ってよ会議
torumakabe
1
530
ブロックテーマ、WordPress でウェブサイトをつくるということ / 2026.02.07 Gifu WordPress Meetup
torounit
0
180
プロダクト成長を支える開発基盤とスケールに伴う課題
yuu26
4
1.3k
Cosmos World Foundation Model Platform for Physical AI
takmin
0
870
顧客の言葉を、そのまま信じない勇気
yamatai1212
1
350
学生・新卒・ジュニアから目指すSRE
hiroyaonoe
2
600
レガシー共有バッチ基盤への挑戦 - SREドリブンなリアーキテクチャリングの取り組み
tatsukoni
0
210
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1032
470k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
Embracing the Ebb and Flow
colly
88
5k
Context Engineering - Making Every Token Count
addyosmani
9
650
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
62
YesSQL, Process and Tooling at Scale
rocio
174
15k
Music & Morning Musume
bryan
47
7.1k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
290
Designing for Performance
lara
610
70k
Typedesign – Prime Four
hannesfritz
42
2.9k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.6k
Statistics for Hackers
jakevdp
799
230k
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の中⾝を同期的に⾒るというずるが必要になるが、 多分実装でカバーできる) 安⼼して使おう!