iT邦幫忙

2022 iThome 鐵人賽

DAY 29
1
Modern Web

Nuxt 3 學習筆記系列 第 29

[Day 29] Nuxt 3 發布網站前的建構打包 (Build) 與靜態網站生成 (Static Site Generation)

  • 分享至 

  • xImage
  •  

前言

當網站開發完成或有導入 CI/CD,在準備發布網站前,我們會將 Nuxt 網站的開發專案透過 Nuxt 提供的指令,我們可以來建構出正式環境所需要的版本,這個建構的過程你可以理解為專案將會打包需要的依賴套件、編譯與轉換相關的 Vue SFC 與樣式等,甚至幫你壓縮這些檔案等許多步驟,這些繁瑣的過程都透過 Nuxt 的建構指令來幫你完成,你可以結合一些設定參數與指令,來幫助你建構出正式環境所需要的網站專案,最後再進行部署的動作。

Nuxt 3 專案如何建構正式環境版本

當我們建立一個乾淨的 Nuxt 3 專案,可以使用 package.jsonscripts 內的指令來進行建構或預渲染產生靜態頁面。

  • npm run build
  • npm run generate

或者你也可以使用 Nuxt CLI 來達到一樣的效果

  • npx nuxi build
  • npx nuxi generate

generate 指令會觸發 build 的指令並帶有 prerendertrue 的參數,最終產生出來的目錄可以直接進行部署,不需要再執行一次 build 的指令。

使用預設配置進行建構 - 建構通用渲染 (Universal Rendering) 的網站

這邊我們以這個系列文章所建立的部落格作為範例,來嘗試以預設的配置進行建構,目前 Nuxt 3 預設 nuxt.config.tsssr 屬性為 true,也就使用通用渲染 (Universal Rendering)

我們進入專案目錄,執行下列指令:

npm run build

不需要在額外的配置或步驟,Nuxt 就會自動幫我們打包並建構出可以部署的網站。
https://i.imgur.com/tsHV41j.gif

建構完成後會在專案目錄下多出一個 .output 目錄,public 就是在網站根目錄直接公開打包後的 JS、CSS 圖片等相關檔案。由於通用渲染使用 Nitro 作為服務引擎,所以會需要使用 Node.js 來啟動我們的服務,所以server 則是會放置伺服器端的 Nitro、Server API 處理邏輯等。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617yAGBjPZ3Hf.png

我們可以先在本地執行下列指令來預覽建構出來的網站與 Nitro 是否能運作正常。

node .output/server/index.mjs

當確認沒問題後,就能以 .output 目錄進行網站部署。

使用預渲染建置全靜態頁面網站

前一篇文章有提到,我們可以在 Nuxt 3 建構時期來進行預渲染 (pre-rendering),將專案內需要打 API 請求及動態渲染元件的地方,先渲染生成出 HTML 網頁,這個過程也稱之為靜態網站生成 (Static Site Generation),進而建構出全靜態頁面的網站。

執行下列指令進行靜態頁面生成:

npm run generate

generate 指令會觸發build 的指令並帶有 prerendertrue 的參數,最終會提示產生的目錄 .output/public 可以用來部署至靜態託管伺服器。
https://i.imgur.com/sWAK0uu.gif

當建構完成後,會在專案目錄下多出一個 .output 目錄同時也會有 dist 目錄,可以發現 .output/public 目錄內容與 dist 目錄相同。
https://ithelp.ithome.com.tw/upload/images/20221014/2015261766kiDKvwgH.png

靜態頁面的生成因為Nuxt 使用基於爬蟲的技術為每個頁面產生 HTML 與 Payload 檔案,可以發現產生的靜態頁面目錄結構,也對應著我們專案的路由頁面,而頁面元件資料夾內會由一個 index.html_payload.js 組成。

下圖所產生的結構,是因為我們的部落格資料庫內已經有三筆文章資料,/articles 頁面會取得所有的文章,並列出對應著 /articles/1/articles/2/articles/3 目錄,每個頁面內也都包含預先從 Server API 請求好的文章資料並存於 _payload.js 之中。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617jEaXCTMEYH.png

