envの違い
このサイトに新しい機能を追加する更新をしていた時にハマった
process.env import.meta.env locals.runtime.envの違いに
よく分かってないんだけど、Astro+Cloudflare Workers の場合は、locals.runtime.envを使うべきという事っぽい
解説間違ってるかもだけど
このサイトの構成、Astro で作成して Cloudflare Pages にデプロイ、基本は静的なページで一部動的な部分(API)がありそれは、Astro のインテグレーションで Cloudflare Workers でインテグレーションして Cloudflare Workers で API 部分を動かしてる、っていう感じになってるはずなんだよね
それで、環境変数を使いたい時って大抵 API の部分で使いたいってなると思うんだけど
export async function POST({ locals }) {
const secret = locals.runtime.env.SECRET_KEY;
}
こういう感じにlocals.runtime.envを使わないといけない
まず、サイトは Astro からビルドされて html や js になり、それが Cloudflare に公開されて Workers で動く部分は Workers のサーバーで動く訳だ、Astro は Vite を使ってビルドするぞ
それで API の部分もビルドされるんだよな
import.meta.envは Vite が利用するオブジェクトで Astro は Vite を使ってビルドしてるのでこれがビルド時に使えるんだけど、ビルドする際にこれらの変数は展開されるんだな
それで、展開される訳なんだけど、環境変数が漏れ出ないようにするために、Astro はクライアント側のコードではPUBLIC_*というようなPUBLIC_から始まる環境変数しか使えないようにしてるんだな、それ以外の環境変数は undefined になって展開されるんだ
だから、環境変数にSECRET_KEY=hogeとか入れてた場合クライアント側のコードではconst secret ="hoge"ではなくconst secret = undefinedになるんだな
https://docs.astro.build/en/guides/environment-variables/#vites-built-in-support
環境変数名をPUBLIC_*というようなPUBLIC_から始まる環境変数名にすると
pages/api/test.ts
import type { APIRoute } from "astro"
export const prerender = false
export const GET: APIRoute = async ({ locals }) => {
return Response.json({
buildTime: import.meta.env.PUBLIC_KEY,
runtime: locals.runtime.env.PUBLIC_KEY,
})
}
buildTime: "hoge",
runtime: locals.runtime.env.PUBLIC_KEY,
という感じにビルドされるんだ
デプロイ視点から見てると Cloudflare というサーバー上でコードが動いてるんだけど、その前に Astro(Vite)が一回ビルドしてるからそこで値になってるんだな~
astro buildして dist の中の_worker.js フォルダの中とかの js コード見ると分かりやすいですね
それと
locals.runtime.envは Astro の Cloudflare adapter / integration が dev 時に Workers 互換の env をエミュレートしている
ので開発時も使える
はい
以上、たぶん、うん…
適当まとめ
仕組み | いつ値が決まるか
process.env | Node 実行時
import.meta.env | ビルド時
locals.runtime.env | Workers 実行時
そもそも俺は環境変数はいつ値が決まるかという事を意識してなかったな、それが敗因だぜ