Astro部署Google Cloud Run后客户端PUBLIC环境变量未定义问题
PUBLIC_前缀的环境变量 我正在Turborepo中部署一个SSR模式的Astro应用,已经打包成Docker容器部署到Google Cloud Run。本地开发时,在.env文件配置PUBLIC_VALUE="https://example.com/example",客户端通过import.meta.env.PUBLIC_VALUE能正常获取并使用,yarn run dev完全正常。但部署到Cloud Run后,客户端的该变量显示为undefined。
我熟悉Cloud Run的使用,此前其他应用通过Cloud Console设置环境变量后用process.env可以正常获取,但此处客户端无法拿到import.meta.env.PUBLIC_VALUE。项目构建和运行都没有报错,相关配置如下:
astro.config.js 配置
import { defineConfig } from 'astro/config'; import tailwind from "@astrojs/tailwind"; import react from "@astrojs/react"; import 'dotenv/config'; import node from "@astrojs/node"; export default defineConfig({ integrations: [tailwind(), react()], output: 'server', adapter: node({ mode: "standalone" }) });
Dockerfile 配置
FROM node:18-alpine AS base RUN apk add --no-cache libc6-compat RUN apk update RUN yarn global add turbo FROM base AS builder WORKDIR /app COPY . . RUN turbo prune --scope=admin-frontend --docker FROM base AS installer WORKDIR /app COPY .gitignore .gitignore COPY --from=builder /app/out/json/ . COPY --from=builder /app/out/yarn.lock ./yarn.lock RUN yarn install COPY --from=builder /app/out/full/ . COPY turbo.json turbo.json RUN turbo run build --filter=admin-frontend... FROM base AS runner WORKDIR /app RUN addgroup --system --gid 1001 expressjs RUN adduser --system --uid 1001 expressjs USER expressjs COPY --from=installer /app . ENV HOST=0.0.0.0 ENV PORT=3000 EXPOSE 3000 CMD node ./apps/admin-frontend/dist/server/entry.mjs
原因分析
Astro中PUBLIC_前缀的环境变量是构建时注入客户端代码的:本地开发时,Astro会实时读取.env文件并注入变量;但你的Docker流程是在镜像构建阶段(installer阶段)执行turbo build,此时Cloud Run设置的环境变量还未生效(Cloud Run的环境变量是容器运行时才注入的),导致客户端代码里的import.meta.env.PUBLIC_VALUE被替换为undefined。
即使是SSR模式,客户端代码中的import.meta.env.PUBLIC_*依然遵循构建时注入的规则,不会自动读取运行时的环境变量。
解决方法
方法1:构建镜像时传入环境变量(适合固定值场景)
修改Dockerfile,在构建阶段添加参数接收环境变量,确保构建时注入客户端代码:
# 在installer阶段添加以下内容 ARG PUBLIC_VALUE ENV PUBLIC_VALUE=$PUBLIC_VALUE # 保留原有的RUN turbo run build命令 RUN turbo run build --filter=admin-frontend...
构建镜像时传递参数:
docker build --build-arg PUBLIC_VALUE="https://example.com/example" -t your-image-name .
如果使用Cloud Build,在cloudbuild.yaml中配置args传递该参数即可。
方法2:运行时从服务端传递变量到客户端(适合动态调整场景)
在SSR服务端代码中读取运行时环境变量,通过全局变量或props传递给客户端:
- 在Astro布局文件(如
src/layouts/Layout.astro)中添加服务端代码:
--- // 服务端代码:读取Cloud Run设置的环境变量 const publicValue = process.env.PUBLIC_VALUE; --- <html> <head> <script> // 将变量挂载到window,客户端可直接访问 window.PUBLIC_VALUE = "{publicValue}"; </script> </head> <body> <slot /> </body> </html>
- 客户端组件中使用
window.PUBLIC_VALUE替代import.meta.env.PUBLIC_VALUE。
方法3:通过Vite配置运行时注入变量(推荐SSR场景)
在astro.config.js中通过Vite的define配置,将服务端运行时的环境变量注入客户端代码:
import { defineConfig } from 'astro/config'; import tailwind from "@astrojs/tailwind"; import react from "@astrojs/react"; import node from "@astrojs/node"; export default defineConfig({ integrations: [tailwind(), react()], output: 'server', adapter: node({ mode: "standalone" }), vite: { define: { // 将服务端环境变量转为客户端可识别的格式,运行时生效 'import.meta.env.PUBLIC_VALUE': JSON.stringify(process.env.PUBLIC_VALUE), }, }, });
这种方式不需要修改客户端代码,Cloud Run设置的环境变量会在容器运行时自动注入,重启服务即可更新变量值。
内容的提问来源于stack exchange,提问作者Graunephar

