Blog

Vue-Komponenten automatisch registrieren

Frank van Wijk

Aktualisiert Oktober 16, 2025
5 Minuten

Vue-Komponenten müssen registriert werden, bevor Sie sie verwenden können. Dies erfordert eine Menge Code, den Sie pflegen müssen. Verwenden Sie das Plugin unplugin-vue-components, um Komponenten automatisch zu registrieren.
Ich werde Ihnen sogar erklären, wie dieser Trick auch in Storybook und Jest/Vitest angewendet werden kann.

Das Problem

Nehmen wir an, wir haben diese <app-button> Komponente, die ein <app-icon> rendert.

Die Komponentenvorlage Button weiß nichts von app-icon, bis Sie sie registrieren. Andernfalls denkt sie, dass eine benutzerdefinierte Komponente ist. In unserem Fall ist es eine Vue-Komponente, also müssen wir sie registrieren.

Dasselbe gilt für app-button in der Komponentenvorlage App.

<script setup lang="ts">
// SFC setup function automatically registers imported components
import AppButton from './Button.vue';'
</script>

<template>
  <app-button icon="thumbs-up">Click me</app-button>
</template>
<script lang="ts" setup>
import AppIcon from './Icon.vue';

defineProps<{ icon: string }>();
</script>

<template>
  <button v-bind="$attrs"><app-icon :name="icon" /> <slot></slot></button>
</template>

<style scoped>
button {
  border: 1px solid #42b883;
  border-radius: 6px;
  padding: 0.25rem 0.5rem;
}
</style>

Hier ist der gleiche Code, aber dann in StackBlitz, so dass Sie selbst daran herumspielen können. (Die eingebettete Überprüfung funktioniert nur in Chrome).

Wenn Ihre Anwendung wächst, wird es zu einem Wartungsaufwand, all diese Komponenten lokal zu registrieren, wenn Sie sie verwenden. Dies ist insbesondere dann der Fall, wenn es sich um gemeinsam genutzte Komponenten (UI-Bibliothek) handelt, die an vielen Stellen verwendet werden.

Globale Registrierung von Komponenten

Das erste, was Sie wahrscheinlich tun würden, ist, diese Komponenten global zu registrieren.

import { createApp } from 'vue';
import App from './App.vue';
import Button from './Button.vue';
import Icon from './Icon.vue'; 

const app = createApp(App);

app
  .component('AppButton', Button)
  .component('AppIcon', Icon);

app.mount('#app')

Obwohl Sie die Komponente nicht mehrmals, sondern nur einmal registrieren müssen, müssen Sie dennoch manuell eine Liste der Komponentenimporte und -registrierungen führen.

Lassen Sie uns das ein wenig umstrukturieren:

export { default as Button } from './Button.vue';
export { default as Icon } from './Icon.vue';
import { createApp } from 'vue';
import App from './App.vue';
import * as components from './index';

const app = createApp(App);

for (const componentName in components) {
  app.component(App${componentName}, components[componentName]);
}

app.mount('#app')

Jetzt müssen Sie nur noch eine Liste der Exporte in index.ts pflegen, was schon besser ist.

Beachten Sie, dass wir auch automatisch alle Komponentennamen aus einem Verzeichnis lesen könnten, aber das wird zu komplex, wenn Sie Komponenten in Unterverzeichnissen haben.

Jetzt lassen Sie etwas Magie einfließen. Wir wollen, dass dies automatisch geschieht.

Es gibt einen großen Nachteil bei der globalen Registrierung von Komponenten: Wenn Sie die Komponente nirgendwo verwenden, ist sie immer noch registriert und somit gebündelt. Sie müssen also manuell verfolgen, welche Komponenten in der Anwendung verwendet werden und nicht alle verfügbaren Komponenten importieren/registrieren.

Ein ähnliches Problem tritt auch auf, wenn Sie Bootstrap mit SCSS verwenden. Sie müssen eine Liste der Komponentenstile manuell pflegen. In diesem Fall würde ich Ihnen etwas wie TailwindCSS (JIT-Modus oder PurgeCSS) empfehlen, damit nicht verwendeter Code nicht in Ihrem Bundle enthalten ist. Dies wird Tree Shaking oder Eliminierung von totem Code genannt.

