Skip to content

scaffold への resolveIdTemplate 組み込み + 依存膨張回避策の検討 #907

@YusukeHirao

Description

@YusukeHirao

背景

PR #906@d-zero/site-migratorresolveIdTemplate 純関数を追加した。rewritePageRefs が残す {{<id>}} token を後段ビルド時に実 URL に解決するためのもの。site-migrator 自身は URL を知らないため、組み込みはビルドツール側の責務として残してある。

このイシューでやること

@d-zero/scaffoldkamado.config.ts に id 解決ロジックを組み込み、site-migrator 出力ページが scaffold ビルドでそのまま使えるようにする。

検討時に下記のうちどれを採るか決める必要がある:

案 A: scaffold に inline

kamado.config.ts 内に 10 行程度の regex replace を直接書く。

  • ✅ 依存ツリーを変えない(puppeteer 等が伝播しない)
  • ✅ 一番手数が少ない
  • ❌ site-migrator 側の resolveIdTemplate と仕様コピーが二重化(仕様変更時に同期が必要)

案 B: 新規軽量 workspace パッケージ

@d-zero/page-id-token のような純関数だけの新パッケージを packages/@d-zero/ に作り、scaffold と site-migrator の両方から使う。

  • ✅ 仕様の単一ソース化
  • ✅ scaffold 経由で puppeteer が伝播しない(純関数だけのパッケージなので依存ゼロ)
  • ❌ パッケージ数が増えるオーバーヘッド(release タグ、CI、ドキュメント等)

案 C: 別リポの @d-zero/shared に移す

@d-zero/shared (別リポ) に純関数を移し、scaffold と site-migrator の両方から使う。

  • ✅ 仕様の単一ソース化
  • ✅ 既存の共有パッケージなのでパッケージ数は増えない
  • ❌ 別リポへの PR が必要(本リポ単独で完結しない)

案 D: site-migrator を publish 解禁してそのまま import

  • ✅ 既に書いた API がそのまま使える
  • ❌ scaffold 経由で @nitpicker/crawlerpuppeteer(Chromium 100MB+ postinstall)が伝播し、site-migrator を使わない scaffold ユーザーに不要な代償

実装メモ(採用案が決まったら参照)

// kamado.config.ts (概要)
const idToUrl = new Map<number, string>();

pageList: async (pageAssetFiles) => {
  idToUrl.clear();
  for (const file of pageAssetFiles) {
    const { metaData } = await file.get();
    if (typeof metaData.id === 'number') idToUrl.set(metaData.id, file.url);
  }
  // kamado は mutable な配列を期待するので spread でコピー
  return [...pageAssetFiles];
},
compilers: [
  pageCompiler({
    replace: (content) => resolveIdTemplate({ html: content, idMap: idToUrl, onUnresolved: ... }),
    // ...
  }),
],

注意点

  • pageList は kamado の getGlobalData 経由でサーバ起動時に 1 度だけ走る。dev サーバ中にページを増減した場合は再起動が必要(kamado 自体がそうなっている)。
  • pageCompiler.options.globalData.dir が設定されているときだけ kamado は pageList を呼ぶので、globalData を外す方向の改修と組み合わせる場合は注意。
  • as const satisfies UserConfig 構文下では pageList の戻り値型 ((CompilableFile & { title?: string })[]) と引数の readonly CompilableFile[] がミスマッチするので spread コピーが必須。
  • 同一 id を持つページが複数あると last-write-wins で silent に上書きされる。警告を出す仕掛けが要検討。
  • id: "10000"(YAML が文字列で受け取った場合)は typeof === 'number' ガードで silent drop される。数値強制 or 警告のどちらかにする必要あり。

QA レビューで上がった追加観点

  • Number.isSafeInteger チェックで極大 id の精度欠落を検出
  • assignPageIds → buildPageIdLookup → rewritePageRefs → resolveIdTemplate のラウンドトリップ統合テスト
  • 連続トークン {{1}}{{2}} / 隣接 {{1}}{{1}} の置換境界
  • ?q=foo#h を含む URL が idMap の値側にある場合のクエリ二重化挙動(README の "callers が前処理する" 仕様の回帰テスト)

関連 issue (別リポ)

関連 PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions