SlideShare uma empresa Scribd logo
1 de 30
Baixar para ler offline
Na#ve ESM への道
∼ 最終章: Babel / TypeScript Modules との闘い ∼
Node 学園 35 時限目 / 2021-02-24
@teppeis
1
自己紹介
• @teppeis / Teppei Sato
• サイボウズから来ました。
• もちろん We are hiring!!!
• プロダクト開発チーム
• フロントエンドエキスパートチーム
2
Node.js の ES Modules 対応って
どうなったの?
3
前回までのあらすじ
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
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
2021 年は Na've ESM の時代に?
• 前述の通り、Node v12 系以上は ESM を実装済み
• Node v10 は 2021-04-30 に EOL
• つまり、5 月以降は全 Node 環境で Na5ve ESM が利用可能!
• やったー、全部 ESM で書こうぜー
6
h"ps:/
/blog.sindresorhus.com/get-ready-for-esm-aa53530b3f77 7
h"ps:/
/twi"er.com/jus2nfagnani/status/1356012934564958212 8
そんな風に思っていた時期が
私にもありました。
9
鬼門: CJS Interop
10
CJS Interop
CJS から ESM へスムーズな移行を進めるために検討されてきた相
互互換機能
• CJS から ESM をロードできる
• ESM から CJS をロードできる
仕様の複雑さと既存パッケージとの互換性から、ここまで Node
の ESM 対応を遅らせてきた鬼門でもある
11
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
import CJS from ESM: named import
// cjs.js
exports.named = "foo";
// esm.mjs
import { named } from "./cjs.js";
//// named: "foo"
• exports のプロパティが named import される
13
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
ところで
Babel と TypeScript はどうだっけ?
15
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
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
無理矢理書くこともできるが
// node_modules/foo/index.ts
export default "foo!";
// main.mjs
import def from "foo";
const { foo } = def;
//// foo: "foo!"
これなら動くが、import したい全ての npm パッケージについて内
部的に Babel / TS を使っているかを調べて書き分ける必要があり、
書き味も体験も非常に厳しい。
18
Babel Modules ≠ ES Modules
TypeScript Modules ≠ ES Modules
19
ここまでは
Babel / TypeScript ベースの
CJS な npm パッケージを
Na5ve ESM からロードする話
20
TypeScript で
Na-ve ESM を書くのは
もっと厳しい
21
TypeScript で Na-ve ESM を出力したい
公式にはサポートされてないので基本的に厳しい
• .mjs を出力できない
• .mjs を入力できない
• moduleResolution:node が Node の ESM 仕様と異なる
• imports / exports mapping に未対応
22
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
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
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
Babel / TypeScript が対応しても
• 既に npm 公開された大量の Babel / TS Modules はトランスパイ
ル済みであり、挙動は変わらない
• 更新のない Babel / TS Modules は Na4ve ESM からは扱いにく
い存在として残り続ける
• npm 界に ESM 対応のアップデートが広がるのを待つしかない
• 時間が解決するのか...
27
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
ところで、
どうして Na$ve ESM を書きたいんだっけ?
• 皮肉にも、CJS Interop の実装が進んだ結果、CJS でも特に不満
がない状況になりつつある
• ESM のセールスポイントだった tree-shaking も、静的解析の発
展により Webpack や Parcel が CJS にも対応し始めた
• それでも ESM を書くと キマる んだ!
29
まとめ
• Na$ve ESM は Node.js の中だけなら 5 月から自由に使える
• しかし Babel / TypeScript ベースの npm パッケージを default import すると
いろいろハマって厳しい
• この状況は各種ツールと既存 npm パッケージが更新されるまでだいぶ続き
そう
• TypeScript で Na$ve ESM が書けるようになるのはまだまだ先
• しばらくは TypeScript で CJS を書く今の生活が続きそう
30

Mais conteúdo relacionado

Mais procurados

Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugMasatoshi Tada
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織Takafumi ONAKA
 
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!Tetsutaro Watanabe
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)NTT DATA Technology & Innovation
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐりKazuyuki TAKASE
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法についてYuji Otani
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較Akihiro Suda
 
コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」Masahito Zembutsu
 
SolrとElasticsearchを比べてみよう
SolrとElasticsearchを比べてみようSolrとElasticsearchを比べてみよう
SolrとElasticsearchを比べてみようShinsuke Sugaya
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったことドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと増田 亨
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Kohei Tokunaga
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法Tetsutaro Watanabe
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方増田 亨
 
暗号技術の実装と数学
暗号技術の実装と数学暗号技術の実装と数学
暗号技術の実装と数学MITSUNARI Shigeo
 
