Astro + Vite 生产环境变量为何失效:PUBLIC_ 前缀是关键
导语
在 Astro + Vite 项目中,开发者常遇到一个典型问题:本地开发一切正常,生产构建却抛出 TypeError: Cannot read properties of undefined (reading "API_URL")。.env 文件存在、变量已定义,但生产环境中它就是 undefined。本文译自 dev.to 上的一篇排查记录,作者拆解了这一常见陷阱的成因与两种修复路径。
译注:本文原文发布于 dev.to,作者为 popdasedev,原文链接见文末。
问题现象
作者在生产构建中遇到的报错如下:
TypeError: Cannot read properties of undefined (reading "API_URL")同样的代码在开发环境运行良好,.env 文件就在那里,变量也确实定义了。然而到了生产环境,它变成了 undefined。这是 Vite 与 Astro 最常见的坑之一,而错误信息本身几乎不提供任何线索。
核心规则:只有 PUBLIC_ 前缀会暴露给客户端
Vite 只会把以 PUBLIC_ 为前缀的环境变量暴露给客户端,其余全部保留在服务端。
PUBLIC_API_URL=https://api.example.com
API_SECRET=abc123如果你在客户端组件中引用 import.meta.env.API_SECRET,结果就是 undefined。这不是变量缺失,而是 Vite 有意隐藏了它。这是特性而非缺陷——它能防止你把 API 密钥打包发给每一位访客。
典型症状
.env中定义了API_KEY- 组件调用了
import.meta.env.API_KEY - 开发环境正常工作
- 生产环境返回
undefined - 代码抛出
TypeError
Vite 在开发模式下较为宽松,而在生产构建阶段,任何没有 PUBLIC_ 前缀的变量都会被剥离。
修复方案
方案一:重命名变量
如果该值可以安全暴露:
PUBLIC_API_URL=https://api.example.com然后用新名称引用:
const apiUrl = import.meta.env.PUBLIC_API_URL方案二:保留在服务端
如果该值是密钥,把它移入 Astro API 路由,例如 src/pages/api/something.json.ts:
export const prerender = false
export async function GET() {
const response = await fetch("https://api.example.com/data", {
headers: { Authorization: `Bearer ${import.meta.env.API_SECRET}` }
})
const data = await response.json()
return new Response(JSON.stringify(data))
}随后在客户端调用 /api/something.json,密钥始终留在服务端。
Cloudflare 的隐藏陷阱
即使修复了前缀问题,第二个问题往往还会出现。.env 文件不应提交到 Git,而 Cloudflare 也不会读取它。你需要在 Cloudflare 控制台的 Settings → Environment variables 中,为 Production 和 Preview 分别设置相同的变量,然后触发一次新的部署。
通用原则
| 变量类型 | 可见范围 | 是否可暴露 |
|---|---|---|
PUBLIC_ 前缀 | 客户端与服务端 | 安全 |
| 其他任意变量 | 仅服务端 | 不安全 |
只要一个值没有 PUBLIC_ 前缀,就应当把它当作密钥对待。
原文链接
https://dev.to/popdasedev/why-my-env-variables-were-undefined-in-production-astro-vite-1ac1