223015c/02: - glossar landkarte: klausur, prosa, reihenfolge (host→client→server→req→res→protokoll), tcp/http als beispiel - glossar adressen/daten/eigenschaften/protokolle: prosa-sätze - tcp/ip-modell: nichtssagenden satz ersetzt - dateneinheiten: merkhilfe durch prosa ersetzt - osi vs tcp/ip: bg right statt h:440, prosa statt einzeiler - port: tabelle→liste, prosa statt bullets - ip vs mac vs port: prosa - tcp vs udp, http-methoden, status-codes, einheiten: prosa - selektoren id + farben: klausur markiert - farben: mdn-link, prosa-satz dhbw/01: - farben: prosa-satz synchronisiert - über-mich: collage-bild hinzugefügt
1445 lines
29 KiB
Markdown
1445 lines
29 KiB
Markdown
---
|
||
marp: true
|
||
theme: gaia
|
||
paginate: true
|
||
backgroundColor: #fff
|
||
header: "Web Engineering – DHBW Stuttgart"
|
||
footer: "Michael Czechowski – SoSe 2026"
|
||
title: Web Engineering
|
||
---
|
||
|
||
<style>
|
||
:root {
|
||
--color-foreground: #1a1a2e;
|
||
--color-highlight: #d63384;
|
||
--color-dimmed: #4a4a6a;
|
||
}
|
||
section.invert {
|
||
--color-foreground: #fff;
|
||
}
|
||
section {
|
||
font-size: 1.4rem;
|
||
}
|
||
h1 {
|
||
color: #a02060;
|
||
}
|
||
section.invert h1 {
|
||
color: #fff;
|
||
}
|
||
h2 {
|
||
color: #1f2937;
|
||
}
|
||
section.invert h2 {
|
||
color: #f48fb1;
|
||
}
|
||
pre {
|
||
background: #0f0f23;
|
||
color: #d63384;
|
||
border-radius: 8px;
|
||
border-left: 3px solid #d63384;
|
||
}
|
||
pre code {
|
||
background: transparent;
|
||
color: inherit;
|
||
}
|
||
code {
|
||
background: #1a1a2e;
|
||
color: #d63384;
|
||
padding: 0.15em 0.4em;
|
||
border-radius: 4px;
|
||
}
|
||
a {
|
||
color: var(--color-highlight);
|
||
}
|
||
</style>
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _header: '' -->
|
||
<!-- _backgroundColor: #000 -->
|
||
|
||

|
||
|
||
# Web Engineering
|
||
|
||
**DHBW Stuttgart** · Informatik / Wirtschaftsinformatik
|
||
|
||
**Sommersemester 2026**
|
||
|
||
---
|
||
|
||
<!-- _class: lead -->
|
||
|
||
# Herzlich Willkommen!
|
||
|
||
## 1. Sitzung: 08.05.2026
|
||
|
||
---
|
||
|
||
# Über mich
|
||
|
||

|
||
|
||
**Michael Werner Czechowski**
|
||
|
||
- Systems and Platform Engineer
|
||
- Schwerpunkte:
|
||
- Web-Technologien, Barriere-Armut, Open Source
|
||
- Hintergrund:
|
||
- Philosophie (Uni Stuttgart)
|
||
- Wirtschaftsinformatik (Leibniz-FH Hannover)
|
||
- Honorardozent (DHBW Stuttgart, HdM Stuttgart, Leibniz-FH)
|
||
- Kontakt: michael.czechowski@lehre.dhbw-stuttgart.de
|
||
|
||
---
|
||
|
||
# Vorlesungsplan
|
||
|
||
| Sitzung | Datum | Thema |
|
||
|---------|-------|-------|
|
||
| 1 | 08.05. | Intro, Projektgruppen, Internet 101 |
|
||
| 2 | 15.05. | HTML und CSS (Frameworks) |
|
||
| 3 | 22.05. | JS (Frameworks) und npm |
|
||
| 4 | 29.05. | nodeJS: Scripting, Running and Building |
|
||
| 5 | 05.06. | Express API, CRUD und "Middlewares" |
|
||
| 6 | 12.06. | **Projektwerkstattbericht** |
|
||
| 7 | 19.06. | Testing (unit, integration, end-to-end) |
|
||
| 8 | 26.06. | TypeScript |
|
||
| 9 | 03.07. | Docker, Proxies and DBs |
|
||
| 10 | 10.07. | Wrap-up & Projektsupport |
|
||
| 11 | 17.07. | **Präsentation** |
|
||
|
||
---
|
||
|
||
# Prüfungsleistung – Übersicht
|
||
|
||
Eigenes Projekt: **Web-App** ODER **Backend** (API/CLI — Command-Line Interface).
|
||
|
||
**Grundanforderungen (75 Punkte)**
|
||
|
||
| Punkte | Bereich |
|
||
|--------|---------|
|
||
| 20 | Idee, Konzeption, Planung |
|
||
| 5 | Plattformunabhängigkeit |
|
||
| 25 | Clean Code (KISS, SOLID, DI, Testing, Error Handling) |
|
||
| 15 | Präsentation |
|
||
| 10 | Dokumentation |
|
||
|
||
**Zusatzpunkte (max. 10):** TypeScript, Docker, Dev/Prod-Parity, `.env`, npm-Publish, Domain, HTTPS, Responsive Design.
|
||
|
||
---
|
||
|
||
# Prüfungsleistung – Idee & Konzeption (20 P.)
|
||
|
||
- "Powerpoint"-Präsentation + Folien
|
||
- Aussagekräftiger Arbeitstitel + Beschreibung
|
||
- **Elevator Pitch** (max. 1 Min.)
|
||
- Repo-Link (GitHub / GitLab / Codeberg / BitBucket)
|
||
- **Logs**: wie hat sich Projekt verändert vs. Ursprungsidee?
|
||
- Schematischer Projektaufbau (UML o. Ä.)
|
||
|
||
---
|
||
|
||
# Prüfungsleistung – Clean Code (25 P.)
|
||
|
||
- `README.md` (clone, start, contribute)
|
||
- **KISS** – Keep It Simple, Stupid
|
||
- **SOLID:**
|
||
- **S**ingle Responsibility Principle
|
||
- **O**pen/Closed Principle
|
||
- **L**iskov Substitution Principle
|
||
- **I**nterface Segregation Principle
|
||
- **D**ependency Inversion Principle
|
||
- **DI** – Dependency Injection
|
||
- **Testing-Pyramide** (Unit, Integration, E2E)
|
||
- **Exception/Error Handling**
|
||
|
||
---
|
||
|
||
# Prüfungsleistung – Abgabe & Termine
|
||
|
||
- **Code-Upload:** bis 27.07.
|
||
- **Präsentation:** 17.07. (Gruppen, ~10 Min.)
|
||
|
||
Details: https://git.dailysh.it/DHBW/pruefungsleistung
|
||
|
||
---
|
||
|
||
# Internet 101 – Zeitleiste
|
||
|
||
| Jahr | Ereignis |
|
||
|------|----------|
|
||
| 1966 | ARPANET |
|
||
| 1969 | RFCs |
|
||
| 1986 | IETF |
|
||
| 1992 | Internet Society |
|
||
| 1974 | TCP/IP und HTTP(S) |
|
||
| 1987 | Domain Names und DNS |
|
||
| 1993 | "Erster" Browser: Mosaic |
|
||
| 1994 | W3C (HTML, XML, CSS, SVG, WCAG etc.) |
|
||
| 1995 | ECMAScript (JS) |
|
||
| 2006/08 | V8 JS Runtime Engine |
|
||
| Heute | 1,3 Mio. km Unterseekabel |
|
||
|
||
---
|
||
|
||
<!-- _header: '' -->
|
||
<!-- _footer: '' -->
|
||
|
||

