Vue Custom Elements
Es ist möglich, mithilfe des Frameworks Vue interaktive Elemente für inf-schule zu erstellen. Man spricht in diesem Zusammenhang von Custom Elements. Um den Umgang mit Vue zu lernen, bietet sich die offizielle Dokumentation an. Diese Anleitung konzentriert sich auf die Einbindung von Elementen in inf-schule.
Vorbereiten des Projektes
Navigiere im Terminal in ein Verzeichnis, in dem der Projektordner erstellt werden soll. Das Projekt wird dann mit dem Befehl npm create vue@latest
initiiert.
Die folgende Konfiguration sollte gewählt werden:
- Projektname: Der gewünschte Projektname, der entsprechende Unterordner bekommt den gleichen Namen.
- TypeScript ist optional.
- Die restlichen Punkte können mit No beantwortet werden.
Anschließend wird das Projekt vorbereitet. Die Befehle sollten ohne Fehler ausgeführt werden. Sollten Fehler auftreten, fehlen eventuell noch Pakete, die dann nachinstalliert werden müssen, und anschließend muss das Projekt neu initiiert werden.
Test der Entwicklungsumgebung
Die Entwicklungsumgebung bietet die Möglichkeit, das Projekt lokal ohne weiteren Webserver zu testen.
Dafür im Terminal in das Verzeichnis des Projektes navigieren und den Befehl npm run dev
ausführen.
Nach ein paar Sekunden sollte im Terminal nun eine Adresse und ein Port erscheinen, unter dem das Projekt erreichbar ist, falls es keine Fehler gibt. Die Seite kann mit dem Buchstaben "o" geöffnet werden.
Der Server kann im Hintergrund weiterlaufen und überwacht die Änderungen im Projekt. Wird eine Projektdatei verändert und gespeichert, so wird das Projekt aktualisiert
und die Seite im Brower neu geladen, sodass die Änderungen direkt geprüft werden können. Den Server beendet man wie üblich über die Tastenkombination "control + c" oder mit dem Buchstaben "q".
Konfiguration als Custom Element vornehmen
Der Befehl npm run build
erzeugt aktuell noch eine komplette Vue-App, die sich nicht als einzelnes Element in inf-schule einbauen lässt.
Folgende Änderungen sind dafür nötig:
./src/main.ts oder ./src/main.js
In dieser Datei wird festgelegt, welche Komponenten des Projektes in der späteren Datei vorhanden sein sollen. In Zeile 8 wird ebenfalls der HTML-Tag festgelegt, über den die Komponente eingebunden werden kann. Die Zeile 3 sowie die Zeilen 7 und 8 müssen für alle Komponenten kopiert und angepasst werden, die später als Element in inf-schule aufrufbar sein sollen.
import { createApp, defineCustomElement } from 'vue'
import App from './App.vue'
import Komponente1 from './components/Komponente1.vue'
createApp(App).mount('#app')
const FullNameElement = defineCustomElement(Komponente1);
customElements.define('komponente-1', FullNameElement);
./vite.config.ts oder ./vite.config.js
In dieser Datei wird festgelegt, dass ein Custom Element erstellt werden soll. Einige Zeilen sind schon vorhanden, ein paar Dinge müssen ergänzt werden. Hier der komplette Code der Datei:
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
const customElementFlag = process.argv.includes("--custom-element")
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue({
customElement: customElementFlag,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
rollupOptions: {
// für deterministische Dateinamen, siehe hier:
// https://github.com/vitejs/vite/issues/378#issuecomment-789366197
output: {
entryFileNames: `[name]-[hash].js`,
chunkFileNames: `[name]-[hash].js`,
assetFileNames: `assets/[name].[ext]`,
},
},
},
})
./package.json
In dieser Datei müssen nur zwei Zeilen verändert werden, damit bei der Ausführung von npm run dev
und npm run build
auch das Custom Element erstellt wird:
...
"dev": "vite",
...
"build-only": "vite build -- --custom-element",
...
./src/App.vue
Diese Datei enthält die Elemente, die lokal beim Befehl npm run dev
angezeigt werden sollen.
Im einfachsten Fall wird nur eine einzelne Komponente eingeladen (hier Komponente1
):
<script setup>
import Komponente1 from './components/Komponente1.vue'
</script>
<template>
<Komponente1/>
</template>
Optional für TypeScript: <script setup>
→ <script setup lang="ts">
Mit dem vorgeschlagenen Vorgehen werden die Elemente im Testmodus (npm run dev
) nicht als Custom Element, sondern direkt in die Testseite integriert.
Das erleichtert das schnelle Testen von Veränderungen im Code, aber kann zu inkonsistentem Verhalten zwischen beiden Modi führen:
Im Gegensatz zur direkten Einbindung wird bei der Einbindung per Custom Element zur Kapselung ein Shadow DOM erzeugt.
Dadurch werden beispielsweise HTML-Elemente innerhalb der Komponente nicht direkt mit document.getElementById
& Co. gefunden (sollte in der Regel auch nicht nötig sein, aber kann zu Kompatibilitätsproblemen mit Bibliotheken führen).
Um auch im Testmodus ein Custom Element einzuladen:
-
Das Flag
--custom-element
auch für den Testmodus setzen (siehe ./package.json) -
In ./src/App.vue das Element mit dem HTML-Tag für das Custom Element einladen (etwa
<komponente-1></komponente-1>
statt<Komponente1/>
)
Custom Element erstellen
Damit das Element erstellt wird, muss der Befehl npm run build
ausgeführt werden.
Es wird der Ordner ./dist/
erstellt. Wichtig für inf-schule ist nur die
Datei ./dist/index.js
.
Custom Element auf inf-schule einbinden
Damit das Element auf einer Inhaltsseite genutzt werden kann, müssen folgende Dateien geändert werden:
Vue-Projekt ./dist/js/index.js → inf-schule ./assets/thirdparty/projektname/js/
Die Datei ./dist/js/index-[hash].js
muss im inf-schule-Repository unter ./assets/thirdparty/projektname/js/
abgelegt werden.
./site/plugins/inf-schule/config/features.json
Das Feature muss registriert werden. Dafür muss die Datei ./site/plugins/inf-schule/config/features.json
angepasst werden. Hier wird der Ordner zur benötigten JavaScript-Datei im JSON-Format dem Featurenamen zugeordnet:
"projektname": {
"jsModuleFolder": [
"assets/thirdparty/projektname/js/"
]
}
Damit das Element auf einer Inhaltsdatei genutzt werden kann, muss es über das Attribut
features
geladen werden. In unserem Beispiel über features: projektname
.
Das Element kann jetzt an passender Stelle in der Inhaltsdatei über das festgelegte HTML-Tag
eingebunden werden, in unserem Beispiel <komponente-1></komponente-1>
.