Teil 1 - Tooling für die App einrichten

Dieses Lab ist Teil der Amenity Finder Serie, einer umfassenden Anleitung, die Schritt für Schritt zeigt, wie man eine Web-Applikation mithilfe von Web-Components entwickelt. In jedem Teil der Serie werden spezifische Aspekte der Entwicklung behandelt und es werden bewährte Methoden und Techniken vermittelt, um eine moderne und skalierbare Webanwendung aufzubauen.

Im ersten Teil der Amenity Finder Serie widmen wir uns der Einrichtung des Entwicklungsumfelds und der Werkzeuge für unsere Applikation. Wir stellen sicher, dass alle erforderlichen Tools korrekt konfiguriert sind, um die Entwicklung der Web-Components-basierten Applikation zu unterstützen.

Wenn du mit diesem Lab bereits vertraut bist, kannst du im zweiten Teil der Amenity Finder Serie lernen, wie du das Grundlayout für deine Amenity Finder Applikation implementieren kannst.

Vorbereitung

Ziele

In diesem Lab verfolgen wir folgende Ziele:

  • Initialisierung eines neuen Projekts mit open-wc: Wir beginnen mit der Initialisierung eines neuen Projekts unter Verwendung des open-wc-Starters. Open-wc ist ein bewährtes Toolkit für die Entwicklung von Web-Components und bietet eine Vielzahl an nützlichen Tools, Konfigurationen und bewährten Methoden. Durch die Initialisierung eines Projekts mit open-wc stellen wir sicher, dass wir eine solide Grundlage haben, um mit Web-Components zu arbeiten.
  • Tooling in der package.json und in der IDE einrichten: Um das Tooling für unsere Web-Components-Entwicklung einzurichten, bearbeiten wir die package.json-Datei unseres Projekts. Hier können wir verschiedene Skripte hinzufügen, um beispielsweise den Build-Prozess, das Testen oder das Starten der Entwicklungsserver zu automatisieren. Darüber hinaus können wir zusätzliche Abhängigkeiten hinzufügen, die uns bei der Entwicklung unterstützen. Zusätzlich richten wir unsere IDE oder unseren Texteditor ein, um von hilfreichen Plugins wie Prettier, ESLint oder lit-plugin zu profitieren. Diese Tools unterstützen uns bei der Codeformatierung, Fehlererkennung und bieten eine bessere Entwicklungsumgebung für Web-Components.
  • Deploy der neuen App über surge.sh in die Cloud (optional): Als optionales Ziel können wir unsere fertige Web-Components-App in die Cloud deployen, um sie für andere zugänglich zu machen. Eine beliebte Plattform für das Deployment von statischen Websites ist surge.sh. Surge.sh ermöglicht es uns, unsere Anwendung mit nur wenigen einfachen Schritten zu deployen und sie unter einer öffentlichen URL verfügbar zu machen. Dies bietet die Möglichkeit, die Anwendung mit anderen zu teilen oder sie auf verschiedenen Geräten zu testen.

Schritte

Das Setup der Amenity Finder Applikation umfasst sechs Schritte, wobei die letzten drei optional sind und nicht zwingend durchgeführt werden müssen.

  1. Projekt initialisieren
  2. Applikation starten
  3. Git-Repository Aufsetzen
  4. Husky Aufsetzen (optional)
  5. IDE Setup (optional)
  6. Cloud Deployment (optional)

Branch

Der erste Teil des Amenity Finder Labs ist auf GitHub verfügbar.

Für weiterführende Informationen zu den behandelten Themen empfehlen wir dir, die folgenden Links zu besuchen:


Los geht’s!

Projekt initialisieren

Wir initialisieren unser Projekt mithilfe von Open Web Component Recommendations (open-wc). open-wc ist eine Sammlung von Empfehlungen und Einstellungen für Projekte auf Basis von Web-Components. Die Empfehlungen decken viele Bereiche wie Entwicklung, Linting, Testing, Publishing usw. ab.

open-wc bietet auch einen npm initializer für das Aufsetzen von neuen Projekten an. Wir setzen unsere Applikation mit diesem Generator auf, indem wir den folgenden Befehl ausführen:

$ npx @open-wc/create@0.38.70

(Eigentlich wäre der Befehl noch kürzer, nämlich npm init @open-wc. Allerdings möchten wir sicherstellen, dass wir mit den möglichst gleichen Versionen arbeiten. Um bei einem npm initializer Package die Version angeben zu können, müssen wir den darunterliegenden Befehl npx verwenden.)

