⚔️

【Vue.js】複数のコンポーネントをまとめてimportしてみた

2023/04/20に公開

はじめに

Vue.jsでのフロントエンド開発で、コンポーネントを20個ほどimportしてただ描画するだけのコンポーネントを作ることになりました。
ただimportしてtemplateで描画するだけなんですが、なぜかまとめてimportして、ループで描画したいと思ってしまい。なんとか実装できたので、その方法を共有したいと思います。
※ベストプラクティスでもなんでもないです。

当初の実装

Vue.jsで開発していれば、下記のようになると思います。

Index.vue
<script setup lang="ts">
import Hoge from './components/Hoge.vue';
import Fuga from './components/Fuga.vue';
// importつづく
</script>

<template>
  <Hoge />
  <Fuga />
  // コンポーネントつづく
</template>

修正後の実装

まず、componentsフォルダにindex.tsファイルを作ります。
描画したいvueファイルをひたすらexportしていきます。
注意点:使わないvueファイルの記述はしないこと。描画したいものだけにしてください。

index.ts
export { default as Hoge } from './Hoge.vue';
export { default as Fuga } from './Fuga.vue';
// exportつづく

次にindex.tsをvueファイルでimportします。
下記のようにすることでimport文を1行にすることができました。

Index.vue
<script setup lang="ts">
import * as C from './components';
</script>

Cとしてimportしたものはオブジェクトなので、その値の配列を生成します。

Index.vue
<script setup lang="ts">
import * as C from './components';

const components = Object.values(C);
</script>

ご参考)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/values

これで、ループ用の配列が準備できました。この配列をtemplateに記載すれば完了です。

Index.vue
<script setup lang="ts">
import * as C from './components';

const components = Object.values(C);
</script>

<template>
  <component :is="Component" v-for="(Component, index) in components" :key="index" />
</template>

ご参考)
https://ja.vuejs.org/guide/essentials/component-basics.html#dynamic-components

単体テスト

UTはvitestを使って書いてみました。

Index.test.ts
import * as C from 'src/components'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { mount, VueWrapper } from '@vue/test-utils'
import Index from 'src/components/Index.vue'

const createWrapper = (): VueWrapper =>
  mount(Index, {
    global: {
      plugins: [//依存するpluginがあれば記載, pinia, i18n, router .etc],
      components: {
        ...C,
      },
    },
  })

describe('Index.vue', () => {
  let wrapper: VueWrapper<any>
  beforeEach(() => {
    wrapper = createWrapper()
  })
  afterEach(() => {
    wrapper.unmount()
  })

  it('コンポーネントが描画されること', () => {
    const Hoge = wrapper.findComponent(C.Hoge)
    const Fuga = wrapper.findComponent(C.Fuga)

    expect(Hoge.exists()).toBe(true)
    expect(Fuga.exists()).toBe(true)
  })
})

終わりに

この記載方法は、必ずしも推奨される記述ではないと思います。
そして、この方法を使用する場合は以下の点に注意してください。

  1. どのコンポーネントが使用されているかが分かりにくくなることがあります。
  2. 未使用のコンポーネントがインポートされることで、バンドルサイズが大きくなる可能性があります。

常に適切な方法を検討し、プロジェクトの要件に合った実装方法を選択してください。

Discussion