深入 Nuxt SSG 靜態網站生成:靈活控制每一個輸出細節

2024-08-18

Nuxt 不僅支持服務端渲染 (SSR),還提供了靜態網站生成 (SSG) 的強大功能,讓開發者能將網站輕鬆部署到任何支援 JAMstack 的平台上。

本文將深入介紹如何利用 Nuxt 生成靜態網站,並詳細探討如何控制生成過程中的各種行為和配置選項。從預渲染設置到 assets 輸出管理,一步步展示如何靈活地掌控 Nuxt 靜態網站的生成。

生成靜態網站

在 Nuxt 中生成靜態網站非常簡單,只需要執行以下的指令即可。

Terminal
nuxt generate

控制預渲染 (Prerendering)

默認情況下,Nuxt 會在生成靜態網站時將每個頁面進行預渲染,並生成對應的 HTML 檔案。

如果你希望生成一個僅用於客戶端渲染 (Client-Side Rendering) 的 SPA 網站,可以通過在配置中將 ssr 設置為 false 來禁用預渲染功能。

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false
})

控制輸出路徑

Nuxt 使用 Nitro 進行預渲染,並將靜態網站輸出至預設的 .output/public 目錄下。

如果需要更改輸出目錄,可以通過以下配置來控制輸出路徑:

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    output: {
      dir: resolve('./.my-output'),
      publicDir: path.join(__dirname, './.my-output/public'),
    }
  }
})

輸出檔案目錄結構

在預渲染並生成靜態網站後,Nuxt 預設會產生以下的目錄結構。

在這個章節,我們將介紹每個檔案和目錄的用途,並探討相關配置。

📂 _nuxt

這個目錄包含網站的 assets 檔案,也包括所有的 CSS 和 JavaScript 文件。

你可以通過配置 app.buildAssetsDir 更改該目錄的名稱。

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    buildAssetsDir: '/_my_assets/'
  }
})

📂 _nuxt/builds

該目錄包含 App Manifest 的相關文件,這些文件提供了最新構建的 routestimestamp 等。

如果你不需要這些功能,可以通過配置 experimental.appManifest 關閉此功能,從而避免生成該目錄。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    appManifest: false
  }
})

📄 _nuxt/*.js

Nuxt 使用 ViteRollup 進行 JavaScript 打包。

你可以通過配置 vite.buildrollupOptions 來控制 JavaScript 文件的輸出格式,以下提供了幾個常見的配置示例:

  • 自定義輸出檔名格式 (output.entryFileNames, output.chunkFileNames)
    nuxt.config.ts
    export default defineNuxtConfig({
      vite: {
        build: {
          rollupOptions: {
            output: {
              entryFileNames: '_nuxt/my-[name]-[hash].js',
              chunkFileNames: '_nuxt/my-[name]-[hash].js'
            }
          }
        }
      }
    })
    
  • 將所有 *.js 檔案合併為單一文件 (output.inlineDynamicImports)
    nuxt.config.ts
    export default defineNuxtConfig({
      vite: {
        build: {
          rollupOptions: {
            output: {
              inlineDynamicImports: true
            }
          }
        }
      }
    })
    

📄 _nuxt/*.css 和其他 assets

你可以通過配置 vite.build 來控制 CSS 和其他 assets 的輸出格式,以下提供了一些設定範例:

自定義輸出檔名格式 (rollupOptions.output.assetFileNames)

nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    build: {
      rollupOptions: {
        output: {
          assetFileNames: '_nuxt/my-[name]-[hash].[ext]',
          // or
          assetFileNames: (assetInfo) => {
            if (assetInfo?.name?.endsWith('.css'))
              return '_nuxt/style-[name]-[hash].css'
            return '_nuxt/[name]-[hash].[ext]'
          }
        }
      }
    }
  }
})

這個設置將影響所有 assets,包括圖片、字體等。


將所有 *.css 檔案合併為單一文件 (cssCodeSplit)

nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    build: {
      cssCodeSplit: false
    }
  }
})

對於存放在 assets/ 目錄下的其他檔案(如圖片、字型等),它們可能會被複製到 _nuxt 目錄中。

如果你希望強制將所有資產文件內嵌(inline),而不是複製到 _nuxt 目錄,你可以使用以下配置來實現:

nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    build: {
      assetsInlineLimit: Number.MAX_SAFE_INTEGER
    }
  }
})

📄 _payload.json

該文件在 SSR 或預渲染過程中用來傳遞頁面的 payload 資料。

如果你不需要外部載入該文件,並希望在生成靜態網站時不生成此文件,可以通過配置 payloadExtraction 來禁用它。

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: false
  }
})

📄 200.html404.html

這兩個文件在 SSG 時生成,作為 SPA 網站的 fallback 頁面。

如果你不需要這些文件,可以通過配置 nitro.prerender.ignore 來避免生成。

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    prerender: {
      ignore: ['/200.html', '/404.html']
    }
  }
})

📄 index.html

Nuxt 會為你網站的每個頁面都生成對應的 index.html 文件,作為靜態網站的入口。

Preload 與 Prefetch

這些 Resource Hints 可以幫助瀏覽器提前加載資源,從而加快網站加載速度。

index.html
<!DOCTYPE html>
<html data-capo="">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="preload" as="fetch" crossorigin="anonymous" href="/_payload.json?93d23bea-82a5-406d-92a4-feb73d5bf1b8">
    <link rel="modulepreload" as="script" crossorigin href="/_nuxt/D9xaLgge.js">
    <link rel="prefetch" as="script" crossorigin href="/_nuxt/BXlAlM0q.js">
    <link rel="prefetch" as="script" crossorigin href="/_nuxt/BRJtm5m-.js">
    <link rel="prefetch" as="script" crossorigin href="/_nuxt/CZvqSstT.js">
    <script type="module" src="/_nuxt/D9xaLgge.js" crossorigin></script>
  </head>
  <body>
    ...
  </body>
</html>

如果需要禁用 preloadprefetch,可以使用 Nuxt Hooksbuild:manifest 進行自定義,以下示範了如何禁用這些功能:

nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'build:manifest': (manifest) => {
      console.log('manifest', manifest)
      for (const key in manifest) {
        manifest[key].dynamicImports = []
        manifest[key].prefetch = false
        manifest[key].preload = false
      }
    }
  }
})

總結

Nuxt 不僅提供了簡單易用的靜態網站生成功能,還通過預設配置進行了大量優化,幫助開發者在構建網站時省去許多繁瑣的步驟。無論是預渲染、assets 管理還是目錄結構,Nuxt 都處理得井然有序。

同時,Nuxt 也保留了高度的自定義空間,允許開發者靈活地控制每個輸出細節,從而實現更加精細的網站優化和配置。這種平衡了簡單性與靈活性的設計,使 Nuxt 成為生成高效靜態網站的理想選擇。

後記

本文的心得分享來自我最近的一個開源項目 nuxt-single-html 🌟,這是一個可以將 Nuxt 網站所有 JavaScript, CSS 和其他 assets 內嵌到單個 HTML 文件中的工具,適用於一些特殊場景下的靜態網站生成需求,歡迎前往查看。

🎉  感謝您的閱讀,不仿看看我的其他文章,也歡迎在 XGitHub 上交流。