iT邦幫忙

2023 iThome 鐵人賽

DAY 14
1
Vue.js

Nuxt 3 實戰筆記系列 第 14

[Day 14] Nuxt 3 最佳化圖片 動態調整請求控制圖片大小 - Nuxt Image

  • 分享至 

  • xImage
  •  

前言

Nuxt Image 是 Nuxt 的一個模組,顧名思義讓你可以在 Nuxt 專案中使用圖片時,可以幫助你最佳化圖片,Nuxt Image 它所做的是,使用者使用瀏覽器瀏覽網站時,若包含圖片不論是由網站自身提供抑或是使用其所支援的圖片服務提供商的圖片網址,Nuxt Image 可以根據設定來提供最佳的圖片大小,以利首次載入圖片的速度及降低伺服器傳輸給使用者的流量與延遲,進而提升使用者體驗與降低伺服器負擔與成本。

Nuxt 3 安裝 Nuxt Image

安裝套件

執行下列指令安裝 Nuxt Image:

npm install -D @nuxt/image

添加 @nuxt/image 至專案內 nuxt.config.ts 檔案的 modules 屬性中。

export default defineNuxtConfig({
  modules: ['@nuxt/image']
})

至此就完成了 Nuxt Image 的安裝,在專案內可以直接使用套件所提供的元件 <NuxtImg><NuxtPicture>,基本上在你想要最佳化的圖片標籤位置,直接替換掉原生的 imgpicture 就可以了。

Nuxt v3.8 版本,已經具備自動安裝 Nuxt Image 的功能,當你使用 Nuxt Image 所提供的元件時,在啟動開發伺服器時,也會提示你自動安裝與配置 Nuxt Image

替換成 ,你也可以使用

<img src="/image.jpg" />

<NuxtImg src="/image.jpg" />
<nuxt-img src="/image.jpg" />

替換成 ,你也可以使用

<picture src="/picture.jpg" />

<NuxtPicture src="/picture.jpg" />
<nuxt-picture src="/picture.jpg" />

Nuxt Image 圖片路徑

當你想要使用 Nuxt 專案內所提供的圖片,預設情況,你應該將圖片放置在 public 目錄下,使其可以以根路徑 / 進行瀏覽,這樣子圖片才能正常的顯示,舉例來說,以下的程式碼表示載入專案目錄下 public/images/cat.jpg 檔案。

<nuxt-img src="/images/cat.jpg" />

若你想要使用 assets 目錄下的圖片檔案,在你使用 元件時,是不能夠直接將 src 路徑設定為 ~/assets/images/cat.jpg,因為 assets 會經過建構工具編譯的關係,這將會導致 Nuxt Image 無法正確的顯示圖片。

正確的做法是進行全域設定,在專案內 nuxt.config.ts 檔案中添加 image 並設定 dir 參數指向圖片目錄。

export default defineNuxtConfig({
  image: {
    dir: 'assets/images'
  }
})

設定完畢後,並非使用波浪符 ~ 作為開頭,而是需要以根路徑 / 來作為圖片路徑的開頭,來指定圖片路徑。以下面程式碼為例,將訪問的圖片路徑為 /assets/images/cat.jpg

<nuxt-img src="/cat.jpg" />

Nuxt Image 常用屬性參數

當你使用了 元件,基本上就是 的替代品,除了擁有原生標籤屬性特性能使用外,Nuxt Image 更會與其搭配的參數,最佳化元件的圖片使用。

在預設的情況下,使用了 unjs/ipx 來進行圖片的代理,白話來說,不管本地的圖片或外部的圖片連結,都將經過這個代理層來重新產生一張圖片,例如長寬調整、質量調整,使其圖片變輕量加快使用者下載圖片的速度。

width / height

當你使用了屬性 widthheight,原生 img 是會將圖片在顯示時以設定的寬高做顯示,假設圖片實際大小為 986 x 580 px,而我們顯示僅需要寬度 300px (高度自動調整),那麼圖片其實可以先經過壓縮在回傳給使用者,如此可以降低使用者下載圖片的成本與提高顯示速度,原始圖片大小與實際顯示的大小差距越大,那麼最佳化的圖片所帶來的影響,也就提升的更明顯。

以下面程式碼為例,car.jpg 原圖寬高大小為 986px * 580px,而標籤設定顯示寬度 300px。

<img src="/cat.jpg" width="300" />

<NuxtImg src="/cat.jpg" width="300" />

最終渲染出來的程式碼,使用 NuxtImg 元件的圖片會以包含了**代理層(unjs/ipx)**的網址進行顯示。

