イマドキの React Native での SVG ファイルの取り扱い方
これは Farmnote Advent Calendar 17 日目の記事です。
TL;DR
今は SVGR を使って React component に変換して使おう。多分そのうち react-native-svg でファイル読み込みがサポートされる予定なのでそちらに移行しよう。
現状確認
React Native で SVG を書き下したい場合は react-native-svg という package で FA。 React Native Community の管理下にあるのでメンテナンスが放棄される可能性が低い。
ところが react-native-svg はファイル読み込みをサポートしていない。これは不便ということで react-native-svg-uri という package ができた。
が、 Image と同様の source prop で表示したいファイルを指定すると Android での release build ができない。 svgXmlData prop を使うという workaround はあるが Metro Bundler に SVG ファイルを読み込ませる形になるのでうまくない。つまり使えない。
そうこうしている間に次の issue でファイル読み込みをサポートするという意思表明がされている。
SVGO の非公開メソッドを使って parser を書くという方針のよう。どう転ぶかわからないけどカンバンには載っているので生暖かく見守ろう。
workaround
というわけで SVG ファイルを読み込んで表示させる自然な手段が現状ない。のは困るので SVGR を使って SVG ファイルを React component に変換するという方針でいってみる。
いちいち手で変換するのは面倒なのでスクリプトを組んでみた。 TypeScript で出力する。
#!/bin/sh
set -eux
ROOT=$(cd "$(dirname "$0")/.."; pwd)
cd "${ROOT}"
yarn svgr \
--native \
--template ./bin/svgr-template.js \
--out-dir ./src/components/icons \
--ext tsx \
assets/images/
指定しているテンプレートファイルはこう。
function template({ template }, opts, { imports, componentName, props, jsx, exports }) {
const typeScriptTpl = template.smart({ plugins: ['typescript'] });
return typeScriptTpl.ast`
import React from 'react';
import Svg, { SvgProps } from 'react-native-svg';
const ${componentName} = (props: SvgProps) => ${jsx};
export default ${componentName};
`;
}
module.exports = template;
即席にしてはちゃんと動いている。これを npm script などで駆動させてやればメンテナンスフリーで SVG ファイルを表示できるようになる。