至此我們就可以將 .output 目錄部署至伺服器或靜態託管服務,而且也不需要在使用 Node.js 伺服器來服務這些靜態檔案。

手動設定預渲染的路由規則

我們使用 generate 指令所產生的全靜態頁面網站,是基於 Nuxt 的爬蟲技術來分析頁面,如同前個例子文章頁面的產生所描述,如果我們的資料庫存在著 200 筆資料,但 /articles 頁面所打的 API 總是只回傳最新的 10 筆,那麼那些沒有路由連結可以連結過去的文章頁面,就無法被 Nuxt 的爬蟲所分析到,也就無法產生對應的靜態頁面。

為了解決這個問題,我們可以藉由配置 Nitro 的預渲染路由,來手動的設定哪些頁面要進行預渲染產生靜態頁面,或者忽略產生靜態頁面。

export default defineNuxtConfig({
  nitro: {
    prerender: {
      ignore: [],       // 忽略特定路由不進行預渲染
      routes: [],       // 指定路由進行預渲染
      crawlLinks: true  // 啟用 Nuxt 爬蟲蒐集頁面連結來進行預渲染
    }
  }
})

當然,也可以搭配 buildgenerate 指令做使用,但會稍微有些不一樣。

build

例如,設置如下,並使用 npm run build 指令。

export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: ['/articles', '/articles/2']
    }
  }
})

那麼建構出來的通用渲染網站,就會包含部分頁面是已經預渲染好的靜態頁面。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617Wim98mAvMu.png

generate

當我們使用 generate 時,因為是進行全站的靜態頁面生成,所以基本上涵蓋了所有路由頁面,並且 nitro.prerender.crawlLinks 屬性預設為 true 會啟用 Nuxt 爬蟲來蒐集整的網站的路由頁面,進而開始預渲染產生靜態頁面。

例如,設置如下,並使用 npm run generate 指令。

export default defineNuxtConfig({
  nitro: {
    prerender: {
      ignore: ['/login', '/register'],
      routes: ['/articles/2'],
      crawlLinks: true
    }
  },
})

那麼建構出來的 .output 目錄,就會因為設置了 nitro.prerender.ignore 而忽略 /login/register 頁面的靜態生成 ,而 /articles/2 在網站中因為沒有任何頁面能連結到此,所以 Nuxy 爬蟲無法蒐集到,所以可以手動添加進 nitro.prerender.routes 職中。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617Dint78UWr5.png

如果我們將 nitro.prerender.crawlLinks 屬性設為 false,那麼在產生靜態頁面的時候,就算 /articles 包含了所有文章的連結,Nuxt 爬蟲也就不會蒐集連結來產生靜態頁面,而是僅依照專案目錄下的 pages 所產生出的路由但不包含 [id].vue 這類動態匹配的路由來產生靜態頁面。

建構僅在客戶端渲染的網站

同樣的使用部落格作為範例,來嘗試將 nuxt.config.tsssr 屬性設為 fasle,也就讓網站僅在客戶端渲染 (Client-side Only Rendering)

執行下列指令進行建構:

npm run build

建構完成後,會在專案目錄下多出一個 .output 目錄,可以發現 public 目錄結構與通用渲染建構出的不大一樣,多出了像 Vue 專案建構完成後的 index.html 檔案,來作為顯示的容器。
https://ithelp.ithome.com.tw/upload/images/20221014/20152617UTVKL4Ne4z.png

這邊比較需要留意的地方是,當我們將 ssr 屬性設為 fasle,也還是會在 .output 建構出 server 目錄,也擁有著 .output/server/index.mjs

那這不就意謂著我還是得有 Node.js 服務才能部署嗎?其實你可以這麼理解,當我們設定 Nuxt 僅在客戶端進行渲染,但 Nuxt 專案中仍然可能有Server API,這個屬於伺服器端的 API,總不可能一同打包至前端去做架設吧!所以使用 npm run build 建構出來的專案,都會使用 Nitro 引擎來啟動服務,若有 Server API 的處理邏輯,則會連帶打包進 .output/server 目錄之下。

