Next.js中public目录下.js文件环境变量无法生效问题排查
问题原因
public 目录下的静态 JS 文件(比如你的 crm.js)不会经过 Next.js 的编译处理流程,所以文件里的 process.env.NEXT_PUBLIC_META_CRM_API_KEY 不会被替换成实际的环境变量值——小部件拿到的只是字符串字面量 "process.env.NEXT_PUBLIC_META_CRM_API_KEY",而非真实的 API 密钥,自然会触发授权失败。
解决方案
方法1:全局注入 API 密钥(推荐)
在 layout.tsx 中先通过 Next.js 读取环境变量,再将密钥挂载到全局 window 对象上,让 crm.js 读取这个全局变量:
- 修改 layout.tsx:
import Script from 'next/script'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="zh-CN"> <body> {/* 先注入全局密钥变量 */} <Script id="crm-api-key" strategy="beforeInteractive"> {`window.META_CRM_API_KEY = '${process.env.NEXT_PUBLIC_META_CRM_API_KEY}';`} </Script> {/* 再加载静态脚本 */} <Script src="/crm.js" strategy="afterInteractive" /> {children} </body> </html> ); }
- 修改 crm.js:
// 替换原来的 process.env 写法 const apiKey = window.META_CRM_API_KEY; MetaCRMWidget.init({ apiKey });
方法2:将静态脚本转为客户端组件
把 crm.js 移到 Next.js 的源码目录(比如 src/app),改成客户端组件,这样就能直接使用环境变量:
- 创建
src/app/crm-widget.tsx:
'use client'; import { useEffect } from 'react'; export default function CRMWidget() { useEffect(() => { const apiKey = process.env.NEXT_PUBLIC_META_CRM_API_KEY; // 初始化小部件 MetaCRMWidget.init({ apiKey }); }, []); return null; // 无需渲染DOM元素 }
- 在 layout.tsx 中引入组件:
import CRMWidget from './crm-widget'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="zh-CN"> <body> <CRMWidget /> {children} </body> </html> ); }
*注:如果小部件依赖第三方核心脚本,需要先通过 <Script> 引入该脚本,再在 useEffect 中执行初始化逻辑。
方法3:构建时替换静态文件占位符(适合必须保留静态文件的场景)
如果一定要保留 public 目录下的 crm.js,可以用脚本在构建/开发前替换文件中的占位符:
- 修改 crm.js,用占位符代替环境变量:
const apiKey = '%%NEXT_PUBLIC_META_CRM_API_KEY%%'; MetaCRMWidget.init({ apiKey });
- 在 package.json 中添加预处理脚本:
"scripts": { "predev": "sed -i '' 's/%%NEXT_PUBLIC_META_CRM_API_KEY%%/'\"$NEXT_PUBLIC_META_CRM_API_KEY\"'/g' public/crm.js", "prebuild": "sed -i '' 's/%%NEXT_PUBLIC_META_CRM_API_KEY%%/'\"$NEXT_PUBLIC_META_CRM_API_KEY\"'/g' public/crm.js", "dev": "next dev", "build": "next build", "start": "next start" }
*注:Windows 系统需要替换 sed 命令为 PowerShell 脚本,或使用 cross-env 工具实现跨平台兼容;修改 .env.local 后需要重启开发服务器才会生效。
内容的提问来源于stack exchange,提问作者David Henson
相关产品推荐
相关产品推荐