|
||
|
||
|
||
---
|
||
|
||
# HTTP – Hypertext Transfer Protocol
|
||
|
||
**Request:**
|
||
```
|
||
GET /products HTTP/1.1
|
||
Host: localhost:8080
|
||
```
|
||
|
||
**Response:**
|
||
```
|
||
HTTP/1.1 200 OK
|
||
Content-Type: application/json
|
||
|
||
[{"id": 1, "name": "Produkt A"}, ...]
|
||
```
|
||
|
||
---
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _header: '' -->
|
||
<!-- _backgroundColor: #000 -->
|
||
|
||
# Onboarding
|
||
## Tools, Runtimes, Workflows
|
||
|
||
---
|
||
|
||
# Werkzeuge & Betriebssystem
|
||
|
||
**Erforderliche Werkzeuge:**
|
||
- **Terminal** (zsh / bash / fish / pwsh) — Kommandozeile
|
||
- **Editor** (siehe folgende Folie)
|
||
- **JavaScript-Runtime** (Node.js / Bun / Deno)
|
||
- **Browser mit DevTools** (Chromium / Firefox / Safari)
|
||
- **Git** — verteiltes Versionskontrollsystem (Stand der Industrie)
|
||
|
||
**OS-Empfehlung:**
|
||
|
||
| OS | Status |
|
||
|----|--------|
|
||
| **macOS** | First-class, viele Tools "just work" |
|
||
| **Linux** | First-class, beste Server-Parität |
|
||
| **Windows + WSL2** | Empfohlen — Windows-CLI hat Edge Cases |
|
||
| **Windows nativ** (PowerShell) | Funktioniert, aber holpriger Pfad |
|
||
|
||
---
|
||
|
||
# Node.js installieren – macOS
|
||
|
||
Empfohlen: **LTS** (aktuell **Node.js 24** — Stand 2026).
|
||
|
||
Paketmanager: **[Homebrew](https://brew.sh)**
|
||
|
||
```bash
|
||
# Homebrew installieren (falls nicht vorhanden)
|
||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||
|
||
# Node.js LTS installieren
|
||
brew install node@24
|
||
|
||
# Version prüfen
|
||
node --version
|
||
npm --version
|
||
```
|
||
|
||
Alternative: Installer von [nodejs.org](https://nodejs.org)
|
||
|
||
---
|
||
|
||
# Node.js installieren – Linux
|
||
|
||
Empfohlen: **LTS** (aktuell **Node.js 24**).
|
||
|
||
**Debian / Ubuntu** ([NodeSource](https://github.com/nodesource/distributions)):
|
||
```bash
|
||
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
||
sudo apt install -y nodejs
|
||
```
|
||
|
||
**Arch / Manjaro:**
|
||
```bash
|
||
sudo pacman -S nodejs npm
|
||
```
|
||
|
||
**Fedora / RHEL:**
|
||
```bash
|
||
sudo dnf module install nodejs:24/common
|
||
```
|
||
|
||
→ Distro-Pakete sind oft **veraltet**. Versionsmanager (folgende Folie) bevorzugen.
|
||
|
||
---
|
||
|
||
# Node.js installieren – Windows
|
||
|
||
Empfohlen: **LTS** (aktuell **Node.js 24**).
|
||
|
||
**Option 1: winget** (empfohlen, Win 10/11):
|
||
```powershell
|
||
winget install OpenJS.NodeJS.LTS
|
||
```
|
||
|
||
**Option 2: Chocolatey** ([chocolatey.org](https://chocolatey.org)):
|
||
```powershell
|
||
choco install nodejs-lts
|
||
```
|
||
|
||
**Option 3: Scoop** ([scoop.sh](https://scoop.sh)):
|
||
```powershell
|
||
scoop install nodejs-lts
|
||
```
|
||
|
||
**Option 4:** Installer von [nodejs.org](https://nodejs.org)
|
||
|
||
→ **Empfehlung:** WSL2 + Linux-Workflow nutzen.
|
||
|
||
---
|
||
|
||
# Direkt-Install: Wenn es eng wird
|
||
|
||
**Typisches Szenario** in Studium und Beruf — drei parallele Projekte mit unterschiedlichen Anforderungen:
|
||
|
||
| Projekt | Stack | Node-Version |
|
||
|---------|-------|--------------|
|
||
| Praktikums-API | Express (Legacy) | 18.x (LTS Hydrogen) |
|
||
| Studienarbeit | Next.js 15 | 22.x (LTS Jod) |
|
||
| Aktuelles Lab-Projekt | neueste Features | 24.x (Iron, current LTS) |
|
||
|
||
System-Install kennt nur **eine** Node-Version global.
|
||
|
||
**Symptome im Alltag:**
|
||
- `npm install` bricht mit `engines`-Warning ab
|
||
- native Module (z. B. `node-sass`) bauen nicht
|
||
- CI-Pipeline ist grün, lokal rot — oder umgekehrt
|
||
- erheblicher Zeitverlust beim Debuggen von Versions-Konflikten
|
||
|
||
→ Lösung: **Versionsmanager** und Node-Version pro Projekt pinnen.
|
||
|
||
---
|
||
|
||
# Node-Versionsmanager
|
||
|
||
Verschiedene Projekte brauchen oft verschiedene Node-Versionen. **Lösung:** Versionsmanager.
|
||
|
||
| Tool | Sprache | Geschwindigkeit | Plattform |
|
||
|------|---------|-----------------|-----------|
|
||
| **nvm** | Bash | langsam (Shell-Funktion) | macOS, Linux |
|
||
| **fnm** | Rust | sehr schnell | macOS, Linux, Windows |
|
||
| **asdf** | Bash | mittel, multi-language | macOS, Linux |
|
||
| **volta** | Rust | schnell, pinning per `package.json` | alle |
|
||
|
||
```bash
|
||
# fnm
|
||
curl -fsSL https://fnm.vercel.app/install | bash
|
||
fnm install --lts # aktuell Node 24
|
||
fnm use lts-latest
|
||
|
||
# .nvmrc / .node-version automatisch
|
||
echo "lts/*" > .nvmrc
|
||
fnm use # liest .nvmrc
|
||
```
|
||
|
||
---
|
||
|
||
# Alternative Runtimes
|
||
|
||
| Runtime | Erschienen | Engine | USP |
|
||
|---------|------------|--------|-----|
|
||
| **Node.js** | 2009 | V8 (C++) | Standard, größtes Ökosystem |
|
||
| **Deno** | 2020 | V8 (Rust) | Sicherheit, TypeScript nativ, Std-Lib |
|
||
| **Bun** | 2022 | JavaScriptCore (Zig) | Geschwindigkeit, all-in-one |
|
||
|
||
```bash
|
||
# Deno
|
||
curl -fsSL https://deno.land/install.sh | sh
|
||
deno run main.ts
|
||
|
||
# Bun
|
||
curl -fsSL https://bun.sh/install | bash
|
||
bun install
|
||
bun run dev
|
||
```
|
||
|
||
→ Im Kurs primär **Node.js**. Bun und Deno sind ebenfalls zulässig.
|
||
|
||
---
|
||
|
||
# Editor
|
||
|
||
- **VS Code** (empfohlen) — kostenlos, große Plugin-Auswahl
|
||
- **JetBrains WebStorm** — sehr mächtig, kostenpflichtig
|
||
- kostenlos für Studierende via [JetBrains Education](https://www.jetbrains.com/community/education/#students)
|
||
- **Vim / Neovim / Emacs** — für CLI-Profis
|
||
- **Zed** — modern, schnell
|
||
|
||
---
|
||
|
||
# Browser DevTools
|
||
|
||
Chromium / Firefox / Safari — `F12` oder `Cmd+Opt+I`
|
||
|
||
<small>Chromium = Open-Source-Basis von Chrome, Edge, Brave, Opera, Vivaldi etc.</small>
|
||
|
||
**Wichtigste Panels:**
|
||
- **Network** — HTTP-Requests, Responses, Timing
|
||
- **Console** — `console.log`, JS-Errors, REPL
|
||
- **Elements** — DOM-Inspektor, Live-CSS-Editor
|
||
- **Sources** — Debugger, Breakpoints, Source-Maps
|
||
- **Performance** — Profiling, Frame-Rate, FPS
|
||
- **Application** — LocalStorage, Cookies, Service Workers
|
||
|
||
---
|
||
|
||
# HTTP-Clients
|
||
|
||
- **Bruno** ([usebruno.com](https://usebruno.com)) — open source, git-friendly
|
||
- **Hoppscotch** ([hoppscotch.io](https://hoppscotch.io)) — open source, browser-basiert (vormals Postwoman)
|
||
- **Insomnia** / **Postman** — etabliert, freemium
|
||
- **curl** / **httpie** — CLI (Command-Line Interface, scriptbar)
|
||
|
||
---
|
||
|
||
# Git Setup & Workflow
|
||
|
||
**Einmalige Konfiguration:**
|
||
```bash
|
||
git config --global user.name "Vorname Nachname"
|
||
git config --global user.email "vorname.nachname@example.com"
|
||
git config --global init.defaultBranch main
|
||
git config --global pull.rebase true
|
||
```
|
||
|
||
**SSH-Key für GitHub/GitLab:**
|
||
```bash
|
||
ssh-keygen -t ed25519 -C "vorname.nachname@example.com"
|
||
cat ~/.ssh/id_ed25519.pub # → in GitHub-Settings einfügen
|
||
```
|
||
|
||
**Tägliche Befehle:**
|
||
```bash
|
||
git status # was hat sich geändert?
|
||
git add <file> # für Commit vormerken
|
||
git commit -m "feat: ..." # Conventional Commits
|
||
git push # hochladen
|
||
git pull --rebase # neueste Änderungen holen
|
||
```
|
||
|
||
---
|
||
|
||
# Projekt-Skeleton
|
||
|
||
```bash
|
||
mkdir mein-projekt && cd mein-projekt
|
||
git init
|
||
npm init -y # erzeugt package.json
|
||
echo "node_modules" > .gitignore
|
||
echo ".env" >> .gitignore
|
||
npm install express
|
||
```
|
||
|
||
**`package.json` minimal:**
|
||
```json
|
||
{
|
||
"name": "mein-projekt",
|
||
"version": "0.1.0",
|
||
"type": "module",
|
||
"scripts": {
|
||
"start": "node index.js",
|
||
"dev": "node --watch index.js"
|
||
}
|
||
}
|
||
```
|
||
|
||
`.env` für Secrets (nie committen!), `.env.example` mit Dummy-Werten committen.
|
||
|
||
---
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _header: '' -->
|
||
<!-- _backgroundColor: #000 -->
|
||
|
||
# HTML – Hypertext Markup Language
|
||
|
||
---
|
||
|
||
# Was ist HTML? (1/2)
|
||
|
||
**H**yper**T**ext **M**arkup **L**anguage
|
||
|
||
- **Keine** Programmiersprache
|
||
- Am ehesten eine Formattierungssprache
|
||
- Beschreibt **Struktur und Aufbau** einer Webseite
|
||
|
||
```html
|
||
<p>Das ist ein Absatz.</p>
|
||
<input type="date" />
|
||
```
|
||
|
||
Erfunden 1989 von Tim Berners-Lee. Aktuelle Version: HTML5 (seit 2014).
|
||
|
||
---
|
||
|
||
# Was ist HTML? (2/2)
|
||
|
||
- Mit HTML werden **HTML-Dokumente** beschrieben (`index.html`)
|
||
- Ein HTML-Dokument beschreibt das **Document Object Model (DOM)**
|
||
- Der DOM ist eine **hierarchische Baumstruktur** (Eltern, Kinder, Geschwister)
|
||
- *parent* nodes / elements
|
||
- *child* nodes / elements
|
||
- *sibling* nodes / elements
|
||
|
||
<small>In HTML sprechen wir von **Elementen**, in JavaScript eher von **Nodes**.</small>
|
||
|
||
---
|
||
|
||
# HTML-Anatomie (1/2)
|
||
|
||
Formattierungssprache mit strenger Syntax:
|
||
|
||
```
|
||
<element attribute="value"> ... </element>
|
||
```
|
||
|
||
- Öffnende und schließende Tags müssen identisch sein
|
||
- Schließendes Tag hat ein `/` nach der Spitzklammer
|
||
|
||
---
|
||
|
||
# HTML-Anatomie (2/2)
|
||
|
||
Wir unterscheiden **umschließende** und **selbst-schließende** Tags.
|
||
|
||
**Umschließend:**
|
||
- `<b> ... </b>` – fett-gedruckter Text (inline)
|
||
- `<a> ... </a>` – Hyperlink
|
||
- `<body> ... </body>` – sichtbarer Teil eines HTML-Dokuments
|
||
- `<details> ... </details>` – Aufklapp-Text / Akkordion
|
||
|
||
**Selbst-schließend:**
|
||
- `<img />` – Bild, Vektorgrafik
|
||
- `<input />` – Eingabefeld
|
||
- `<meta />` – Metadaten
|
||
|
||
---
|
||
|
||
# Darstellungsebene und Metadaten
|
||
|
||
```html
|
||
<html>
|
||
<head>
|
||
METADATEN
|
||
</head>
|
||
<body>
|
||
DARSTELLUNGSEBENE
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
Ein HTML-Dokument besteht aus zwei Teilen:
|
||
- `<head> ... </head>` – Metadaten für Browser, Suchmaschinen, Social Sharing
|
||
- `<body> ... </body>` – darzustellender Inhalt, Text, Formulare
|
||
|
||
---
|
||
|
||
# HTML Metadaten
|
||
|
||
```html
|
||
<html>
|
||
<head>
|
||
<title>DHBW Stuttgart</title>
|
||
<meta name="description" content="Studium mit Praxis" />
|
||
<meta property="og:image" content="https://...." />
|
||
</head>
|
||
...
|
||
</html>
|
||
```
|
||
|
||
<small>*Webseiten besuchen nicht nur Menschen, sondern auch Suchmaschinen, Bots, Screen-Reader. Metadaten helfen beim "Verstehen" der Inhalte.*</small>
|
||
|
||
---
|
||
|
||
# HTML Metadaten – Vertiefung
|
||
|
||
| Tag | Funktion |
|
||
|-----|----------|
|
||
| `<title>` | Browser-Tab, Suchergebnis-Titel |
|
||
| `<meta charset>` | Zeichenkodierung (Umlaute!) |
|
||
| `<meta viewport>` | Mobile Darstellung |
|
||
| `<meta description>` | Suchergebnis-Snippet (max 160 Zeichen) |
|
||
|
||
**Open Graph** (Social-Media-Vorschau):
|
||
```html
|
||
<meta property="og:title" content="Artikel-Titel">
|
||
<meta property="og:image" content="https://example.com/preview.jpg">
|
||
```
|
||
|
||
→ Wirkt auf Mastodon, LinkedIn, Signal, Slack, MS Teams ...
|
||
|
||
**SEO:** Google nutzt `<title>` + `<meta description>` für Ranking + Snippet.
|
||
|
||
---
|
||
|
||
# HTML-Tags und Attribute
|
||
|
||

|
||
|
||
```html
|
||
<body>
|
||
<p class="wichtig">Das ist ein wichtiger Absatz.</p>
|
||
<p>Das ist ein gewöhnlicher Absatz.</p>
|
||
</body>
|
||
```
|
||
|
||
| Teil | Bezeichnung |
|
||
|------|-------------|
|
||
| `<p>` | Opening Tag |
|
||
| `class="wichtig"` | Attribut |
|
||
| `Das ist ein wichtiger Absatz.` | Inhalt |
|
||
| `</p>` | Closing Tag |
|
||
|
||
---
|
||
|
||
# HTML-Tags und Attribute (selbst-schließend)
|
||
|
||

|
||
|
||
```html
|
||
Geburtsdatum <input type="date" />
|
||
```
|
||
|
||
| Teil | Bezeichnung |
|
||
|------|-------------|
|
||
| `<input ...` | Eingabefeld |
|
||
| `type="date"` | Attribut *type* mit Wert *date* |
|
||
| `... />` | Schließendes `/` im (öffnenden) Tag |
|
||
|
||
---
|
||
|
||
# Vollständiges Grundgerüst
|
||
|
||

|
||
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<title>Portfolio von ...</title>
|
||
<meta name="description" content="..." />
|
||
<meta property="og:image" content="https://...." />
|
||
</head>
|
||
<body>
|
||
<h1>Hallo Welt!</h1>
|
||
<p>Das ist mein erster Absatz.</p>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
---
|
||
|
||
# Die wichtigsten Tags
|
||
|
||
| Tag | Bedeutung |
|
||
|-----|-----------|
|
||
| `<h1>` … `<h6>` | Überschriften (h1 = größte) |
|
||
| `<p>` | Absatz (Paragraph) |
|
||
| `<a href="..."> ... </a>` | Hyperlink |
|
||
| `<img src="..." />` | Bild |
|
||
| `<ul>`, `<ol>`, `<li>` | Listen |
|
||
| `<div>` | Container / Box |
|
||
| `<span>` | Inline-Container |
|
||
| `<input type="...">` | Eingabefeld |
|
||
|
||
<small>Semantische Tags (`<header>`, `<main>`, `<article>`, `<footer>`, `<nav>`, `<aside>`) wichtig für Accessibility.</small>
|
||
|
||
---
|
||
|
||
# Natives HTML
|
||
|
||
Was früher mit JavaScript gelöst wurde, kann HTML heute selbst. JS dafür einzusetzen ist heute oft ein **Code Smell**.
|
||
|
||
| Funktion | HTML-Element |
|
||
|----------|--------------|
|
||
| Aufklapp-Text | `<details>` + `<summary>` |
|
||
| Popup / Modal | `<dialog>` |
|
||
| Fortschrittsbalken | `<progress>` |
|
||
| Datum-Auswahl | `<input type="date">` |
|
||
| Validierung | Attribute: `required`, `min`, `max`, `pattern` |
|
||
|
||
---
|
||
|
||
# Beispiel: Details/Summary
|
||
|
||
<small>*Akkordion · Accordion · Aufklappmenü · Collapsible*</small>
|
||
|
||

|
||
|
||
```html
|
||
<details>
|
||
<summary>Klick mich!</summary>
|
||
<p>Dieser Text ist versteckt.</p>
|
||
</details>
|
||
```
|
||
|
||
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/details)</small>
|
||
|
||
---
|
||
|
||
# Beispiel: Details/Summary (geöffnet)
|
||
|
||

|
||
|
||
```html
|
||
<details open>
|
||
<summary>Klick mich!</summary>
|
||
<p>Dieser Text war versteckt.</p>
|
||
</details>
|
||
```
|
||
|
||
---
|
||
|
||
# Beispiel: Button
|
||
|
||

|
||
|
||
```html
|
||
<button>Add to favorites</button>
|
||
```
|
||
|
||
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/button)</small>
|
||
|
||
---
|
||
|
||
# Beispiel: Input/Eingabefeld
|
||
|
||

|
||
|
||
```html
|
||
<input
|
||
type="text"
|
||
maxlength="8"
|
||
size="10" />
|
||
```
|
||
|
||
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/input)</small>
|
||
|
||
---
|
||
|
||
# Beispiel: Dialog
|
||
|
||
<small>*Modal · Modales Fenster · Popup · Overlay · Dialogfenster*</small>
|
||
|
||

|
||
|
||
```html
|
||
<dialog open>
|
||
<p>Greetings, one and all!</p>
|
||
<form method="dialog">
|
||
<button>OK</button>
|
||
</form>
|
||
</dialog>
|
||
```
|
||
|
||
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/dialog)</small>
|
||
|
||
---
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _header: '' -->
|
||
<!-- _backgroundColor: #000 -->
|
||
|
||
# CSS – Cascading Style Sheets
|
||
|
||
---
|
||
|
||
# Was ist CSS?
|
||
|
||
**C**ascading **S**tyle **S**heets
|
||
|
||
```css
|
||
p {
|
||
color: blue;
|
||
font-size: 16px;
|
||
}
|
||
```
|
||
|
||
- Trennt **Inhalt** (HTML) von **Darstellung** (CSS)
|
||
- "Cascading" = Regeln können überschrieben werden
|
||
- Eine CSS-Datei kann viele HTML-Seiten stylen
|
||
|
||
---
|
||
|
||
# CSS einbinden
|
||
|
||
**Option 1: Externe Datei** ✓
|
||
```html
|
||
<link rel="stylesheet" href="style.css">
|
||
```
|
||
|
||
**Option 2: Style-Tag**
|
||
```html
|
||
<style>p { color: blue; }</style>
|
||
```
|
||
|
||
**Option 3: Inline** ✗
|
||
```html
|
||
<p style="color: blue;">...</p>
|
||
```
|
||
|
||
→ Standard ist externe Datei. Inline vermeiden (schwer zu warten, keine Wiederverwendung).
|
||
|
||
---
|
||
|
||
# CSS-Anatomie
|
||
|
||

|
||
|
||
```css
|
||
selector {
|
||
property: value;
|
||
}
|
||
```
|
||
|
||
**Beispiel:**
|
||
```css
|
||
h1 {
|
||
color: #333333;
|
||
font-size: 2rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
```
|
||
|
||
Selektor → was wird gestylt
|
||
Property → welche Eigenschaft
|
||
Value → welcher Wert
|
||
|
||
---
|
||
|
||
# Selektoren: Element
|
||
|
||

|
||
|
||
```css
|
||
/* Alle <p>-Elemente */
|
||
p {
|
||
color: gray;
|
||
}
|
||
|
||
/* Mehrere Elemente gleichzeitig */
|
||
h1, h2, h3 {
|
||
font-family: sans-serif;
|
||
}
|
||
```
|
||
|
||
Element-Selektoren sind die einfachsten. Komma = "oder".
|
||
|
||
---
|
||
|
||
# Selektoren: Klasse
|
||
|
||

|
||
|
||
```html
|
||
<p class="wichtig">Dieser Text ist wichtig.</p>
|
||
<p>Dieser nicht.</p>
|
||
```
|
||
|
||
```css
|
||
.wichtig {
|
||
color: red;
|
||
font-weight: bold;
|
||
}
|
||
```
|
||
|
||
**Punkt** vor dem Namen = Klasse. Beliebig oft anwendbar; ein Element kann mehrere Klassen haben.
|
||
|
||
---
|
||
|
||
# Selektoren: ID
|
||
|
||

|
||
|
||
```html
|
||
<nav id="hauptnavigation">...</nav>
|
||
```
|
||
|
||
```css
|
||
#hauptnavigation {
|
||
background: #333;
|
||
padding: 1rem;
|
||
}
|
||
```
|
||
|
||
**Raute** vor dem Namen = ID.
|
||
|
||
⚠️ IDs sollten **einmalig** pro Seite sein. In der Praxis: Klassen meist besser.
|
||
|
||
---
|
||
|
||
# Selektoren: Kombinationen
|
||
|
||

|
||
|
||
```css
|
||
/* Nachfahre (beliebig tief verschachtelt) */
|
||
article p { line-height: 1.6; }
|
||
|
||
/* Direktes Kind (eine Ebene) */
|
||
nav > a { text-decoration: none; }
|
||
|
||
/* Nächstes Geschwister */
|
||
h2 + p { font-size: 1.2rem; }
|
||
|
||
/* Element mit Klasse */
|
||
p.wichtig { color: red; }
|
||
```
|
||
|
||
---
|
||
|
||
# Spezifität: Welche Regel gewinnt?
|
||
|
||

|
||
|
||
| Selektor | Spezifität |
|
||
|----------|------------|
|
||
| Element (`p`) | 0,0,0,1 |
|
||
| Klasse (`.wichtig`) | 0,0,1,0 |
|
||
| ID (`#header`) | 0,1,0,0 |
|
||
| Inline (`style="..."`) | 1,0,0,0 |
|
||
|
||
```css
|
||
p { color: blue; } /* 0,0,0,1 */
|
||
.text { color: green; } /* 0,0,1,0 → gewinnt */
|
||
#intro { color: red; } /* 0,1,0,0 → gewinnt über beide */
|
||
```
|
||
|
||
---
|
||
|
||
# CSS Spezifität – Vertiefung
|
||
|
||
| Selektor | Inline | IDs | Klassen | Elemente | Gesamt |
|
||
|----------|--------|-----|---------|----------|--------|
|
||
| `p` | 0 | 0 | 0 | 1 | 0,0,0,1 |
|
||
| `.info` | 0 | 0 | 1 | 0 | 0,0,1,0 |
|
||
| `p.info` | 0 | 0 | 1 | 1 | 0,0,1,1 |
|
||
| `#header` | 0 | 1 | 0 | 0 | 0,1,0,0 |
|
||
| `#header .nav a` | 0 | 1 | 1 | 1 | 0,1,1,1 |
|
||
|
||
**Regeln:**
|
||
- Eine Klasse (0,0,1,0) schlägt **jede Anzahl** Elemente (0,0,0,99)
|
||
- Eine ID schlägt jede Anzahl Klassen
|
||
- `!important` bricht alles → vermeiden
|
||
|
||
**Best Practice:** Flache Spezifität. BEM-Methodik (`.block__element--modifier`) hält sie niedrig.
|
||
|
||
---
|
||
|
||
# Box-Modell
|
||
|
||

|
||
|
||
Jedes HTML-Element ist eine rechteckige **Box**.
|
||
|
||
**Schichten innen → außen:**
|
||
|
||
- **content** – Inhalt (Text, Bild)
|
||
- **padding** – Innenabstand
|
||
- **border** – Rahmen
|
||
- **margin** – Außenabstand
|
||
|
||
<small>Gesamt-Breite = `width + padding + border + margin`. Tipp: `box-sizing: border-box` rechnet padding + border mit ein.</small>
|
||
|
||
---
|
||
|
||
# Box-Modell: CSS
|
||
|
||

|
||
|
||
```css
|
||
.box {
|
||
width: 200px;
|
||
height: 100px;
|
||
padding: 20px;
|
||
border: 2px solid black;
|
||
margin: 10px;
|
||
}
|
||
```
|
||
|
||
**Wichtig:**
|
||
```css
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
```
|
||
→ width/height inkludiert padding + border.
|
||
|
||
---
|
||
|
||
# Farben
|
||
|
||

|
||
|
||
CSS kennt fünf Notationen für Farben: **Keyword**, **Hex**, **RGB**, **RGBA** (mit Transparenz) und **HSL**.
|
||
|
||
```css
|
||
/* Keyword */
|
||
color: red;
|
||
color: rebeccapurple;
|
||
|
||
/* Hex */
|
||
color: #FF0000;
|
||
color: #F00;
|
||
|
||
/* RGB / RGBA */
|
||
color: rgb(255, 0, 0);
|
||
color: rgba(255, 0, 0, 0.5);
|
||
|
||
/* HSL */
|
||
color: hsl(0, 100%, 50%);
|
||
```
|
||
|
||
---
|
||
|
||
# Einheiten
|
||
|
||
| Einheit | Bedeutung |
|
||
|---------|-----------|
|
||
| `px` | Pixel (absolut) |
|
||
| `%` | Prozent vom Elternelement |
|
||
| `em` | Relativ zur Schriftgröße des Elements |
|
||
| `rem` | Relativ zur Schriftgröße des Root-Elements |
|
||
| `vw` / `vh` | Prozent der Viewport-Breite/-Höhe |
|
||
|
||
**Empfehlung:**
|
||
`rem` für Schrift, `%` oder `vw/vh` für Layout.
|
||
|
||
---
|
||
|
||
# Pseudo-Klassen
|
||
|
||

|
||
|
||
```css
|
||
/* Hover */
|
||
a:hover { color: red; }
|
||
|
||
/* Besuchter Link */
|
||
a:visited { color: purple; }
|
||
|
||
/* Fokussiertes Element */
|
||
input:focus { border-color: blue; }
|
||
|
||
/* Erstes/n-tes Kind */
|
||
li:first-child { font-weight: bold; }
|
||
li:nth-child(odd) { background: #eee; }
|
||
```
|
||
|
||
`:` vor dem Namen = Pseudo-Klasse.
|
||
|
||
---
|
||
|
||
# Pseudo-Elemente
|
||
|
||

|
||
|
||
```css
|
||
/* Vor dem Inhalt einfügen */
|
||
.required::before {
|
||
content: "* ";
|
||
color: red;
|
||
}
|
||
|
||
/* Erster Buchstabe */
|
||
p::first-letter {
|
||
font-size: 2em;
|
||
}
|
||
```
|
||
|
||
`::` = Pseudo-Element (erzeugt "virtuelles" Element)
|
||
`:` = Pseudo-Klasse (wählt existierendes Element im Zustand)
|
||
|
||
---
|
||
|
||
# Layout: Flexbox
|
||
|
||
```css
|
||
.container {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
}
|
||
```
|
||
|
||
→ Eindimensionales Layout (Zeile *oder* Spalte). Tiefer in `02_css_extended`.
|
||
|
||
---
|
||
|
||
# Layout: Grid
|
||
|
||
```css
|
||
.grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20px;
|
||
}
|
||
```
|
||
|
||
→ Zweidimensionales Layout (Zeilen *und* Spalten gleichzeitig).
|
||
|
||
---
|
||
|
||
# Responsive Design
|
||
|
||

|
||
|
||
```css
|
||
/* Mobile First: Basis-Styles */
|
||
.container {
|
||
padding: 1rem;
|
||
}
|
||
|
||
/* Ab 768px (Tablet) */
|
||
@media (min-width: 768px) {
|
||
.container { padding: 2rem; }
|
||
}
|
||
|
||
/* Ab 1024px (Desktop) */
|
||
@media (min-width: 1024px) {
|
||
.container { padding: 3rem; }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
# Responsive Design – Vertiefung
|
||
|
||
**Mobile First** ist Standard: Basis-CSS für kleine Screens, dann Erweiterungen.
|
||
|
||
| Breakpoint | Gerät | Media Query |
|
||
|------------|-------|-------------|
|
||
| < 576px | Smartphone (Portrait) | Basis |
|
||
| ≥ 576px | Smartphone (Landscape) | `@media (min-width: 576px)` |
|
||
| ≥ 768px | Tablet | `@media (min-width: 768px)` |
|
||
| ≥ 992px | Desktop | `@media (min-width: 992px)` |
|
||
| ≥ 1200px | Large Desktop | `@media (min-width: 1200px)` |
|
||
|
||
**Viewport-Meta-Tag (kritisch!):**
|
||
```html
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
```
|
||
|
||
**Moderne Alternativen:** `clamp()`, Container Queries, CSS Grid `auto-fit`/`auto-fill`.
|
||
|
||
---
|
||
|
||
<!-- _class: invert -->
|
||
<!-- _header: '' -->
|
||
<!-- _backgroundColor: #000 -->
|
||
|
||
# JavaScript
|
||
|
||
---
|
||
|
||
# JavaScript Grundlagen
|
||
|
||
```javascript
|
||
// Variablen
|
||
let name = "Welt";
|
||
const alter = 25;
|
||
|
||
// Funktionen
|
||
function gruss(name) {
|
||
return `Hallo, ${name}!`;
|
||
}
|
||
|
||
// Arrow Functions
|
||
const add = (a, b) => a + b;
|
||
|
||
// Arrays
|
||
const arr = [1, 2, 3];
|
||
arr.map(x => x * 2); // [2, 4, 6]
|
||
```
|
||
|
||
---
|
||
|
||
# DOM Manipulation
|
||
|
||
```javascript
|
||
// Element auswählen
|
||
const title = document.querySelector('h1');
|
||
|
||
// Inhalt ändern
|
||
title.textContent = 'Neue Überschrift';
|
||
|
||
// Event Listener
|
||
button.addEventListener('click', () => {
|
||
alert('Geklickt!');
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
# Fetch API
|
||
|
||
```javascript
|
||
fetch('/api/products')
|
||
.then(res => res.json())
|
||
.then(data => {
|
||
console.log(data);
|
||
})
|
||
.catch(err => console.error(err));
|
||
```
|
||
|
||
---
|
||
|
||
# Async/Await
|
||
|
||
```javascript
|
||
async function loadProducts() {
|
||
try {
|
||
const res = await fetch('/api/products');
|
||
const data = await res.json();
|
||
return data;
|
||
} catch (err) {
|
||
console.error('Fehler:', err);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
<!-- _header: '' -->
|
||
<!-- _footer: '' -->
|
||
<!-- _backgroundColor: #050517 -->
|
||
|
||

|
||
|
||
---
|
||
|
||
<!-- _backgroundColor: #050517 -->
|
||
<!-- _color: #e2e8f0 -->
|
||
|
||
# Web Engineering Mandala
|
||
|
||
Interaktive version: [nextlevelshit.github.io/web-engineering-mandala](https://nextlevelshit.github.io/web-engineering-mandala/)
|
||
|
||
3 Schichten:
|
||
- **Core Layer** — JS, HTML, CSS (vanilla)
|
||
- **Build Layer** — bundlers, runtimes, template engines, pre/post processors
|
||
- **Application Layer** — frontend, backend, frameworks, SSR, CSS-utilities
|
||
|
||
3 Segmente: HTML (blau) · JavaScript (rot) · CSS (grün) · Mittelpunkt: `package.json`
|
||
|
||
---
|
||
|
||
# JavaScript Frameworks – Kategorien
|
||
|
||
| Kategorie | Beispiele |
|
||
|-----------|-----------|
|
||
| **CSS Frameworks** | Tailwind, Bootstrap, shadcn/ui |
|
||
| **Frontend Frameworks** | React, Vue, Svelte, Astro |
|
||
| **Rendering / Meta** | Next.js, Nuxt, Gatsby |
|
||
| **Build Tools / Bundler** | Webpack, Vite, Parcel, esbuild |
|
||
| **Backend Frameworks** | Express, Fastify, NestJS |
|
||
|
||
---
|
||
|
||
# Vanilla JS – Counter
|
||
|
||
```html
|
||
<button id="myButton">Clicked 0 times</button>
|
||
<script>
|
||
let count = 0;
|
||
const btn = document.getElementById('myButton');
|
||
btn.addEventListener('click', () => {
|
||
count++;
|
||
btn.textContent = `Clicked ${count} times`;
|
||
});
|
||
</script>
|
||
```
|
||
|
||
✓ hohe Kompatibilität, simpel
|
||
✗ State-Management, Re-Rendering wird schnell komplex
|
||
|
||
---
|
||
|
||
# React – Counter (JSX)
|
||
|
||
```jsx
|
||
import { useState } from "react";
|
||
|
||
function MyButton() {
|
||
const [count, setCount] = useState(0);
|
||
|
||
return (
|
||
<button onClick={() => setCount(count + 1)}>
|
||
Clicked {count} times
|
||
</button>
|
||
);
|
||
}
|
||
```
|
||
|
||
- **Component-Based** Architecture
|
||
- **Virtual DOM**, JSX, Hooks
|
||
- großes Ökosystem (React Router, Redux, …)
|
||
|
||
---
|
||
|
||
# Vue 3 – Composition API
|
||
|
||
```vue
|
||
<script setup>
|
||
import { ref } from "vue";
|
||
const count = ref(0);
|
||
</script>
|
||
|
||
<template>
|
||
<button @click="count++">
|
||
Clicked {{ count }} times
|
||
</button>
|
||
</template>
|
||
```
|
||
|
||
- **Reactive Data Binding**
|
||
- Single-File Components (`.vue`)
|
||
- Vue Router, Pinia (State)
|
||
|
||
---
|
||
|
||
# Svelte – Counter
|
||
|
||
```svelte
|
||
<script>
|
||
let count = 0;
|
||
</script>
|
||
|
||
<button on:click={() => count += 1}>
|
||
Clicked {count} {count === 1 ? 'time' : 'times'}
|
||
</button>
|
||
```
|
||
|
||
- **Compiler-Based** – kein Runtime-Framework
|
||
- Reactive Assignments (`let`)
|
||
- Built-in Animationen
|
||
|
||
---
|
||
|
||
# Astro – Content-First
|
||
|
||
```astro
|
||
---
|
||
const greeting = "Hallo DHBW";
|
||
---
|
||
<html>
|
||
<body>
|
||
<h1>{greeting}</h1>
|
||
<MyReactButton client:load />
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
- **Islands Architecture** – Komponenten mehrerer Frameworks mischen
|
||
- Default: kein JS im Output (nur statisches HTML)
|
||
- Hydration on demand (`client:load`, `client:visible`)
|
||
|
||
---
|
||
|
||
# Rendering Frameworks
|
||
|
||
| | Frontend | SSR | SSG | File Routing |
|
||
|---|---|---|---|---|
|
||
| **Next.js** | React | ✓ | ✓ | `/app/page.js` |
|
||
| **Nuxt** | Vue | ✓ | ✓ | `/pages/*.vue` |
|
||
| **Gatsby** | React | – | ✓ | GraphQL Data |
|
||
|
||
---
|
||
|
||
# Build Tools – Webpack
|
||
|
||
- Module Bundling (JS, CSS, Images)
|
||
- Module Loaders + großes Plugin-Ökosystem
|
||
- Code Splitting, HMR
|
||
- Konfigurations-lastig (`webpack.config.js`)
|
||
|
||
→ Standard für viele Legacy-Setups.
|
||
|
||
---
|
||
|
||
# Build Tools – Vite
|
||
|
||
```javascript
|
||
// vite.config.js
|
||
import { defineConfig } from "vite";
|
||
|
||
export default defineConfig({
|
||
server: {
|
||
proxy: {
|
||
"/api": {
|
||
target: "http://localhost:4567",
|
||
changeOrigin: true,
|
||
rewrite: (path) => path.replace(/^\/api/, "")
|
||
}
|
||
}
|
||
}
|
||
});
|
||
```
|
||
|
||
- Rollup unter der Haube, **HMR mit ES Modules**
|
||
- Tree-Shaking, Code Splitting, React + Vue out-of-the-box
|
||
|
||
---
|
||
|
||
# Build Tools – Parcel
|
||
|
||
```json
|
||
{
|
||
"name": "my-project",
|
||
"source": "src/index.html",
|
||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||
"scripts": {
|
||
"start": "parcel",
|
||
"build": "parcel build"
|
||
},
|
||
"devDependencies": {
|
||
"parcel": "latest"
|
||
}
|
||
}
|
||
```
|
||
|
||
- **Zero-Config**
|
||
- Auto-Resolution, HMR
|
||
- TS / CSS-Preprocessors out-of-the-box
|
||
|
||
---
|
||
|
||
# Microfrontends
|
||
|
||
- Mehrere unabhängige Frontend-Apps in einer Page
|
||
- Module Federation (Webpack 5)
|
||
- **single-spa**: https://single-spa.js.org/
|
||
- Anwendungsfall: große Teams, unterschiedliche Tech-Stacks pro Domain
|
||
|
||
→ Komplexitätskosten: nur bei echtem Skalierungsbedarf.
|
||
|
||
---
|
||
|
||
# Demo-Repos
|
||
|
||
- https://github.com/nextlevelshit/dhbw-client-js (Counter, multi-framework)
|
||
- https://github.com/nextlevelshit/node-cache-api (API + Tests)
|
||
- https://github.com/nextlevelshit/dhbw-docker (Compose-Stack)
|
||
|