Vue の Component はもう import しなくていい【Storybook 対応】

# はじめに
[ユニークビジョン株式会社](https://qiita.com/organizations/uniquevision) では
- Vue.js + Vite
- Storybook + Vite

な環境でフロントエンドを開発しています。
開発していると、**コンポーネントを手動で import する単純作業が何度も発生してしまいます。**
面倒なので import しなくて済む方法を探しました。

# unplugin-vue-components

https://github.com/antfu/unplugin-vue-components

有名な plugin です。
導入はドキュメント通りに

```bash
npm i unplugin-vue-components -D
```

```vite.config.ts
import Components from 'unplugin-vue-components/vite'

export default defineConfig({
  plugins: [
     Components({ /* options */ }),
  ],
})
```

で完了です。

これで

```App.vue
<template>
  <div>
    <HelloWorld msg="Hello Vue 3.0 + Vite" />
  </div>
</template>

<script>
import HelloWorld from './src/components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>
```

が

```App.vue
<template>
  <div>
    <HelloWorld msg="Hello Vue 3.0 + Vite" />
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
```

こう書けるようになります。

# 型を読み込ませる
しかしこのままでは **VSCode 上で型が効かない状態**になってしまいます。
そこで、`dts: true` として、

```vite.config.ts
import Components from 'unplugin-vue-components/vite'

export default defineConfig({
  plugins: [
     Components({
       dts: true,
     })
  ],
})
```

```
npm run serve
```
すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474068/d1d1d412-9081-a21e-3e57-db6656800eac.png)

`components.d.ts` が生成されます。これを tsconfig.json で `include` に含めます。

```tsconfig.json
{
  "include": [
    "components.d.ts"
  ]
}
```

これで型を読み込んでくれるようになります！
その後は `npm run serve` している間、コンポーネントを作成すると型定義 components.d.ts に自動追加してくれるようです。
このファイルは .gitignore に含めるのが良さそうです。

# Storybook でも使えるようにする
このままでは Storybook では **「import していないコンポーネントは import していない」と見なされてしまい、何も表示されません。**

そこで、下記のように設定します。

```diff_javascript:.storybook/main.js
+const Components = require('unplugin-vue-components/vite');

module.exports = {
  stories: ['../src/**/*.stories.ts'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-links',
  ],
  framework: '@storybook/vue3',
  core: {
    builder: '@storybook/builder-vite',
  },
+  async viteFinal(config) {
+    config.plugins.push(Components({
+      dts: true,
+      dirs: [
+        'src/components'
+      ],
+    }))
+
+    return config;
+  },
};
```

Storybook から unplugin-vue-components を設定する場合は、上記のようにコンポーネントのディレクトリを明確にする必要があるようです。しかも **`../src` ではなく `src` を指定する必要がある**ことになかなか気付けず結構ハマりました。

これで Vue.js と Storybook でコンポーネントを import しなくて済むようになりました！

# アプリ本体と Storybook で設定ファイルを共有する

単純に unplugin-vue-components の設定を外部に切り出すことでファイルを共通化できます。

```unplugin.config.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Components = require('unplugin-vue-components/vite');

module.exports = Components({
  dts: true,
});
```

```diff_javascript:vite.config.ts
import Components from './unplugin.config.js'

export default defineConfig({
  plugins: [
-     Components({
-       dts: true,
-     })
+     Components
  ],
})
```

```diff_javascript:.storybook/main.js
-const Components = require('unplugin-vue-components/vite');
+const Components = require('../unplugin.config');

module.exports = {
  stories: ['../src/**/*.stories.ts'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-links',
  ],
  framework: '@storybook/vue3',
  core: {
    builder: '@storybook/builder-vite',
  },
  async viteFinal(config) {
-    config.plugins.push(Components({
-      dts: true,
-      dirs: [
-        'src/components'
-      ],
-    }))
+    config.plugins.push(Components)

    return config;
  },
};
```

# 注意点
デフォルトでは、`src/components` 以下のコンポーネントのみ自動 import されます。もし、`src/pages` などから import している場合は、`dirs` オプションに `src/pages` を追加してください。

```unplugin.config.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Components = require('unplugin-vue-components/vite');

module.exports = Components({
  dts: true,
  dirs: [
    'src/components', // デフォルトで読み込まれるディレクトリ
    'src/pages', // コンポーネントが入っているパスを追加する
  ],
});
```

# 参考
https://github.com/antfu/unplugin-vue-components/issues/207

# おわりに
弊社での開発の話やフロントエンド周りのことを呟いています。よければフォローお願いします。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ユニークビジョンという会社のエンジニアです。<br>フロントエンド開発と品質向上に取り組んでいるので、そのあたり興味ある方はフォローしていただけると嬉しいです。<br><br>品質の高いサービスを提供し続ける会社であるために／品質向上チーム <a href="https://t.co/vI7YsKL6QW">https://t.co/vI7YsKL6QW</a></p>&mdash; シライシ@ユニークビジョン (@punksy2) <a href="https://twitter.com/punksy2/status/1576934123670630404?ref_src=twsrc%5Etfw">October 3, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>