Ein weiteres Beispiel ist Angular Dependency Injection. Wenn Sie Dienste oder Komponenten registrieren, die nicht verwendet werden, erhalten Sie keine Warnung. Das passiert oft, wenn Sie TestBed in einem Unit-Test konfigurieren.

Mehr dazu in einem zukünftigen Blogbeitrag.

Die beste globale Lösung besteht darin, die Komponenten automatisch zu registrieren. Wenn während der Kompilierung ein benutzerdefiniertes HTML-Element in einer Vorlage gefunden wird, in unserem Fall <app-button> und <app-icon>, fügt es die Registrierungsanweisungen für Sie hinzu.

Es gibt ein Vue-Plugin, das sich um diese Aufgabe kümmert. Es heißt unplugin-vue-components. Hier verwende ich Vite, aber für Vue CLI, Rollup oder Webpack ist die Konfiguration so ziemlich die gleiche.

So funktioniert es:

import Components from 'unplugin-vue-components/vite'

export default defineConfig({
  plugins: [
    Components({
      resolvers: [
          (name) => {
            if (name.startsWith('App')) {
              return { name: App${name}, from: '@/' };
            }
          },
        ],
    }),
  ],
});

Für jedes benutzerdefinierte Element wird der Callback ausgelöst. So wird für <app-button> der name den Wert AppButton haben. Hier werden nur die Komponentennamen abgeglichen, die mit App beginnen. Passen Sie den Mustervergleich an Ihre Bedürfnisse an.

Es wird von index.ts im src-Verzeichnis importiert, da die Der Code>@/ alias ist standardmäßig als ./src eingerichtet. Relative Importe funktionieren nicht, da unplugin-vue-components Importanweisungen lokal in den Komponentenskripten erzeugt.

Wenn Sie Komponenten aus Bibliotheken von Drittanbietern wie Vuetify oder HeadlessUI automatisch registrieren möchten, wird das genau so funktionieren. Es gibt sogar voreingestellte Resolver, die Sie verwenden können.

Was ist mit Storybook oder Jest/Vitest?

Storybook und Jest haben ihren eigenen Kompilierungsprozess, so dass Sie den gesamten Setup-Code neu erstellen müssen, damit dies funktioniert.

Storybook basiert standardmäßig auf Webpack (4 oder 5). Sie könnten also die gleiche unplugin-vue-components Konfiguration wie oben in einer separaten webpack.config.js Datei für Storybook (wieder)verwenden.
Ich würde sogar empfehlen, den Vite Builder für Storybook zu verwenden, damit Sie alles von Vite nutzen können, wenn Ihre App auch Vite verwendet. Es wird ohnehin viel schneller als Webpack dienen/erstellen.

In Jest würden Sie wahrscheinlich Vue Test Utils oder Testing Library verwenden. Es gibt eine global.components Einstellung, um Komponenten global zu registrieren. Sie können dies pro Test oder für Ihre gesamte Testsuite tun.

Die Komponenten, die Sie in Ihren Tests nicht rendern wollen, werden stubbed (oder Sie verwenden shallowMount, wovon ich aber abrate).

Ähnlich wie bei Storybook gibt es auch eine Alternative für Unit-Tests, die Vite nutzt. Sie heißt Vitest.
Sie kompiliert mit Vite (= esbuild, das superschnell ist ⚡️), so dass Sie Ihre Vite-Konfiguration einschließlich der Konfiguration unplugin-vue-components wiederverwenden können, um die Komponenten automatisch zu laden.

⚠️ Hinweis: Ich habe in unplugin-vue-components einen Fehler gefunden, der dazu führt, dass Stubs in Vitest nicht mehr funktionieren, also seien Sie vorsichtig. Wenn es bei Ihnen nicht funktioniert, verwenden Sie einfach die "forloop-Technik", wie oben gezeigt. Der Nachteil der größeren Bündelgröße ist bei der Ausführung von Unit-Tests nicht relevant.

Verfasst von

Frank van Wijk

Frank is a senior frontend consultant focusing on quality and maintainability.

Contact

Let’s discuss how we can support your journey.