トランスパイル
とらんすぱいる
新しい構文や別言語のコードを、ブラウザが実行できるJavaScriptへ変換すること。
概要
トランスパイルは、あるプログラミング言語のソースコードを、別の(あるいは同じ言語の別バージョンの)ソースコードへ変換することです。Web 開発の文脈ではほぼ「新しい構文や TypeScript のような拡張言語で書いたコードを、ブラウザが確実に実行できる JavaScript へ変換すること」を指します。代表的なツールが Babel と TypeScript コンパイラ(tsc)で、近年は esbuild や SWC といった高速な実装も広く使われています。
コンパイルとの違いは変換の「高さ」にあります。コンパイルが一般にソースコードを機械語などの低水準な形式へ落とすのに対し、トランスパイルは同程度の抽象度のソースコード同士の変換です(trans + compile の合成語)。開発者は最新の言語機能や型システムの恩恵を受けて書き、実行環境には枯れた JavaScript を届ける — この「書く言語と動かす言語の分離」を成立させる工程がトランスパイルです。
なぜ生まれたか
JavaScript には他の言語にない特殊な制約があります。実行環境がユーザーのブラウザであるため、開発者が処理系のバージョンを選べないことです。言語仕様(ECMAScript)に便利な新構文が入っても、古いブラウザを使うユーザーがいる限り、そのまま書けば一部の環境で構文エラーになります。ES2015(ES6)でクラス・アロー関数・モジュールなど大量の機能が一気に追加されたとき、この「仕様とブラウザ実装のずれ」は深刻な問題になりました。
そこで生まれたのが「新しい構文で書き、配布前に古い構文へ機械的に書き換える」という解決です。Babel(2014年、当初の名は 6to5)は ES2015 のコードを ES5 相当へ変換し、開発者が「ブラウザの普及を待たずに」新機能を使える道を開きました。同時期に登場した TypeScript(2012年)は、型注釈という JavaScript にない機能を加えた言語をトランスパイルで JavaScript に落とすアプローチで、「言語そのものを拡張したい」という要求にも同じ手法が有効なことを示しました。CoffeeScript など先行の altJS(JavaScript 代替言語)を含め、「実行環境は変えられないが、書く言語は変えられる」という発想の転換がトランスパイルの原点です。
詳細
変換パイプラインの中身
トランスパイラの内部は古典的なコンパイラの前半と同じ構造です。ソースコードを字句・構文解析して AST(抽象構文木 — コードを木構造のデータで表したもの)を作り、AST 上で変換を施し、そこからコードを再生成します。たとえばアロー関数のノードを見つけたら等価な function 式のノードへ置き換える、といった変換がプラグインとして積み重なります。Babel が「どのブラウザをサポートするか」の指定(browserslist)から必要な変換だけを選べるのは、変換がこの粒度で分割されているからです。
構文変換とポリフィル — 役割分担
トランスパイルで解決できるのは「構文」の問題だけです。Promise や fetch のような新しい組み込みオブジェクト・API が古い環境に存在しない問題は、構文を書き換えても解決しません。こちらを担うのがポリフィル — 欠けている機能を JavaScript 自身で実装して補う追加コード — です。新しい書き方は構文変換で、新しい機能はポリフィルで、と役割が分かれており、両方を揃えて初めて古い環境で動きます。この2つの違いを押さえておくと、「変換したはずなのに古いブラウザで動かない」の大半が説明できます。
TypeScript と「型の消去」
TypeScript のトランスパイルには特徴的な性質があります。型注釈は実行時には一切残らず、変換時にすべて取り除かれる(型消去)ことです。つまり型チェックはあくまでビルド時の検査であり、実行される JavaScript に型の保証は含まれません。外部から来るデータ(API のレスポンスなど)が型定義どおりである保証はどこにもない、という点は TypeScript 実務の重要な落とし穴です。逆に言えば、型を消すだけなら構文解析だけで済むため、型チェックを省略して変換だけを高速に行う esbuild / SWC のようなツールが成立し、「変換は高速ツール、型チェックは tsc を別プロセスで」という分業が現代の定番構成になっています。
ソースマップ — 変換後の世界でデバッグする
トランスパイルには副作用があります。ブラウザで実際に動いているのは変換後のコードなので、エラーの行番号やデバッガの表示が、自分の書いたコードと一致しなくなるのです。これを解決するのがソースマップで、変換後コードの各位置が元コードのどこに対応するかを記録したファイルです。ブラウザの開発者ツールはこれを読み、あたかも元の TypeScript や最新構文のコードをそのまま実行しているかのようにデバッグさせてくれます。トランスパイルは通常バンドラのパイプラインに組み込まれて実行されるため、複数の変換を経てもソースマップが正しく連鎖するよう各ツールが連携しています。