NextJS:应用启动时动态环境变量设置遇客户端process.env为空问题
解决Next.js 5.0.0客户端process.env为空的问题(单构建包多环境部署场景)
针对你遇到的Next.js 5.0.0客户端无法读取环境变量,但服务器端正常的问题,结合你单构建包部署到多环境的需求,我来拆解原因并给出适配的解决方案:
核心原因分析
Next.js 5.x版本不像新版有NEXT_PUBLIC_前缀自动暴露客户端环境变量的机制,浏览器环境本身也不存在process对象。而你使用的babel-plugin-inline-dotenv是编译时注入变量,如果是单构建包部署到多环境,这种方式会导致所有环境共用构建时的固定变量,既不符合你的需求,还可能因为客户端编译环节未正确触发插件,导致process.env为空。
推荐解决方案:服务器端动态注入环境变量到客户端
这种方式可以让单构建包在不同环境部署时,动态读取对应环境的变量,同时让客户端能正常获取到需要的变量:
1. 确保服务器端正确加载环境变量
首先安装dotenv(用来加载.env文件):
npm install dotenv --save
如果有自定义服务器入口文件(比如server.js),在顶部添加加载.env的代码:
require('dotenv').config(); const next = require('next'); const http = require('http'); const port = process.env.PORT || 3000; const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); app.prepare().then(() => { http.createServer((req, res) => { handle(req, res); }).listen(port, (err) => { if (err) throw err; console.log(`> Ready on http://localhost:${port}`); }); });
如果没有自定义服务器,Next.js默认的启动脚本也可以修改,在package.json里添加:
"scripts": { "start": "node -r dotenv/config node_modules/.bin/next start", "build": "node -r dotenv/config node_modules/.bin/next build" }
2. 自定义_document.js注入变量到客户端
在pages目录下创建_document.js,通过服务器端的getInitialProps获取环境变量,然后挂载到浏览器的window对象上:
import Document, { Head, Main, NextScript } from 'next/document'; export default class CustomDocument extends Document { static async getInitialProps(ctx) { const initialProps = await Document.getInitialProps(ctx); // 只暴露客户端需要的非敏感变量,不要把密钥、密码等敏感信息放这里! const clientEnv = { API_BASE_URL: process.env.API_BASE_URL, APP_NAME: process.env.APP_NAME }; return { ...initialProps, clientEnv }; } render() { return ( <html> <Head /> <body> <Main /> <script dangerouslySetInnerHTML={{ __html: `window.__CLIENT_ENV__ = ${JSON.stringify(this.props.clientEnv)};` }} /> <NextScript /> </body> </html> ); } }
3. 客户端代码中使用环境变量
在客户端组件里,通过window.__CLIENT_ENV__访问变量,注意要判断是否在浏览器环境:
// 示例页面组件 const HomePage = () => { // 确保只在浏览器环境读取window变量 const apiUrl = typeof window !== 'undefined' ? window.__CLIENT_ENV__.API_BASE_URL : ''; return ( <div> <h1>当前环境API地址:{apiUrl}</h1> </div> ); }; export default HomePage;
为什么不推荐继续用babel-plugin-inline-dotenv?
这个插件是编译时替换process.env的引用,意味着构建时变量就被硬编码到代码里了。如果你用单构建包部署到多环境,所有环境都会使用构建时的变量值,无法实现不同环境的变量差异,完全不符合你的部署需求。
内容的提问来源于stack exchange,提问作者AleG
相关产品推荐
相关产品推荐

