Ce diaporama a bien été signalé.
Le téléchargement de votre SlideShare est en cours. ×

Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜

Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité

Consultez-les par la suite

1 sur 30 Publicité

Plus De Contenu Connexe

Diaporamas pour vous (20)

Similaire à Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜 (18)

Publicité

Plus par Teppei Sato (20)

Plus récents (20)

Publicité

Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜

  1. 1. Na#ve ESM への道 ∼ 最終章: Babel / TypeScript Modules との闘い ∼ Node 学園 35 時限目 / 2021-02-24 @teppeis 1
  2. 2. 自己紹介 • @teppeis / Teppei Sato • サイボウズから来ました。 • もちろん We are hiring!!! • プロダクト開発チーム • フロントエンドエキスパートチーム 2
  3. 3. Node.js の ES Modules 対応って どうなったの? 3
  4. 4. 前回までのあらすじ 2015 年の ES Modules (ESM) 策定からときは流れ、Node.js での ESM 対応は混迷を極めた1 。 しかし 2018 年 10 月、 Node.js Modules Team は ESM 対応計画 2 を なんとかまとめあげ、ようやく実装が進んでいった。 そして 2020 年末にはその計画が実装完了し、2021 年は Na8ve ESM 時代が到来するかに見えた。 2 Plan for New Modules Implementa5on · nodejs/modules 1 前回スライドを参照: You Don't Know ES Modules, Teppei Sato (2016) 4
  5. 5. Node.js ESM 実装状況 基本機能は Node v12.20+, v14.13+ で フラグ無し で提供済み3 • Na$ve ESM import / export • CommonJS interoperability (CJS Interop) • package.json imports / exports mapping 3 ESM import / export と CJS interop は v15 系で stability: stable, v12, v14 系は次の minor リリースで stable になる 予定。imports / exports mapping は v15 系で stable になったが v12, v14 は未定。 5
  6. 6. 2021 年は Na've ESM の時代に? • 前述の通り、Node v12 系以上は ESM を実装済み • Node v10 は 2021-04-30 に EOL • つまり、5 月以降は全 Node 環境で Na5ve ESM が利用可能! • やったー、全部 ESM で書こうぜー 6
  7. 7. h"ps:/ /blog.sindresorhus.com/get-ready-for-esm-aa53530b3f77 7
  8. 8. h"ps:/ /twi"er.com/jus2nfagnani/status/1356012934564958212 8
  9. 9. そんな風に思っていた時期が 私にもありました。 9
  10. 10. 鬼門: CJS Interop 10
  11. 11. CJS Interop CJS から ESM へスムーズな移行を進めるために検討されてきた相 互互換機能 • CJS から ESM をロードできる • ESM から CJS をロードできる 仕様の複雑さと既存パッケージとの互換性から、ここまで Node の ESM 対応を遅らせてきた鬼門でもある 11
  12. 12. import ESM from CJS // esm.mjs export default "foo"; export const named = "bar"; // cjs.js const { default: def, named } = await import("./esm.mjs"); //// def: "foo" //// named: "bar" • dynamic import を使用 • ESM と同じ使い勝手で、違和感はない 12
  13. 13. import CJS from ESM: named import // cjs.js exports.named = "foo"; // esm.mjs import { named } from "./cjs.js"; //// named: "foo" • exports のプロパティが named import される 13
  14. 14. import CJS from ESM: default import // cjs.js module.exports = "foo"; // esm.mjs import cjs from "./cjs.js"; //// cjs: "foo" • module.exports が default import される 14
  15. 15. ところで Babel と TypeScript はどうだっけ? 15
  16. 16. Babel / TypeScript の ESM → CJS 変換 // Before (ESM in Babel) export default "foo"; // After (CJS) Object.defineProperty(exports, "__esModule", { value: true }); exports.default = "foo"; • default export は、exports.default に変換される • おや?Node.js の CJS Interop と仕様が違うぞ! 16
  17. 17. Babel / TypeScript で CJS にトランスパイルされた npm パッケージを Na5ve ESM からロードしたいけど // node_modules/foo/index.ts export default "foo!"; // main.mjs import foo from "foo"; //// foo: { default: "foo!" } default export された値を 期待通りに default import できない! 17
  18. 18. 無理矢理書くこともできるが // node_modules/foo/index.ts export default "foo!"; // main.mjs import def from "foo"; const { foo } = def; //// foo: "foo!" これなら動くが、import したい全ての npm パッケージについて内 部的に Babel / TS を使っているかを調べて書き分ける必要があり、 書き味も体験も非常に厳しい。 18
  19. 19. Babel Modules ≠ ES Modules TypeScript Modules ≠ ES Modules 19
  20. 20. ここまでは Babel / TypeScript ベースの CJS な npm パッケージを Na5ve ESM からロードする話 20
  21. 21. TypeScript で Na-ve ESM を書くのは もっと厳しい 21
  22. 22. TypeScript で Na-ve ESM を出力したい 公式にはサポートされてないので基本的に厳しい • .mjs を出力できない • .mjs を入力できない • moduleResolution:node が Node の ESM 仕様と異なる • imports / exports mapping に未対応 22
  23. 23. TypeScript で無理矢理書くこともできるが // foo.ts export default "foo!"; // main.ts import foo from "./foo.js"; import 文で拡張子を省略せず .js を指定し(.ts ではない)、 pacakge.json で type:"module" にすることで、変換後に Na$ve ESM として無理矢理動かすことは可能。 しかし ts-node など周辺ツールが未対応で jest も動かせない。 23
  24. 24. TypeScript Modules を import 不可能 // node_modules/foo/index.ts export default "foo!"; // main.ts import def from "foo"; const { foo } = def; //// TS2339 Error: Property 'foo' does not exist on type 'String'. TS が CJS に変換したパッケージに同梱された型定義が Node ESM 仕様と食い違うため、TS Na-ve ESM から default import しようと すると 型エラーかランタイムエラーのどちらか になる。 24
  25. 25. 今後どうなるのか? 25
  26. 26. Babel / TypScript 陣営の動き • Babel は新オプション importInterop:"node" を検討している4 • TypeScript は最近の動きは見えない • 2020 年 3 月に新しい moduleResolution フラグを作る方針 というコメント5 があったが、続報なし 5 Design Mee*ng Notes, 3/27/2020 · Issue #37897 · microso=/TypeScript 4 Implement importInterop: "node" op+on for module transforms by nicolo-ribaudo · Pull Request #12838 · babel/babel 26
  27. 27. Babel / TypeScript が対応しても • 既に npm 公開された大量の Babel / TS Modules はトランスパイ ル済みであり、挙動は変わらない • 更新のない Babel / TS Modules は Na4ve ESM からは扱いにく い存在として残り続ける • npm 界に ESM 対応のアップデートが広がるのを待つしかない • 時間が解決するのか... 27
  28. 28. Sindre はどうしてるの? そんなこともあろうかと、既存の TypeScript ベースの npm パッケージにあら かじめ workaround を仕込んでいた!6 export default got; module.exports = got; module.exports.default = got; module.exports.__esModule = true; これで TypeScript からも Na-ve ESM からも default import 可能。 ただし dirty hack で副作用もあるのでご利用は計画的に。 6 h$ps:/ /github.com/sindresorhus/got/blob/v11.8.1/source/index.ts#L127-L130 28
  29. 29. ところで、 どうして Na$ve ESM を書きたいんだっけ? • 皮肉にも、CJS Interop の実装が進んだ結果、CJS でも特に不満 がない状況になりつつある • ESM のセールスポイントだった tree-shaking も、静的解析の発 展により Webpack や Parcel が CJS にも対応し始めた • それでも ESM を書くと キマる んだ! 29
  30. 30. まとめ • Na$ve ESM は Node.js の中だけなら 5 月から自由に使える • しかし Babel / TypeScript ベースの npm パッケージを default import すると いろいろハマって厳しい • この状況は各種ツールと既存 npm パッケージが更新されるまでだいぶ続き そう • TypeScript で Na$ve ESM が書けるようになるのはまだまだ先 • しばらくは TypeScript で CJS を書く今の生活が続きそう 30

×