tscの代わりにBabelにトランスパイルをまかせてみた
モノリポでパッケージを作る際にtsc
の代わりにbabel
を使ってみたかったので、これを機に色々調べてみた。
参考にしたのはこのサイト。
Using Babel with TypeScript | Learn TypeScript
Babelってなんだ
Babelは主にECMAScript 2015+のコードを、古いブラウザや環境での後方互換性をもったバージョンのJavaScriptに変換するために使用されるツール。
Babelがtscに代わって使われる理由はJSXをJavaScriptに変換できるから。 tscは変換できない。なのでReactをプロジェクトで使っている場合はBabelが必要になる。
必要なパッケージのインストール
とりあえず、TypeScriptやデコレーターだったりを使いたいので、それらをトランスパイルするのに必要なパッケージをまとめてみた。
@babel/core
- Babelのコアとなるライブラリ
@babel/preset-env
- 最新のJavaScriptの機能を使いつつ、それらをサポートしていないブラウザをターゲットにするためのプラグインの集まり。
@babel/preset-typescript
- TypeScriptのコードをJavaScriptに変換するためのプログラインの集まり
@babel/cli
- Babelを実行するために使われるコマンドラインツール。
babel-plugin-transform-typescript-metadata
@babel/plugin-proposal-decorators
@babel/plugin-proposal-class-properties
- 静的なクラスプロパティとプロパティ初期化構文で宣言されたプロパティを変換するプラグイン
babel-plugin-module-resolver
tsc-alias
yarn add -D @babel/core @babel/preset-env @babel/preset-typescript @babel/cli @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators babel-plugin-module-resolver babel-plugin-transform-typescript-metadata
設定ファイルを作成する
.babelrc
というファイルをルートディレクトリに作成する。
中身は次のようにする。
{ "presets": ["@babel/preset-env", "@babel/preset-typescript"], "plugins": [ "babel-plugin-transform-typescript-metadata", ["@babel/plugin-proposal-decorators", { "version": "legacy" }], "@babel/plugin-proposal-class-properties", [ "module-resolver", { "root": ["."], "alias": { "~": "./src" } } ], ] }
babel-plugin-transform-typescript-metadata
は@babel/plugin-proposal-decorators
よりも前に記述しないといけないので注意する。
トランスパイルはBabelに任せて、tsc
では型チェックのみを行いたいので、noEmit
はfalse
に、declaration
はtrue
に、そしてemitDeclarationOnly
をtrue
に設定する。
... "compilerOptions": { ... "outDir": "dist", ... "noEmit": false, // 型定義ファイルは出力したいのでfalse "declaration": true, // 型定義ファイルの生成を指示する "emitDeclarationOnly": true, // 型定義ファイルのみ生成する ... }, ...
outDir
はBabelの出力先と一致させておく。ここではdist
を設定する。
スクリプトを追加する
build
スクリプトとしてpackage.jsonに次のコマンドを追加する。
... "scripts": { "build": "tsc -p tsconfig.json -d && tsc-alias -p tsconfig.json && npx babel ./src --extensions '.ts,.tsx' --out-dir ./dist", ... } ...
--out-file dist/index.js
ではなく--out-dir ./dist
を設定することに注意する。
もし--out-file dist/index.js
を指定してしまうと、./src/index.ts
のみがトランスパイルされて、distディレクトリに出力される。たとえ./src/index.ts
内で./src/classes/Sample.ts
をインポートしていたとしてもdist/classes
にSample.js
が出力されることはない。
tsc-alias
を使わないと~/classes/...
のようなエイリアスパスがそのまま型定義ファイルに出力されてしまう。なのでそれを防ぐためにtsc
による型定義ファイルの出力後に、tsc-alias
を使って型定義ファイル中のエイリアスパスを相対パスに置き換える必要がある。
module-resolverの設定
tsconfig.jsonで次のようにエイリアスを設定している場合
... "paths": { "~/*": ["./src/*"], }, "baseUrl": ".", ...
module-resolver
の設定は次のようにする。
... [ "module-resolver", { "root": ["."], "alias": { "~": "./src" } } ], ...
まとめ
Reactなどのフレームワークを触り始めたばかりのころに、WebpackやらBabelやらという当時の自分にはわからない単語が多すぎたせいで、なぜか今でもBabelを敬遠してしまっていた。
今回改めて自分で設定ファイル書いたりプラグイン追加してみたりしたけど、案外難しいことはなかった。
やっぱり自分で使ってみるのが一番ですね。
参考
Using Babel with TypeScript | Learn TypeScript
TypeScript: Documentation - Using Babel with TypeScript
TypeScript で型を検査する|【React/Redux】カンバンボードを実装して Web フロントエンド上級者を目指そう!|Techpit
GitHub - microsoft/tsyringe: Lightweight dependency injection container for JavaScript/TypeScript
GitHub - tleunen/babel-plugin-module-resolver: Custom module resolver plugin for Babel
Next.js + TypeScript + デコレータ + reflect-metadata を動かす
GitHub - justkey007/tsc-alias: Replace alias paths with relative paths after typescript compilation