Nuxt (進階)

生命週期

應用層級生命週期(App-Level)

這些方法主要出現在專案中的特定檔案中,例如 nuxt.config.jspluginsmiddlewarelayouts 等。

  1. nuxt.config.js

    • plugins:設定要在 Nuxt 初始化前/後載入的外掛,可指定 mode: 'client'mode: 'server'
    • modules:建構時執行的模組。
    • build:控制資源編譯等建構行為。
    • generate:對應靜態網站導出。
  2. Nuxt 初始化順序:

    • nuxt.config.js 讀取與解析
    • 載入 Module
    • 執行 Plugin
    • client-side plugin:僅於瀏覽器執行
    • server-side plugin:僅於伺服器執行
    • 處理 Middleware(全域或頁面層)
    • 載入 Layout(若有)
    • 加載與渲染 Page Component

SSR + CSR 行為的時間線圖

【伺服器端(SSR)執行流程】
┌────────────────────────────────────────────┐
│            Nuxt 應用初始化(Node.js)       │
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│         呼叫頁面元件的 asyncData()          │ ← 抓取資料並合併進 data()
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│            呼叫 fetch()(若有定義)         │ ← 也可抓資料,手動塞入 data()
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│     組合完成 HTML(含預取資料),送回給瀏覽器 │
└────────────────────────────────────────────┘

============================================
            ↓(HTML 傳回瀏覽器)↓
============================================

【客戶端(CSR)初始化流程】
┌────────────────────────────────────────────┐
│      Nuxt 應用 Hydration(掛載到 DOM)      │ ← 此時才可操作 DOM
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│        呼叫 mounted() 等 DOM 相關鉤子        │ ← 只會在瀏覽器執行
└────────────────────────────────────────────┘
                    │
                    ▼
(使用者開始互動,點擊連結進行路由切換)

【客戶端路由切換流程】
┌────────────────────────────────────────────┐
│           Nuxt 載入新頁面元件               │
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│       呼叫 asyncData() / fetch()            │ ← 在 client 端重新執行一次
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│        頁面內容更新並重新渲染               │
└────────────────────────────────────────────┘
                    │
                    ▼
┌────────────────────────────────────────────┐
│      呼叫 mounted() 等瀏覽器端鉤子           │ ← 新頁面 DOM 初始化
└────────────────────────────────────────────┘

Page/Component 層級生命週期(依 SSR 或 CSR 而異)

SSR(伺服器端執行時):

生命週期方法 說明
asyncData(context) 在元件初始化前呼叫,僅頁面元件可用,回傳值會合併進 data()
fetch(context) 抓取資料但不自動合併,支援元件與頁面使用(Nuxt 2.12+)。
middleware(context) 執行中介邏輯(如驗證)。
validate(context) 路由驗證,回傳 false 跳轉 404。
layout(context) 指定使用哪個 layout。
head() 設定頁面 <head>(meta、title 等)。
beforeCreate / created() 僅在瀏覽器中執行(SSR 中無法觸發)。

CSR(客戶端導覽時):

以上方法會再次於 client 執行(如 asyncData、fetch、middleware)。


Vue 原生元件生命週期(Nuxt 中執行時機)

Vue 方法 SSR 執行 CSR 執行
beforeCreate
created
beforeMount
mounted
destroyed

在 SSR 中無 DOM,請將相關操作延後至 mounted 或檢查 process.client

mounted() {
  const el = document.getElementById('my-div')
  console.log(el)
}

if (process.client) {
  window.addEventListener('scroll', ...)
}

路由切換時(客戶端)

在瀏覽器導覽(非重新整理)時:

  • 呼叫 middleware
  • 呼叫 validate
  • 呼叫 asyncData / fetch
  • 呼叫 beforeRouteEnter, beforeRouteUpdate
  • 渲染新頁面元件

Context 提供的參數

