【実務・中級編】 tsconfig-pathsとtsc-aliasによるビルド後のパス解決 – TypeScript実践ガイド

なぜ `tsconfig-paths` だけでは地獄を見るのか?──ビルド後のパス解決を完全攻略する

フロントエンドの現場で中級レベルに差し掛かると、誰もが一度は「相対パス地獄」に直面するはずだ。`../../../components/Button` のような記述がコードベースに溢れかえると、リファクタリングのたびに心臓が止まるような思いをするよね。

そこで多くのエンジニアが手を出すのが `tsconfig.json` の `paths` 設定だ。だが、ここで罠がある。多くの人が陥るのが、「tsconfigの設定だけで解決したつもりになり、ビルド後のNode.js環境で『Module not found』を食らって深夜に絶望する」というパターンだ。

今日は、この「パスエイリアスの正体」と、実務で絶対にコケないための最適解を伝授する。

—

1. なぜパスエイリアスは「解決」されないのか?

まず、大前提を叩き込んでおこう。`tsconfig.json` の `paths` は、TypeScriptコンパイラ(tsc)が型チェックを行う際に「どこからモジュールを探せばいいか」を教えるための地図に過ぎない。

tscは、ソースコードをJavaScriptに変換する際、import文のパスを書き換えてはくれないんだ。

例えば、`@/components/Button` と書いても、tscはそのまま `@/components/Button` という文字列をJSファイルに出力する。当然、Node.jsやブラウザのモジュール解決システムは「`@` なんて名前のディレクトリはどこにもないよ!」と怒り出す。これがパスエイリアス問題の正体だ。

2. 開発環境と本番環境の「二重構造」を理解する

この問題を解決するには、以下の2つのフェーズでアプローチを変える必要がある。

1. 開発環境 (ts-node / ts-node-dev): `tsconfig-paths` を使って、実行時に動的にパスを解決させる。
2. 本番環境 (tsc + tsc-alias): コンパイル済みのJS内のパスを、相対パス(`../../`など)に物理的に書き換える。

特に重要なのが「2」だ。これを行わないと、`dist` や `build` ディレクトリに吐き出されたコードは、外部ライブラリの依存関係に頼らない限り動かない。

3. 実践:tsc-alias で物理的にパスを書き換える

現場で最も確実かつ軽量なのが、`tsc-alias` を導入することだ。ビルド後のJSファイル内にあるエイリアスを、Node.jsが理解できる相対パスに置換してくれる。

インストール

npm install –save-dev tsc-alias

設定と実行方法

`package.json` の `scripts` を以下のように書き換えるのがベストプラクティスだ。

{
“scripts”: {
“build”: “tsc && tsc-alias”
}
}

これだけで、`dist/index.js` 内の `@/components/Button` は、自動的に `./components/Button` に書き換わる。魔法のようだが、実は単なる文字列置換の力技。だが、この「泥臭い解決策」こそが、ランタイム依存を増やさないためのプロの選択なんだ。

—

4. コピペで使える設定サンプル

プロジェクトのルートにある `tsconfig.json` の設定例を挙げておく。これを見れば、何が重要か一目で分かるはずだ。

{
“compilerOptions”: {
“baseUrl”: “.”, // ベースディレクトリをルートに設定
“paths”: {
“@/”: [“src/”] // @をsrc配下として扱う
},
“outDir”: “./dist”, // コンパイル後の出力先
“rootDir”: “./src” // ソースの場所
}
}

これで、コード内では以下のようにスッキリ書ける。

// src/index.ts
// 相対パスの深さを気にせず、どこからでもアクセスできる
import { Button } from “@/components/Button”;

console.log(“パス解決成功!”);

—

5. シニアからのアドバイス:なぜ「ビルド後」にこだわるのか

現場でこの設定を突き詰めると、たまに「モジュールバンドラー(ViteやWebpack)が解決してくれるなら、`tsc-alias` は不要では?」という質問を受ける。

確かに、Viteを使っているなら `vite.config.ts` で `resolve.alias` を設定すればフロントエンドの実行は成功する。しかし、バックエンド(Node.js)との共有コードや、テスト(Jest / Vitest)でのパス解決を考えた時、`tsconfig.json` とビルドツール側で設定が乖離していると、必ずどこかでバグが生まれる。

「ソースコードの型定義(tsconfig)を正とし、それを実態(ビルド後のJS)に反映させる」

この一貫性を保つことこそが、大規模な開発で技術的負債を積まないための鉄則だ。

パスエイリアスは単なる「見た目の整理」ではない。チーム全体の開発体験(DX)を左右する重要なアーキテクチャの一部なんだ。ぜひ、この設定をプロジェクトの標準にして、快適な開発ライフを送ってほしい。応援しているよ。

コメント

タイトルとURLをコピーしました