背景
PR #906 で @d-zero/site-migrator に resolveIdTemplate 純関数を追加した。rewritePageRefs が残す {{<id>}} token を後段ビルド時に実 URL に解決するためのもの。site-migrator 自身は URL を知らないため、組み込みはビルドツール側の責務として残してある。
このイシューでやること
@d-zero/scaffold の kamado.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/crawler → puppeteer(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
背景
PR #906 で
@d-zero/site-migratorにresolveIdTemplate純関数を追加した。rewritePageRefsが残す{{<id>}}token を後段ビルド時に実 URL に解決するためのもの。site-migrator 自身は URL を知らないため、組み込みはビルドツール側の責務として残してある。このイシューでやること
@d-zero/scaffoldのkamado.config.tsに id 解決ロジックを組み込み、site-migrator 出力ページが scaffold ビルドでそのまま使えるようにする。検討時に下記のうちどれを採るか決める必要がある:
案 A: scaffold に inline
kamado.config.ts内に 10 行程度の regex replace を直接書く。resolveIdTemplateと仕様コピーが二重化(仕様変更時に同期が必要)案 B: 新規軽量 workspace パッケージ
@d-zero/page-id-tokenのような純関数だけの新パッケージをpackages/@d-zero/に作り、scaffold と site-migrator の両方から使う。案 C: 別リポの
@d-zero/sharedに移す@d-zero/shared(別リポ) に純関数を移し、scaffold と site-migrator の両方から使う。案 D: site-migrator を publish 解禁してそのまま import
@nitpicker/crawler→puppeteer(Chromium 100MB+ postinstall)が伝播し、site-migrator を使わない scaffold ユーザーに不要な代償実装メモ(採用案が決まったら参照)
注意点
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: "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 (別リポ)
@d-zero/shared/resolve-id-template追加 issue (案 C の受け入れ先)関連 PR
resolveIdTemplate純関数追加)rewritePageRefsで{{<id>}}token を生成)extractMainContent+extractPages)@d-zero/site-migratorの新設)