Als Erstes sollten wir den folgenden Output sehen:

        _.,,,,,,,,,._
     .d''           ``b.       Open Web Components Recommendations
   .p'      Open       `q.
 .d'    Web Components  `b.    Start or upgrade your web component project with
 .d'                     `b.   ease. All our recommendations at your fingertips.
 ::   .................   ::
 `p.                     .q'
  `p.    open-wc.org    .q'
   `b.     @openWc     .d'
     `q..            ..,'      See more details at https://open-wc.org/init/
        '',,,,,,,,,,''


Note: you can exit any time with Ctrl+C or Esc
? What would you like to do today? › - Use arrow-keys. Return to submit.
❯   Scaffold a new project

Da wir eine neue App aufsetzen, wählen wir hier die Option Scaffold a new project.

Der Generator führt uns nun durch mehrere Fragen. Diese beantworten wir wie folgt:

tl;dr

Die voreiligen Leser finden nachfolgend eine Zusammenfassung der Antworten für den @open-wc Generator. Eine detaillierte Beschreibung folgt weiter unten.

✔ What would you like to do today? › Scaffold a new project
✔ What would you like to scaffold? › Application
✔ What would you like to add? › Linting (eslint & prettier), Building (rollup)
✔ Would you like to use typescript? › No
✔ Would you like to scaffold examples files for? › Building (rollup)
✔ What is the tag name of your app shell element? … amenity-finder
✔ Do you want to write this file structure to disk? › Yes
✔ Do you want to install dependencies? › Yes, with npm
Erklärungen zu den Fragen und Antworten
  • What would you like to scaffold?
    • Wir wählen Application, da wir eine Applikation und keine eigenständige Webkomponente bauen.
  • What would you like to add?
    • Hier beschränken wir uns auf die Optionen Linting (eslint & prettier) und Building (rollup).
    • Linting liefert uns unter anderem Konfigurationen für Code-Linting mittels ESLint sowie eine automatische Code-Formatierung mithilfe von Prettier. ESLint gehört heute zum Quasi-Standard für statische Analysen von JavaScript (oder auch TypeScript) Programmcode. Prettier ist ein «opinionated code formatter», der mit vielen verschiedenen Sprachen umgehen kann. Wir müssen uns so keine Sorgen um eine konsistente Formatierung machen. Beide Tools haben ein umfangreiches Ökosystem und können mittels Plugins für verschiedene Anwendungsfälle erweitert werden.
    • Bei der Entwicklung werden wir dank @web/dev-server ohne einen Build (buildless) unterwegs sein. Für ein optimiertes Produktions-Bundle verwendet open-wc Rollup.
    • Demoing (storybook) lassen wir für unseren Anwendungsfall ganz weg. Wer sich trotzdem für den Anwendungsfall von Storybook für die Dokumentation (und Testing) von Web-Components interessiert, kann dies im Demoing-Abschnitt auf der open-wc Webseite nachlesen.
    • Den Punkt Testing (karma) lassen wir zum jetzigen Zeitpunkt ebenfalls noch aus. Wir kommen später in einem separaten Kapitel zum Thema Testing noch einmal darauf zurück.
    • Building (rollup) wird für das Builden eines Bundles für die Produktion verwendet.
  • Would you like to use typescript?
    • Um möglichst nah bei der Web-Plattform zu bleiben, werden wir unsere Applikation in JavaScript schreiben und wählen daher No.
  • What is the tag name of your application/web component?
    • Wir bauen einen Restaurant-Finder und wählen für den Custom-Tag daher die englische Übersetzung amenity-finder. Über den <amenity-finder>-Tag wird unsere Applikation später im HTML-Dokument eingebunden.
  • Do you want to write this file structure to disk?
    • Zum Schluss bestätigen wir noch das Schreiben der gesamten Projektverzeichnisstruktur mit Yes.
  • Do you want to install dependencies?
    • Optional kann der open-wc Generator für uns auch noch alle npm-Dependencies im Zielordner installieren. Dies können wir entweder mit Yarn oder npm machen. Über die Vor- und Nachteile der beiden Tools herrscht auch im 2021 Uneinigkeit. Weil npm als Teil der Node-Installation mitgeliefert wird, holen wir unsere Dependencies damit und wählen hier Yes, with npm.

Applikation starten

