Über unsMediaKontaktImpressum
Katharina Bähr 28. August 2018

Aurelia – ein standard-basiertes JavaScript-Single-Page-Application-Framework

Noch immer ebbt die Flut der JavaScript-Frameworks nicht ab. Wie eine Umfrage zeigt, gibt es jedoch einige Frontend-Frameworks, welche sich allgemeiner Beliebtheit erfreuen und sich fest etabliert haben [1]. Neben Angular, React oder auch Vue.js taucht in der Umfrage noch ein weiteres Framework auf, welches zwar nicht neu, aber vielerorts eher unbekannt ist – Aurelia. Die Besonderheit an Aurelia ist die starke Orientierung an Web-Standards und der Fokus auf Benutzerfreundlichkeit. Dieser Artikel gibt eine Einführung, und zeigt anhand eines Programmierbeispiels, welche Konventionen und Prinzipien Aurelia verfolgt und welche Vorteile dies für die Ausdrucksstärke und Verständlichkeit des Codes mit sich bringt.

Was Aurelia auszeichnet

In der heutigen Webentwicklung gibt es eine Vielzahl von Frameworks, Bibliotheken und Werkzeugen, die einem das Leben erleichtern sollen. Täglich kommen neue hinzu und die Art und Weise, wie Webanwendungen entwickelt werden, ändert sich regelmäßig. Hierbei nicht den Überblick zu verlieren, ist schwer. Und obwohl diese Lösungen Arbeit abnehmen, bringen sie durch spezielle Syntax und spezifische Lösungswege oftmals auch viel Komplexität in ein Projekt. Der Einsatz muss daher gut abgewogen werden.

Bei Aurelia handelt es sich um ein JavaScript-Single-Page-Application-Framework [2], bei dessen Entwicklung großer Wert darauf gelegt wird, Komplexität zu reduzieren und den Entwicklern einen einfachen Einstieg und ein gutes Entwicklungs-Erlebnis zu bieten.

Das Framework baut auf bereits existierenden Browser-APIs und Sprachfeatures auf und basiert auf den neuen EcmaScript-6- und -7-Spezifikationen [3] sowie auf Web Components [4]. Dadurch müssen Webentwickler weniger framework-spezifische Lösungswege und Syntax lernen und können viel von ihrem bereits bestehendem Wissen über HTML und JavaScript anwenden.

Ein weiterer Grundsatz um Framework-spezifischen Code zu vermeiden, ist die Verwendung des Convention over Configuration-Prinzips [5]. Um wiederkehrende Konfiguration und Codefragmente zu reduzieren, hat Aurelia einprägsame und leicht merkbare Annahmen getroffen. Beispielsweise müssen HTML- und JS-Dateien lediglich gleich benannt werden und sie gehören als Komponente zusammen. Dies reduziert eventuelle Fehler bei der Konfiguration und hat den Effekt, dass vieles "einfach so" funktioniert, ohne dass viel darüber nachgedacht werden muss. Dabei können alle Konventionen bei Bedarf auch überschrieben werden. 

