Frontend ohne JavaScript

Einleitung

Im Web wird überwiegend Javascript und darauf bauende Frameworks genutzt. Als drittes Projekt haben wir beschlossen zu erkunden, welche Alternativen es dazu gibt: Frontendentwicklungsmöglichkeiten, die auf Javascript verzichten.
Wir haben zwei Technologien untersucht und entsprechend zwei kleine Apps erstellt, eine mit HTMX und eine mit Blazor.

HTMX

HTMX ist eine JavaScript-Bibliothek, die es einfacher macht, Webseiten interaktiv zu gestalten, ohne dass man viel eigenen JavaScript-Code schreiben muss. Man kann damit zum Beispiel Teile einer Webseite aktualisieren, ohne die Seite komplett neu zu laden. Das ist praktisch, weil es die Benutzererfahrung verbessert, ohne dass man viel technisches Know-how haben muss. Mit HTMX kann man also Webseiten dynamischer machen, ohne dass es kompliziert wird.

Hier sind einige der wichtigsten Funktionen von HTMX:

Einfachheit der Verwendung: HTMX macht es einfach, dynamische Interaktionen zu Webseiten hinzuzufügen, indem es HTML-Attribute verwendet, anstatt benutzerdefinierten JavaScript-Code zu schreiben. Integration mit HTML: HTMX integriert sich nahtlos in HTML und funktioniert gut mit vorhandenen JavaScript-Frameworks und -Bibliotheken. Leichte AJAX-Anforderungen: HTMX ermöglicht das Aktualisieren bestimmter Teile einer Webseite über leichte und intuitive AJAX-Anfragen. Unterstützung für HTML-Ereignisse: HTMX nutzt standardmäßige HTML-Ereignisse wie Klicks und das Absenden von Formularen, um dynamische Aktionen auszulösen, ohne zusätzlichen JavaScript-Code schreiben zu müssen. Kompatibilität mit vorhandenen Servern: HTMX funktioniert mit vorhandenen Servern und erfordert keine wesentlichen Änderungen auf Serverseite, um implementiert zu werden. Bootstrap-Plugin: HTMX bietet ein Plugin für Bootstrap, das die Integration von HTMX mit dem Front-End-Framework Bootstrap vereinfacht.

Blazor

Blazor ist ein von Microsoft entwickeltes Open-Source-Framework, das es ermöglicht, interaktive Webanwendungen mit C# und .NET zu erstellen. Blazor ist in der Lage, C#-Code direkt im Browser auszuführen, ohne dass JavaScript benötigt wird. Dies wird durch die Verwendung von WebAssembly ermöglicht, einem offenen Standard, der es ermöglicht, Code in einer Vielzahl von Programmiersprachen in Webanwendungen auszuführen.

Komponenten

Blazor-Anwendungen bestehen aus Komponenten, die wiederverwendbare, eigenständige Teile der Benutzeroberfläche darstellen. Diese Komponenten werden in razor geschrieben. Razor ist eine Syntax, ähnlich zu JSX in React.

@page "/counter" @* URL, unter der die Komponente erreichbar ist *@

<PageTitle>Counter</PageTitle> @* Einbindung einer anderen Komponente *@

<h1>Counter</h1> @* Überschrift *@

<p role="status">Current count: @currentCount</p> @* Anzeige des aktuellen Zählerstands *@

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    // C#-Code
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

Property binding und sonstige Features, die man von modernen Frontend-Frameworks gewohnt ist, sind auch in Blazor vorhanden.

Render Modes

Blazor unterstützt zwei Render-Modi: Server und WebAssembly. Im Server-Modus wird der C#-Code auf dem Server ausgeführt und das Ergebnis an den Browser gesendet. Im WebAssembly-Modus wird der C#-Code im Browser ausgeführt.

Versuch

In diesem Versuch haben wir die Leistungsfähigkeit von HTML-over-the-wire Technologien durch die Entwicklung einer einfachen TODO-App getestet. Dabei haben wir zwei unterschiedliche Ansätze untersucht: HTMX und Blazor. Diese Technologien ermöglichen es, dynamische Webanwendungen zu erstellen, indem HTML-Fragmente dem Client gesendet werden, anstatt ganze Seiten neu zu laden. HTMX ermöglicht die dynamische Aktualisierung von Seiteninhalten mit minimalem JavaScript-Aufwand, während Blazor es Entwicklern ermöglicht, Webanwendungen mit C# und .NET zu entwickeln.