Das Resultat des open-wc Generators sollte ein Verzeichnis amenity-finder mit der folgenden Verzeichnisstruktur sein. Wir werden auf diese Struktur in der nächsten Lektion näher eingehen.

amenity-finder/
├── assets/
│   └── open-wc-logo.svg
├── src/
│   ├── amenity-finder.js
│   └── AmenityFinder.js
├── .editorconfig
├── .gitignore
├── custom-elements.json
├── index.html
├── LICENSE
├── package.json
├── package-lock.json
├── README.md
├── rollup.config.js
└── web-dev-server.config.mjs

Wir wechseln mit $ cd amenity-finder in das Applikationsverzeichnis1 und können mit $ npm start die Applikation starten. Falls ihr vorher die Frage Do you want to install dependencies? mit No beantwortet habt, muss vorher noch $ npm install ausgeführt werden, um die npm-Dependencies zu installieren.

Das Start-Skript sollte die URL http://localhost:8000/ automatisch im Browser öffnen. Et voilà! Unsere Applikation startet und du solltest den folgenden Screen sehen:

Screenshot der Amenity Finder Applikation nach initialem Setup

Git-Repository Aufsetzen

Damit wir unseren Entwicklungsfortschritt tracken und unsere Anpassungen versionieren können, setzen wir noch ein lokales Git-Repository auf.

$ git init
$ git add -A .
$ git commit -am 'Initial import'

Husky aufsetzen (optional)

Das open-wc-Setup verwendet Husky für die Installation von Git Hooks. So wird bei jedem Commit zum Beispiel der $ npm run lint Befehl gestartet. Damit kann verhindert werden, dass falsch formatierter Code oder Code der die statische Analyse mit ESLint nicht ohne Fehler durchläuft, in das Repository committed werden kann.

Husky installiert die Git Hooks automatisch bei npm install in das .git Verzeichnis. Haben wir allerdings beim initialen Setup die Frage Do you want to install dependencies? mit Yes beantwortet, sind die Hooks nicht installiert worden, weil wir uns zum Zeitpunkt von npm install ausserhalb des Projekt-Roots befunden haben. Mit npm rebuild können wir die Hooks nachträglich installieren lassen.

Ihr könnt nun selber einfach testen, ob bei jedem Commit Husky die lint-Befehle ausführt.


IDE Setup (optional)

Wir beschränken uns in dieser Lektion auf das Setup von IntelliJ IDEA resp. den anderen JetBrains IDE-Varianten wie WebStorm oder PhpStorm. Anleitung für weitere Entwicklungsumgebungen wie z. B. Visual Studio Code, Atom oder Sublime Text sind auf der open-wc Webseite zu finden.

Die aktuelle Version 2021.x von IntelliJ IDEA Ultimate unterstützt ESLint und Prettier von Haus aus. In anderen JetBrains IDE-Varianten müssen womöglich folgende Plugins installiert werden:

ESLint und Prettier werden am besten wie folgt konfiguriert:

IntelliJ ESLint Konfiguration IntelliJ Prettier Konfiguration

Cloud Deployment (optional)

Wir wollen unsere Applikation anderen zur Verfügung stellen. Dafür muss sie auf einem Webserver öffentlich zugänglich sein. Weil sie aus rein statischen Files (HTML und JavaScript) besteht, brauchen wir dafür nur ein einfaches statisches Hosting. Heute gibt es zahlreiche Anbieter für diesen Anwendungsfall. Wir werden in unserem Beispiel Surge verwenden. Weitere beliebte Alternativen sind Github Pages, Netlify, Heroku, Vercel oder Google Firebase.

Mit npm start hatten wir bisher nur einen Development-Server gestartet. Beim initialen Setup hatten wir allerdings auch einen Build, den wir für ein produktives Deployment verwenden können, aufgesetzt (respektive hat dies npm init @open-wc für uns getan). Den Build können wir mit dem folgenden Befehl starten …

$ npm run build

… und erhalten den folgenden Output:

> amenity-finder@0.0.0 build
> rimraf dist && rollup -c rollup.config.js && npm run analyze -- --exclude dist


index.html → dist...

The service worker file was written to dist/sw.js
The service worker will precache 2 URLs, totaling 18 kB.

created dist in 2.5s

> amenity-finder@0.0.0 analyze
> cem analyze --litelement "--exclude" "dist"

[5:35:19 PM] @custom-elements-manifest/analyzer: Created new manifest.