Aurelia verwendet das MV*-Applikations-Entwurfsmuster. MV* bedeutet, dass für die Strukturierung des Codes sowohl das MVVM-, das MVC- als auch das MVP-Pattern angewandt werden kann [6]. Somit kann eine Aurelia-Anwendung ähnlich wie in anderen Sprachen (z. B. WPF oder C#) strukturiert und bereits bekannte Entwurfsmuster angewandt werden. 

Auch bei der eigenen Binding Language [7] wurde eine eingängige und selbst erklärende Syntax entworfen. Die Binding Language dient dazu, Daten, Event Handler und Funktionen an HTML-Elemente, -Attribute oder -Events zu binden und somit eine Verbindung zwischen View- und ViewModel-Controller zu schaffen. Um beispielsweise eine Variable aus dem ViewModel an ein HTML-Attribut zu binden, kann value.bind oder z. B. explizit value.two-way oder value.to-view verwendet werden. Auf DOM-Events registriert man sich hingegen mit dem Eventnamen ohne den Prefix "on" gefolgt von .delegate oder .trigger, also beispielsweise <button click.delegate="clickHandler()">. Wird ein binding verwendet, wird es von Aurelia erkannt, interpretiert und ein Beobachter (Change Observer) aufgesetzt, um Änderungen zu erkennen. 

Dieses Beispiel beleuchtet natürlich nur einen Teil von Aurelia, die Binding Language ist wesentlich mächtiger als hier dargestellt. So demonstriert es jedoch die gute Lesbarkeit und HTML-Konformität, die Aurelia besonders macht.

Web Components

Wie zuvor erwähnt, basiert Aurelia zu großen Teilen auf Web Components, einem Verbund von den vier Web-API-Spezifikationen Custom Elements, HTML Imports, HMTL Templates und Shadow DOM [8]. Diese ermöglichen es, eigene und in sich gekapselte HTML-Tags zu erstellen, die in Webanwendungen beliebig wiederverwendet werden können. 

Ein gutes Beispiel, warum Web Components hilfreich sind, ist das <input type="date">-Element, welches eine UI und Funktionalität zum Auswählen eines Datums bereitstellt. Doch da sich dieses in jedem Browser anders verhält und nicht erweiterbar ist, gibt es Implementierungen von verschiedenen Anbietern wie beispielsweise datepicker von jQuery [9]. Diese bringen aber wiederum oft das Problem mit sich, dass einiges an Code eingebunden werden muss, und der Code sowie das Styling nicht isoliert vom Rest der Anwendung sind. Web Components bieten hierfür die Lösung und versprechen native browser-unabhängige, konfigurierbare Komponenten, welche ihre Umgebung nicht beeinflussen.

Obwohl die Spezifikationen erst vor kurzem fertiggestellt wurden, und diese auch noch nicht von allen Browsern unterstützt werden [10], hat Aurelia auf diesen aufgebaut, fehlende Implementierungen bereitgestellt und so den Browser-Support sichergestellt. In Zukunft wird es dann möglich sein, mit einem Werkzeug von Aurelia Komponenten spezifikationskonform zu exportieren und auch in anderen Webanwendungen zu verwenden [11].

Wo kommt Aurelia her?

Der Visionär und Leiter des Aurelia-Projektes [12] heißt Rob Eisenberg [13] und hat bereits an verschiedenen Frameworks mitgearbeitet. Vor der Entwicklung von Aurelia war er Mitglied im Angular 2-Team und verließ dieses, nachdem es Unstimmigkeiten bezüglich des Framework-Designs gegeben hatte.

Aurelia ist Open Source (MIT License [14]) und wird von Robs Firma Blue Spire [15] entwickelt. Blue Spire beschäftigt sich hauptsächlich mit Software und bietet Beratung, Schulungen und kommerziellen Support an. Bei der Entwicklung nutzt Rob seine Erfahrungen aus der Framework-Entwicklung, um ein standard-basiertes Framework mit einer niedrigen Lernkurve zu entwickeln. Dabei legt er großen Wert auf Kompatibilität zu anderen Frameworks und Stabilität der APIs. Es gibt ein aktives Kernteam, umgeben von einer kleinen aber aktiven Community. Aus meiner Erfahrung hat sich dies bisher nicht nachteilig ausgewirkt.

Quickstart

Um schnell mit Aurelia loslegen zu können, gibt es das Aurelia CLI. Dieses bietet bereits Unterstützung für verschiedene Build-Werkzeuge, CSS-Präprozessoren und Test-Bibliotheken. So ist es einfach möglich, eine Anwendung beispielsweise mit TypeScript, Webpack, SASS, Karma und PhantomJS zu generieren [16].

Alle benötigten Bibliotheken werden über npm (und je nach Konfiguration via jspm) per Kommandozeile installiert [17]. Über Webpack oder Gulp kann ein Webserver gestartet sowie alle weiteren benötigten Aufgaben wie das Transpilieren von TypeScript und SASS oder das Ausführen von Tests erledigt werden.

Entwicklung mit Aurelia in der Praxis

Um einen besseren Eindruck von Aurelia zu bekommen und es nicht nur theoretisch zu betrachten, wollen wir in diesem Abschnitt eine kleine ToDo-Anwendung mit Aurelia und TypeScript entwickeln. Hierfür benötigen wir einen Editor (z. B. Visual Studio Code [18]), eine Kommandozeile, Internetverbindung und einen Browser. Außerdem muss Node.js installiert sein.

Die fertige Anwendung wird aus zwei Ansichten bestehen, eine zum Anlegen und eine zum Anzeigen von ToDos. Die komplette Demo ist auch unter Github zu finden [19].

Projekt erstellen

Um die Anwendung zu erstellen, verwenden wir die oben erwähnte Aurelia CLI [20], die wir zuerst installieren und den Assistenten zur Erstellung eines neuen Projektes ausführen.

npm install aurelia-cli
au new

Wir vergeben einen beliebigen Projektnamen, wählen die Option "Default TypeScript" und akzeptieren alle weiteren Defaults. Das daraufhin generierte Projekt verwendet TypeScript, Webpack, Karma und Jest [21]. Danach können wir in das neue Verzeichnis wechseln und auf der Konsole den Befehl

au run --watch

ausführen. Damit wird die Anwendung gebaut. Im Hintergrund wird zudem ein Webserver gestartet, der die Web-App ausgeliefert. Nachdem der Befehl ausgeführt wurde, ist die Anwendung im Browser unter http://localhost:9000 erreichbar und begrüßt uns mit "Hello World!".
 
In der Projektstruktur ist im Rahmen dieses Tutorial hauptsächlich der src-Ordner wichtig. Alle weiteren Ordner und Dateien dienen zur Organisation, zum Bauen oder zum Testen des Projekts.

Komponenten

Aurelia-Anwendungen werden hauptsächlich über Komponenten definiert. Sie verknüpfen Views (HTML) mit dem entsprechenden ViewModel bzw. Controller (Java-/TypeScript). Um eine Komponente zu erstellen, müssen wir lediglich eine .html- und .ts-Datei mit gleichem Namen in einem gemeinsamen Ordner ablegen.

In dem src-Ordner finden wir bereits die App-Komponente, bestehend aus den Dateien app.html und app.ts, welche automatisch bei der Projektgenerierung erstellt wurde und den Code für die Begrüßung enthält.

Nun erstellen wir eine weitere Komponente mit dem Namen "Todo". Hierfür legen wir die Dateien todo.html und todo.ts in einem neuen Ordner src/todo an. Zusätzlich fügen wir in die todo.html ein <template>-Tag und eine Überschrift ein.

todo.html:

<template>
    <h1>Todos</h1>
</template>

Das <template>-Tag stammt aus der HTML-Template-Spezifikation (einer der Web-Component-Spezifikationen) und dient dazu, HTML-Fragmente zu definieren. Es besitzt keine eigene Repräsentation und wird somit nicht im DOM gerendert.

In der todo.ts definieren wir die Klasse Todo.

todo.ts:

export class Todo {
}

In dieser Klasse zeigen wir später alle ToDos an und geben einen Überblick über deren Status.

Da wir noch eine zweite View für das Erstellen von ToDos erstellen möchten, erweitern wir die App-Komponente um einen Router. Dieser Router ermöglicht es uns, verschiedene Komponenten innerhalb unserer Anwendung anzusteuern und darzustellen. Hierfür ersetzen wir <h1>${message}</h1> in der Datei app.html mit <router-view></router-view> und die Variable message in der Datei app.ts durch

import { RouterConfiguration, Router } from "aurelia-router";
 
configureRouter(config: RouterConfiguration, router: Router): void {
    this.router = router;
    config.title = "Aurelia Tutorial";
    config.map([
      { route: ["", "todo"], name: "todo-list", moduleId: "todo/todo" },
      { route: "todo/add", name: "add-todo", moduleId: "todo/add" }
    ]);
  }

Damit wir den Router verwenden können, müssen wir zuerst die RouterConfiguration und den Router aus dem Paket aurelia-router importieren. Die Funktion configureRouter wird dann von Aurelia automatisch aufgerufen.

Innerhalb der Router-Konfiguration haben wir zwei Routen angelegt. Über diese Routen können die Komponenten über die Browser-URL erreicht und angezeigt werden. Der Leer-String in der ersten Routendefinition route: ["", "todo"], bestimmt, dass dies die Standard-Route ist. Sie verweist auf die zuvor angelegte Komponente Todo (in diesem Kontext auch module genannt) unter dem Datei-Pfad todo/todo. Das Feld "name" kann frei vergeben werden und definiert den Schlüssel unter welcher wir diese Route ansteuern können. Der zweite Eintrag in der Routendefinition definiert eine Komponente Add, über welche wir später neue ToDos hinzufügen werden.

Sobald die App-Komponente geladen wurde, wird der Router die Standard-Route und somit die Todo-Komponente laden und die entsprechende todo.html als View anzeigen.

Datenmodellierung

Damit wir neue ToDos anlegen können, erstellen wir eine Model-Klasse todo-model.ts im Ordner todo.

todo/todo-model.ts:

export class TodoModel {
    constructor(private description: string, private deadline: string, private priority: string) {
    }
}

Alle Variablen die wir im Konstruktor mit private bezeichnen, werden automatisch als Klassenvariable gesetzt. Dies ist ein Feature von TypeScript. Unsere ToDos besitzen nun eine Beschreibung, ein Erledigungsdatum und eine Dringlichkeit und können durch den constructor erzeugt werden.

Für die zweite Seite legen wir nun die Add-Komponente im Order todo an, in welcher wir später neue ToDos in Form unseres TodoModel erzeugen.

todo/add.ts:

export class Add {
}

In der todo/add.html definieren wir ein Formular zum Anlegen von neuen ToDos.

todo/add.html:

<template>
    <h3>Todos</h3>
    <h4>Add new todo</h4>
    <form>
        <input type="text">
        <input type="date">
        <select>
            <option>High</option>
            <option>Medium</option>
            <option>Low</option>
        </select>
        <button type="submit">Add todo</button>
    </form>
</template>

Wir haben zwei Input-Felder für die Beschreibung und das Erledigungsdatum des anzulegenden ToDos, sowie eine Selectbox für das Auswählen der Dringlichkeit hinzugefügt. Hierbei handelt es sich bisher noch um einfaches HTML. Um unsere ToDos zu speichern, erstellen wir einen TodoService. Dieser stellt eine Liste von TodoModel-Objekten bereit.

todo/todo-service.ts:

import { TodoModel } from "./todo-model";

export class TodoService {
    todos: Array<TodoModel> = [];
    constructor() {
    }
}

Diesen Service wollen wir in unser todo/todo.ts und der todo/add.ts verwenden. Mithilfe des autoinject-Decorators können wir uns den TodoService per Dependency Injection in unsere Klassen hineinreichen lassen [22]. Damit dies funktioniert, müssen wir unsere Klassen mit @autoinject() auszeichnen und den Service im constructor hinzufügen.
 
todo/add.ts:

import { TodoService } from "./todo-service";
import { autoinject } from "aurelia-framework";

@autoinject()
export class Add {
    constructor(private todoService: TodoService) {
    }
}

Der autoinject-Decorator ist TypeScript-spezifisch. Ohne TypeScript müssten wir @inject(TodoService) schreiben und jeden verwendeten Service explizit nennen. In Aurelia sind Services nichts weiter als exportierte Klassen und standardmäßig Singletons. Bei Bedarf kann dies jedoch mithilfe des Dependency-Injection-Containers umkonfiguriert werden [23].

In der todo/todo.html fügen wir noch einen Link hinzu und bieten hiermit die Möglichkeit, auf die Add-Komponente zu navigieren.

todo/todo.html:

<template>
    <h3>Todos</h3>
    <a route-href="route: add-todo">Add new todo</a>
</template>

Wir identifizieren die Route, auf die wir verlinken wollen, durch den Namen add-todo, den wir zuvor in der configureRouter-Funktion vergeben haben.

Daten- und Event-Handling

Als Nächstes schauen wir uns an, wie Views mit ViewModel verknüpft und Daten zwischen diesen ausgetauscht werden können. Hierfür verwenden wir Data und Event Binding. Die Syntax von Aurelias Data Binding erinnert dabei ein wenig an die von Knockout [24]. Statt eines data-bind wird allerdings der Attribut- oder Event-Name gefolgt von einem Punkt und einer Binding Expression verwendet.

Nun verbinden wir das Formular in der todo/add.html mit dem ViewModel.

todo/add.html:

<template>
    <h3>Todos</h3>
    <h4>Add new todo</h4>
    <form submit.delegate="addTodo()">
        <input type="text" value.bind="description">
        <input type="date" value.bind="deadline">
        <select value.bind="priority">
            <option>High</option>
            <option>Medium</option>
            <option>Low</option>
        </select>
        <button type="submit">Add todo</button>
    </form>
</template>

Über den Eventhandler submit.delegate="addTodo()" haben wir uns auf das Form-Event onSubmit abonniert und delegieren (mit dem binding .delegate) das Abhandeln des Events an eine addTodo()-Funktion im ViewModel. Bei den Inputfeldern und der Selectbox binden wir mit dem Schlüsselwort .bind den Wert (value) an eine entsprechende Variable im ViewModel.

Wird die Binding Expression .bind verwendet, wird der passende Binding-Mode automatisch von Aurelia ausgewählt [25]. Meistens ist dies .one-way. Nur für bestimmte Elemente, unter anderem Formelemente, wählt Aurelia ein .two-way-binding. Möchte man den Binding-Mode selbst wählen, verwendet man stattdessen ein binding explizit und schreibt beispielsweise value.one-way.

In der todo/add.ts fügen wir die referenzierten Variablen und Funktion addTodo() hinzu.

todo/add.ts:

import { TodoModel } from "./todo-model";

export class Add {

    description: string;
    priority: string;
    deadline: Date;

    constructor(private todoService: TodoService) {
        this.description = "";
        this.priority = "Medium";
        /*Small hack to bring the date into a format
        the input type="date" element can handle*/
        this.deadline = new Date().toISOString().substring(0, 10);
    }

    addTodo() {
        const todo = new TodoModel(this.description, this.deadline, this.priority);
        this.todoService.todos.push(todo);
    }
}

In der addTodo()-Funktion erstellen wir ein neues TodoModel und fügen es der Liste von ToDos in unserem TodoService hinzu. Nachdem wir ein ToDo erstellt haben, fügen wir noch einen Redirect-Link ein, um nach dem Erstellen eines neuen ToDos direkt zur Übersicht aller ToDos zurückzukehren.

todo/add.ts:

import { Router } from "aurelia-router";
...
...
constructor(private todoService: TodoService, private router: Router) {
    ...
}
...
addTodo() {
    ...
    this.router.navigateToRoute("todo-list");
}

Unsere Komponente zum Hinzufügen von ToDos ist hiermit komplett. Wir können neue ToDos über ein Formular anlegen und speichern diese im TodoService. Als Nächstes werden wir diese gespeicherten ToDos in einer Liste anzeigen.

Für die Ansicht der ToDos fügen wir in der todo/todo.html eine HTML-Liste hinzu, welche über alle vorhandenen ToDos iteriert und diese darstellt.

todo/todo.html:

<template>
    <h3>Todos</h3>
    <a route-href="route: add-todo">Add new todo</a>
    <ul>
        <li repeat.for="todo of todos">
            ${todo.description} - ${todo.deadline} - ${todo.priority}
        </li>
    </ul>
</template>

Zum Iterieren über die Liste verwenden wir repeat.for, was für Arrays, Objekte und andere iterierbare Datentypen wie Map und Set angewandt werden kann. Um auf die Liste von ToDos zugreifen zu können, legen wir in der todo/todo.ts eine Getter-Methode an, welcher uns die ToDos aus dem TodoService liefert.

todo/todo.ts:

...
get todos() {
    return this.todoService.todos;
}
...

Bei Getter-Methoden erkennt das Binding-System automatisch, wenn es sich wie bei todos() nicht um eine Variable handelt, sondern um einen Wert, der von einer Funktion berechnet wird. Um Änderungen an diesem Wert mitzubekommen, wird der Wert periodisch auf Änderungen überprüft, das sogenannte "dirty checking". Um dirty checking zu vermeiden, kann der @computedProperties(todoService.todos)-Decorator verwendet werden, um dem Binding-System mitzuteilen, dass ein Listener für todoService.todo aufgesetzt werden soll.

Custom Web Components

Wir können nun in unserer Anwendung ToDos anzeigen und neue erstellen. Um ToDos auch als erledigt markieren zu können, erstellen wir eine eigene Komponente. Diese wird das HTML für eine ToDo kapseln und den Zustand, ob sie erledigt wurde, speichern. Wir ersetzen dann einen Teil des HTML-Markup in der todo/todo.html mit der Komponente.

Unter resources/elements/todo-item.ts erstellen wir unser TodoItemCustomElement, welches anschließend als <todo-item></todo-item> im HTML verwendet werden kann. Der Tag-Name ergibt sich dabei durch den Namen der Klasse. An diesen CustomElement zu hängen, ist eine optionale Konvention, um hervorzuheben, worum es sich bei dieser Klasse handelt.

resources/elements/todo-item.ts:

import { bindable } from "aurelia-framework";

export class TodoItemCustomElement {
    @bindable item;

    constructor() {
        this.item = {};
    }

    done() {
        this.item.done = true;
    }
}

Wir übergeben der Komponente ein TodoModel, um es im HTML anzuzeigen und dessen Zustand zu manipulieren. Hierfür verwenden wir @bindable item, wodurch wir definieren, dass Daten über das Attribut "item", also <todo-item item.bind="">, in die Komponente hereingereicht werden können.
 
Im HTML zeigen wir die Datenfelder des TodoModels an und definieren einen Button, mit dem wir das ToDo auf erledigt setzen.

resources/elements/todo-item.html:

<template>
    ${item.description} - ${item.deadline} - ${item.priority}
    <button click.delegate="done()">Done</button>
</template>

Sobald der Button geklickt und das onclick-Event auslöst, wird die done()-Funktion auf dem ViewModel ausgeführt und das ToDo als erledigt markiert. In der todo/todo.html ersetzen wir nun das Anzeigen der ToDo-Details durch die neue TodoItem-Komponente. Hierfür müssen wir die Komponente zuerst mit dem <require>-Tag referenzieren.

todo/todo.html:

<template>
    <require from="resources/elements/todo-item"></require>
    ...
     <ul>
        <li repeat.for="todo of todos">
            <todo-item item.bind="todo"></todo-item>
        </li>
    </ul>
    ...

Über das Attribut "item" binden wir das jeweilige Todo an das neue <todo-item>. Bei Custom Elements wird für .bind standardmäßig ein .two-way-binding verwendet. Hierdurch können wir innerhalb der Komponente die Property item.done auf true setzen und diese Änderung wird in dem entsprechenden TodoModel im Service persistiert.

Damit für den Benutzer sichtbar wird, wenn eine ToDo bereits erledigt wurde, fügen wir als letztes noch etwas CSS hinzu.

resources/elements/todo-item.css:

.done {
    text-decoration: line-through;
}

In der TodoItem-Komponente müssen wir noch die CSS-Datei im HTML referenzieren und die erstellte .done-Klasse in Abhängigkeit davon, ob das ToDo bereits erledigt wurde oder nicht, anwenden.

resources/elements/todo-item.html:

<template>
    <require from="./todo-item.css"></require>
    <span class="${item.done ? "done" : ""}">
        ${item.description} - ${item.deadline} - ${item.priority}
    </span>
    <button show.bind="!item.done" click.delegate="done()">Done</button>
</template>

Hierfür können wir den ternären Operator direkt im CSS-Attribut verwenden.

Weiterhin blenden wir mit show.bind="!item.done" den Button aus, sobald eine ToDo bereits erledigt wurde. Ein show.bind="true" übersetzt Aurelia dann im CSS als display: block !important;.

Wir haben nun eine kleine ToDo-Anwendung bestehend aus zwei Views (Add und Todo), einem Service (TodoService) und einem Custom-Element (TodoItem) geschrieben. Dabei haben wir den Router verwendet, um innerhalb der App-Komponente entweder die Todo-Komponente oder die Add-Komponente anzuzeigen und zwischen diesen zu navigieren.

Um ein ToDo zu erstellen, haben wir das TodoModel verwendet und erstellte Instanzen anschließend in eine Liste im TodoService hinzugefügt. So konnten wir den Zustand unserer ToDos zwischen den Komponenten teilen.

Weniger Framework ist mehr

Am Beispiel dieser ToDo-Anwendung wurde gezeigt, wie mithilfe von Dependency Injection, Data Binding, Components und Custom Elements eine Aurelia-Anwendung entwickelt wird. Der Großteil der Anwendung basiert dabei auf Standard-HTML und JavaScript.

Eine größere Anwendung würde man ganz ähnlich entwickeln. Neben dem Auslagern von Business-Logik in Services, ist es wichtig, Komponenten richtig zu schneiden und die Anwendung durch diese zu strukturieren. Je nach Anwendung kann es auch sinnvoll sein, Frameworks wie RxJS oder Redux zum State Management zu verwenden [26]. Für einen tieferen Einstieg und weitere Informationen zum Thema kann ich die Aurelia-Homepage mit der API- und Quellcode-Dokumentation sowie den Blogbeiträgen und Anleitungen empfehlen [27].

In meinem aktuellen Projekt, an welchem wir seit über zwei Jahren mit durchschnittlich drei Webentwicklern arbeiten, schätzen wir Aurelia unter anderem für die Leichtigkeit, mit der neue Entwickler Fuß fassen können und für die gute Les- und Wartbarkeit des Codes.

Autorin

Katharina Bähr

Katharina arbeitet als Webentwicklerin bei Zühlke. Als Lösungspartner für Business-Innovationen begleitet Zühlke Unternehmen bei der Umsetzung ihrer Vision von der Idee bis zum Markterfolg.
>> Weiterlesen
Kommentare (0)

Neuen Kommentar schreiben