iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Modern Web

Nuxt 3 學習筆記系列 第 26

[Day 26] Nuxt 3 Public 與 Assets 資源目錄

  • 分享至 

  • xImage
  •  

前言

在網站的開發過程中,多少會使用到圖片、樣式或設定字體,而當這些檔案若沒有外部連結或某些需求下需要包含在專案內做使用,最後連帶這些檔案一起部署。在使用 create-vue 建立的 Vue 的專案下包含了 public 與 src 內的 assets 目錄,這兩個目錄都是可以放置這類不常變動的靜態資源,但這兩個目錄各自因為一些特性,建議放置的檔案類型依據使用目的有所區別。

Nuxt 3 的靜態資源

Nuxt 3 使用專案下的兩個目錄來提供使用者處理圖片、樣式或字體,這兩個目錄分別為 publicassets

public 目錄

在 Nuxt 3 的專案根目錄下,存在一個名為 public 的目錄,這個目錄如同 Vue 中的 public 目錄或 Nuxt 2 中的 static 目錄。這個目錄下的檔案,將會由 Nuxt 直接於網站的根路徑,例如 / 提供存取。

例如建立 ./public/robots.txt 將可以使用 http://localhost:3000/robots.txt 存取。

通常我們會在 public 目錄放置不常更動的檔案,或是需要保留檔案的名稱,例如 robots.txt 就需要一個固定的名稱,才能正確的被搜尋引擎的爬蟲所解析再決定檢索的規則,抑或 sitemap.xmlfavicon.ico 檔案等,都很適合放置在 public 目錄。

你可能也會想,那圖片或 CSS 樣式,我也不常變動,難道就不能放置在 public 目錄嗎?

行,當然行,哪次不行!

舉個例子,我們將一張圖片 bg.png 放置於 public 目錄下,專案目錄下其他檔案就先不列,整個結構大概長的像下面這樣。

nuxt-app/
├── public/
│   └── bg.png
└── app.vue

根據規則,我可以使用 http://localhost:3000/bg.png 存取,如下圖我們確實成功的能存取到圖片。
https://ithelp.ithome.com.tw/upload/images/20221011/20152617c5F5wD8yAs.png

所以,我們在 app.vue 新增如下程式碼,使用 /bg.png 來等同訪問 ./public/bg.png 檔案:

<template>
  <div>
    <img src="/bg.png" />
  </div>
</template>

也確實能在網頁中使用 <img src="/bg.png" /> 來顯示圖片。
https://ithelp.ithome.com.tw/upload/images/20221011/20152617UU9QjR6CQJ.png

既然 public 目錄已經能提供靜態資源的連結,那麼為什麼還有一個名為 assets 的目錄呢?接下來我們先介紹 assets 目錄,最後再來總結一下差異。

assets 目錄

Nuxt 3 使用 ViteWebpack 來建構專案進行打包,這些建構工具主要功能是用來處理 JavaScript 檔案將其編譯、轉換或壓縮等,但它們可以透過各自的插件Loader 來處理其他檔案類型的資源,例如樣式、字體或 SVG 等。

舉例來說,我們在 assets 下建立一個 Sass 的樣式,當這個 Sass 檔案被載入使用,就會經過插件Loader 來進行 CSS 的預處理及編譯,最終產生一個 CSS 檔案,也可以針對單純的 CSS 檔案進行壓縮。又或者說,當使用 <img>src 屬性設定載入我們放置在 assets 的圖片或圖示,最終需要轉換為 Base64 編碼而不是產生一個連結,我們也需要依賴建構工具插件的擴展來幫助。

其主要的目的,不外乎就是為了效能與解決瀏覽器的快取。放置在 assets 目錄下的檔案,可能會被插件Loader 進行轉換或壓縮,最終產生出來的檔案也具備連結可以進行存取。

如果使用 public 目錄下導出的 /bg.png,就算我們替換了 bg.png 圖片,可能就會因為檔案根據檔案名稱被瀏覽器快取住,導致前端還是看到舊的檔案。我們在使用 assets 目錄下的檔案時雖然檔名都是 bg.png,但在建構時產生的檔案通常會夾帶 Hash,例如,bg.16a2f98c.png,如此一來我們每次更新圖片,都都會隨機的產生一組 Hash 就能防止瀏覽器快取,導致好像網站更新失效的錯覺。

舉例來說,我們以相同的圖片,改放置於 ./assets/bg.png

nuxt-app/
├── assets/
│   └── bg.png
└── app.vue
<template>
  <div>
    <img src="~/assets/bg.png" />
  </div>
</template>

在開發環境 ~/assets/bg.png 會轉換為 /_nuxt/assets/bg.png,實際上也能使用 http://localhost:3000/_nuxt/assets/bg.png 進行訪問。
https://ithelp.ithome.com.tw/upload/images/20221011/20152617tuQYrNIO5T.png

除了 ~/assets 可以對應 assets 目錄外,也可以參考官方的 alias 更多或自訂別名來使用相對路徑

但當你的網站部署完成或啟動建構出來的專案,會發現圖片檔名包含了 Hash,例如 /_nuxt/bg.0a299ea1.png
https://ithelp.ithome.com.tw/upload/images/20221011/20152617YtG4UCsS0Z.png

最後我們以最終建構出來的專案結構對比如下圖,在 public 目錄下的檔案,會原封不動的照搬至 .output/public 下,也就可以使用 /bg.png 存取;而放置在 assets 下的檔案,可能會被處理加工,最後檔案名稱會加上一個 Hash 並放置在 .output/public/_nuxt 下,也就需要使用 /_nuxt/bg.0a299ea1.png 存取。
https://ithelp.ithome.com.tw/upload/images/20221011/20152617g12KiRIbZs.png

小結

總結來說多數情況建議把靜態資源放置在 assets,也因為靜態資源多為 SFC 所使用,通常也會放置最多檔案,最後建構時也會因為建構工具的設定來進行轉換或壓縮,最後添加 Hash 來提供存取,也因為每次建構產生的檔案都不一樣,所以不適合直接以完整的 URL 供外部連結使用。而當有些例外情況不適合,例如 robots.txtsitemap.xml 這類的檔案不需要經過額外處理且需要絕對路徑保持檔案名稱,那就得放置在 public 目錄下提供存取。


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

參考資料


上一篇
[Day 25] Nuxt 3 邁向國際化 - 使用 Nuxt I18n 實作多國語系
下一篇
[Day 27] Nuxt 3 測試 (Testing) 與錯誤處理 (Error handling)
系列文
Nuxt 3 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Wolke
iT邦新手 1 級 ‧ 2023-01-10 11:02:21
<img src="~/assets/bg.png" />

如果要動態載入,依照官網說明
https://nuxtjs.org/docs/directory-structure/assets
是改成

<img :src="require(`~/assets/bg.png`)" />

在 nuxt 2 可以
但 nuxt 3 會報錯 Cannot find module

不知道有解無
感謝回覆

Ryan iT邦新手 2 級 ‧ 2023-01-11 15:21:34 檢舉

已現階段來說,Nuxt 3 還沒辦法像像 Nuxt 2 可以直接使用 require 來動態的載入資源,不過核心開發成員 Daniel Roe 有提供一個作法你可以參考看看,範例程式

原討論串
Assets with dynamic names are not resolved #7121

我要留言

立即登入留言