<img src="/cat.jpg" width="300">

<img src="/_ipx/w_300/cat.jpg" width="300" data-nuxt-img="">

可以觀察到 src="/_ipx/w_300/cat.jpg",其中 w_300 正是開發時傳入的屬性 width="300",這個參數添加在 /_ipx/ 後頭,表示調整圖片寬度為 300。如果你的 Nuxt 執行在 http://localhost:3000 這個網址,你也可以使用 http://localhost:3000/_ipx/w_300/cat.jpg 來進行瀏覽,可以發現到,原本應該下載 224 KB 的圖片,因為代理層的關係,這個圖片連結的圖片僅需要 15 KB。

https://ithelp.ithome.com.tw/upload/images/20230929/20152617bTdjC70gp0.png

當然你也可以同時設定寬高:

<NuxtImg src="/cat.jpg" width="300" height="200"  />

最終代理層產生相對應的連結:

<img src="/_ipx/s_300x200/cat.jpg" width="300" height="200" data-nuxt-img="">

sizes

指定不同螢幕尺寸的圖片的響應式大小。

屬性以空白分隔,每個螢幕尺寸可以對應一個圖片寬度大小。

<NuxtImg src="/cat.jpg" sizes="sm:50vw md:70vw lg:800px" />

sm:50vw 表示在螢幕大小符合 640px 以上,圖片寬度使用 320px = 640 * 50%,md:80vw 表示在螢幕大小符合 768px 以上,圖片寬度使用 576px = 768px * 75%,lg:960px 表示在螢幕大小符合 960px 以上,圖片寬度使用 800px

產生的網頁原始碼:

<img src="/_ipx/w_800/cat.jpg" data-nuxt-img="" sizes="(max-width: 640px) 50vw, (max-width: 768px) 70vw, 800px" srcset="/_ipx/w_320/cat.jpg 320w, /_ipx/w_538/cat.jpg 538w, /_ipx/w_800/cat.jpg 800w">

將會依據螢幕寬度自動產生與套用不同圖片大小的代理層的連結,以此來為響應式網頁來節省下載圖片的成本。

圖片連結 圖片資訊
/_ipx/w_320/cat.jpg 尺寸:320 * 188 px,檔案大小:16.7 KB
/_ipx/w_538/cat.jpg 尺寸:538 × 316 px,檔案大小:40.3 KB
/_ipx/w_800/cat.jpg 尺寸:800 * 471 px,檔案大小:77.1 KB

fit

可以讓需要調整圖片大小時或需要裁減時參考的設定屬性,fit 屬性包含預設的 cover,與 containfillinsideoutside 共有五個值可以做設定。

<NuxtImg fit="cover" src="/cat.jpg" />

format

你可以使用這個選項來決定圖片的預設格式,若傳入多個值,例如 avif, webp,將根據瀏覽器所支援格式及順序來使用。

<NuxtImg format="webp" src="/cat.jpg" />

<NuxtImg format="avif,webp" src="/cat.jpg" />

quality

最終產生圖片的質量。

<NuxtImg quality="80" src="/cat.jpg" />

Nuxt Image 全域設定

你也可以在專案內 nuxt.config.ts 檔案中,添加 image 來設定 Nuxt Image 的全域設定選項,當使用元件或直接呼叫使用 Nuxt Image 時,若沒有傳入數值將以全域的設定作為參考。

export default defineNuxtConfig({
  image: {
    // 這邊放置 Nuxt Image 模組的相關設定選項
  }
})

常用選項

domain

若要在外部網站啟用圖片最佳化,請在此設定允許最佳化的網域。

export default defineNuxtConfig({
  image: {
    domains: ['nuxtjs.org'],
  }
})

provider

當元件中或呼叫 $img 時未指定圖片服務提供商則採用的默認設定,通常會在這裡設定好整個專案會使用到的圖片提供商,預設則是:static

export default defineNuxtConfig({
  image: {
    provider: 'cloudinary',
    cloudinary: {
      baseURL: 'https://res.cloudinary.com/<company>/image/fetch/',
    }
  }
})

providers

若官方所提供支援清單沒有找到符合你的圖片服務提供商,你也可以在這裡自訂提供商與相關程式,詳細可以參考官方的 Custom Provider

export default defineNuxtConfig({
  image: {
    customProvider: {
        name: 'customProvider', // 可選參數,用來複寫外層名稱作為提供商名稱
        provider: '~/providers/custom', // 實作自訂提供商的處理程式
        options: {
          // 自訂提供商選項
        }
      }
  }
})

