🔖

Vue.js のコンポーネントを名前付きでエクスポートしたい

2023/08/13に公開

状況

以下のような App.vueChildComponent があるとする。

src/App.vue
<script setup lang="ts">
import ChildComponent from './components/ChildComponent.vue';
</script>

<template>
    <h1>App.vue</h1>
    <ChildComponent></ChildComponent>
</template>
src/components/ChildComponent.vue
<script setup lang="ts">
</script>

<template>
    <h2>ChildComponent.vue</h2>
</template>

App.vueChildComponent と、ファイル名と同名でインポートしている。
しかし FooBar など、ファイル名と全く異なる名前でインポートしても特に問題ない。

のだが、

  • 毎回ファイル名をコピペするのが面倒
  • 別名でインポートされる可能性があるのもなんかヤダ
  • VS Code でのインポートの追加が効かず、自分で import 文を書かねばならない

などが気になっていた。

検討案

なんとか解決できんかな、と以下を検証してみた。

  1. index.ts を作成してインポート/エクスポート
  2. <script> タグにて自分自身をインポート/エクスポート

index.ts を作成してインポート/エクスポート

コンポーネントと同一ディレクトリ、もしくは親ディレクトリなどに index.ts を作成し、以下のように記載する。

src/components/index.ts
import ChildComponent from './ChildComponent.vue';
export { ChildComponent };

もしくは省略して以下のように。

src/components/index.ts
export { default as ChildComponent } from './ChildComponent.vue';

App.vue<template><Foo と入力しているタイミングでインポート候補が表示されるようになる。

1 つ目の ./components から import した場合は 以下のように。

src/App.vue
<script setup lang="ts">
import { ChildComponent } from './components';
</script>

<template>
    <h1>App.vue</h1>
    <ChildComponent></ChildComponent>
</template>

この場合、インポート名は index.ts で指定した名称のみが指定可能となる。

次に 2 つ目の ./components/ChildComponent.vue から import した場合は 以下のように。

src/App.vue
<script setup lang="ts">
import ChildComponent from './components/ChildComponent.vue';
</script>

<template>
    <h1>App.vue</h1>
    <ChildComponent></ChildComponent>
</template>

./components/ChildComponent.vue からの import 文は元々と同じだが、インポートの追加が楽にはなるし、インポートする名前も自動的に設定される。ただしインポート名を自由に変更されてしまう可能性は残る。

<script> タグにて自分自身をインポート/エクスポート

<script> タグを利用して自分自身でエクスポートしてみる。

ChildComponent.vue を以下のように変更する。

src/components/ChildComponent.vue
<script>
export { default as ChildComponent } from './ChildComponent.vue';
</script>

<script setup lang="ts">
</script>

<template>
    <h2>ChildComponent.vue</h2>
</template>

<script setup> では export ができないが、併用可能な <script> にて export は可能なので、 <script> タグ内に記述する。

https://ja.vuejs.org/api/sfc-script-setup.html#usage-alongside-normal-script

上記から一部引用

<script setup> は、通常の <script> と一緒に使うことができます。次のことが必要な場合は、通常の <script> が必要になることがあります:

  • inheritAttrs や、プラグインで有効になるカスタムオプションなど、<script setup> では表現できないオプションを宣言する(3.3+ では defineOptions で置き換え可能)
  • 名前付きのエクスポートを宣言する
  • 副作用を実行したり、一度しか実行してはいけないオブジェクトを作成する

この 2 つ目に該当、、、するのだろうか、、、。まあともかく動作はする。

App.vue は以下のようになる。

src/App.vue
<script setup lang="ts">
import { ChildComponent } from './components/ChildComponent.vue';
</script>

<template>
    <h1>App.vue</h1>
    <ChildComponent></ChildComponent>
</template>

ただしこちらの場合も default export からの import は引き続き可能ではある。

まとめ

  • どちらの場合も default export からの import を行う可能性は残る
    • しかし VS Code のインポートの追加が機能するだけでもメリットはあると感じる
  • <script> での export について、循環参照的な状況にならないのか
    • npm run dev, npm run build ともに問題ない様子ではある

別ファイルを作成する必要もない <script> タグでのエクスポートが良いのではないか、と思うのだけど、ざっと検索してみたものの特に事例が見当たらないし、私自身の Vue.js や JS/TS の知見も浅いのでこれでいいのかなー、という疑問は残る。どうなんだろ。

Discussion