Next.js 中 NEXT_PUBLIC_ 环境变量为何修改后不生效

发布于 更新于 1,081 字 4 分钟阅读

#Next.js 中 NEXT_PUBLIC_ 环境变量为何修改后不生效

#Next.js 中 NEXT_PUBLIC_ 环境变量为何修改后不生效

在 Next.js 项目中,一个常见现象是:容器里的环境变量已经更新,执行 echo​ 也能看到新值,但浏览器端仍然请求旧地址。问题通常不在环境变量是否成功注入,而在于对 NEXT_PUBLIC_ 变量生效时机的理解。

#核心原因:NEXT_PUBLIC_ 是构建时变量

Next.js 会把所有以 NEXT_PUBLIC_​ 开头的环境变量暴露给浏览器端代码。在执行 npm run build​(即 next build​)时,这些变量的值会被内联替换并写入最终生成的 JavaScript 静态文件

例如:

Shell
NEXT_PUBLIC_API_URL=https://api-old.example.com npm run build

客户端代码:

typescript
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

在构建产物中,其效果近似于:

typescript
const apiUrl = "https://api-old.example.com";

因此,它不是浏览器运行时动态读取的配置,而是构建阶段已经确定的常量。

#为什么容器启动时修改变量没有效果

假设镜像构建时使用了旧地址,等到容器启动时才注入新值:

Shell
docker run \
  -e NEXT_PUBLIC_API_URL=https://api-new.example.com \
  your-next-app

此时容器进程确实能读到新值:

Shell
echo "$NEXT_PUBLIC_API_URL"

但前端 JavaScript 文件早已在镜像构建阶段生成,其中仍然写着旧地址。浏览器下载的是这些静态文件,自然不会读取容器启动后才设置的变量。

简而言之:

容器中的环境变量是新值,不代表已经构建完成的浏览器端代码也是新值。

#本地开发时的缓存影响

使用 npm run dev​ 时,Next.js 也可能因为 .next​ 缓存或开发服务未重启而继续使用旧配置。修改 .env​、.env.local 等文件后,建议:

  1. 停止开发服务;
  2. 删除 .next 缓存目录;
  3. 重新执行 npm run dev
Shell
rm -rf .next
npm run dev

如果使用 Windows PowerShell:

PowerShell
Remove-Item -Recurse -Force .next
npm run dev

#可选解决方案

#方案一:在构建阶段传入正确变量

如果每个环境都单独构建镜像,可以在构建时注入变量:

dockerfile
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL

RUN npm run build

构建镜像时传值:

Shell
docker build \
  --build-arg NEXT_PUBLIC_API_URL=https://api.example.com \
  -t your-next-app .

该方式简单直接,但不同环境需要不同构建产物。

#方案二:通过服务端读取运行时变量

不要在客户端直接读取 NEXT_PUBLIC_ 变量,而是在服务端代码中读取普通环境变量,再通过接口、服务端组件或页面数据传给客户端。

typescript
const apiUrl = process.env.API_URL;

普通服务端环境变量可在 Node.js 进程运行时读取,更适合容器启动阶段注入。

需要注意:不要把密码、密钥等敏感值发送给客户端。

#方案三:提供运行时配置文件

容器启动时生成一个浏览器可访问的配置文件,例如 /runtime-config.js

JavaScript
window.__RUNTIME_CONFIG__ = {
  API_URL: "https://api.example.com"
};

业务代码在浏览器端读取:

typescript
const apiUrl = window.__RUNTIME_CONFIG__.API_URL;

这种方式可以实现“构建一次、部署到多个环境”,但需要处理类型声明、加载顺序、缓存策略以及配置文件生成流程。

#方案四:使用相对路径与反向代理

如果前端和 API 由同一域名提供,可以让前端始终请求相对路径:

typescript
fetch("/api/users");

再由 Nginx、Ingress 或网关把 /api 转发到实际后端。这样可以减少前端对环境地址的依赖,也通常更适合容器化部署。

#排查清单

遇到变量修改后不生效时,可以依次检查:

  • 变量是否以 NEXT_PUBLIC_ 开头;
  • 变量是在 next build 之前还是之后设置的;
  • 当前运行的镜像是否使用新变量重新构建;
  • 浏览器下载的 JavaScript 文件中是否仍包含旧值;
  • .next 目录是否残留缓存;
  • 开发服务或生产进程是否已经重启;
  • 浏览器、CDN、Service Worker 是否缓存了旧静态资源;
  • 该配置是否更适合改为服务端运行时变量或反向代理配置。

#总结

NEXT_PUBLIC_ 的关键语义不是“公开的运行时环境变量”,而是“在构建时写入客户端代码的公开变量”。

如果变量需要在容器启动时动态变化,应避免仅依赖 NEXT_PUBLIC_,改用服务端读取、运行时配置文件或反向代理;如果继续使用它,就必须在构建前设置正确的值并重新生成前端产物。

zxb的博客

评论

还没有评论,来说点什么吧。

评论经发布者审核后公开
46 篇文档

文档树

12 个章节

本文目录

搜索文档

输入关键词,立即搜索当前分享。