Nextjs集成Firebase Messaging时出现Reference error: self is not defined
解决Next.js + Firebase Messaging 8.10.0 出现「Reference error: self is not defined」的问题
错误原因
Next.js 是服务端渲染(SSR)框架,你的Notification组件被导入到_app.js后,会在服务端和客户端都执行。而 Firebase Messaging 的初始化代码依赖浏览器环境的全局对象self,服务端没有这个对象,因此触发报错。
修复方案
1. 动态导入 Notification 组件,禁用 SSR
在_app.js中不要直接导入组件,改用 Next.js 的dynamic函数导入,指定仅在客户端渲染:
import dynamic from 'next/dynamic' const Notification = dynamic(() => import('../components/Notification'), { ssr: false }) function MyApp({ Component, pageProps }) { return ( <> <Notification /> <Component {...pageProps} /> </> ) } export default MyApp
2. 在 Firebase 工具文件中做环境判断
修改Firebase.js,确保仅在浏览器环境下初始化 Messaging:
import firebase from 'firebase/app' import 'firebase/messaging' let messaging = null // 仅在浏览器环境初始化 if (typeof self !== 'undefined') { const firebaseConfig = { // 你的 Firebase 配置信息 } if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig) messaging = firebase.messaging() } } export const requestToken = async () => { if (!messaging) return null try { const token = await messaging.getToken({ vapidKey: '你的 VAPID 公钥' }) return token } catch (error) { console.error('获取推送令牌失败:', error) return null } }
3. 在组件中仅在客户端注册 Service Worker
在Notification.js中,使用useEffect钩子确保 Service Worker 注册逻辑仅在浏览器执行:
import { useEffect } from 'react' import { requestToken } from '../utils/Firebase' export default function Notification() { useEffect(() => { // 检查浏览器是否支持 Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/firebase-messaging-sw.js') .then(async (registration) => { // 关联 Service Worker 和 Messaging const messaging = await import('firebase/messaging').then(m => m.default.messaging()) messaging.useServiceWorker(registration) // 请求推送令牌 const token = await requestToken() console.log('推送令牌:', token) }) .catch(error => { console.error('Service Worker 注册失败:', error) }) } }, []) return null // 该组件无需渲染 UI }
额外注意事项
- 确保
firebase-messaging-sw.js放在public文件夹根目录,Next.js 会将其作为静态资源对外暴露,Service Worker 才能正确被加载。 - 验证你的 Firebase 配置和 VAPID 密钥是否正确,VAPID 密钥需要在 Firebase 控制台的「云消息传递」中生成。
内容的提问来源于stack exchange,提问作者Daniel_Kamel
相关产品推荐
相关产品推荐