強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話Yoshitaka Kawashima
 

Mais procurados (20)

Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
Oss貢献超入門
Oss貢献超入門Oss貢献超入門
Oss貢献超入門
 
初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!初心者向けMongoDBのキホン!
初心者向けMongoDBのキホン!
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
実践 NestJS
実践 NestJS実践 NestJS
実践 NestJS
 
DockerとPodmanの比較
DockerとPodmanの比較DockerとPodmanの比較
DockerとPodmanの比較
 
コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」
 
SolrとElasticsearchを比べてみよう
SolrとElasticsearchを比べてみようSolrとElasticsearchを比べてみよう
SolrとElasticsearchを比べてみよう
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 
ドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったことドメイン駆動設計に15年取り組んでわかったこと
ドメイン駆動設計に15年取り組んでわかったこと
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法MongoDBが遅いときの切り分け方法
MongoDBが遅いときの切り分け方法
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
暗号技術の実装と数学
暗号技術の実装と数学暗号技術の実装と数学
暗号技術の実装と数学
 
強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話強いて言えば「集約どう実装するのかな、を考える」な話
強いて言えば「集約どう実装するのかな、を考える」な話
 

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

VSハッカソン TypeScript ハンズオン
VSハッカソン TypeScript ハンズオンVSハッカソン TypeScript ハンズオン
VSハッカソン TypeScript ハンズオンKazuhide Maruyama
 
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejsTakayoshi Tanaka
 
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京hecomi
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsuNanha Park
 
OpenGLプログラミング
OpenGLプログラミングOpenGLプログラミング
OpenGLプログラミング幸雄 村上
 
Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話
Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話
Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話yuosaka
 
つながるJavaとTFS
つながるJavaとTFSつながるJavaとTFS
つながるJavaとTFS__Black
 
Aspnet mvc 6の今を紹介
Aspnet mvc 6の今を紹介Aspnet mvc 6の今を紹介
Aspnet mvc 6の今を紹介Makoto Nishimura
 
鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用について鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用についてmichiosuzuki
 
鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用について鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用についてmichiosuzuki
 
Babelで先取り次世代javascript
Babelで先取り次世代javascriptBabelで先取り次世代javascript
Babelで先取り次世代javascriptTsuyoshi Maeda
 
新しい Visual Studio & .NET と新時代のアーキテクチャ
新しい Visual Studio & .NET と新時代のアーキテクチャ新しい Visual Studio & .NET と新時代のアーキテクチャ
新しい Visual Studio & .NET と新時代のアーキテクチャ慎一 古賀
 
Mozillaのビルドインフラ
MozillaのビルドインフラMozillaのビルドインフラ
MozillaのビルドインフラMakoto Kato
 
Embedded framework and so on
Embedded framework and so onEmbedded framework and so on
Embedded framework and so ontoyship
 
20121217 jawsug-yokohama
20121217 jawsug-yokohama20121217 jawsug-yokohama
20121217 jawsug-yokohamaTetsuya Chiba
 

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

ES6 in Practice
ES6 in PracticeES6 in Practice
ES6 in Practice
 
VSハッカソン TypeScript ハンズオン
VSハッカソン TypeScript ハンズオンVSハッカソン TypeScript ハンズオン
VSハッカソン TypeScript ハンズオン
 
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
 
Clang Modules
Clang ModulesClang Modules
Clang Modules
 
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
Hello, C++ + JavaScript World! - Boost.勉強会 #11 東京
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsu
 
OpenGLプログラミング
OpenGLプログラミングOpenGLプログラミング
OpenGLプログラミング
 
Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話
Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話
Denoで動くReactフレームワークAleph.jsでポートフォリオサイトをリプレイスした話
 
Net fringejp2016
Net fringejp2016Net fringejp2016
Net fringejp2016
 
つながるJavaとTFS
つながるJavaとTFSつながるJavaとTFS
つながるJavaとTFS
 
Aspnet mvc 6の今を紹介
Aspnet mvc 6の今を紹介Aspnet mvc 6の今を紹介
Aspnet mvc 6の今を紹介
 
鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用について鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用について
 
鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用について鈴木:Net commonsでの中国語使用について
鈴木:Net commonsでの中国語使用について
 
Babelで先取り次世代javascript
Babelで先取り次世代javascriptBabelで先取り次世代javascript
Babelで先取り次世代javascript
 
新しい Visual Studio & .NET と新時代のアーキテクチャ
新しい Visual Studio & .NET と新時代のアーキテクチャ新しい Visual Studio & .NET と新時代のアーキテクチャ
新しい Visual Studio & .NET と新時代のアーキテクチャ
 
