Nuxt.jsとStorybook(5.3以降)の両方でFont Awesomeを使えるようにする


少し格闘した結果、Nuxt.jsのアプリとStorybookの両方でFont Awesomeを使ったコンポーネントを表示できるようにできました😤

こんな感じに…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216963/7c2edab4-b883-d8d5-c270-72e121dcdbab.png)

## 構成

簡単なNuxt.js + Storybookの構成にしています。

```
.
├── .storybook
│   ├── main.js
│   └── preview.js
│   
├── components
│   ├── Component.vue
│   └── index.stories.js
│
├── nuxt.config.js
├── package.json
```

また、Font Awesomeのアイコンは次の方針で読み込みます。

 * production(Nuxt.js)側: 少しでも容量を軽くするために **必要なフォントのみを読み込む**
 * development(Storybook)側: フォントを指定する手間を省くため **すべての使用可能なフォントを読み込む**


## Storybook 5.3からは設定ファイルが `main.js` に変わる

使った環境はStorybook 5.3以降と **設定ファイルの構造が新しくなった** ものになります。

```json:package.json(抜粋)
...
  "dependencies": {
    "nuxt": "^2.0.0"
  },
  "devDependencies": {
    "@storybook/vue": "^5.3.17"
  }
...
```

Storybook 5.3からは `config.js` が `main.js` に変わり、storyを表示する部分に関わる設定は `preview.js`(下の図にないが) として新設されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216963/fc601fd9-9c9e-451b-df1e-ce9b58ec5872.png)
引用: https://medium.com/storybookjs/declarative-storybook-configuration-49912f77b78

従来の方法も使えますが、Storybook 6系になるまでは移行を考えておきましょう。

> The old config.js syntax and configurable hierarchy separators will be supported until Storybook version 6.0. 

ここでは新しくなった `main.js` については詳しく解説しません。


## npmパッケージを導入する

はじめに、FontAwesomeを使用可能にするパッケージを導入します。

```bash
yarn add nuxt-fontawesome \
@fortawesome/fontawesome-svg-core \
@fortawesome/vue-fontawesome \
@fortawesome/free-solid-svg-icons \
@fortawesome/free-regular-svg-icons \
@fortawesome/free-brands-svg-icons 
```

## Nuxt.js 用の設定

こちらは、少しでも容量を軽くするために使うアイコンだけを読み込みます。
アイコンの指定は、 `fas` でも `fab` でも `fa + アイコン名のキャメルケース` となります。

```js:./nuxt.config.js
  modules: [
    'nuxt-fontawesome',

...

  fontawesome: {
    imports: [
      {
        set: '@fortawesome/free-brands-svg-icons',
        icons: ['faVuejs']
      },
      {
        set: '@fortawesome/free-solid-svg-icons',
        icons: ['faTimesCircle']
      }
    ]
  },
```


## Storybook用の設定

こちらは **Font Awesomeのアイコンをすべて読み込みます。** 

`main.js` はStorybookで表示したいstoryの場所を指定します。

```js:.storybook/main.js
module.exports = {
  stories: ['../components/**/*.stories.js'],
...
```

**`preview.js` でFont Awesomeをすべてのstoryに読み込みます。**
`configure` のパスは `main.js` で指定したパスとつじつまが合うようにします。 

```js:.storybook/preview.js
import { configure } from '@storybook/vue'
import Vue from 'vue'

import { library } from '@fortawesome/fontawesome-svg-core'
import { fas } from '@fortawesome/free-solid-svg-icons'
import { fab } from '@fortawesome/free-brands-svg-icons'
import { far } from '@fortawesome/free-regular-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
library.add(fas, far, fab)

Vue.component('font-awesome-icon', FontAwesomeIcon)
configure(require.context('../components', true, /\.stories\.js$/), module)
```

## Nuxtコンポーネント

この設定により、コンポーネント側では `FontAwesomeIcon` コンポーネントを呼び出すだけでNuxt.jsとStorybookで同一のアイコンが表示されます。

各コンポーネント、 `*.stories.js` にFont Awesomeをimportするコードを書く必要がなくなります✌️

* `fa-`のprefixを取り除いて指定します。
  * `fab fa-vuejs` の例( https://fontawesome.com/icons/vuejs?style=brands )

```vue:./components/Component.vue
<template>
  <div>
    <font-awesome-icon :icon="['fab', 'vuejs']"/>
  </div>
</template>
```


## 参考

Declarative Storybook configuration - Storybook - Medium
https://medium.com/storybookjs/declarative-storybook-configuration-49912f77b78

FortAwesome/vue-fontawesome: Font Awesome 5 Vue component
https://github.com/FortAwesome/vue-fontawesome

Font awesome を Vue.js で使ってみよう - Qiita
https://qiita.com/kurararara/items/d76776a7dc2d763a068b