# 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. 測試在不同環境下的表現
修復完成後,應用應該能夠正常進行服務器端渲染,同時保持所有客戶端功能正常運作。