GameWith Developer Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

GameWith の フロントエンド を TypeScript へマイグレーションする #GameWith #TechWith

はじめに

こんにちは!Incremental Stream Team の @53able です!

今回は現在自分が着手中の TypeScript マイグレーション PJ について書いていきたいと思います!

GameWith の JavaScript

まず GamewWith の JavaScript について紹介していきたいと思います。

JavaScript のボリューム

Cloc というツールを利用し JavaScript のコード行をカウントしてみました。

github.com

brew 経由でインストールし、cloc ディレクトリ名 を実行すれば、カウントしてくれます。

brew install cloc
cloc /Gamewith

結果は3万6千行でした!

JavaScript のビルドフロー

次に、ビルドフローについて紹介します。

GameWith は Gulp を利用して JavaScript を連結・圧縮しています。

gulpjs.com

GameWith メインリポジトリでは Vue, React といったフレームワークは導入しておらず、jQuery を利用しています。

※GameWithDesignSystem のリポジトリでは Vue を利用しています

tech.gamewith.co.jp

TypeScript 化

今回 GameWith の3万6千行を一度に TypeScript 化し、リリースするのは現実的ではないと判断しました。

そのため、ファイル単位で TypeScript 化して修正をするという影響範囲を小さくしたマイグレーションのフローにしました。

新しいビルドフロー

TypeScript 化の際に長年積み上げてきた Gulp で行っているビルドフローの改修はとてもリスクが大きいため、Gulp は引き続き利用することにしました。

新しいビルドフローは Gulp の前に TypeScript を割り込ませ、既存のフローをできるだけ変更せず導入を考えています。

JavaScript を中間コードとして扱う発想でこの新しいビルドフローを考えました。

マイグレーションの作業フロー

JavaScript -> TypeScript は ts-migration というツールを利用しました。

github.com

今回マイグレーションの作業フローを作るにあたって、以下の作業を行いました。

  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 を利用しました

github.com

最終的に完成した自動化のスクリプトは下記のように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ファイルずつ案件を担当するエンジニアがマイグレーションできるフローにしました!

まだマイグレーションは始まったばかりですが、完走したいと思います!

Twitter

Twitter にてテックブログの投稿をツイートしていますので、よろしければフォローをお願いします!

twitter.com

Wanted!

一緒に働く仲間(特にサーバサイドエンジニア)を絶賛募集中です!

以下 Wantedly のページからぜひカジュアル面談へお申し込みください!

www.wantedly.com