Mozillaのビルドインフラ
MozillaのビルドインフラMozillaのビルドインフラ
Mozillaのビルドインフラ
 
Embedded framework and so on
Embedded framework and so onEmbedded framework and so on
Embedded framework and so on
 
20121217 jawsug-yokohama
20121217 jawsug-yokohama20121217 jawsug-yokohama
20121217 jawsug-yokohama
 

Mais de Teppei Sato

サイボウズの給与交渉戦 - Boss Side -
サイボウズの給与交渉戦 - Boss Side -サイボウズの給与交渉戦 - Boss Side -
サイボウズの給与交渉戦 - Boss Side -Teppei Sato
 
Recent compat-table issues
Recent compat-table issuesRecent compat-table issues
Recent compat-table issuesTeppei Sato
 
kintoneがAWSで目指すDevOpsQAな開発
kintoneがAWSで目指すDevOpsQAな開発kintoneがAWSで目指すDevOpsQAな開発
kintoneがAWSで目指すDevOpsQAな開発Teppei Sato
 
Automated Dependency Updates with Renovate
Automated Dependency Updates with RenovateAutomated Dependency Updates with Renovate
Automated Dependency Updates with RenovateTeppei Sato
 
君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?Teppei Sato
 
サイボウズのフロントエンド開発 現在とこれからの挑戦
サイボウズのフロントエンド開発 現在とこれからの挑戦サイボウズのフロントエンド開発 現在とこれからの挑戦
サイボウズのフロントエンド開発 現在とこれからの挑戦Teppei Sato
 
サイボウズの現在と未来
サイボウズの現在と未来サイボウズの現在と未来
サイボウズの現在と未来Teppei Sato
 
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ーTeppei Sato
 
サイボウズの開発を支えるKAIZEN文化
サイボウズの開発を支えるKAIZEN文化サイボウズの開発を支えるKAIZEN文化
サイボウズの開発を支えるKAIZEN文化Teppei Sato
 
JavaScript Language Update 2016 (LLoT)
JavaScript Language Update 2016 (LLoT)JavaScript Language Update 2016 (LLoT)
JavaScript Language Update 2016 (LLoT)Teppei Sato
 
You Don't Know ES Modules
You Don't Know ES ModulesYou Don't Know ES Modules
You Don't Know ES ModulesTeppei Sato
 
Closure Compiler Updates for ES6
Closure Compiler Updates for ES6Closure Compiler Updates for ES6
Closure Compiler Updates for ES6Teppei Sato
 
Our wish to Flowtype
Our wish to FlowtypeOur wish to Flowtype
Our wish to FlowtypeTeppei Sato
 
Flowtype Introduction
Flowtype IntroductionFlowtype Introduction
Flowtype IntroductionTeppei Sato
 
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略Teppei Sato
 
本当のClosure Compilerをお見せしますよ。
本当のClosure Compilerをお見せしますよ。本当のClosure Compilerをお見せしますよ。
本当のClosure Compilerをお見せしますよ。Teppei Sato
 
JavaScript Unit Test Why? What? How?
JavaScript Unit Test Why? What? How?JavaScript Unit Test Why? What? How?
JavaScript Unit Test Why? What? How?Teppei Sato
 

Mais de Teppei Sato (20)

サイボウズの給与交渉戦 - Boss Side -
サイボウズの給与交渉戦 - Boss Side -サイボウズの給与交渉戦 - Boss Side -
サイボウズの給与交渉戦 - Boss Side -
 
Recent compat-table issues
Recent compat-table issuesRecent compat-table issues
Recent compat-table issues
 
kintoneがAWSで目指すDevOpsQAな開発
kintoneがAWSで目指すDevOpsQAな開発kintoneがAWSで目指すDevOpsQAな開発
kintoneがAWSで目指すDevOpsQAな開発
 
Automated Dependency Updates with Renovate
Automated Dependency Updates with RenovateAutomated Dependency Updates with Renovate
Automated Dependency Updates with Renovate
 
君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?君はyarn.lockをコミットしているか?
君はyarn.lockをコミットしているか?
 
サイボウズのフロントエンド開発 現在とこれからの挑戦
サイボウズのフロントエンド開発 現在とこれからの挑戦サイボウズのフロントエンド開発 現在とこれからの挑戦
サイボウズのフロントエンド開発 現在とこれからの挑戦
 
サイボウズの現在と未来
サイボウズの現在と未来サイボウズの現在と未来
サイボウズの現在と未来
 
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
離れた場所でも最高のチームワークを実現する方法 ーサイボウズ開発チームのリモートワーク事例ー
 
