TypeScript × React × Webpack のプロジェクトでsvgをimportしてjsxとして使用する

August 20, 2019

画像などのjs以外のリソースをimportしてjsxで使用したいということがまぁまぁあると思います。react-svg-loaderというパッケージを使うとsvgをimportしてjsxとして使用することができます。

react-svg-loader - npm

インストール

npm i react-svg-loader --save-dev

導入

インラインで直接使う場合は以下のようにimportすればOKです。この書き方初めて知りました。

import Image1 from 'react-svg-loader!./image1.svg';

Webpackで使用する

Webpackで使用する場合は、READMEの導入を参考にwebpack.config.jsloaderに設定を追加します。

{
  test: /\.svg$/,
  use: [
    {
      loader: "babel-loader"
    },
    {
      loader: "react-svg-loader",
      options: {
        jsx: true // true outputs JSX tags
      }
    }
  ]
}

ReactのコードもREADMEにならってこのように書きます。jsxで書けるのがいいですね。

import Image1 from './image1.svg';
<Image1 width={50} height={50}/>

エラーが出ました

Webpackを起動するとエラーが出ました。jsxをゴニョゴニョしてるところでエラーが出てるのでしょうかね?もしかしたらTypeScriptを使ってるのでts-loaderでjsxをコンパイルしているからなのかな?

ERROR in ./image1.svg
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: ****/hoge.svg: Unexpected token (5:6)

試しに以下のoptionsの項目を削除してみました。するとエラーが消えました。

options: {
  jsx: true // true outputs JSX tags
}

SVGOで最適化

SVGOというsvgを最適化して、サイズを軽くしてくれるnode.js製のライブラリがあります。optionsでsvgoを使用することもできます。

GitHub - svg/svgo: Node.js tool for optimizing SVG files

webpack.config.jsを次のようにします。

{
  test: /\.svg$/,
  use: [
    "babel-loader",
    {
      loader: "react-svg-loader",
      options: {
        svgo: {
          plugins: [
            { removeTitle: false }
          ],
          floatPrecision: 2
        }
      }
    }
  ]
}

TypeScriptのコンパイルエラー

TypeScriptを使用しているとこのようなエラーが出ます。

[tsl] ERROR in hoge.tsx(7,20)
      TS2307: Cannot find module './image1.svg'.

WebpackでTypeScriptを使用しているときにコード以外のリソースをimportしようとするとモジュールが存在しないのでコンパイルエラーになります。そこで自前の型定義ファイルを作ることで回避します。

TypeScript#importing-other-assets | webpack

custom.d.tsというファイルをプロジェクトのトップレベルに配置します。中身は下記のような定義を書いておきます。

declare module "*.svg" {
  const content: any;
  export default content;
}

これでモジュールとして認識されるようになるので読み込めるようになります。

Jestのテストでエラー

Jestでコンポーネントファイルのテストを書いているのですが、テストを走らせるとsvgの読み込みのところでエラーが出ました。

at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:471:17)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:513:25)
      at Object.<anonymous> (src/Hoge.tsx:7:1)

Jestのテストでもsvgを読み込めるようにjest-svg-transformerをインストールしてみました。

jest-svg-transformer - npm

jest.config.jstransformを下記のようにするとsvgを読み込めるようになり、エラーが解消されました。

{
  "transform": {
    "^.+\\.svg$": "jest-svg-transformer"
  }
}