HTMX

Wir haben eine einfache TODO-App entwickelt, um die Funktionalität von HTMX zu testen. Diese App ermöglicht es Benutzern, Aufgaben hinzuzufügen, zu bearbeiten und zu löschen, alles ohne JavaScript zu schreiben. Das Frontend der App besteht aus HTML, HTMX und Tailwind CSS, während das Backend in Django geschrieben ist, um die serverseitige Logik zu handhaben.

htmx todo app

Die todo-Liste wird initial einmal geladen.

<ul
  id="todos-list"
  class="list-disc list-inside mt-4"
  hx-get="{% url 'get_todos' %}"
  hx-trigger="load"
></ul>

Das Hinzufügen neuer TODOs erfolgt über den “Add TODO” Button, der als Submit Button dient. Dabei wird die Eingabe an /add_todo geschickt. Als target wird die TODOs Liste definiert, wo die Antwort vom Server, ein list-item, gerendert wird.

<form
  id="todo-form"
  hx-post="{% url 'add_todo' %}"
  hx-swap="beforeend"
  hx-target="#todos-list"
  hx-trigger="submit"
  hx-on::after-request="this.reset()"
>
  {% csrf_token %}
  <input type="text" name="todo" class="w-full border rounded px-2 py-1 mb-2" />
  <div class="flex justify-between">
    <button
      type="button"
      class="bg-blue-500 text-white px-4 py-2 rounded"
      hx-post="{% url 'all_done' %}"
      hx-trigger="click"
      hx-target="#todos-list"
      hx-swap="innerHTML"
      hx-on::after-request="alert('Done for the day!')"
    >
      All done
    </button>
    <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">
      Add Todo
    </button>
  </div>
</form>

Performance Während wir durch die Website navigieren, bemerken wir,

