JA Deployment Build Process - aku11i/phantom GitHub Wiki

ビルドプロセス

English | 日本語

このドキュメントでは、配布用のPhantomをビルドする方法とビルドシステムのアーキテクチャについて説明します。

ビルド概要

Phantomは、高速で効率的なビルドのためにesbuildを使用したカスタムTypeScriptビルドスクリプトを使用します。

ビルドスタック

  • ビルドツール: esbuild(非常に高速なJavaScriptバンドラー)
  • 言語: TypeScript
  • ターゲット: Node.js v22+
  • モジュール形式: ESモジュール(ESM)
  • 出力: 自己完結型実行可能ファイル

ビルドスクリプト

ソース: build.ts

ビルドプロセスはTypeScriptファイルで定義されています:

import { build } from "esbuild";
import { chmod, mkdir } from "node:fs/promises";
import { dirname } from "node:path";

async function main() {
  const entryPoint = "src/bin/phantom.ts";
  const outfile = "dist/phantom.js";

  // 出力ディレクトリが存在することを確認
  await mkdir(dirname(outfile), { recursive: true });

  // esbuildでビルド
  await build({
    entryPoints: [entryPoint],
    outfile,
    bundle: true,
    platform: "node",
    target: "node22",
    format: "esm",
    sourcemap: true,
    minify: false,
    banner: {
      js: "#!/usr/bin/env node",
    },
  });

  // 実行可能にする
  await chmod(outfile, 0o755);
}

ビルド設定

esbuildオプション

オプション 目的
bundle true すべての依存関係を単一ファイルにバンドル
platform "node" Node.js環境をターゲット
target "node22" Node.js v22の機能を使用
format "esm" ESモジュールを出力
sourcemap true デバッグ用のソースマップを生成
minify false コードを読みやすく保つ
banner #!/usr/bin/env node ファイルを実行可能にする

出力構造

dist/
├── phantom.js      # メイン実行可能ファイル(バンドル済み)
└── phantom.js.map  # デバッグ用ソースマップ

ビルドの実行

基本的なビルド

# ビルドを実行
pnpm build

# または直接実行
npx tsx build.ts

ビルド出力

$ pnpm build
Building Phantom...
✓ Built dist/phantom.js (150KB)
✓ Made executable
Build completed in 0.2s

ビルドプロセスの詳細

1. 依存関係の解決

esbuildは自動的に:

  • すべてのインポートを解決
  • TypeScriptファイルをバンドル
  • node_modulesを処理(開発時のみ)
  • package.jsonのexportsを尊重

2. TypeScriptコンパイル

  • TypeScriptはesbuildによってコンパイル
  • 個別のtscステップは不要
  • 型チェックは別途実行
  • 高速な増分ビルド

3. モジュールバンドリング

入力:                      出力:
src/                       dist/phantom.js
├── bin/phantom.ts   →     (単一のバンドルファイル)
├── cli/handlers/*
├── core/worktree/*
└── core/git/*

4. 実行可能ファイルの作成

ビルドスクリプトは:

  1. シェバン(#!/usr/bin/env node)を追加
  2. 実行権限を設定(chmod 755
  3. すぐに実行できるCLIツールを作成

ビルドの最適化

なぜミニファイしないのか?

minify: false  // 以下の理由で読みやすく保つ:
  1. デバッグ - スタックトレースが有用なまま
  2. サイズ - すでに小さい(~150KB)
  3. パフォーマンス - ランタイムの違いは無視できる
  4. セキュリティ - 隠すべき機密コードなし

バンドルサイズ分析

何が含まれているかを確認:

# バンドルを分析
npx esbuild src/bin/phantom.ts --bundle --analyze

# 出力に表示される内容:
# - ファイルサイズ
# - 含まれるモジュール
# - ツリーシェイキングの結果

開発ビルド vs 本番ビルド

開発ビルド

現在のビルド設定は開発用に最適化されています:

{
  sourcemap: true,   // デバッグサポート
  minify: false,     // 読みやすい出力
}

本番ビルド(必要な場合)

本番最適化の場合:

{
  sourcemap: false,  // より小さいサイズ
  minify: true,      // 圧縮された出力
  treeShaking: true, // デッドコードを削除
}

ビルド統合

package.jsonスクリプト

ソース: package.json#L13-L14

{
  "scripts": {
    "build": "tsx build.ts",
    "prepublishOnly": "pnpm run build"
  }
}

自動ビルド

  • 公開時: prepublishOnlyがビルドを実行
  • CI/CD: GitHub Actionsでビルドが実行
  • ローカル開発: 手動でpnpm build

クロスプラットフォームの考慮事項

ファイルパス

ビルドはパスを正しく処理します:

// Node.jsのpathモジュールを使用
import { dirname, join } from "node:path";

// ハードコードされたパスではない
const outfile = join("dist", "phantom.js");

改行コード

  • ビルドはLF改行を出力
  • Git設定により一貫性を確保
  • Windows、macOS、Linuxで動作

実行権限

// Unix形式の権限
await chmod(outfile, 0o755);

// 以下と同等: -rwxr-xr-x
// 所有者: 読み取り、書き込み、実行
// グループ: 読み取り、実行
// その他: 読み取り、実行

ビルド成果物

含まれるもの

ビルドには以下が含まれます:

  • src/からのすべてのソースコード
  • 型定義(コンパイル時に除去)
  • ランタイム依存関係なし
  • 開発依存関係なし

除外されるもの

バンドルされないもの:

  • テストファイル(*.test.ts
  • 開発依存関係
  • TypeScriptソースファイル
  • ドキュメント

ビルドパフォーマンス

メトリクス

典型的なビルド時間:

  • フルビルド: ~200ms
  • 増分: ~50ms
  • ウォッチモード: 即座

なぜesbuildか?

他のバンドラーとの比較:

ツール ビルド時間 機能
esbuild 0.2秒 高速、シンプル
Webpack 3-5秒 複雑、プラグイン
Rollup 2-3秒 ツリーシェイキング
tsc 1-2秒 型チェックのみ

ビルドのトラブルシューティング

よくある問題

1. ビルドが失敗する

# Nodeバージョンを確認
node --version  # v22+である必要があります

# クリアして再ビルド
rm -rf dist
pnpm build

2. インポートエラー

// ✓ 正しい - 拡張子付き
import { something } from "./module.js";

// ✗ 間違い - 拡張子なし
import { something } from "./module";

3. モジュールが見つからない

# 依存関係がインストールされていることを確認
pnpm install

# インポートパスを確認
# 相対パスまたはnode_modulesからである必要があります

ビルドの問題をデバッグ

# 詳細なesbuild出力
npx esbuild src/bin/phantom.ts \
  --bundle \
  --platform=node \
  --log-level=debug

# バンドルされた出力を確認
cat dist/phantom.js | less

カスタムビルドタスク

ビルド前のステップを追加

// build.ts内
async function prebuild() {
  // distディレクトリをクリーン
  await rm("dist", { recursive: true, force: true });
  
  // バージョン情報を生成
  await generateVersion();
}

async function main() {
  await prebuild();
  await build({ /* ... */ });
}

