svgファイルをReactコンポーネントに変換する方法
やりたいこと
.svg
を .tsx
の拡張子に変換したい
技術選定
- React
- TypeScript
- Next.js
- @svgr/cli
実現方法
SVGRというツールを用いることで簡単に実現できた
前提知識
SVGRとは何か?
svgファイル から Reactコンポーネント にコマンド1つで簡単に変換できる CLI ツール
SVGR の基本構成
svgファイル(.svg) → SVGR → React Component(.jsx | .tsx)
svg を jsx に変換する基本手順
1. 実行ファイルをinstallする
yarn add -D @svgr/cli
2. CLIコマンドを叩く
npx @svgr/cli -d src/components/icons public/icons
※ -d [出力先のディレクトリ名] [svgファイルが格納されているディレクトリ名]
- ※1 Usage: npx @svgr/cli [-d out-dir] [--ignore-existing] [src-dir]
- ※2 npx : ローカルインストールしたコマンドを実行するために使用される便利コマンド
この2つのステップでpublic/icons
にあるsvgファイルが
src/components/icons
にjsファイルとして出力される
実際の現場で運用する際はいちいち2のnpxコマンドを叩くのはとても面倒。
package.json
のscripts配下にエイリアス登録しておくと使い回しやすいので
package.json
のscripts配下に実行コマンドをエイリアス登録しておくと良い
"scripts": {
"icons": "npx @svgr/cli -d src/components/icons public/icons"
}
これでyarn icons
と叩くだけでsvgファイルを
コマンド1つでコンポーネントファイル(js)に変換できる
ただし、この設定のままだと svgファイル を jsファイル にしか変換できない。
やりたいことは svg を tsx に変換したいだったので
SVGR の設定ファイルを作成して編集する必要がある。
svg を tsx に変換する手順
- 設定ファイル(
.svgrrc.js
)を作成する - 設定ファイルに
typescript: true
と記載する
module.exports = {
typescript: true
}
この設定ファイルをルートディレクトリ
に
作成した上でもう一度yarn icons
と叩く
そうすると、svgファイル
からtsxファイル
に変換できる。
svg から tsx に変換できた ↓ |
---|
補足事項
上記、設定のままだと以下のように
default export
のコンポーネントに変換される
import * as React from 'react'
function SvgVectorRight(props: React.SVGProps<SVGSVGElement>) {
return (
<svg xmlns='http://www.w3.org/2000/svg' width={32} height={32} {...props}>
<path d='M19.414 27.414l10-10a2 2 0 000-2.828l-10-10a2 2 0 10-2.828 2.828L23.172 14H4a2 2 0 100 4h19.172l-6.586 6.586c-.39.39-.586.902-.586 1.414s.195 1.024.586 1.414a2 2 0 002.828 0z' />
</svg>
)
}
export default SvgVectorRight
自分はdefault export
ではなく名前付きexport
のコンポーネントに変換したかった
これは、SVGR | template を編集することで、実現することができた
@svgr/cli version 5系の場合
// .svgrrc.js
module.exports = {
typescript: true,
template: ({ template }, opts, { imports, componentName, props, jsx }) => {
const plugins = ['jsx']
if (opts.typescript) {
plugins.push('typescript')
}
const typeScriptTpl = template.smart({ plugins })
return typeScriptTpl.ast`${imports}
export const ${componentName} = (${props}): JSX.Element => {
return ${jsx};
}
`
},
}
上記、設定ファイルにした上で、もう一度yarn icons
を叩くと
以下のように名前付きexport
のコンポーネントに変換された
import * as React from 'react'
export const SvgVectorRight = (props: React.SVGProps<SVGSVGElement>): JSX.Element => {
return (
<svg xmlns='http://www.w3.org/2000/svg' width={32} height={32} {...props}>
<path d='M19.414 27.414l10-10a2 2 0 000-2.828l-10-10a2 2 0 10-2.828 2.828L23.172 14H4a2 2 0 100 4h19.172l-6.586 6.586c-.39.39-.586.902-.586 1.414s.195 1.024.586 1.414a2 2 0 002.828 0z' />
</svg>
)
}
@svgr/cli version 6系の場合
SVGR | template | Migrate to v6 に記載されている通りです。
version 6系
を install した場合
templateの関数の引数の渡し方が変化しているので注意が必要です。
// .svgrrc.js
module.exports = {
typescript: true,
template: (variables, { tpl }) => {
return tql`
${imports}
export const ${variables.componentName} = (${variables.props}): JSX.Element => {
return ${variables.jsx};
}
`
},
}
これで自分は「やりたいこと」を実現できました!
最後に
ほとんどコピペで実現可能だと思うんで
Reactのアイコンの管理方法に悩んでいる人はぜひ活用してみてください!
Discussion