🧊

@astrojs/node はprerenderされたページをどう扱うのか

AstroのNode.jsアダプタを使って、基本的にサーバーで動作するサイトを作るとする。

このとき、astro.config.jsoutput: "server"を指定しつつも、Aboutページのような静的なページは、export const prerender = trueすることもできる。

ただこのprerenderされたページって、そういえばどうやってレスポンスされるんやっけ?

既に静的に生成されてるなら、Nodeまでリクエストを到達させなくてもよくない?CDNで静的アセットとして存在しなかったリクエストだけ、Nodeに任せたいかもなって。

そんなとき、どうやるのか。

そもそも

そういう用途のために、このアダプターにはmodeというオプションがあった。

export default defineConfig({
  output: "server",
  adapter: node({
    mode: "middleware", // or `"standalone"`
  }),
});

このmodeを見て、ビルド時のエントリーポイントの中身が変わる仕掛け。

https://github.com/withastro/adapters/blob/f487c91f0b59ca6adb22a12de85fc6bbf67cd843/packages/node/src/server.ts#L19-L20

middlewareモード

https://github.com/withastro/adapters/blob/f487c91f0b59ca6adb22a12de85fc6bbf67cd843/packages/node/src/middleware.ts

このモードでは、Expressや既成のフレームワークのMiddlewareとして動く。 fn(req, res, next, locals)というI/Oを想定してた。

動的な部分のみが対象となるので、静的に生成したものに関しては、何もしてくれない。

上物の実装側で、./dist/client配下に生成されたものを、自分でサーブしないといけない。

standaloneモード

https://github.com/withastro/adapters/blob/f487c91f0b59ca6adb22a12de85fc6bbf67cd843/packages/node/src/standalone.ts

こっちのモードでビルドすると、node ./dist/server/entry.mjsでそのままサーバーが起動するコードになる。 中身はExpressとかではなく、node:http(s)で書かれた素直な実装になってた。

middlewareモードとは違って、静的ファイルも対象にしてくれてる。

https://github.com/withastro/adapters/blob/f487c91f0b59ca6adb22a12de85fc6bbf67cd843/packages/node/src/serve-static.ts

node:fsでファイルを見つけて、それをsendを使ってStreamingで返してるだけ。

pillarjs/send: Streaming static file server with Range and conditional-GET support https://github.com/pillarjs/send

./dist/client配下に生成されるファイルはハッシュを含むファイル名になってるので、アグレッシブにキャッシュさせる設定にしてあるとのこと。

Cache-Control: public, max-age=31536000, immutable

というわけで

どちらのモードにするにせよ、./dist/client配下を自分で先に返すようにしちゃえばいい。

その裏がstandalonemiddlewareモードかは、お好きにどうぞという感じ。

@astrojs/node | Docs https://docs.astro.build/en/guides/integrations-guide/node/