ビルド後のステップ

async function postbuild() {
  // 追加ファイルをコピー
  await copyFile("LICENSE", "dist/LICENSE");
  
  // メタデータを生成
  await writeFile("dist/metadata.json", JSON.stringify({
    version,
    buildTime: new Date().toISOString(),
  }));
}

CI/CDビルドプロセス

GitHub Actionsビルド

CIパイプラインは以下を実行:

- name: Build
  run: pnpm build

- name: Verify build
  run: |
    test -f dist/phantom.js
    test -x dist/phantom.js

リリースビルド

npmリリース用:

# バージョンバンプ
npm version patch

# ビルドして公開
npm publish
# prepublishOnlyが自動的にビルドを実行

ビルドのベストプラクティス

1. ビルドを高速に保つ

  • 速度のためにesbuildを使用
  • 不要な変換を避ける
  • 可能な場合はキャッシュ

2. 再現可能なビルド

  • 依存関係をロック(pnpm-lock.yaml
  • 正確なNodeバージョンを指定
  • 一貫した環境を使用

3. ビルドの検証

常にビルドを検証:

# ビルドされた実行可能ファイルをテスト
./dist/phantom.js --version
./dist/phantom.js list

# ファイルサイズを確認
ls -lh dist/phantom.js

4. ソースマップ

開発に含める:

  • デバッグサポート
  • エラースタックトレース
  • パフォーマンスプロファイリング

高度なビルドトピック

カスタムesbuildプラグイン

// 例: ビルド情報を追加
const buildInfoPlugin = {
  name: "build-info",
  setup(build) {
    build.onResolve({ filter: /^BUILD_INFO$/ }, () => ({
      path: "BUILD_INFO",
      namespace: "build-info",
    }));
    
    build.onLoad({ filter: /.*/, namespace: "build-info" }, () => ({
      contents: JSON.stringify({
        version: process.env.npm_package_version,
        buildTime: new Date().toISOString(),
      }),
      loader: "json",
    }));
  },
};

// ビルドで使用
await build({
  plugins: [buildInfoPlugin],
  // ... その他のオプション
});

ウォッチモード

開発用:

// build.tsに追加
if (process.argv.includes("--watch")) {
  const ctx = await context({
    // ... ビルドオプション
  });
  
  await ctx.watch();
  console.log("変更を監視中...");
}

まとめ

Phantomのビルドプロセスは:

  1. 高速 - esbuildによるサブ秒ビルド
  2. シンプル - 単一のTypeScriptファイル設定
  3. 信頼性 - 一貫した、再現可能な出力
  4. 効率的 - 小さく、自己完結型の実行可能ファイル
  5. 開発者フレンドリー - ソースマップと読みやすい出力

ビルドシステムは、効率的で配布可能なCLIツールを生成しながら、開発者体験を優先します。