2022年6月13日
tscをGoに移植
(2022-1-26)by DongYoon Kang
本記事は、原著者の許諾のもとに翻訳・掲載しております。
筆者はTypeScript型チェッカーtscをRustではなく、Goに移植しようと思います。拡張可能なRustプラットフォームSWCの作者の発言としては、奇妙に聞こえるかもしれません。理由を説明したいと思います。
なぜtscを移植するのか
TypeScriptの普及が進むにつれて、大規模プロジェクトではあるジレンマに直面しています。型チェックは、ワークフローの中で最も時間がかかるプロセスの一つになっているのです。開発者は、イテレーションのサイクルを遅らせることなく、型安全を保証することを望んでいます。 tsc(TypeScript Compiler)は、型の妥当性をチェックし、コードをJavaScriptにコンパイルします。コードの量が多いほど、コンパイルには時間がかかります。中規模から大規模のTypeScriptプロジェクトでは、このコンパイルに膨大な時間がかかります。開発者はワークフローのトランスパイル部分をSWCに置き換えることができますが、それでも型チェックはボトルネックとなっています。
型チェッカーとは何か
型チェッカーは、実行前にプログラムを検証し、関数呼び出しや変数割り当ての値が正しいことを確認します。また、いたるところで型を指定することがないよう、可能な限り変数の型を推測します。型チェックは、自信を持って開発を行い、エラーをなくし、大規模なコードベースのリファクタリングをよりスムーズに行うことを可能にします。
なぜRustではないのか
筆者はtscをRustで書き直そうと試みました。最初はサイドプロジェクトとして取り組み、大いに楽しみました。tscのソースコードを見ずに型チェックのロジックを作り直す作業を開始しました。 筆者が書き直したRust版の初期テストでは、型チェックのスピードがtscの62倍に改善されていました。SWCとtscのコンパイル時間を測定するため、公式TypeScriptコンパイラのコンフォーマンス(適合性)テストスイートを使用しました。結果は以下の通りです(8スレッド使用):
- tsc:133.2秒
- Rustリライト版:2.13秒(62倍速い)
最終的に、tscのような巨大プロジェクトを書き直すのは、継続するのが極めて難しいことを悟りました。しかし、パフォーマンスの向上はかなりのものだったため、別の方法として完全なリライトではなく移植を試してみることにしたのです。そこで、TypeScriptのソースコードを見始めました。 tscは共有の可変性を多く使い、ガベージコレクションに依存する部分が多くあります。筆者はRustの支持者であり、信者ですが、このプロジェクトに合ったツールではないと感じます。このプロジェクトでRustを使用するには、unsafeを使用しなければならない場面が多すぎました。 tscは共有の可変性に依存しており、周期的な可変参照を持っています。Rustはこの挙動を防ぐよう設計されています。同じデータに対し二つの参照を持つこと(共有の可変性)は、Rustでは定義されていない挙動です。 どの言語を選ぶかは、好みではなく作業によって決めるべきです。筆者はRustを好みますが、このプロジェクトのためにGoとZigを試し、Goを使うことにしました。
オープンソース化するのか
tscをGoに移植する作業は、Vercelがスポンサーとして資金を提供しています。将来的にはオープンソース化する予定です。この新バージョンのtscをSWCとともに使用するためのブリッジも作成します。 型チェックのサポートを得て、SWCはJavaScriptとTypeScriptのツールチェーン全体のパフォーマンス向上に取り組んでいます。
- ✅トランスパイル(Babelの代替)
- 🚧型チェック(tscの代替)
- 🚧最小化(Terserの代替)
- 🚧バンドリング(webpackの代替)
プロジェクトの最新情報については、Twitterをフォローしてください。
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa