アトミックデザインにおけるコンポーネントのAuto importの問題について色々と調査した件

## Nuxt2.15.x以降のコンポーネントimportに関して

- [@nuxt/components](https://github.com/nuxt/components) はバージョン 2 が使えるようになります
- コンポーネント名にディレクトリ名を付与したタグを使うことができるようになり、コンポーネントの import や宣言などの記述を省略することができます (記述の省略は 2.14 でも可能でしたが 2.15 で先の記述の使用が可能となりました)

### ディレクト名付きのコンポーネント名

例えば下記のフォルダー構造

```
| components/
---| my/
------| form/
---------| TextArea.vue
```

templateではこのタグで使えます

```javascript
<template>
  ...中略
  <MyFormTextArea />
</template>
```

### アトミックデザインを採用したコンポーネント設計にはいくつかの問題があります

アトミックデザインを採用した場合、コンポーネントフォルダー構造はこんな感じになります。
PC / スマホ版のコンポーネントはそれぞれ pc / spフォルダーに入れてます。

```
| components/
---| atoms/
------| pc/
------| sp/
---| molecules/
------| pc/
------| sp/
---| organisms/
------| pc/
------| sp/
---| templates/
------| pc/
------| sp/
```

しかし、アトミックデザインの設計におけるコンポーネントのAuto importにはいくつか問題が起きてしまいます。

### 同名コンポーネントが存在する

Nuxt 2.14以前では、同名コンポーネントが存在すると、コンポーネント名はうまく解析できませんでした。

下記はnuxtサーバーを立ち上げた際に表示するWARNメッセージです。
![2.14では同名コンポーネント名はうまく解析できない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/147456d0-0404-075d-d641-0f5a2a515c27.png)

もしtemplateで下記のようにCashBackBannerを使おうとしたら

```
<template>
  ...中略
  <CashBackBanner />
</template>
```
chromeのdev toolのconsoleタブにこのようなエラーが出てきてしまいまして、該当コンポーネントは表示できません。

```
[Vue warn]: Unknown custom element: <CashBackBanner> - did you register 
the component correctly? For recursive components, 
make sure to provide the "name" option.
```

同名の場合はauto importではなく、import構文 + componentsに追加する必要があります。

```javascript
import CashBackBanner from '~/components/atoms/pc/CashBackBanner';
...
export default {
  components: {
    CashBackBanner,
  },
}
```

そして、この同名コンポーネント問題はNuxtを2.15以降に更新することで解決できます。

だがしかし！特定のファイル名はやはり同名ファイル問題が起きてしまいます。
下記みたいに、ネストしたルート + フォルダー名にはアンダースコアが含まれてる + ファイル名はindex.vueの場合は問題が起きます。

![1 ファイル名はindexの場合はうまくコンポーネント名を解析できない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/35e34241-9220-1c21-6c8a-7a7f2258cf49.png)

#### 同名ファイル(index.vue)問題の解決方法

解決方法は簡単で、index.vueを別のファイル名にすればいいです。ここではtemplate.vueに改名します。
/search/lines 配下のネストしたフォルダー内のindex.vueをすべてtemplate.vueに改名しました。

![2.2 ファイル名をindexからtemplateに変更.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/7bee430a-d7c9-67ae-c4b1-fe884a80e6e7.png)

これで同名ファイル問題の問題を解決できて、コンポーネント名もうまく解析されます。

#### 解析されたコンポーネント名はどこで確認するのか

Nuxtはコンポーネントのファイル名が変更されたり、nuxt.config.jsにてcomponents プロパティを更新されるたび、自動的にコンポーネント名を解析、生成されます。

コンポーネント名は下記のパスから確認できます

```
// Nuxt 2.14以前のバージョンは確認できてませんのでわかりませんが、わかるのは下記になります。
Nuxt 2.14
.nuxt/components/plugin.js
Nuxt 2.15
.nuxt/components/index.js
```

中身はこんな感じで自動生成されたコンポーネント名を確認できます。
![2.3 コンポーネント名の自動解析がうまくできました.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/a1530418-3154-5b00-e820-534b29d397b5.png)

templateファイルでauto importするならここのコンポーネント名を参考すれば良いです。逆に同名ファイル問題でうまく解析されてないコンポーネント名はここに生成されないから、うまくauto importできないから、import構文 + componentsで手動でimportするしかないです。

ちなみに上記画像でわかりますが、パスにアンダースコアを含まれる場合でも、生成されるコンポーネント名にはアンダースコアがなくなりますのでご注意を。

あと下記エラーが発生する場合、このファイルのコンポーネント名を確認してからauto importすれば解決できます。

```
[Vue warn]: Unknown custom element: <CashBackBanner> - did you register 
the component correctly? For recursive components, 
make sure to provide the "name" option.
```

#### フォルダー名込みのコンポーネント名は長すぎる問題

自動生成されたコンポーネント名はネストしたフォルダー名も含まれてるからかなり長くなります。
![5 atomsのspフォルダーのコンポーネント名は依然に長い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/52e973d9-996f-e688-7725-243c530de649.png)

#### 解決方法
これを解決するためnuxt.config.jsに下記設定を追加します。
![4 configのatomsのprefixをfalseにする.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/2dbc6d71-9446-f4f2-2730-1161caabdc1a.png)

すると生成されるコンポーネント名は下記になります。
先頭のAtomsがなくなり、すっきりになりました。
![6 atomsのprefexをfalse後のコンポーネント名.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/3b0ed660-6281-5cd2-9e56-fe9f0c8f807f.png)

他のフォルダーパスもconfigに追加します。
![componentのフォルダーを全部設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/fc501d64-6c32-3ee7-15fd-0c4031916eb6.png)
これで同名のコンポーネントをauto imortしたければ、PC版のコンポーネントには ‘Pc' + コンポーネント名、SP版のコンポーネントには 'Sp’ + コンポーネント名で使え分ければいいです。

## おまけ：Lazy load + Auto imort

Auto importを使わずに、コンポーネントをLazy loadするためcomponentsプロパティに () => import構文を使わなければなりません。Lazy loadすることで、v-ifがtrueのコンポーネントだけダウロードされてパフォーマンスを改善することができます。
![7 lazy loadのauto import 変更前 .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/c9ca5fe1-30f5-51f0-0903-2778f3a0a6e9.png)

Nuxt 2.13以降は下記のようにコンポーネント名の前に 'Lazy' をつけることで簡単にLazy loadを実行できます。
![8 lazy loadのauto import 変更後 .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392079/d53ceb43-ef66-efab-ee6e-c87f88228443.png)

## 最後に
アトミックデザインを採用するとこういう問題が起きるなんて想定しなかったんですが、なんとか解決できました。ついでに自動生成されたコンポーネント名をどこを調べれば良いのかもわかったからいい勉強になりました。
最後まで見てくれてありがとうございます。
それではまた。