Next.js Static Files 優化簡介
CDN
內容傳遞網路(CDN) 是指一組分佈在不同地理位置的伺服器,協同工作以提供網際網路內容的快速交付。可以從離使用者最近的伺服器取的資源以便更快速的傳遞資源給使用者,加快網站載入速度及減少主網伺服器的流量負載。
assetPrefix
nextjs 在 CDN 相關的優化提供了 assetPrefix 可以設定。
const isProd = process.env.NODE_ENV === 'production' module.exports = { // Use the CDN in production and localhost for development. assetPrefix: isProd ? 'https://cdn.mydomain.com' : undefined, }
assetPrefix 會加在 `/_next/static` 資料夾前面,如圖所示:
![](https://assets.matters.news/embed/ed67ce93-d079-4826-95b9-7760b9fb64c1.png)
![](https://assets.matters.news/embed/bff4d15e-c76b-418c-b3b3-67fc2e2a1f6e.png)
不過 CDN 有設定是可以指向要 cache 的路徑,所以不需要把 _next/static 傳上 CDN,因為 Next.js 目前對 CDN的優化的設定只有 assetPrefix ,所以我的優化思路是盡量讓 asset files 的路徑 在 next build 完後都放在 _next/static 。這勢必就要改變我們的部分引入檔案的寫法,所以我先重新了解一次 next/image 。
next/image
Nextjs 官方推薦我們 圖片都是用 next/image 引入,因為這個優化圖片的功能非常強大,它能做到:
- 優化大小,圖片長寬多少就指回傳相對應大小的圖片尺寸
- 自動處理 Cumulative Layout Shift 問題
- 頁面看到圖片才載入資源,加快頁面載入速度
- 方便管理不同來源的圖片資源
local images
使用 import 的方式引入圖片的話,可以像使用 html img tag 一樣不用特地加上 height , width ,要加入參數是因為 nextjs 會透過 尺寸參數 優化圖片載入時的 Cumulative Layout Shift 問題。而因為 local images 可以讓 nextjs 在 build time時 就算好尺寸。
import Image from 'next/image' import profilePic from '../public/me.png' <Image src={profilePic} alt="Picture of the author" />
這是大部分開發者可能會忽略的 next/image 載入圖片的方式,因為官方文件大多也都是用 `/me.png` 等 絕對路徑的方式引入圖片,但這個方式的引入方式能在 next build 時把圖片放到 __next/static/media 內,因此能用 assetPrefix 用 CDN 路徑優化。
remote images
這是官方文件預設的引入圖片的方式,為什麼可以直接用 `/me.png` 就能去得 `public/me.png`的原因是 next/image 的預設loader是指向 自己網站的 public 資料夾 - nextjs 自己提供的 asset file serve 空間。因為方便 CDN 設定,我個人習慣是把本機端的素材 改用 import 方式載入,如果要用CDN優化 也能將 public 的 素材丟掉 另外的 static filed server 讀取。
如果需要讀取 外部圖片資源 則需要再 next.config.js 設定 remotePatterns 或 domain,以防資安問題。
module.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: 'example.com', port: '', pathname: '/account123/**', }, ], }, }
react-svg/ svgr
關於 svg 的優化方式我是選擇避免使用 next/image 引入 svg 檔案,而是改用 react-svg , svgr 等套件引入,因為 svg 通常會需要 js 改寫樣式,使用 lib 讓 svg 當作元件比較好操作,而 svg 的套件 也會優化 svg 的檔案大小,而 svg 套件大多都是編譯svg後 inline 在 html 上,加上檔案都比較小,所以我僅用套件優化而已。
從 css 引入 static files
css 也能用 絕對路徑的方式 引入 public 資料夾的素材,但為了方便 CDN優化,我會選擇用 相對路徑的方式優化,一樣在 build time 會放進 __next/static/media
![](https://assets.matters.news/embed/59ee4f91-e877-4ad6-9caf-a623e5317037.png)
![](https://assets.matters.news/embed/c54f8f49-645c-4d30-86e6-4879d540d0a0.png)
字體優化
nextjs 自身就會壓縮字體大小,所以要進一步優化就是 把字體丟到CDN 減少主網的流量。
URL Imports
這是新版的實驗性功能,因為 lib 如果都從 node_modules 引入的話,會讓編譯完了 nextjs app.js 變太肥大,而這個功能就是能讓 套件能透過 外部網址的方式把 檔案丟給外部資源載入,這樣也能加快載入頁面的速度。往後進一步優化可在使用,URL Imports 載入 lib
module.exports = {experimental: {urlImports: ['https://example.com/modules/'],}, }
import { a, b, c } from 'https://example.com/modules/some/module.js'
總結
- 使用 assetPrefix 設定 CDN 優化 __next/static
- 盡可能讓 專案內的本地資源 next/build 完後 放進 __next/static 以便 CDN 優化
- 或是將 public 的資源丟到 CDN 直接從CDN網址讀取圖片
- svg 檔案 使用 react-svg , svgr 套件優化
- npm package 改用 URL Imports 引入 (實驗中)