Der Build unserer Applikation landet also im dist Verzeichnis. Mit einem einfachen Webserver können wir den Inhalt dieses Verzeichnis über unseren localhost auf einem Port ausliefern und so einfach eine Webserver-Umgebung simulieren:

$ npx http-server dist

Standardmässig wird ein Server auf dem Port 8080 gestartet. Ist dieser besetzt, wird beim Port einfach hochgezählt bis ein freier Port gefunden wurde. Unter http://127.0.0.1:8080/ sollten wir also den Build unserer Applikation sehen.

Nun müssen wir noch Surge installieren um dann über den surge Kommandozeile-Befehl das Deployment in die Cloud machen zu können:

$ npm install surge --global

Das Deployment erledigen wir dann über den Befehl:

$ surge dist

Haben wir noch kein Benutzerkonto bei Surge, können wir im gleichen Zug einen erstellen. Bestehende Benutzer können mit dem Surge-Benutzerkonto einloggen. Surge erstellt für uns eine zufällige Subdomain auf surge.sh und lädt den Inhalt unseres dist Verzeichnisses hoch. Ein Beispiel-Output des vorherigen Befehls könnte so aussehen:

   Welcome to surge! (surge.sh)
   Login (or create surge account) by entering email & password.

          email: psiska@inventage.com
       password:

   Running as psiska@inventage.com (Student)

        project: dist
         domain: itchy-frog.surge.sh
         upload: [====================] 100% eta: 0.0s (7 files, 176809 bytes)
            CDN: [====================] 100%
     encryption: *.surge.sh, surge.sh (229 days)
             IP: 138.197.235.123

   Success! - Published to itchy-frog.surge.sh

Unsere Applikation ist nun unter http://itchy-frog.surge.sh/ aufrufbar. Ohne weitere Konfiguration erstellt Surge bei jedem Deployment eine solche zufällige Domain. Damit unsere Applikation immer unter der gleichen Domain erreichbar ist, können wir das Surge entweder über den --domain Parameter mitgeben, oder wir legen eine Datei CNAME mit der Domain als Inhalt an.

In unserem Fall ist der --domain Parameter der einfachere Weg (weil der Inhalt von dist durch Rollup generiert wird und wir so vorerst nichts an der Rollup-Konfiguration rollup.config.js anpassen müssen). Damit wir uns die Befehle und Parameter nicht merken müssen, erstellen wir uns dafür ein npm-Skript im package.json.

--- package.json
+++ package.json
     "build": "rimraf dist && rollup -c rollup.config.js && npm run analyze -- --exclude dist",
     "start:build": "web-dev-server --root-dir dist --app-index index.html --open",
     "analyze": "cem analyze --litelement",
-    "start": "web-dev-server"
+    "start": "web-dev-server",
+    "deploy": "surge --domain itchy-frog.surge.sh dist"
   },
   "dependencies": {
     "lit": "^2.0.0-rc.4"

Danach können wir unsere Applikation mit $ npm run deploy mit Surge deployen.

ACHTUNG: Der $ npm run deploy Befehl ist nur für das Deployment des Inhalts des dist Verzeichnis zuständig. Vor jedem Deployment müssen wir npm run build ausführen, um einen aktuellen Build der Applikation zu erhalten. Möchte man dies nicht, kann das deploy Skript entsprechend noch um einen Aufruf des build Skripts ergänzt werden:

--- package.json
+++ package.json
     "start:build": "web-dev-server --root-dir dist --app-index index.html --open",
     "analyze": "cem analyze --litelement",
     "start": "web-dev-server",
-    "deploy": "surge --domain itchy-frog.surge.sh dist"
+    "deploy": "npm run build && surge --domain itchy-frog.surge.sh dist"
   },
   "dependencies": {
     "lit": "^2.0.0-rc.4"

Glückwunsch!

Du hast den ersten Teil der Amenity Finder Serie abgeschlossen. In diesem Teil haben wir das Tooling für die App aufgesetzt. Du hast eine aktuelle Node.js Installation eingerichtet und eine geeignete IDE oder Editor ausgewählt. Dadurch bist du bereit, mit der Entwicklung der Amenity Finder Applikation zu beginnen. Im zweiten Teil werden wir das Basis-Layout für die App implementieren.


Footnotes

1 Wir führen von hier an alle Befehle jeweils im amenity-finder Verzeichnis aus.