※本ストーリーは当社運営の「GameWith Developer Blog」の転載になります。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
はじめに
こんにちは!Incremental Stream Team の @53able です!
今回は現在自分が着手中の TypeScript マイグレーション PJ について書いていきたいと思います!
GameWith の JavaScript
まず GamewWith の JavaScript について紹介していきたいと思います。
JavaScript のボリューム
Cloc というツールを利用し JavaScript のコード行をカウントしてみました。
brew
経由でインストールし、
cloc ディレクトリ名
を実行すれば、カウントしてくれます。
brew install cloc
cloc /Gamewith
結果は3万6千行でした!
JavaScript のビルドフロー
次に、ビルドフローについて紹介します。
GameWith は Gulp を利用して JavaScript を連結・圧縮しています。
GameWith メインリポジトリでは Vue, React といったフレームワークは導入しておらず、jQuery を利用しています。
※GameWithDesignSystem のリポジトリでは Vue を利用しています
TypeScript 化
今回 GameWith の3万6千行を一度に TypeScript 化し、リリースするのは現実的ではないと判断しました。
そのため、ファイル単位で TypeScript 化して修正をするという影響範囲を小さくしたマイグレーションのフローにしました。
新しいビルドフロー
TypeScript 化の際に長年積み上げてきた Gulp で行っているビルドフローの改修はとてもリスクが大きいため、Gulp は引き続き利用することにしました。
新しいビルドフローは Gulp の前に TypeScript を割り込ませ、既存のフローをできるだけ変更せず導入を考えています。
JavaScript を中間コードとして扱う発想でこの新しいビルドフローを考えました。
マイグレーションの作業フロー
JavaScript -> TypeScript は
ts-migration
というツールを利用しました。
今回マイグレーションの作業フローを作るにあたって、以下の作業を行いました。
1.ts-migration をいくつか適当なファイルに実行
2.生成された TypeScript のファイルを ESLint で整形し既存の JavaScript のファイルと目で差分のチェック
3.次に、自動化したいフローを洗い出すため手動でファイル操作を行いました
1.ts-migration はフォルダをターゲットに動作するため、変換用フォルダへ JavaScript をコピーする
2.ts-migration をフォルダ指定で実行し TypeScript へマイグレーション
3.マイグレーションで変換後の TypeScript を元の JavaScript と同じ場所へコピーする
4.TypeScript を tsc でコンパイルし、オリジナルの JavaScript が上書きされる ( ここで JavaScript 👉 TypeScript 👉 JavaScript の差分がわかる)
5.TypeScript 化された JavaScript は ESLint 対象外、ファイルを削除し、.gitignore に追加する
ts-migration は、ディレクトリをターゲットに TypeScript へマイグレーションするので、一旦変換用のディレクトリに作業ファイルをコピーしてマイグレーションを実行するようにしています。
手動で作業を確認後、同等の動作を Node で動作するスクリプトを書き、自動化をしました。
※スクリプトを書く際に js-fire を利用しました
最終的に完成した自動化のスクリプトは下記のように3つになりました。
// 1. 変換させるたのフォルダへ JavaScript をコピーする
npm run migrate -- start /GameWith/xxx.js
// 2. `ts-migration` をフォルダ指定で実行し TypeScript へマイグレーション
// 3. マイグレーションで変換後の TypeScript を元の JavaScript と同じ場所へコピーする
// 4. TypeScript を `tsc` でコンパイルし、オリジナルの JavaScript が上書きされる
npm run migrate:sync
// 5. TypeScript 化された JavaScript は ESLint 対象外、ファイルを削除し、`.gitignore` に追加する
npm run migrate -- end /GameWith/xxx.js
スクリプトは下記のようなイメージです。
const migration = {
start: async (jsFile) => {
// 1. 変換させるたのフォルダへ JavaScript をコピーする
return jsFile;
},
end: async (jsFile) => {
// 5. TypeScript 化された JavaScript は ESLint 対象外、ファイルを削除し、`.gitignore` に追加する
return jsFile;
},
};
fire(migration);
おわりに
破壊的なビルドフローの変更ではなく、既存ファイル以前のソースコードを設けることにより、マイグレーションコストを格段に減らしました。
TypeScript へマイグレーションしますが、中間コードが JavaScript なので、既存ファイルと共存は問題ないようにしています。
また、短期間ですべての JavaScript をマイグレーションしてしまうと既存の動いている他案件とコンフリクトし、解消するコストがかなり高くなってしまうため、修正の際に1ファイルずつ案件を担当するエンジニアがマイグレーションできるフローにしました!
まだマイグレーションは始まったばかりですが、完走したいと思います!
☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆
現在、GameWithでは「ゲームをより楽しめる世界を創る」というMissionの下、そんな世界を実現するべく仲間を募集しております。記事をご覧頂き、少しでもご興味を持って頂けましたら嬉しい限りです。