Skip to main content

Command Palette

Search for a command to run...

Chrome browser devtools Googlebot server error 無法載入頁面

Updated
2 min read
S

I was the main web front-end engineer responsible for developing and maintaining the customer-facing platform for WisdomHall (品學堂) in 2024 Q3 Q4, code reviewed by CTO and a senior engineer. http://learning.wisdomhall.com.tw has total active 257k users, according to their Facebook post: https://www.facebook.com/share/p/1MnjbwZxCV/ My tech stack includes JavaScript, Vue 2, Nuxt 2, git, and Docker.

在這個檔案中,我看到 pathname computed property 直接訪問了 window 對象。在 SSR (Server-Side Rendering) 環境中這會導致錯誤,因為服務器端沒有 window 對象。我們需要修改這部分代碼:

主要改動:

  • 使用 process.client 檢查是否在客戶端環境

  • 在服務器端使用 Nuxt 的 $route.path 作為替代

這樣修改的好處是:

  • 避免 SSR 時的錯誤

  • 保持功能一致性

  • 提供更好的錯誤處理

另外,建議也添加一些錯誤處理:

computed: {
  pathname() {
    try {
      if (process.client) {
        return window.location.pathname
      }
      return this.$route.path
    } catch (error) {
      console.error('Error getting pathname:', error)
      return this.$route.path // 使用路由路徑作為後備
    }
  }
}

process.client 是 Nuxt.js 提供的一個全局變量,讓我們詳細解釋它:

1.什麼是 process.client?

  • if (process.client) { // 這段代碼只會在瀏覽器中執行 // window, document 等瀏覽器 API 在這裡是可用的}

2.為什麼需要它?

    • Nuxt.js 是一個同構框架(Isomorphic Framework)

      • 代碼會在兩個環境中運行:

        • 服務器端(SSR):Node.js 環境

        • 客戶端(Browser):瀏覽器環境

3.使用場景:

// 常見的使用場景
if (process.client) {
  // 瀏覽器 API
  window.addEventListener('scroll', ...)
  localStorage.setItem(...)
  document.querySelector(...)

  // 只想在客戶端載入的模塊
  require('some-browser-only-package')
}

4.對應的服務器端檢查:

if (process.server) {  
  // 這段代碼只會在服務器端執行  
  // Node.js API 在這裡是可用的
}

5.實際運作原理:

// 編譯後的代碼大致如下
const process = {
  client: typeof window !== 'undefined',
  server: typeof window === 'undefined'
}

錯誤處理最佳實踐:

computed: {
  pathname() {
    try {
      if (process.client) {
        return window.location.pathname
      }
      // 服務器端後備方案
      return this.$route.path
    } catch (error) {
      console.error('pathname error:', error)
      return this.$route.path
    }
  }
}

生命週期中的使用:

export default {
  mounted() {
    // mounted 只在客戶端執行,所以這裡不需要 process.client 檢查
    window.addEventListener('resize', this.handleResize)
  },

  beforeDestroy() {
    // 同樣,beforeDestroy 也只在客戶端執行
    window.removeEventListener('resize', this.handleResize)
  },

  asyncData() {
    // asyncData 只在服務器端執行,這裡不需要 process.server 檢查
  }
}
  1. 常見陷阱:
// ❌ 錯誤寫法
data() {
  return {
    windowWidth: window.innerWidth // 會在 SSR 時報錯
  }
}

// ✅ 正確寫法
data() {
  return {
    windowWidth: process.client ? window.innerWidth : 0
  }
}
  1. 性能考慮:
// 條件編譯:webpack 會在打包時移除未使用的代碼
if (process.client) {
  // 這段代碼不會包含在服務器端的包中
  require('heavy-browser-only-library')
}
  1. 調試技巧:

    // 可以用來檢查當前運行環境
    console.log('Current environment:', {
      isClient: process.client,
      isServer: process.server,
      hasWindow: typeof window !== 'undefined'
    })
    

這個機制是 Nuxt.js 同構應用的核心特性之一,正確使用它可以:

  • 避免 SSR 相關錯誤

  • 優化代碼大小

  • 提高應用性能

  • 改善開發體驗

More from this blog

Vue 3 的雞毛蒜皮各種小特性

在 Nuxt 3 專案中,這是一個被稱為「自動導入 (auto-imports)」的特性 我:為何 showPost 不用引用就可以直接使用? [id].vue: 1 lines selecteduseAsyncData Gemini: stat_minus_1Thinking 在 Nuxt 3 專案中,這是一個被稱為「自動導入 (auto-imports)」的特性。 Nuxt 會自動掃描特定目錄下的檔案,例如 composables/ 和 utils/,並將其中定義的函式、變數等在整個應用程...

Sep 25, 20251 min read

請用 10 歲小孩能懂的方式,解釋 Virtual DOM 觀念

當然可以!以下是一個 10 歲小孩也能懂的方式來解釋 Virtual DOM(虛擬 DOM) 是什麼: 🎨 想像你在畫畫一棵樹 你有一張畫紙(這是網頁上的畫面),你正在畫一棵樹 🌳。 有一天你想把樹的葉子從綠色換成黃色,因為是秋天了 🍂。 做法一: 你把整棵樹擦掉,重新畫一棵新的黃色葉子樹。🧽✏️ 這樣很花時間,而且很累對吧? 做法二(更聰明的做法): 你先在一張透明的描圖紙上畫一樣的樹,看看哪裡需要改,發現「只要把葉子塗黃就好!」然後你只改葉子的顏色,其他部分都不動,畫起來又快又省力...

Sep 22, 20252 min read

ChatGPT 用 10 歲孩童能聽懂的方法,解釋 webpage cookies 的原理跟用途

請用十歲孩童能聽懂的方法,解釋網頁 cookie 的原理跟用途 1. Cookie 是什麼? 想像你去一家餅乾店(網站),老闆給你一張小紙條,寫著你的名字和喜好(例如你喜歡巧克力餅乾)。這張小紙條就是「Cookie」。 但它不是可以吃的餅乾,而是電腦裡的一小段文字紀錄,網站會存到你的瀏覽器裡。 2. 它是怎麼運作的? 你第一次到網站 → 網站寫一張小紙條(Cookie)給你。 你下次再來 → 你把小紙條交給老闆(網站)。 老闆一看,就知道: 你是誰 你喜歡什麼 你上次逛到哪一頁 ...

Sep 17, 20251 min read

sunpochin

56 posts