You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js的public文件夹内文件中访问环境变量?

解决Next.js中public文件夹内Service Worker无法访问环境变量的问题

问题原因

public目录下的文件属于静态资源,Next.js不会对它们做编译处理,也不会替换其中的process.env变量——因为process是Node.js环境的对象,浏览器/service worker环境里根本不存在,所以直接写会报错。

可行解决方案

1. 构建时自动注入环境变量(推荐)

写一个简单的Node脚本,在项目构建前把环境变量替换到service worker模板里,生成最终的firebase-messaging-sw.js到public目录:

  • 第一步:在项目根目录创建模板文件firebase-messaging-sw.template.js,内容如下:
const firebaseConfig = {
    apiKey: "{{NEXT_PUBLIC_FIREBASE_API_KEY}}",
    authDomain: "{{NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN}}",
    projectId: "{{NEXT_PUBLIC_FIREBASE_PROJECT_ID}}",
    storageBucket: "{{NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET}}",
    messagingSenderId: "{{NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID}}",
    appId: "{{NEXT_PUBLIC_FIREBASE_APP_ID}}",
    measurementId: "{{NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID}}",
};

// 后续Firebase初始化代码
importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging.js');

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
// ...其他messaging逻辑
  • 第二步:创建注入脚本scripts/generate-sw.js:
const fs = require('fs');
const path = require('path');

// 读取模板文件
const templatePath = path.join(__dirname, '../firebase-messaging-sw.template.js');
const templateContent = fs.readFileSync(templatePath, 'utf8');

// 替换环境变量
const replacedContent = templateContent
    .replace("{{NEXT_PUBLIC_FIREBASE_API_KEY}}", process.env.NEXT_PUBLIC_FIREBASE_API_KEY)
    .replace("{{NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN}}", process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN)
    .replace("{{NEXT_PUBLIC_FIREBASE_PROJECT_ID}}", process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID)
    .replace("{{NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET}}", process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET)
    .replace("{{NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID}}", process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID)
    .replace("{{NEXT_PUBLIC_FIREBASE_APP_ID}}", process.env.NEXT_PUBLIC_FIREBASE_APP_ID)
    .replace("{{NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID}}", process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID);

// 生成最终sw文件到public目录
const outputPath = path.join(__dirname, '../public/firebase-messaging-sw.js');
fs.writeFileSync(outputPath, replacedContent);
  • 第三步:修改package.json的scripts,在构建/开发前执行脚本:
{
  "scripts": {
    "prebuild": "node scripts/generate-sw.js",
    "build": "next build",
    "dev": "node scripts/generate-sw.js && next dev"
  }
}

这样每次开发或构建时,都会自动把环境变量注入到service worker文件里,public目录下的最终文件是已经替换好变量的版本。

2. 从主应用传递配置到Service Worker

在注册service worker的时候,把firebase配置通过postMessage发送过去:

  • 主应用代码(比如pages/_app.js或组件内):
import { useEffect } from 'react';

useEffect(() => {
  const registerSW = async () => {
    if ('serviceWorker' in navigator) {
      const firebaseConfig = {
        apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
        authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
        // ...其他配置项
      };
      const swRegistration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
      // 向service worker发送配置
      swRegistration.active.postMessage({ type: 'SET_FIREBASE_CONFIG', config: firebaseConfig });
    }
  };
  registerSW();
}, []);
  • 修改firebase-messaging-sw.js,监听消息接收配置:
let firebaseConfig = null;

self.addEventListener('message', (event) => {
  if (event.data.type === 'SET_FIREBASE_CONFIG') {
    firebaseConfig = event.data.config;
    // 初始化Firebase
    importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js');
    importScripts('https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging.js');
    firebase.initializeApp(firebaseConfig);
    const messaging = firebase.messaging();
    // ...后续逻辑
  }
});

这种方法不需要修改构建流程,但要注意service worker的生命周期,确保配置传递完成后再初始化Firebase。


内容的提问来源于stack exchange,提问作者Tsabary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 11:55:42