SVGアイコンをGitHubで管理し、フォントを自動ビルドして使いたい

この記事は [ミライトデザイン Advent Calendar 2021](https://qiita.com/advent-calendar/2021/miraito-inc) 17日目の記事です。

## やりたかったこと

某サイトでは古からの経緯でサイト内で使うアイコンファイルはPNGで書かれていた。
しかし、細切れ画像で辛い、小さくて汚い、画像の表示がめんどくさい。
（スプライト画像にするとか、画像大きくするとか、手法はいろいろあるけど割愛）

- 大きくしてもきれいに表示したい
- ファイルロードを効率化したい
- CSSクラスあてただけで簡単に呼び出したい
- アイコンファイルはせっかくだから独立したリポジトリで管理したい

SVGアイコンをまとめてフォントファイル化したら解決じゃん！
ということで表題のことを全自動でできるように整備してみた奇跡です。

今回もろもろはNode.js使ってます。

## アイコン用のリポジトリを準備

### パッケージ設定ファイル

ということでさっくりとリポジトリを作成して `package.json` を準備しよう。

```json:package.json
{
  "name": "hoge-icons",
  "version": "1.0.0",
  "description": "icon fonts for hoge",
  "main": "index.js",
  "scripts": {
    "build": "node index.js",
    "postinstall": "npm run build"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/****/hoge-icons.git"
  },
  "author": "ariaki",
  "license": "proprietary",
  "private": true,
  "dependencies": {
    "webfonts-generator": "^0.4.0"
  }
}
```

設定のポイントは次のとおり。

- フォントをビルドする処理は `index.js` に記述
- 他のプロジェクトで `npm ci` されたときに自動ビルドされるよう `scripts.postinstall` を設定
- フォントをビルドするために [webfonts-generator](https://www.npmjs.com/package/webfonts-generator) を利用

### ディレクトリ構成

ディレクトリ構成は次のとおり。

```
hoge-icons/
  + icons/
     + icon1.svg
     + icon2.svg
     + ...
  + index.js
  + package.json
```

### ビルドスクリプト

このスクリプトでは `icons/` ディレクトリ配下の全SVGファイルをまとめて1つのフォントとしてビルドする。
ビルド結果は　`dest/` ディレクトリに格納され、フォントファイルとscssファイルが出力される。

```js:index.js
const fs = require('fs');
const path = require('path');
const webfontsGenerator = require('webfonts-generator');
const ICONS_PATH = 'icons/';

// icons配下のSVGファイルを取得して配列に詰める
const files = fs.readdirSync(ICONS_PATH, { withFileTypes: true });
const fileList = files.filter(function(dirent){
  return dirent.isFile() && /.*\.svg/.test(dirent.name);
}).map(function(dirent){
  return path.join(ICONS_PATH, dirent.name);
});

// フォントを生成する
webfontsGenerator({
  files: fileList,
  dest: 'dest/',
  cssDest: 'dest/malicons.scss',
  cssFontsUrl: '#{$hoge-icon-font-path}',
  fontName: 'hogeicons',
  templateOptions: {
    classPrefix: 'hogeicon-',
    baseSelector: '.hogeicon'
  }
}, function(error) {
  if (error) {
    console.log('Build failed.', error);
  } else {
    console.log('Build done.');
  }
});
```

手動ビルドする場合は次のコマンドを実行。

```
$ npm run build
```

実行したら `build done.` と表示され、次のファイルができるはずだ。

```
hoge-icons/
  + dest/
     + hogeicons.eot
     + hogeicons.scss
     + hogeicons.svg
     + hogeicons.ttf
     + hogeicons.woff
     + hogeicons.woff2
```

## 別プロジェクトから取り込んで使う

### インストール

先ほどのパッケージをGitHubにプッシュしたら、使いたいプロジェクトで `npm install` しよう。

```
$ npm install git+ssh://git@github.com/xxxx/hoge-icons.git
```

うまく動けばインストール時にフォントがビルドされるはずだ。
`node_modules/hoge-icons/dest/` ディレクトリに作られたファイルを使おう。
（必要に応じて `ln -s` とかでインポートしやすいディレクトリにリンクするといいかも）

### scssビルド設定

以下の例に従い、Webアプリのscssでフォントアイコン用の設定をインポートする。

```assets/css/app.scss
// ...（略）...
// フォントファイルが存在するパス（ブラウザ上で読み込むためのパス）
$hoge-icon-font-path: "/fonts/hoge-icons";
// scssファイルが存在するパス（ビルド時に読み込むためのローカルパス）
@import "../../node_modules/hoge-icons/dest/hogeicons.scss";
// ...（略）...
```

### さぁフォントを使おう

いよいよアイコンフォントを使う出番だ！
次のようにHTMLを出力してみよう。`icon1` の部分はファイル名を指定しよう。

```html:index.html
<!-- ...（略）... -->
<i class="hogeicon hogeicon-icon1"></i>
<!-- ...（略）... -->
```

## さいごに

SVGファイルを使えばアイコンがきれいになるぞ！
みんなもレッツアイコン作成！