Astro v4.3 (2024/02/02更新)
Astro v4.3でbuild.formatに'preserve'
が追加された。
'preserve'
ではファイル構成のままビルドされる。
src/pages/about.astro -> dist/about.html
src/pages/about/index.astro -> dist/about/index.html
build.format: 'file'でindex.htmlを生成する
Astroはbuild.formatを'file'
に設定することで各ページをディレクトリではなくHTMLファイルとしてビルドする。
しかしこの設定ではルート以外のindex.astroからindex.htmlが生成されない。Astroファイルと出力されるHTMLファイルの対応は以下のようになる。
src/pages/index.astro -> dist/index.html
src/pages/foo/index.astro -> dist/foo.html
src/pages/foo/bar.astro -> dist/foo/bar.html
src/pages/foo/index.astro
からはdist/foo.html
を生成したい、つまりpages以下のディレクトリ構造を保ったままHTMLを生成したいときのために、ビルド後のファイルをリネームするAstroインテグレーションを作った。
Astroインテグレーションのhookにはビルドが完了した後に実行されるastro:build:done
がある。
astro:build:done
のroutes
オプションで、生成されたルートとそのメタデータのリストが取得できるので、ここからインデックスルートのHTMLファイルを探し、リネームする。
環境
- Astro: v4.0.3
該当するHTMLファイルを抽出
astro:build:done
のroutes
オプションは以下のプロパティを持つ。
-
route.type
:ルートがHTMLページかそれ以外のエンドポイントかどうか。 -
route.component
:元のファイルのパス。 -
route.pathname
:出力されたページのパス。動的ルートではundefined
になる。
全ルートから/
以外のindex.(astro|md|mdx|html)
を抽出しリネームする。
ソースコード
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { AstroIntegration } from "astro";
let shouldRename = false;
export default function createIntegration(): AstroIntegration {
return {
name: "astro-index-pages",
hooks: {
"astro:config:done": ({ config }) => {
// build.format: 'file'の時のみリネームする
if (config.build.format === "file") {
shouldRename = true;
}
},
"astro:build:done": async ({ dir, routes }) => {
if (!shouldRename) {
return;
}
const outDirPath = fileURLToPath(dir);
await Promise.all(
routes
.filter((route) => {
return (
route.type === "page" &&
route.pathname &&
route.pathname !== "/" &&
path.parse(route.component).name === "index"
);
})
.map(async ({ pathname }) => {
if (!pathname) return;
// リネーム先のディレクトリパス
const targetDirPath = path.join(outDirPath, pathname);
// リネーム前のファイルパス
const beforeFilePath = path.join(outDirPath, `${pathname}.html`);
// リネーム先のファイルパス
const afterFilePath = path.join(outDirPath, pathname, "index.html");
await fs.mkdir(targetDirPath, { recursive: true });
await fs.rename(beforeFilePath, afterFilePath);
}),
)
.then(() => {
logger.info('Success');
})
.catch((err) => {
logger.error(err);
});
},
},
};
}
作成したインテグレーションを設定ファイルに追加する。
import { defineConfig } from 'astro/config'
import indexPages from './astro-index-pages';
export default defineConfig({
integrations: [
indexPages()
]
})
生成されるHTMLファイルは以下になる。
src/pages/index.astro -> dist/index.html
src/pages/foo/index.astro -> dist/foo/index.html
src/pages/foo/bar.astro -> dist/foo/bar.html
おまけ
Write index routes as index.html with build.format: 'file' by matthewp · Pull Request #9209 · withastro/astroでインデックスルートを無視しないbuild.format: 'preserve'
が考案されている。(まだDraftだが……)
このプルリクがマージされたらこのインテグレーションはいらなくなる。
→Astro v4.3でbuild.formatに'preserve'
が追加された。