dass der Hauptinhalt schnell nach dem initialen Laden der Seite angezeigt wird. Dies legt nahe, dass HTMX dazu beiträgt, den Largest Contentful Paint (LCP) zu optimieren, was eine schnelle Ladezeit und eine schnelle Anzeige des Hauptinhalts gewährleistet. Während wir durch die Website navigieren, bemerken wir, dass der Hauptinhalt schnell nach dem initialen Laden der Seite angezeigt wird. Dies legt nahe, dass HTMX dazu beiträgt, den Largest Contentful Paint (LCP) zu optimieren, was eine schnelle Ladezeit und eine schnelle Anzeige des Hauptinhalts gewährleistet. Anschließend interagieren wir mit verschiedenen Elementen der Seite, z. B. indem wir ein Formular senden oder auf ein interaktives Element klicken. Wir bemerken, dass die Reaktionszeit des Browsers auf unsere Eingaben fast sofort ist, was darauf hindeutet, dass HTMX hilft, die First Input Delay (FID) niedrig zu halten und eine reaktionsschnelle Antwort auf Benutzereingaben sicherzustellen. Schließlich bemerken wir beim Scrollen der Seite keine unerwarteten Elementbewegungen oder plötzliche Verschiebungen während des Inhaltsladens. Dies deutet darauf hin, dass HTMX dazu beiträgt, den Cumulative Layout Shift (CLS) niedrig zu halten, was eine stabile Anordnung der Elemente auf der Seite und eine nahtlose Navigation gewährleistet. Zusammenfassend kann die Verwendung von HTMX dazu beitragen, die Benutzererfahrungsmetriken auf einer Website zu optimieren, indem sie schnelles Laden, reaktionsschnelle Benutzerinteraktionen und eine stabile Layoutanordnung fördert, was zu einer insgesamt besseren Benutzererfahrung führt. #### Einschränkungen HTML-over-the-Wire-Technologien wie HTMX bieten eine Möglichkeit, Frontend-Entwicklung ohne JavaScript zu betreiben, indem sie die Interaktivität und dynamische Aktualisierungen einer Webseite durch serverseitig gerendertes HTML ermöglichen. Obwohl HTMX viele Möglichkeiten bietet, gibt es auch einige Einschränkungen. In manchen Szenarien kann auch die Verwendung von JavaScript in Verbindung mit HTMX-Attributen erforderlich sein, um die Anforderungen Ihrer Anwendung vollständig zu erfüllen. Ein kritischer Aspekt ist die Browserkompatibilität. Obwohl HTMX moderne Webstandards einsetzt, könnten ältere Browser oder solche mit begrenzter Unterstützung für diese Standards Probleme bereiten. Ein weiteres wichtiges Anliegen ist die Performance. Da HTMX jede Interaktion mit dem Server verarbeitet, können Performanceprobleme auftreten, insbesondere bei hoher Latenz zwischen Client und Server oder bei gleichzeitigem Zugriff vieler Benutzer. Die Zustandsverwaltung kann ebenfalls eine Hürde sein, da HTMX keinen integrierten Mechanismus für die Zustandsverwaltung bietet. Dies kann zu einem erhöhten Serververkehr und einer möglicherweise schlechteren Benutzererfahrung führen. Zusätzlich können Schwierigkeiten bei der SEO-Performance und Barrierefreiheit auftreten, da nicht alle Suchmaschinen und assistiven Technologien dynamische Inhalte korrekt interpretieren können, was die SEO-Performance und Barrierefreiheit beeinträchtigen könnte. Die Implementierung komplexerer Interaktionen und UI-Elemente stellt ebenfalls eine Herausforderung dar. Während HTMX viele Möglichkeiten bietet, könnten sehr komplexe Anforderungen möglicherweise nicht ausschließlich mit HTMX realisiert werden, da JavaScript oft mehr Flexibilität und Kontrolle bietet. In einigen Fällen könnten auch komplexe Datenmanipulationen vor dem Senden von Anfragen erforderlich sein, die möglicherweise nicht alle mit HTMX-Attributen abgedeckt werden können, was die Notwendigkeit von JavaScript nahelegt. HTMX bietet zwar integrierte Mechanismen zur Behandlung von Serverantworten und zum Aktualisieren von DOM-Elementen basierend auf diesen Antworten, jedoch könnten für eine benutzerdefinierte Verarbeitung der Serverantworten oder bei komplexen Bedingungslogiken für Anfragen JavaScript-Event-Listener erforderlich sein, um die erforderliche Logik zu implementieren. Bei der Integration von HTMX in eine bestehende Codebasis könnten Kompatibilitätsprobleme mit bestehenden Bibliotheken und Frameworks auftreten, was zusätzlichen Arbeitsaufwand bedeuten kann. Und schließlich, wenn man mit Drittanbieter-Bibliotheken oder -Frameworks arbeitet, die nicht explizit mit HTMX-Attributen kompatibel sind, könnte JavaScript erforderlich sein, um die Integration zu erleichtern oder benutzerdefinierte Lösungen zu implementieren.

Extensions/Libraries für HTMX Extensions erweitern die Funktionalität von