context 物件可在 asyncData, fetch, middleware, plugin 中使用,包含:

  • app, store, route, params, query
  • req, res(僅限 server)
  • redirect, error
  • $axios(若有安裝 axios module)

asyncData vs fetch 比較

項目 asyncData(context) fetch(context)
📌 用途 頁面元件資料預取 元件/頁面皆可用
📦 合併資料 ✅ 自動合併至 data() ❌ 需手動設值
🧭 可用位置 僅限 pages/*.vue 通用元件與頁面
🌍 SSR 執行
🖥 CSR 執行 ✅(路由切換時) ✅(路由切換時)
🧪 可使用 await
🛠 可使用 this
🔁 可重複觸發 ✅(使用 $fetch()
🧩 特殊控制 fetchOnServer, fetchDelay, $fetchState

asyncData 範例

export default {
  async asyncData({ params, $axios }) {
    const data = await $axios.$get(`/api/post/${params.id}`)
    return { post: data }
  }
}

fetch 範例

export default {
  data() {
    return { post: null }
  },
  async fetch() {
    this.post = await this.$axios.$get(`/api/post/123`)
  }
}

fetch 的進階屬性

export default {
  fetchOnServer: true,   // 可設為 false 僅在 client 執行
  fetchDelay: 100,       // 延遲執行 fetch(毫秒)
  async fetch() { ... }  // 自訂資料抓取邏輯
}
<div v-if="$fetchState.pending">載入中...</div>
<div v-else-if="$fetchState.error">出錯了</div>
階段 fetch 執行時機 this 可用? created() 跑完? 可操作 DOM?
SSR before Vue instance created ✅(模擬)
CSR 初次 預設不執行(已 SSR 過)
CSR 切換時 after created before mounted

Nuxt 常用的 Router 元件與使用方式

路由元件

元件 用途
<nuxt-link> 客戶端路由連結(類似 <a>
<nuxt-child> 顯示巢狀路由
<nuxt> 主畫面內容載入
<nuxt-link to="/about">關於我們</nuxt-link>
<nuxt-link :to="{ name: 'users-id', params: { id: 123 } }">使用者 123</nuxt-link>

nuxt-child

<!-- pages/users/_id.vue -->
<template>
  <div>
    <h1>使用者頁面</h1>
    <nuxt-child />
  </div>
</template>

nuxt

<!-- layouts/default.vue -->
<template>
  <div>
    <Header />
    <nuxt />
    <Footer />
  </div>
</template>

使用 Vue Router API

可在任何元件使用 $router, $route

this.$router.push({ name: 'users-id', params: { id: 123 } })

Nuxt Plugin

基本概念

  • 提供 Nuxt 啟動前註冊套件、初始化邏輯的方式
  • 可注入全域工具、函式
  • 可限定執行於 clientserver
  • 支援 context 參數與 inject() 注入

建立 plugin 檔案

// plugins/myPlugin.js
export default (context, inject) => {
  const hello = () => console.log('哈囉 Plugin!')
  inject('hello', hello)
}

註冊 plugin

export default {
  plugins: ['~/plugins/myPlugin.js']
}

使用 plugin

mounted() {
  this.$hello() // 顯示:哈囉 Plugin!
}

指定 plugin 執行環境

plugins: [
  { src: '~/plugins/clientOnly.js', mode: 'client' },
  { src: '~/plugins/serverOnly.js', mode: 'server' }
]

也可使用副檔名:

  • xxx.client.js → 僅在 client 執行
  • xxx.server.js → 僅在 server 執行

context 可用屬性

export default (context, inject) => {
  // context.app, context.store, context.route, context.params, context.req, ...
  // context.$axios(若有安裝 axios module)
}

plugin 使用情境

情境 說明
使用 Vue.use(...) 套件 VueToast, VueLazyload
建立自訂工具 如格式化、API 客戶端
使用第三方函式庫 lodash, dayjs
注入 API client 封裝 axios 並全域注入