搜尋 remix SVG as react component 會找到SVGR 官方提供的 remix 設定,但感覺太複雜了。其實可以直接用 vite-plugin-svgr 來處理就好。
步驟
先安裝套件:
npm i --D vite-plugin-svgr @svgr/plugin-jsx @svgr/plugin-prettier @svgr/plugin-svgoyarn add --D vite-plugin-svgr @svgr/plugin-jsx @svgr/plugin-prettier @svgr/plugin-svgo然後在專案根目錄新增 svgr.config.cjs 與 svgo.config.cjs。使用 .cjs 是因為用 .js 設定檔沒辦法讓 npm run remix vite:dev 啟動專案。錯誤訊息如下:
[vite] Internal server error: require() of ES Module (略)/svgo.config.js from (略)/node_modules/cosmiconfig/dist/loaders.js not supported.Instead change the require of svgo.config.js in (略)/node_modules/cosmiconfig/dist/loaders.js to a dynamic import() which is available in all CommonJS modules.接著在 svgr.config.cjs 中設定要引用的外掛(plugin):
module.exports = { plugins: ["@svgr/plugin-svgo", "@svgr/plugin-jsx", "@svgr/plugin-prettier"],};不需要加上 typescript: true,因為轉成 .tsx 反而會讓 vite 無法順利解析。錯誤訊息大概長這樣:
7:34:05 PM [vite] Internal server error: Transform failed with 1 error:(略)/app/assets/icons/arrow_back.svg?react:2:12: ERROR: Expected "from" but found "{"
Expected "from" but found "{" 1 | import * as React from 'react'; 2 | import type { SVGProps } from 'react'; | ^ 3 | const SvgArrowBack = (props: SVGProps<SVGSVGElement>) => ( 4 | <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} viewBox="0 0 24 24" {...props}>然後在 svgo.config.cjs 設定 .svg 的加工需求:
module.exports = { plugins: [ { name: "removeAttrs", params: { attrs: "(fill|fill-rule|style)", }, }, ],};選擇移除 fill 和 style 是因為我會透過 tailwind css 來控制 .svg (圖示)的顏色。
再把設定檔與 vite-plugin-svgr 加進 vite.config.js:
import svgr from "vite-plugin-svgr";import svgrOptions from "./svgr.config.cjs";
export default { // ... plugins: [svgr({ svgrOptions })],};快完成了。在 ./app 資料夾內建立 custom.d.ts。檔名中的 custom 可以換成其他名稱。在 custom.d.ts 加入以下內容:
declare module "*.svg" { const content: string; export default content;}
declare module "*.svg?react" { import * as React from "react"; export const ReactComponent: React.FunctionComponent< React.ComponentProps<"svg"> >; export default ReactComponent;}這代表這個專案的 .svg 檔有兩種用法。一個是在路徑尾巴加上 ?react 把 .svg 當成 React 元件用。一個是不加上 ?react 來載入 .svg 的檔案路徑。參考以下範例:
import arrowBackSrc from "~/assets/icons/arrow_back.svg";import ArrowBack from "~/assets/icons/arrow_back.svg?react";
function IconButton() { return ( <button> <ArrowBack className="block h-6 w-6" /> <img src={arrowBackSrc} alt="" /> </button> );}最後,把 custom.d.ts 加進 tsconfig.json 的 compilerOptions.types 中:
{ "compilerOptions": { "types": ["@remix-run/node", "vite/client", "./app/custom.d.ts"] }}完成 👏