HTMX, indem sie zusätzliche Features und Werkzeuge bereitstellen, um die Entwicklung zu erleichtern. Ein Beispiel hierfür ist beispielsweise eine Debug-Erweiterung, die das Debugging vereinfacht. Eine andere Erweiterung heißt Ajax-Header und ermöglicht es, ganz einfach einen Ajax-Header zum HTTP-Request hinzuzufügen. Man kann auch ganz einfach eigene HTMX Extensions schreiben, und diese dann im eigenen Code verwenden. ```html


#### Vorteile von HTMX

Einfache und intuitive HTML-basierte Syntax: HTMX verwendet eine einfache und
intuitive Syntax, die auf HTML basiert, was die Entwicklung von interaktiven
Webanwendungen erleichtert.

Dynamische Interaktivität direkt in HTML ohne JavaScript: HTMX ermöglicht
dynamische Interaktivität direkt in HTML, ohne dass JavaScript-Code erforderlich
ist. Dies erleichtert die Entwicklung und Wartung von Webanwendungen erheblich.

Leichte Integration in bestehende HTML-Webseiten: HTMX lässt sich problemlos in
bestehende HTML-Webseiten integrieren, ohne dass umfangreiche Änderungen am
vorhandenen Code erforderlich sind, was die Anpassung an bestehende Projekte
erleichtert.

Leichtgewichtige Bibliothek mit nur wenigen kB: HTMX ist eine leichtgewichtige
Bibliothek, die nur wenige Kilobyte groß ist. Dadurch werden Ladezeiten
minimiert und die Leistung der Webanwendung optimiert.

### Blazor

Im Versuch mit Blazor haben wir mehrere Features aber auch Einschränkungen uns
persönlich angeschaut.

#### Performance

Zunächst einmal haben wir die Performance von Blazor betrachtet. Hierbei muss
man sagen, dass es nicht ganz einfach ist wegen der vielen Konfigurationen und
Rendermodi die Performance von Blazor zu messen.

##### InteractiveServer

Im InteractiveServer-Modus wird der Server für jeden Event-Handler aufgerufen
und sendet den modifizierten DOM zurück. Demnach ist die Performance stark von
Netzwerklatenzen abhängig. Außerdem geht dieser Modus dem Trend entgegen, dass
die Clients einer Anwendung immer mehr Rechenleistung haben.

Daher eignet sich dieser Modus besonders für alte Client-Geräte und fast
ausschließlich lokal-benutzte Anwendungen.

An sich ist der Server jedoch nach tests rechts performant und überlastet das
Frontend auf keinen Fall mit zu vielen Daten.

##### Wasm

Mit einem Payload von 8.50 MB für dotnet.wasm ist das initiale Laden nicht für
alle clients möglich daher ist es nicht für alle Anwendungen geeignet.

Responsiveness ist auch im Interpreter-Modus akzeptabel. In diesem Modus wird
ans Frontend ein C# Interpreter geschickt, der dann den bytecode ausführt.

Mit dem AOT-Modus wird der C# Code in WebAssembly übersetzt und dann ausgeführt.
Mit einer bundle size von 29MB kann man den Modus nicht für mobile Anwendungen
anbieten. Rohe Performance konnten wir leider nicht testen.

### Virtual List

Blazor unterstützt standardmäßig das Rendern von virtuellen Listen, was ein
wichtiges Werkzeug zur Verbesserung der Leistung ist. Das Rendern von virtuellen
Listen ermöglicht es Ihnen, große Listen effizient zu rendern, indem nur die
sichtbaren Elemente auf dem Bildschirm gerendert werden, anstatt die gesamte
Liste zu rendern. Dies kann die Leistung Ihrer Blazor-Anwendung erheblich
verbessern, insbesondere beim Umgang mit großen Datensätzen.

Um das Rendern von virtuellen Listen in Blazor zu aktivieren, können Sie das
`Virtualize`-Komponente verwenden, das vom Blazor-Framework bereitgestellt wird.
Das `Virtualize`-Komponente kümmert sich um das effiziente Rendern nur der
sichtbaren Elemente und das Handhaben von Scroll-Ereignissen.

Hier ist ein Beispiel, wie Sie das `Virtualize`-Komponente in Blazor verwenden
können:

```html
<div style="height:500px;overflow-y:scroll">
  <Virtualize Items="allFlights" Context="flight">
    <span @key="flight">@flight</span><br />
  </Virtualize>
</div>
```

### Javascript Interop

Javascript interop ist ein sehr wichtiger Bestandteil des Webassembly Ansatzes,
da mehr als 30 Jahre im Web nur Javascript verwendet wurde. Daher muss auch
Blazor eine Möglichkeit bieten, mit Javascript zu interagieren.

In Blazor funktioniert das indem man an des window Objekt Funktionen anhängt,
die dann in C# aufgerufen werden können. Vorteil dahinter ist ganz klar die
Einfachheit. Als Webentwickler scheut man sich aber eigentlich davor, das window
Objekt zu manipulieren.

```html
<head>
    <script>
        function someJsFunction(a) {
            console.log(a);
            return "Hello from JS";
        }
    </script
</head>
```

In C# kann man dann die Funktion wie folgt aufrufen:

```csharp
@inject IJSRuntime JS