サイボウズの開発を支えるKAIZEN文化
サイボウズの開発を支えるKAIZEN文化サイボウズの開発を支えるKAIZEN文化
サイボウズの開発を支えるKAIZEN文化
 
SPAと覚悟
SPAと覚悟SPAと覚悟
SPAと覚悟
 
JavaScript Language Update 2016 (LLoT)
JavaScript Language Update 2016 (LLoT)JavaScript Language Update 2016 (LLoT)
JavaScript Language Update 2016 (LLoT)
 
You Don't Know ES Modules
You Don't Know ES ModulesYou Don't Know ES Modules
You Don't Know ES Modules
 
Closure Compiler Updates for ES6
Closure Compiler Updates for ES6Closure Compiler Updates for ES6
Closure Compiler Updates for ES6
 
Our wish to Flowtype
Our wish to FlowtypeOur wish to Flowtype
Our wish to Flowtype
 
Effective ES6
Effective ES6Effective ES6
Effective ES6
 
Flowtype Introduction
Flowtype IntroductionFlowtype Introduction
Flowtype Introduction
 
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
Closure CompilerのES6対応 あるいはES6時代のAltJS生存戦略
 
本当のClosure Compilerをお見せしますよ。
本当のClosure Compilerをお見せしますよ。本当のClosure Compilerをお見せしますよ。
本当のClosure Compilerをお見せしますよ。
 
DockerがYAVAY!
DockerがYAVAY!DockerがYAVAY!
DockerがYAVAY!
 
JavaScript Unit Test Why? What? How?
JavaScript Unit Test Why? What? How?JavaScript Unit Test Why? What? How?
JavaScript Unit Test Why? What? How?
 

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

  • 1. Na#ve ESM への道 ∼ 最終章: Babel / TypeScript Modules との闘い ∼ Node 学園 35 時限目 / 2021-02-24 @teppeis 1
  • 2. 自己紹介 • @teppeis / Teppei Sato • サイボウズから来ました。 • もちろん We are hiring!!! • プロダクト開発チーム • フロントエンドエキスパートチーム 2
  • 3. Node.js の ES Modules 対応って どうなったの? 3
  • 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. 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. 2021 年は Na've ESM の時代に? • 前述の通り、Node v12 系以上は ESM を実装済み • Node v10 は 2021-04-30 に EOL • つまり、5 月以降は全 Node 環境で Na5ve ESM が利用可能! • やったー、全部 ESM で書こうぜー 6
  • 11. CJS Interop CJS から ESM へスムーズな移行を進めるために検討されてきた相 互互換機能 • CJS から ESM をロードできる • ESM から CJS をロードできる 仕様の複雑さと既存パッケージとの互換性から、ここまで Node の ESM 対応を遅らせてきた鬼門でもある 11
  • 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. 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. 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. ところで Babel と TypeScript はどうだっけ? 15
  • 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. 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. 無理矢理書くこともできるが // 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. Babel Modules ≠ ES Modules TypeScript Modules ≠ ES Modules 19
  • 20. ここまでは Babel / TypeScript ベースの CJS な npm パッケージを Na5ve ESM からロードする話 20
  • 21. TypeScript で Na-ve ESM を書くのは もっと厳しい 21
  • 22. TypeScript で Na-ve ESM を出力したい 公式にはサポートされてないので基本的に厳しい • .mjs を出力できない • .mjs を入力できない • moduleResolution:node が Node の ESM 仕様と異なる • imports / exports mapping に未対応 22
  • 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. 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
  • 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. Babel / TypeScript が対応しても • 既に npm 公開された大量の Babel / TS Modules はトランスパイ ル済みであり、挙動は変わらない • 更新のない Babel / TS Modules は Na4ve ESM からは扱いにく い存在として残り続ける • npm 界に ESM 対応のアップデートが広がるのを待つしかない • 時間が解決するのか... 27
  • 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. ところで、 どうして Na$ve ESM を書きたいんだっけ? • 皮肉にも、CJS Interop の実装が進んだ結果、CJS でも特に不満 がない状況になりつつある • ESM のセールスポイントだった tree-shaking も、静的解析の発 展により Webpack や Parcel が CJS にも対応し始めた • それでも ESM を書くと キマる んだ! 29
  • 30. まとめ • Na$ve ESM は Node.js の中だけなら 5 月から自由に使える • しかし Babel / TypeScript ベースの npm パッケージを default import すると いろいろハマって厳しい • この状況は各種ツールと既存 npm パッケージが更新されるまでだいぶ続き そう • TypeScript で Na$ve ESM が書けるようになるのはまだまだ先 • しばらくは TypeScript で CJS を書く今の生活が続きそう 30