presets

這個屬性可以用來設定多種預設的最佳化設定,可以幫助你在整個專案上統一相同類型的圖片設定。

舉例來說,我可以設定一個 avatar 的預設,大小固定 50px 且調整為 jpg 格式。

export default defineNuxtConfig({
  image: {
    avatar: {
      modifiers: {
        format: 'webp',
        width: 50,
        height: 50
      }
    }
  }
})

設定完畢後,你就能直接在元件中直接使用這個 avatar 作為基礎預設。

<NuxtImg preset="avatar" src="/cat.jpg" />

Nuxt Image 服務提供商設定

有些情況你會不希望網站內的圖片由自己來提供服務,除了佔據流量與儲存空間外,就算使用了 Nuxt Image 預設的代理層也還是由自己的伺服器做處理與提供,這樣其實並沒有最高效的降低伺服器負擔與成本。

如果你使用的圖片是由外部提供商來提供圖片服務,例如:CloudFlareUnsplashCloudinary 等,那麼 Nuxt Image 所整合的服務提供商的最佳化設定,將有利於我們整個專案的圖片最佳化。

Cloudinary 為例,當你使用這個服務時,控制面板會有一個 Cloud Name,下方會有一個數值例如 nuxt3imgs,這個數值就是我們需要填入至設定中。

https://ithelp.ithome.com.tw/upload/images/20230929/201526170NlRChiF8C.png

修改專案內 nuxt.config.ts 檔案如下 填上 nuxt3imgs

export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    cloudinary: {
      baseURL: 'https://res.cloudinary.com/<your-cloud-name>/image/upload/'
    }
  }
})

我們就可以將 Cloudinary 上的一張 https://res.cloudinary.com/nuxt3imgs/image/upload/v1693216888/cat.jpg 圖片,以下程式碼進行呈現:

<NuxtImg sizes="sm:50vw md:70vw lg:800px" src="v1693216888/cat.jpg" />

因為已經設定了 baseURL 所以您只需要填寫 https://res.cloudinary.com/nuxt3imgs/image/upload/ 之後的路徑。

產生的網頁原始碼:

<img src="https://res.cloudinary.com/nuxt3imgs/image/upload/f_auto,q_auto,w_800/v1693216888/cat.jpg" onerror="this.setAttribute('data-error', 1)" data-nuxt-img="" sizes="(max-width: 640px) 50vw, (max-width: 768px) 70vw, 800px" srcset="https://res.cloudinary.com/nuxt3imgs/image/upload/f_auto,q_auto,w_320/v1693216888/cat.jpg 320w, https://res.cloudinary.com/nuxt3imgs/image/upload/f_auto,q_auto,w_538/v1693216888/cat.jpg 538w, https://res.cloudinary.com/nuxt3imgs/image/upload/f_auto,q_auto,w_800/v1693216888/cat.jpg 800w">

可以發現所有的圖片連接都是依賴外部的 Cloudinary 網址,並使用了 Cloudinary 所提供的最佳化參數來做圖片的壓縮調整。

小結

使用者最終瀏覽到的依然是圖片,只是在這個過程中我們使用 Nuxt Image 透過自身的代理層或圖片服務提供商,最佳化了圖片大小或傳輸的延遲,它可以將不僅將本地圖片與其他來自其他網址的圖片,根據寬度與高度,自動調整圖片的大小,它還可以為圖片自動產生 RWD 專門使用的各種尺寸圖片。使用 Nuxt Image 搭配圖片服務提供商,可以獲得最好的最佳化體驗,不僅可以仰賴提供商的流量與 CND 加速,各式各樣的調整參數讓一切都變得簡單,使用者也能獲得最佳的瀏覽體驗。


感謝大家的閱讀,歡迎大家給予建議與討論,也請各位大大鞭小力一些:)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。

參考資料


上一篇
[Day 13] Nuxt 3 使用路由中間件(Middleware)實作身份驗證與實作技巧
下一篇
[Day 15] Nuxt 3 使用 useHead 動態設定 HTML Head 與 Meta Tag
系列文
Nuxt 3 實戰筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Dylan
iT邦新手 1 級 ‧ 2023-10-29 17:07:28

介紹 fit 的 code 好像有錯,應該是:

- <NuxtImg preset="cover" src="/cat.jpg" />
+ <NuxtImg fit="cover" src="/cat.jpg" />
Ryan iT邦新手 1 級 ‧ 2023-10-30 14:26:02 檢舉

非常感謝您,已修正

/images/emoticon/emoticon06.gif

我要留言

立即登入留言