@code {
    var a = new int[] { 1, 2, 3, 4, 5 };
    var text = await JS.InvokeAsync<string>("someJsFunction", a);
}
```

Man beachte hier das keine Typinformation von Typescript oder Jsdoc in C#
übernommen werden daher kann der generic Parameter auch falsch gewählt werden,
was erst zur Laufzeit auffällt.

Es ist aber gut zu wissen, dass Javascript Interop in Blazor möglich ist.

### NuGet

Das Blazor Framework und andere Pakete des .NET Ökosystems weden vom NuGet
Paketmanager verwaltet. NuGet wurde 2010 von einer Microsoft Tochterfirma
veröffentlicht und ist der einzige Paketmanager von .NET und ist unter
https://www.nuget.org verfügbar.

Ähnlich zu anderen Paketmanagern bietet NuGet eine Command Line Interface
wodurch er bedient werden kann. Über 100.000 Pakete werden angeboten. Im
Vergleich zu den 2.000.000 Paketen vom NPM Paketmanagers wirkt diese Zahl
gering, dennoch werden die wichtigsten Bereiche, wie zum Beispiel das Arbeiten
mit Datum/Uhrzeit somit abgedeckt.

Fazit

HTMX

Insgesamt bietet HTMX eine benutzerfreundliche Lösung für die Integration von dynamischen Interaktionen in Webseiten, ohne dabei auf komplexe JavaScript-Codierung angewiesen zu sein. Durch die Verwendung von einfachen HTML-Attributen können Entwickler AJAX-Anfragen und andere Interaktionen hinzufügen, um die Benutzererfahrung zu verbessern, während gleichzeitig die Zugänglichkeit und Suchmaschinenoptimierung erhalten bleiben. HTMX ist daher eine praktische Option für diejenigen, die die Interaktivität ihrer Webseiten auf einfache und effiziente Weise steigern möchten.

Blazor

Zu Blazor gibt es viele Vorurteil, weil die Idee allein etwas ungewöhnlich ist. Dabei waren wir auch ganz klar mit Vorurteilen herangegangen von denen sich auch viele bestätigt haben.

Use-Cases

Zunächst einmal war uns zu Anfang kein Use-Case für Blazor eingefallen, da wir uns nicht vorstellen konnten, dass es wirklich sinnvoll ist, C# im Web zu verwenden, da dadurch immer ein Performance-Verlust, entweder durch Bundle-Size, Netzwerklatenzen oder Interpretations-overhead entsteht.

Für Blazor Server stellen wir uns als einzigen Use-Case eine Lokale Anwendung vor, die im lokalen Netzwerk eine Anwendung bereitstellt. Hierbei hat man ganz klar Vorteile, da zu einem Komplexität der Anwendung reduziert wird und Clients weniger Rechenleistung benötigen.

Für die Wasm Variante sehen wir nur interne Anwendungen, weil die Bundle-Size einfach zu groß für das Internet ist. Hierbei muss man auch den neuste Entwicklung in .NET 8 ansehen, die es ermöglicht mit Blazor Wasm WPF oder Maui Apps zu kombinieren.

Developer Experience (DX)

An sich muss man sagen, dass die DX von Blazor für die Nische, der .NET Web Entwicklung recht gut ist. Features wie Hot-Reload funktionieren meistens in Wasm und Server. Ein paar Komponenten-Libraries sind auch schon vorhanden und man kann die meisten .NET Libraries verwenden.

Jedoch ist man als JS-Entwickler anderes gewöhnt devtools fehlen, hot reload greift nicht immer und bei Fehler stürzt ohne Rückmeldung der Server ab. Außerdem kann man auch den ganzen Computer zu Absturz bringen, indem man zu schnell Speicher anfordert.

Quellen

  1. https://learn.microsoft.com/de-de/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-8.0

  2. https://learn.microsoft.com/de-de/aspnet/core/blazor/?view=aspnetcore-8.0

  3. https://learn.microsoft.com/de-de/aspnet/core/blazor/fundamentals/?view=aspnetcore-8.0

  4. https://htmx.org/

  5. https://www.reddit.com/r/htmx/comments/r13e9i/xtmx_limitations_and_pitfalls/