今天會先分享個人慣用的靜態資源設定,接著會介紹我滿喜歡的 svg loader @svgr/webpack。這個套件能讓 .svg 直接以「元件」的形式被引用:
import EditIcon from "./edit_icon.svg";
function EditButton() { return ( <button> <EditIcon /> edit profile </button> );}那麽開始吧 (`・ω・´)
webpack 設定
以路徑形式使用圖片
首先在 webpack 設定中加上以下內容:
const webpackDevelopmentConfig: WebpackConfiguration = { module: { rules: [ { test: /\.(png|svg|jpg)$/i, type: "asset/resource", resourceQuery: /url/, }, ], },};沒錯,在 webpack 5 的時代裡,取用靜態資源不強制要求安裝套件 raw-loader / url-loader / file-loader 了。
webpack: Asset Modules types replace all of these loaders by adding 4 new module types.
以上這段規則在做的事情是:當偵測到檔案路徑符合 .png?url / .svg?url / .jpg?url 時,webpack 會提供該檔案在瀏覽器環境中可以使用的路徑。
webpack:
asset/resourceemits a separate file and exports the URL. Previously achievable by usingfile-loader.
所以現在你可以在專案內使用以下方式運用 ./src/asset 資料夾中的圖片檔案了:
import React from 'react';import foxImageUrl from '@Asset/alexander-andrews-unsplash.jpg?url';
function Image() { return <img src={foxImageUrl} alt="fox image" />;}
export default Image;記得 import 路徑結尾要加上我們在 webpack 規則中設定好的 resourceQuery url。
以元件形式使用 svg
先安裝 @svgr/webpack,然後追加以下設定:
const webpackDevelopmentConfig: WebpackConfiguration = { module: { rules: [ { test: /\.(png|svg|jpg)$/i, type: "asset/resource", resourceQuery: /url/, }, { test: /\.svg$/i, issuer: /\.tsx?$/, resourceQuery: { not: [/url/] }, use: [ { loader: "@svgr/webpack", options: { svgo: false, }, }, ], }, ], },};透過 test: /\.svg$/i、resourceQuery: { not: [/url/] } 與 issuer: /\.tsx?$/ 來處理「所有 .tsx 中結尾不為 .svg?url 的內容」。遇到符合前述條件的檔案時,使用 @svgr/webpack 來處理之。
這邊比較弔詭的地方是設定 svgo: false 來讓 css 針對 svg 的尺寸設定可以順利被套用上去。只寫成 use: ['@svgr/webpack'] 或是使用 svgo 官方建議的解決方式在個人的實驗結果中都是失敗的(svg 無法透過 css 調整尺寸)。
🤷
更新 src/env.d.ts
請將以下內容加到 ./src/env.d.ts 中。這能讓 TypeScript 知道「路徑結尾為 .(jpg|png|svg)?url 的檔案會是文字型別」,而「路徑結尾為 .svg 的檔案會是一個 React 元件且擁有 html svg element 的特性(props)」。
declare module "*.jpg?url" { const src: string; export default src;}
declare module "*.png?url" { const src: string; export default src;}
declare module "*.svg?url" { const src: string; export default src;}
declare module "*.svg" { import React from "react"; const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>; export default ReactComponent;}完成!現在你的專案能夠正常顯示圖片內容了 (`・∀・)b
補充:如何選擇圖片格式
綜合平常的開發經驗以及參考 web.dev: Choose the right image format 一文,個人通常會以以下流程來判斷最終要使用哪一種格式來顯示圖片:
- 需要支援透明度:沒什麼選擇,基本上就是
png - 照片、不是色塊分明的圖面:使用
jpg - 色塊分明的圖片(如網站 logo 等):使用
svg或png
確定格式後,我會再根據圖片實際的展示位置決定是否調整檔案尺寸。除了 landing page 這類大面積區塊外,基本上圖片都可以縮小成「畫面上實際展示的大小」即可。
雖然現在是不需要特別斤斤計較流量的時代,但無意義地使用大圖片也會造成 lighthouse 評分低落。開發時若還有餘裕的話,上圖時稍微注意一下也沒有損失 😈