不動産相場チェッカーのWeb版は、HTML(ページの見た目を決めるファイル)1つの中に、デザイン・構造・プログラムの全てが詰め込まれている状態。約1,940行のうち1,200行がプログラム(JavaScript)で、見通しが悪くなっている。
ここにTypeScript(タイプスクリプト = JavaScriptに「型」を追加した言語)を導入する。「型」とは「この変数には文字だけ入る」「この関数は数値を返す」というルールのこと。これがあると、「文字を入れるべき場所に数値を入れてしまった」みたいなミスをプログラム実行前に検出できる。
今のまま放置すると、機能追加のたびに「どこかで予期しない動作をしていないか」を目視で確認する必要があり、見落としによるバグのリスクが積み重なる。
現在のHTMLファイルには、デザイン(CSS = ページの色・大きさ・配置を指定する言語)もプログラム(JavaScript)も全部入っている。これを以下のように分離する:
esbuild(イーエスビルド)は、TypeScriptで書いたプログラムを、ブラウザが理解できるJavaScriptに高速変換するツール。1コマンドで変換が完了する。
| ファイル | 役割 |
|---|---|
src/app.ts | メインプログラム(TypeScriptに変換した本体。約1,200行) |
src/types.ts | 型定義(「このデータはこういう形をしている」というルール集。約80行) |
docs/app.html | デザインと構造だけ残す(プログラムは外部参照に変更) |
docs/app.js | esbuildが自動生成するファイル(ブラウザが読むもの) |
package.json | 開発ツールの一覧(esbuildとTypeScriptを登録) |
tsconfig.json | TypeScriptの設定ファイル(型チェックのルール) |
Cloudflare Workers(中継サーバー)側のファイルは一切変更しない。そちらは既にTypeScriptで書かれている。
これは仕様化テスト(Characterization Test)というアプローチ。テスト駆動開発の第一人者 t-wada さんが「テストがないコードはレガシーコード」と言うように、リファクタリング(=動作を変えずにコードを整理すること)前にテストで現在の動作を"写真に撮る"。移行後に何が壊れたかを即座に検出できる。
プログラムの処理は大きく2種類に分けられる:
document.getElementById や addEventListener を使う処理。ブラウザ環境がないと動かない。テスト対象は計算ロジックだけに絞る。理由は「テストの信頼性と速度を最大化する」ため。画面操作のテストはブラウザ環境が必要で不安定になりやすい。一方、計算ロジックは環境に左右されず高速・確実にテストできる。画面表示はブラウザで目視確認する。
package.json(使うツールの一覧)とtsconfig.json(TypeScriptのルール設定)を新規作成し、esbuild・TypeScript・vitest(テスト実行ツール)をインストールする。1回だけの初期作業。src/types.ts(型定義ファイル)に、国交省APIから返ってくるデータの「形」を定義する。「取引価格は文字列」「面積は文字列」のようなルールを書いておくことで、データの取り扱いミスを防ぐ。src/app.tsに移植する。型を付けて新しい書き方に変換し、テストが全部通ること(GREEN = 青信号)を確認する。テストが失敗しても、テストは書き換えない。実装(プログラム本体)を直す。テストは「正しい動作の記録」なので、書き換えると基準が失われる。なぜファイルを2つだけに分けるのか? 1,200行は「分割が必要」と言えるほどの量ではない。細かく分けすぎると逆にファイル間の依存関係が複雑になって管理しづらくなる。型定義(データの形のルール)だけ分離して、ロジック(処理の中身)は1ファイルにまとめるのが、いちばんシンプル。
なぜ Vite(ヴィート)や React を使わないのか? Vite は開発用サーバー機能が付いてくるが、この規模のアプリには過剰。React はフォーム1個+テーブル2個のアプリには大げさ。esbuild だけで十分。必要になった時に考える(YAGNI = 今必要ないものは作らない原則)。
セキュリティが少し良くなる 今まではHTMLの中にプログラムを直接書いていたので、「HTMLの中のプログラムを許可する」という緩いセキュリティ設定が必要だった。外部ファイルに分離することで、この許可が不要になり、第三者がページに不正なプログラムを注入する攻撃への耐性が向上する。
見た目は何も変わらない 使う側(ブラウザで操作する人)から見ると、画面もボタンも動作も全く同じ。変わるのは「裏側のコードの書き方」だけ。