
Angular ist eines der beliebtesten Frameworks zum Entwickeln von browserbasierten Oberflächen. Um neue Anwendungen, Komponenten, Services, o.ä. zu erstellen, wird hierfür gerne das Angular-CLI verwendet. So ist der folgende Befehl jedem Angular-Entwickler bekannt:
ng generate component Test
Hiermit wird eine neue Komponente mit dem Namen “Test” angelegt. Dieser Befehl ist die Anwendung von Schematics.
In diesem Artikel möchte ich zeigen, dass die Angular-Schematics noch für weitaus mehr genutzt werden können.
Die Idee
Wenn man als Fullstack-Entwickler arbeitet, werden häufig auf beiden “Seiten”, im Backend und Frontend, neue Features implementiert. Hierzu werden häufig eigene Entitäten definiert, inklusive einer Persistenz-, Service- und auch API-Schicht.
Ich möchte daher in diesem Tutorial zeigen, wie für ein Java-Backend (basierend auf Spring Boot) diese grundlegende Struktur erzeugt werden kann.
Schritt für Schritt zu eigenen Schematics
Schritt 1: Installation der Schematics CLI
Zum Erstellen von Schematics ist die Installation der Schematics CLI nötig. Diese kann einfach über folgenden Befehl global installiert werden:
npm install -g @angular-devkit/schematics-cli
Damit ist die Schematics CLI global installiert und kann fortan zum Erstellen und Erweitern von neuen bzw. bestehenden Schematics genutzt werden.
Schritt 2: Erstellen des Schematics-Projekts
Ist die Schematics CLI installiert, kann einfach ein eigenes Projekt erstellt werden:
schematics blank --name=test
Dieser Befehl erstellt ein eigenes Schematics-Projekt. Dabei wird insbesondere die Datei collection.json erstellt. Sie sieht folgendermaßen aus:
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"test": {
"description": "A blank schematic.",
"factory": "./test/index#test"
}
}
}
Die Property $schema definiert dabei, gegen welches Schema die Schematics validiert werden.
schematics beschreibt, welche Schematics in dieser Collection zusammengefasst sind. In diesem Fall ist das lediglich ein Schematic. Es ist aber möglich, mehrere Schematics in einer Collection zusammen zu fassen. Für jedes Schematic werden folgende Properties erzeugt:
- factory: Dieses Attribut verweist auf den Einstiegspunkt zur Anwendung der Schematic. Konkret zeigt sie auf dieFunktion test() in der Datei test.ts
- description: Hier kann textuell beschrieben werden, wozu die Schematic dient.
- schema (optional): Mit einem Schema kann definiert werden, welche Eingaben bei der Erstellung neuer Dateien durch Anwendung der Schematic nötig sind.
- aliases (optional): Mit einem Array können hier eine oder mehrere Alias definiert werden, die zur Ausführung der Schematic führen. Beispielsweise ist in der Angular CLI für den Befehl “generate” der Alias ng g angegeben.
Schritt 3: Implementierung von Schematics
Um nun tatsächlich auch Files und damit einen Mehrwert zu generieren, müssen innerhalb des Ordners der Schematics nun ein weiterer Ordner mit Namen “files” erstellt werden und darin die tatsächlichen Dateien. Ich werde in einem Ordner “model” nun eine Entitätsklasse generieren. Die Dateistruktur sieht dabei nun folgendermaßen aus:
| collection.json
|
\---ease-it-schematics
| index.ts
| index_spec.ts
|
\---files
\---model
__entity@classify__.java
Die Datei __entity@classify__.java entspricht dabei einer zu generierenden Datei. Mit doppelten Underscores wird dabei angezeigt, dass ein Eingabeparameter genutzt werden soll, in diesem Fall entity. Die Notation @classify entspricht einem Funktionsaufruf. Angular CLI stellt diverse Methoden zur Normalisierung von Strings bereit. Momentan sind es die folgenden:
- decamelize(string): Konvertiert einen String, der in Camel-Case geschrieben ist in einen kleingeschriebenen, der durch Underscores getrennt ist (easeIT → ease_it)
- dasherize(string): Underscores, Leerzeichen oder Camel-Case wird durch Bindestriche ersetzt (easeIT → ease-it)
- camelize(string): Erstellt einen String in Camel-Case (mit Kleinbuchstaben am Anfang) (ease_it → easeIt)
- classify(string): Erstellt einen String in Camel-Case (mit Großbuchstaben am Anfang) (ease_it → EaseIt)
- underscore(string): Erstellt einen kleingeschriebenen String, der durch Underscores getrennt ist (Ease IT → ease_it)
- capitalize(string): Erstellt einen String mit großgeschriebenen ersten Buchstaben (easeIT → EaseIT)
- levenshtein(string, string): Berechnet die Levenshtein-Distanz zweier Strings und gibt eine Zahl zurück
Die Datei __entity@classify__.java passe ich so an, dass sie eine einfache Klasse erstellt:
public class <%= classify(entity) %> extends AbstractEntity {
private String <%= property %>;
}
Hier sehen wir, wie die Methoden zur Noramlisierung innerhalb einer Datei angewandt werden. Sie werden geschachtelt in <%= … %> -Tags dargestellt. So erkennt die Schematics CLI, dass sie den hier eingetragenen Text ersetzen soll.
Nach demselben Muster können auch weitere Dateien angelegt werden, die dann von den Schematics ersetzt werden. Das Schema ist dabei allerdings immer dasselbe.
Schritt 4: Definition der Eingabeparameter
Wie bereits beschrieben, kann das Feld “schema” in der Datei collection.json dazu verwendet werden, um Eingabeparameter zu definieren. Dies müssen wir nun tun, bevor wir die Schematics initial testen können. Wir erstellen hierzu eine Datei schema.json im Ordner test:
| collection.json
|
\---ease-it-schematics
| index.ts
| schema.json
|
\---files
\---model
__entity@classify__.java
In die Datei schema.json schreiben wir nun, welche Angaben die Benutzer:innen bei der Anwendung unserer Schematics machen müssen:
{
"$schema": "http://json-schema.org/schema",
"$id": "Test-Schematics",
"title": "Test Schema",
"type": "object",
"properties": {
"entity": {
"type": "string",
"description": "Entity",
"x-prompt": "The name of the entity"
},
"property": {
"type": "string",
"description": "Property",
"x-prompt": "The name of the property"
}
},
"required": [
"entity"
]
}
Wir definieren eine Id, einen Titel und schließlich die Properties, die zur Konfiguration der Schematics benötigt werden. Folgende Felder können dabei angegeben werden:
- type: boolean, string, number, integer oder list.
- enum: Eine Liste, aus der Benutzer:innen den gewünschten Wert auswählen können
- items (nur bei type=”list”): Strings und/oder komplexe Label-Value-Objekte
- minLength (optional): Eine optionale Mindestlänge der Eingabe
- default (optional): Ein optionaler Standardwert
- x-prompt (optional): Ein optionaler Hinweistext an die Benutzer:innen
Schritt 5: Schematics-Funktion anpassen
Nun ist die Schematic prinzipiell fertig. Startet man sie nun, wird allerdings der Text “Nothing to be done.” angezeigt. Es fehlt also noch etwas.
Der Einstiegspunkt der Schematic ist noch immer genauso, wie er initial erstellt wurde. Dies ist allerdings nicht korrekt. Wenn man sich die Funktion ansieht, dann erkennt man, dass hier nichts passiert:
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
export function test(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
return tree;
};
}
Es wird ein Tree-Objekt und ein SchematicContext übergeben. Anstelle hier etwas zu unternehmen und genau zu definieren, was bei der Ausführung passieren soll, wird der Tree einfach zurückgegeben. Wir müssen hier allerdings definieren, welche Dateien als Vorlage dienen und genutzt werden sollen. Wir passen die Funktion also folgendermaßen an:
import {strings} from "@angular-devkit/core";
import {apply, MergeStrategy, mergeWith, move, Rule, SchematicContext, template, Tree, url} from "@angular-devkit/schematics";
export function test(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
const templateSource = apply(url("./files"), [
template({
...strings,
..._options
}),
move(".")
]);
const rule = mergeWith(templateSource, MergeStrategy.Default);
return rule(tree, _context);
};
}
Nun laden wir uns die Templates aus dem Ordner “files” und erstellen eine Regel zum Mergen der Dateien mit den gemachten Eingaben. Diese wenden wir nun an und geben sie schließlich zurück. So werden die Dateien letztendlich erstellt.
Schritt 6: Schematics bauen, testen und nutzen
Abschließend müssen wir die Schematics noch bauen. Dies geschieht einfach über den Befehl:
npm run build
Sofern der Build erfolgreich gelaufen ist, können wir die Schematics testen. Hierzu führen wir den folgenden Befehl aus:
schematics .:test
Damit wird aus der Collection in dem Ordner, in dem wir uns mit unserer Kommandozeile gerade befinden (.) die Schematic test ausgeführt. Bei lokalen Schematics werden keine Dateien erzeugt. Die Schematics CLI führt die Schematics dabei als dry-run aus.
Wir können sie nun packen mit
npm run pack
und anschließend installieren:
npm install test-0.0.0.tgz
Selbstverständlich können wir sie auch global installieren (mit Flag –global) und dann einfach benutzen mit
schematics test:test
Fazit
Angular Schematics sind nützlich für alle Entwickler, nicht nur für Frontend-Entwickler mit Fokus auf Angular. Wir in diesem Tutorial gezeigt, können mit Schematics auch einfach Klassen für Backends erzeugt werden.
Ein Beispiel-Projekt findet ihr auch auf github.
Schreiben Sie einen Kommentar