第20章:TypeScriptビルドを速くする(“コンテナ内ビルド”のコツ)🧑💻⚡️📦
この章の狙いはシンプル👇 **「TSのビルドが走る場面でも、待ち時間を短くする」**ことです 😆✨
0) まず結論:速くする“3つの作戦”🏎️💨
- そもそもビルド工程を走らせない(レイヤキャッシュを最大化)🧱
- 走ってしまうなら、差分ビルドを効かせる(BuildKitのキャッシュマウント+tscのincremental)🧠
- 成果物を“きれいに分離”して軽くする(マルチステージで
distだけ運ぶ)🎒
※BuildKitは今どきのDockerでは標準ビルダー扱いです。(Docker Documentation)
※RUN --mount=type=cache でビルド中のキャッシュを“ビルドを跨いで”残せます。(Docker Documentation)
1) “TSビルドが遅い”の正体をざっくり理解👀🧩
TSビルド(tsc)の重さは、だいたいこの2つが支配します👇
- 型チェックが重い(依存ライブラリの型も見る・プロジェクトが大きい等)🧠💦
- 毎回フルビルドに戻ってしまう(差分情報が消える/残らない)🔁😵💫
ここで効くのが incrementalビルド。
incremental: true にすると、前回の情報を .tsbuildinfo に保存して次回を速くできます。(typescriptlang.org)
さらに .tsbuildinfo の置き場は tsBuildInfoFile で好きに変えられます。(typescriptlang.org)
2) いちばん効く形:マルチステージ+distだけ運搬🏗️📦➡️🏃
「ビルド用」と「実行用」を分けて、最後はdistだけ持っていく形が王道です。(Docker Documentation)
✅ 推奨Dockerfile(TSビルド高速化セット)🧑🍳✨
ポイントはここ👇
npm ci等(依存導入)とtsc(ビルド)を別レイヤにしてキャッシュを守る🧱tscに BuildKitキャッシュマウント を与えて、incrementalの情報を残す🧠- 最終ステージは distだけ(軽い!速い!)🪶
## syntax=docker/dockerfile:1
FROM node:24 AS base
WORKDIR /app
## 依存だけ先に入れてキャッシュを最大化
FROM base AS deps
COPY package.json package-lock.json ./
## npmのDLキャッシュをBuildKitに残す(次回から速い)
RUN --mount=type=cache,target=/root/.npm \
npm ci
## ビルド
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY tsconfig.json ./
COPY src ./src
## tscのincremental情報(.tsbuildinfoなど)をBuildKitキャッシュに残す
## 置き場は /app/.cache に集約する作戦
RUN --mount=type=cache,target=/app/.cache \
npm run build
## 実行用(distだけ運ぶ)
FROM node:24-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=dev
COPY --from=build /app/dist ./dist
CMD ["node", "dist/index.js"]
🧠 これで何が嬉しいの?
- 依存が変わらない限り
npm ciが再実行されにくい(キャッシュ大勝利)🏆 - ソースが変わってビルドが走っても、
/app/.cacheが残るので 差分ビルドが効きやすい⚡️ - 最終イメージは
distだけで軽い(起動も配布もラク)🎈
3) tsconfig側の“速くするスイッチ”🔧🧠
✅ まずはこれだけでOK(速さ優先の基本)⚡️
incremental: true…差分ビルドの要(typescriptlang.org)tsBuildInfoFile…差分情報の置き場を固定(typescriptlang.org)skipLibCheck: true…ライブラリ型チェックをスキップして速くする(精度は少し落ちる)(typescriptlang.org)
{
"compilerOptions": {
"outDir": "dist",
"incremental": true,
"tsBuildInfoFile": ".cache/tsbuildinfo",
"skipLibCheck": true
}
}
skipLibCheckは「速いけど、依存ライブラリの型の整合性チェックは弱くなる」やつです。 体感でビルドが軽くなることが多いので、まずONで試す価値ありです💨(typescriptlang.org)
4) “速くならない”あるある😇⚠️
あるある①:.tsbuildinfo が最終イメージに混ざる😵
outDir配下やdistと一緒に保存すると、最終ステージにコピーされがちです。
→ だから .cache/tsbuildinfo に逃がすのが気持ちいいです🛟(typescriptlang.org)
あるある②:キャッシュマウントを使ってるつもりが効いてない🙃
RUN --mount=type=cache は BuildKit前提です。(Docker Documentation)
(今どきは標準だけど、環境によっては無効化されてたりします)
あるある③:COPY . . が雑で毎回いろいろ壊す🧨
テスト・README・ローカル成果物などまで混ざると、ちょい変更でキャッシュ全崩壊します。
→ COPY src ./src みたいに “必要な物だけCOPY” が強い💪✨
5) 🧪ミニ演習:ビルド時間が落ちるのを体感しよう⏱️📉
演習A:まず“分離”だけで速くする🏗️
-
いまのDockerfileを上の「deps / build / runner」構成に寄せる
-
2回ビルドして、2回目がどれだけ速いか見る👀✨
- 2回目が速い=レイヤキャッシュが働いてるサイン🧱
演習B:差分ビルドを効かせる⚡️
tsconfigにincrementalとtsBuildInfoFileを入れる(typescriptlang.org)- Dockerfileの
npm run buildに--mount=type=cache,target=/app/.cacheを付ける(Docker Documentation) srcの小さい変更(1行)→ビルド- もう1回別の小さい変更→ビルド → 2回目以降のビルドが軽くなるのを狙う🎯
演習C:skipLibCheckの効き具合を測る🏎️
skipLibCheck: falseでビルドskipLibCheck: trueでビルド(typescriptlang.org) → 差が出たら「このプロジェクトは型チェックが重め」って分かる👍
6) 🤖AI活用:速くする“レビュー依頼テンプレ”3連発💬✨
① Dockerfileレビュー(キャッシュ目線)🧱
- 「このDockerfileでキャッシュが壊れやすい行を3つ指摘して、直した案を出して」
- 「依存導入(npm ci)とビルド(tsc)のレイヤを分ける最短構成にして」
② tsconfigレビュー(速度と安全のバランス)⚖️
- 「ビルド速度が遅い。
incremental/tsBuildInfoFile/skipLibCheckを使って、メリデメ込みで提案して」
③ “最終イメージが重い”問題の切り分け🪶
- 「最終イメージに開発用ツールやキャッシュが混ざってないかチェックして、削る方針を箇条書きで」
7) まとめ:第20章チェックリスト✅✨
-
depsとbuildを分けて、依存キャッシュを守った🧱 -
distをマルチステージで運ぶ形にした📦(Docker Documentation) -
incrementalとtsBuildInfoFileで差分ビルドの土台を作った🧠(typescriptlang.org) -
RUN --mount=type=cacheで.cacheをビルド間で残した⚡️(Docker Documentation) -
skipLibCheckを試して、速度差を計測した🏎️(typescriptlang.org)
次の第21章は、いよいよ **「ファイルが遅い(特にWindows×コンテナ)」**の現実編です 🪟🐢 ここで “体感が一段階” 変わりますよ…!🔥