はじめに
ユニークビジョン株式会社 では
- Vue.js + Vite
 - Storybook + Vite
 
な環境でフロントエンドを開発しています。
開発していると、コンポーネントを手動で import する単純作業が何度も発生してしまいます。
面倒なので import しなくて済む方法を探しました。
unplugin-vue-components
有名な plugin です。
導入はドキュメント通りに
npm i unplugin-vue-components -D
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
  plugins: [
     Components({ /* options */ }),
  ],
})
で完了です。
これで
<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>
が
<template>
  <div>
    <HelloWorld msg="Hello Vue 3.0 + Vite" />
  </div>
</template>
<script>
export default {
  name: 'App'
}
</script>
こう書けるようになります。
型を読み込ませる
しかしこのままでは VSCode 上で型が効かない状態になってしまいます。
そこで、dts: true として、
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
  plugins: [
     Components({
       dts: true,
     })
  ],
})
npm run serve
components.d.ts が生成されます。これを tsconfig.json で include に含めます。
{
  "include": [
    "components.d.ts"
  ]
}
これで型を読み込んでくれるようになります!
その後は npm run serve している間、コンポーネントを作成すると型定義 components.d.ts に自動追加してくれるようです。
このファイルは .gitignore に含めるのが良さそうです。
Storybook でも使えるようにする
このままでは Storybook では 「import していないコンポーネントは import していない」と見なされてしまい、何も表示されません。
そこで、下記のように設定します。
+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 の設定を外部に切り出すことでファイルを共通化できます。
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Components = require('unplugin-vue-components/vite');
module.exports = Components({
  dts: true,
});
import Components from './unplugin.config.js'
export default defineConfig({
  plugins: [
-     Components({
-       dts: true,
-     })
+     Components
  ],
})
-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 を追加してください。
// 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', // コンポーネントが入っているパスを追加する
  ],
});
参考
おわりに
弊社での開発の話やフロントエンド周りのことを呟いています。よければフォローお願いします。
ユニークビジョンという会社のエンジニアです。
— シライシ@ユニークビジョン (@punksy2) October 3, 2022
フロントエンド開発と品質向上に取り組んでいるので、そのあたり興味ある方はフォローしていただけると嬉しいです。
品質の高いサービスを提供し続ける会社であるために/品質向上チーム https://t.co/vI7YsKL6QW