如果你確定 Nuxt 的專案內沒有自己實作的 Server API,全部是依賴非專案內的 Server API,那麼你可以直接將 public 目錄,視為 Vue 建構出的 dist 目錄來進行部署,因為選擇不再需要 Nitro 引擎來為我們提供 Web Server 的服務,且專案內的前端也都打包完在 public 下可以視為 SPA 網站。

整理這些排列建構參數的組合

相信看到這裡,可能對建構與產生靜態頁面有一點混亂了,這邊稍微整理了一下,大家可以再依據需求來啟用相對應的配置。

npm run build + ssr: true

build + ssr: true

Nuxt 3 預設的建構參數,使用通用渲染 (Universal Rendering) 模式

build + ssr: true + nitro.prerender.crawlLinks: true

使用通用渲染模式,頁面中需要打 API 動態產生的連結而被 Nuxt 爬蟲所蒐集到的頁面將被預渲染成靜態頁面。

build + ssr: true + nitro.prerender.routes + nitro.prerender.crawlLinks: false

使用通用渲染模式,但指定頁面預渲染成靜態頁面。

npm run build + ssr: false

build + ssr: false

僅在客戶端渲染 (Client-side Only Rendering) 的模式,部署時同樣需要使用 server 中的 index.mjs 來啟動 Nitro 伺服器,這樣才能正確的運作 Server API;除非確認專案內完全無依賴專案內的 Server API,則可以直接將 .output/public 視為 Vue 的 dist 目錄進行部署。

npm run generate + ssr: true

generate + ssr: true

使用預渲染產生靜態頁面,預設產生全站靜態頁面,generatenitro.prerender.crawlLinks 屬性預設變為 true,整個網站包含 Nuxt 爬蟲所蒐集到的頁面將被預渲染成靜態頁面。

generate + ssr: true + nitro.prerender.ignore

使用 generate 已經包含整個網站,如果想要忽略某些頁面進行預渲染,可以添加路由至 nitro.prerender.ignore 中。但是需要注意,這些被忽略的頁面如果有使用專案內的 Server API 需求,可能就無法正確的在靜態託管平台運作,而外部的倒是不受影響。

generate + ssr: true + nitro.prerender.routes

雖然使用 generate 已經包含整個網站,但 Nuxt 爬蟲所蒐集到的頁面僅為頁面中產生的,如果連結不存在這些頁面內,只能只接從瀏覽器網址列輸入進入,那麼我們可以將路由添加至 nitro.prerender.routes 來額外補充需要預渲染的頁面。

generate + ssr: true + nitro.prerender.routes + nitro.prerender.crawlLinks: false

同樣會產生全站靜態頁面,但不使 Nuxt 爬蟲所蒐集到的連結頁面,所以這些動態匹配或需要打 API 獲取資料再渲染的頁面,將不會是靜態頁面,因此也需要注意,如果這些頁面有使用專案內的 Server API 需求,可能就無法正確的在靜態託管平台運作,而外部的倒是不受影響。

其它跟建構有關的參數屬性可以再參考官方文件Vitewebpack 建構工具也都能額外設定參數屬性。

小結

Nuxt 的建構指令 build 與產生靜態頁面的 generate 指令,讓我們可以依據不同的情境來決定渲染模式與預渲染的頁面,最終產生的 .output 目錄也會有不一樣的結構。預渲染的頁面與單純的 SPA 也要注意使否有使用到 Nuxt 專案建立的 Server API,再決定是否需要 Nitro 伺服器來啟動正式環境的網站服務。當一切就緒之後最後就能將輸出的目錄打包進行部署。


感謝大家的閱讀,這是我第一次參加 iThome 鐵人賽,請鞭小力一些,也歡迎大家給予建議 :)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。

範例程式碼

參考資料


上一篇
[Day 28] Nuxt 3 渲染模式 (Rendering modes) 與網站使用體驗核心指標 (Core Web Vitals)
下一篇
[Day 30] Nuxt 3 就剩最後一步了 - 部署 (Deployment)
系列文
Nuxt 3 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言