Wasp 0.13 环境变量实战指南:.env.client 与 .env.server 的加载、优先级与构建注入原理
【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp
本文基于 Wasp 0.13 版本文档中的 Env Variables 章节,系统讲解 Wasp 项目中客户端与服务端环境变量的定义、读取方式、开发期与生产期的注入机制,并结合 waspc 编译器源码剖析.env.server/.env.client文件的实际解析链路与REACT_APP_前缀的强制约束。读完本文,你可以独立完成 Wasp 项目在不同环境(开发、预发、生产)下的环境变量配置,并理解 Wasp 在编译与构建阶段如何区分、合并和注入这些变量。
环境变量的基本作用
环境变量(Environment variables)用于根据项目运行的上下文来配置项目,使同一个代码库在不同环境(开发、预发、生产)中表现不同。典型场景包括:
- 开发时连接运行在本地的开发数据库,生产时连接生产数据库;
- 开发时使用测试用的 Stripe 账户,生产时使用真实 Stripe 账户。
部分环境变量是 Wasp 运行所必需的,例如数据库连接串、社交登录(social auth)所需的密钥;你也可以为任意其他目的自定义变量。在 Wasp 中,环境变量既可以在客户端代码中使用,也可以在服务端代码中使用,两者的可见性和注入方式完全不同。
客户端环境变量:REACT_APP_ 前缀与 import.meta.env
客户端环境变量会在构建和打包阶段被嵌入客户端代码,因此它们是公开的、任何拿到前端产物的人都能读到。所以绝不能在其中存放任何机密(如 API secret key)。
为了让 Wasp(底层的 Vite 构建)识别客户端环境变量,它们必须以REACT_APP_为前缀,例如:
REACT_APP_SOME_VAR_NAME=...在客户端代码中通过import.meta.env读取:
console.log(import.meta.env.REACT_APP_SOME_VAR_NAME)console.log(import.meta.env.REACT_APP_SOME_VAR_NAME)源码层面的强制约束:这个前缀并不是约定俗成,而是由 Wasp 生成的 Vite 配置强制设定的。在生成代码模板 waspConfig.ts 中,envPrefix: "REACT_APP_"被列入forcedOptions(强制选项),并且throwIfOverridingForcedOptions会在用户的vite.config.ts试图覆盖它时直接抛出错误。也就是说,从源码结构看,客户端变量前缀在 Wasp 0.13 中是编译器写死的策略,用户无法通过自定义 Vite 配置绕过。
服务端环境变量:process.env 与机密托管
服务端环境变量不会被打包进前端产物,因此可以安全地存放机密值(如 API secret key)。它们不需要任何特殊前缀,直接命名为SOME_VAR_NAME=...即可,并在服务端代码中这样读取:
console.log(process.env.SOME_VAR_NAME)console.log(process.env.SOME_VAR_NAME)一个值得注意的内部细节:Wasp 自己也会向客户端注入一个前缀变量。从 Common.hs 可以看到,REACT_APP_API_URL(serverUrlEnvVarName)由 Wasp 生成器自动设置,用于让客户端组件知道服务端的 URL;同时还会注入一个客户端端口变量。这解释了为什么文档强调“部分环境变量是 Wasp 必需”的——它们由 Wasp 在运行配置中自动生成,而非用户手动提供。
开发期定义环境变量
开发阶段有两种方式向 Wasp 项目提供环境变量:
- 使用
.env文件(推荐); - 使用 shell(适合做临时覆盖)。
1. 使用 .env(dotenv)文件(推荐)
在项目根目录创建两个职责分明的文件:
.env.server—— 提供给服务端的变量;.env.client—— 提供给客户端的变量。
两者的书写格式都是NAME=VALUE:
DATABASE_URL=postgresql://localhost:5432 SOME_VAR_NAME=somevalueREACT_APP_SOME_VAR_NAME=somevalue这两个文件不应提交到版本控制;Wasp 项目模板自带的.gitignore已经默认忽略它们。
编译器如何解析这些文件:在 waspc/src/Wasp/Project/Env.hs 中,dotEnvServer与dotEnvClient两个常量分别固定了.env.server与.env.client的相对文件名,readDotEnvServer/readDotEnvClient负责在项目目录下查找并解析对应文件(文件不存在时返回空列表)。解析入口parseDotEnvFile定义在 waspc/src/Wasp/Env.hs,它基于 dotenv 解析库,并把解析错误从ErrorCall转成IOException,避免把用户写错的 dotenv 文件误报为编译器 bug。
这两个读取动作发生在项目分析阶段:Analyze.hs 中依次调用readDotEnvServer与readDotEnvClient,将结果写入AppSpec的devEnvVarsServer与devEnvVarsClient字段,供后续代码生成与运行使用。
一个贴心的防坑设计:很多用户会下意识地创建普通.env文件,而 Wasp 并不使用这个名字。为此,warnIfTheDotEnvPresent(Env.hs)会在检测到项目根目录存在.env时输出一条编译警告:“Wasp .env files should be named .env.server or .env.client, depending on their use.”,并在 Project.hs 的编译流程中把该警告合并进最终警告列表。如果你在 Wasp 项目里建了.env却发现变量不生效,编译器会主动提醒你原因。
2. 使用 shell
如果在运行 Wasp 命令(如wasp start)的 shell 中设置了环境变量,Wasp 也会识别它们。可以在.profile等配置文件中设置,或在命令前临时定义:
SOME_VAR_NAME=SOMEVALUE wasp start这并非 Wasp 特有,只是 shell 设置环境变量的通用方式。由于在多项目管理中这种方式比较繁琐,官方不推荐把它作为默认配置方式;但它有一个明确优势——这种方式设置的变量优先级高于.env文件中定义的变量,因此非常适合临时覆盖某个特定变量。
优先级在源码中的落点:Env.hs 中的addEnvVarsOverride在合并两组环境变量时,把“传入的变量”放在“已有变量”之前(注释明确写着Incoming first so that they take priority over existing),再经nubEnvVars按变量名去重保留先出现者——这正是“shell 变量覆盖.env文件变量”这一行为的底层实现。
生产期定义环境变量
开发期可以用.env文件轻松管理变量,但生产期必须换一种方式。
客户端环境变量(生产)
再次强调:客户端变量会被嵌入客户端代码、对所有人可读,永远不要在其中存放机密。生产环境下,把它们作为变量提供给构建命令,例如:
REACT_APP_SOME_VAR_NAME=somevalue npm run build背后机制:构建过程中,Wasp(借助 Vite 的替换机制)会把代码中所有import.meta.env.REACT_APP_SOME_VAR_NAME出现的位置替换成你提供的值。由于这发生在构建期,最终值被直接内联(embed)进客户端产物中,运行期客户端不再依赖任何环境变量。
服务端环境变量(生产)
服务端环境变量如何提供,取决于你部署到哪里。例如部署到 Fly 平台时,可以用flyctlCLI 设置 secret:
flyctl secrets set SOME_VAR_NAME=somevalue各部署平台(Fly、Railway、手动部署等)下环境变量的具体定义方式,可参见同版本文档的 部署手动篇,其中对每种部署选项都有详细说明。
小结:开发期与生产期的注入对照
| 维度 | 客户端变量 | 服务端变量 |
|---|---|---|
| 前缀要求 | 必须REACT_APP_(Vite 配置强制) | 无特殊前缀 |
| 读取方式 | import.meta.env.VAR | process.env.VAR |
| 可见性 | 构建后公开可读,严禁存机密 | 不进入前端产物,可存机密 |
| 开发期提供 | 项目根目录.env.client或 shell | 项目根目录.env.server或 shell |
| 生产期提供 | 作为变量传给构建命令(构建期内联替换) | 由部署平台以 secret/env 方式注入 |
| 优先级 | shell 变量覆盖.env文件(addEnvVarsOverride实现) | 同左 |
从源码结构看,Wasp 0.13 的环境变量体系是一条清晰的链路:wasp start/wasp build触发项目分析 →Analyze.hs读取.env.server/.env.client进入AppSpec→ 代码生成阶段把服务端变量传给运行进程、把客户端变量交给 Vite 按REACT_APP_前缀暴露给import.meta.env。理解了这条链路,你在调试“变量为什么不生效”一类问题时,就能快速定位是命名前缀、文件名(.envvs.env.client/.env.server),还是构建时机出了问题。
【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考