# SSR 錯誤修復總結 ## 🐛 問題描述 在 Next.js 應用中遇到了 `ReferenceError: window is not defined` 錯誤,這是因為在服務器端渲染 (SSR) 時嘗試訪問 `window` 對象導致的。 ## ✅ 修復的文件 ### 1. `components/admin/admin-layout.tsx` **問題**:在 SSR 期間直接使用 `window` 對象 **修復**:添加 `typeof window !== 'undefined'` 檢查 ```typescript // 修復前 {window.opener && !window.opener.closed && ( )} // 修復後 {typeof window !== 'undefined' && window.opener && !window.opener.closed && ( )} ``` ### 2. `components/admin/user-management.tsx` **問題**:在函數中直接使用 `window.location.origin` **修復**:添加條件檢查,提供回退值 ```typescript // 修復前 const invitationLink = `${window.location.origin}/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}` // 修復後 const invitationLink = typeof window !== "undefined" ? `${window.location.origin}/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}` : `/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}` ``` ## 🔧 修復策略 ### 1. 條件檢查 ```typescript if (typeof window !== 'undefined') { // 只在客戶端執行 window.location.href = "/" } ``` ### 2. 三元運算符 ```typescript const url = typeof window !== 'undefined' ? `${window.location.origin}/path` : "/path" ``` ### 3. useEffect Hook ```typescript useEffect(() => { // 只在客戶端執行 window.addEventListener('resize', handleResize) return () => window.removeEventListener('resize', handleResize) }, []) ``` ## 📋 已檢查的文件 以下文件已經有正確的 SSR 處理,無需修復: - `components/ui/use-mobile.tsx` - 使用 useEffect - `components/admin/competition-management.tsx` - 有條件檢查 - `components/admin/scoring-link-dialog.tsx` - 有條件檢查 ## 🎯 修復結果 - ✅ 消除了 `window is not defined` 錯誤 - ✅ 保持了客戶端功能正常運作 - ✅ 確保了 SSR 兼容性 - ✅ 提供了適當的回退值 ## 📝 最佳實踐 1. **始終檢查 `window` 對象**:在 Next.js 中,`window` 只在客戶端可用 2. **使用 useEffect**:對於需要在客戶端執行的代碼,使用 `useEffect` Hook 3. **提供回退值**:為 SSR 環境提供適當的默認值 4. **避免在組件頂層使用 `window`**:將 `window` 相關代碼放在函數內部或 useEffect 中 ## 🚀 測試建議 1. 檢查管理員頁面是否正常加載 2. 驗證用戶邀請功能是否正常 3. 確認彈窗關閉功能是否正常 4. 測試在不同環境下的表現 修復完成後,應用應該能夠正常進行服務器端渲染,同時保持所有客戶端功能正常運作。