branch-coexist: 3 neue decks 223015b-2026 / 223015c-2026 / dhbw-2026 daneben main

per user-request einen branch der main-content UND rewrite-content trägt — saubere separierung statt symlink/merge-conflict.

struktur:
- slides/<course>/ → main-content restored, eigene assets (kein new-demo-leak)
- slides/<course>-2026/ → rewrite-content, eigene assets (komplett kopiert + new demos)

Makefile: COURSES += 223015b-2026 223015c-2026 dhbw-2026 mit eigenen NAME/KAPITEL/DEPLOY/KLAUSUR-konfig. Klausur für b+c=1, dhbw=leer. Deploy-paths /hdm/223015b-2026 etc.

make build durchlaufen für alle 6 decks, 0 fehler.

dedup: 223015c+dhbw assets identisch in beiden ordnern (kein neu-demos auf b ergänzt). 223015b 86 → 120 files in -2026 (= +34 neue eroeffner/usb-c-drei-achsen/container-vs-codec/etc).
This commit is contained in:
2026-05-14 21:54:15 +02:00
parent 6209f9f3a0
commit 351e3dfc23
467 changed files with 32391 additions and 4701 deletions
+214 -291
View File
@@ -8,354 +8,277 @@ footer: "Michael Czechowski – SoSe 2026"
---
<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; }
pre { background: #0f0f23; color: #f48fb1; border-radius: 8px; border-left: 3px solid #d63384; }
pre code { background: transparent; color: inherit; }
code { background: #1a1a2e; color: #f48fb1; padding: 0.15em 0.4em; border-radius: 4px; }
a { color: var(--color-highlight); }
: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: #f48fb1;
border-radius: 8px;
border-left: 3px solid #d63384;
}
pre code {
background: transparent;
color: inherit;
}
code {
background: #1a1a2e;
color: #f48fb1;
padding: 0.15em 0.4em;
border-radius: 4px;
}
a {
color: var(--color-highlight);
}
</style>
<!-- _class: lead -->
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
# Kapitel 3 — Node.js Basics
## JavaScript außerhalb des Browsers
# Web Engineering
**DHBW Stuttgart** · Informatik / Wirtschaftsinformatik
**Sommersemester 2026** · Sitzung 4 — Node.js: Scripting, Running and Building
---
# Was ist Node.js?
# Ressourcen zum Selbstlernen
**Ryan Dahl, 2009.** JavaScript-Runtime auf V8 (Chrome's JS-Engine).
Vorher: JS war Browser-only.
Mit Node: JS auch als Server, CLI-Tools, Build-Skripte.
**Heute:** Node ist Standard-Backend für viele Web-Apps. Netflix, LinkedIn, NASA, Walmart.
- **CODE CRISPIES** — [codecrispi.es](https://codecrispi.es/)
- **Online Code-Editor** — [codepen.io](https://codepen.io/pen/)
- **MDN** (Mozilla Developer Network) — [developer.mozilla.org/de/](https://developer.mozilla.org/de/)
- **Flexbox-Spiel** — [flexboxfroggy.com](https://flexboxfroggy.com/)
- **Grid-Spiel** — [cssgridgarden.com](https://cssgridgarden.com/)
---
# Warum Node?
# Inhalt
| Vorteil | Was bedeutet das |
|---------|------------------|
| **JS überall** | gleiche Sprache Frontend + Backend |
| **NPM** | größtes Package-Ökosystem (~3 Mio Packages) |
| **Non-blocking I/O** | viele Verbindungen gleichzeitig |
| **Schnell genug** | V8 optimiert JS aggressiv |
| **Cross-platform** | Linux, macOS, Windows |
1. Node.js: was und warum
2. `node --check`, `node -e` (One-Liner)
3. Module: `require` / `import`, `__dirname` / `__filename`
4. HTTP-Server (built-in)
5. `fs` — Dateien lesen / schreiben
6. `package.json` — Aufbau und Lifecycle
7. npm Scripts
8. Module exportieren
---
# Node Versions-Manager
<!-- _class: invert -->
<!-- _backgroundColor: #000 -->
**fnm** (oder `nvm`, `volta`) — pro Projekt Node-Version.
# Node.js – Scripting, Running and Building
```sh
# Installieren (macOS/Linux)
brew install fnm # oder curl-script
---
# Aktuelle LTS
fnm install --lts
fnm use lts-latest # 24.x
# Node.js – Was ist das?
# Pro Projekt
echo "24" > .nvmrc
fnm use # liest .nvmrc
- JavaScript Runtime (V8 Engine)
- Server-side JavaScript
- npm Package Manager
- Ideal für: APIs, CLI Tools, Automation
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/nodejs-usecases.png)
---
# node --check und node -e
```bash
# Syntax check only
node --check script.js
# One-liner
node -e "console.log('Hallo Welt')"
```
**Aktuell:** Node 24 LTS.
---
# Projekt initialisieren
# node -e Beispiele
```sh
mkdir mein-projekt && cd mein-projekt
npm init -y # erzeugt package.json
```bash
# String
node -e "console.log('Hello ' + process.argv[2])" Welt
# Abhängigkeiten installieren
npm install express # → dependencies
npm install -D vitest # → devDependencies (nur dev)
# File reading (ESM via --input-type)
node --input-type=module -e \
"import { readFileSync } from 'node:fs'; \
console.log(readFileSync('data.json', 'utf8'))"
# Skripte ausführen
npm run start
npm test
# JSON parsen
node -e "console.log(JSON.parse(process.argv[1]))" '{"a":1}'
```
`-y` = alle Defaults akzeptieren.
---
# Module laden – ESM (modern)
`"type": "module"` in `package.json` einschalten.
```javascript
// Eigene Datei (Endung .js erforderlich!)
import { add, greet } from "./utils.js";
// npm Modul (default + named import)
import express from "express";
import { Router } from "express";
// Built-in (mit "node:"-Präfix)
import { readFileSync } from "node:fs";
import { join } from "node:path";
```
<small>**Legacy CJS:** `const express = require("express")` — funktioniert noch, aber ESM ist heute Standard.</small>
---
# package.json
# Pfad-Auflösung in ESM
```javascript
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const configPath = join(__dirname, "..", "config.json");
```
<small>In ESM gibt es **kein** automatisches `__dirname` / `__filename` (anders als CJS). Über `import.meta.url` rekonstruieren.</small>
---
# HTTP Server mit Node.js (Built-in)
**ESM** (modern, `"type": "module"` in `package.json`):
```javascript
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/html" });
res.end("<h1>Hallo Welt!</h1>");
});
server.listen(3000, () => {
console.log("Server läuft auf Port 3000");
});
```
<small>**CommonJS** (legacy): `const http = require("http");` — funktioniert noch, aber neue Projekte nutzen ESM.</small>
---
# fs – Dateien lesen/schreiben
```javascript
import { readFile, readFileSync, writeFile } from "node:fs";
import { readFile as readFileAsync } from "node:fs/promises";
// Promise-API (empfohlen, modern)
const data = await readFileAsync("data.json", "utf8");
console.log(JSON.parse(data));
// Callback-API
readFile("data.json", "utf8", (err, data) => {
if (err) throw err;
console.log(JSON.parse(data));
});
// Sync (nur für Setup / Scripts)
const content = readFileSync("data.json", "utf8");
```
---
# package.json – Das Herzstück
```json
{
"name": "mein-projekt",
"version": "0.1.0",
"type": "module",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "node --watch src/server.js",
"start": "node src/server.js",
"test": "vitest"
"start": "node index.js",
"dev": "node --watch index.js",
"test": "node --test"
},
"dependencies": {
"express": "^5.0.0"
"express": "^4.18.0"
},
"devDependencies": {
"vitest": "^2.0.0"
"nodemon": "^3.0.0"
}
}
```
`"type": "module"` aktiviert ESM.
---
# ESM — modern
# npm Scripts
```javascript
// utils.js
export function greet(name) {
return `Hallo ${name}`;
}
```bash
# npm run <script>
npm run start
npm run dev
export const VERSION = "1.0";
# Mit Argumenten
npm run build -- --production
// main.js
import { greet, VERSION } from './utils.js';
console.log(greet('Ada'), VERSION);
```
**Pflicht:** `.js`-Endung in import-Pfad.
---
# CommonJS — Legacy
```javascript
// utils.cjs
function greet(name) {
return `Hallo ${name}`;
}
module.exports = { greet };
// main.cjs
const { greet } = require('./utils.cjs');
```
**Wann CJS?** Alte Codebases, npm-Packages, die nicht migriert sind. **Default heute:** ESM.
---
# Built-in Modules
```javascript
import { readFile } from 'node:fs/promises';
import { createServer } from 'node:http';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
```
`node:` Prefix macht explizit klar — kein npm-Package.
---
<!-- _class: lead -->
# HTTP-Server
---
# Eingebauter HTTP-Server
```javascript
import { createServer } from 'node:http';
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hallo Welt');
});
server.listen(3000, () => {
console.log('Server läuft auf :3000');
});
```
Nackt — ohne Framework. **Funktioniert.**
---
# Express — der Klassiker
```javascript
import express from 'express';
const app = express();
app.use(express.json()); // parsed JSON-Body
app.use(express.static('public')); // statische Dateien
app.get('/', (req, res) => {
res.send('Hallo Welt');
});
app.post('/api/echo', (req, res) => {
res.json({ youSent: req.body });
});
app.listen(3000);
# Lifecycle scripts
npm install → postinstall
npm start → start (direkt)
```
---
# REST mit Express
# Node.js Module – exports (ESM)
```javascript
const users = [{ id: 1, name: 'Ada' }];
// utils.js — named exports
export const add = (a, b) => a + b;
export const greet = (name) => `Hallo ${name}!`;
app.get('/users', (req, res) => res.json(users));
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id == req.params.id);
user ? res.json(user) : res.sendStatus(404);
});
app.post('/users', (req, res) => {
const user = { id: users.length + 1, ...req.body };
users.push(user);
res.status(201).json(user);
});
```
---
# Alternative Frameworks
| Framework | Stärke |
|-----------|--------|
| **Express** | etabliert, größte Community |
| **Fastify** | schneller, schemas eingebaut |
| **Hono** | leichtgewichtig, Edge-deployable |
| **Koa** | von Express-Autoren, modern |
Für DHBW: **Express** oder **Hono**.
---
# Routing-Pattern
```javascript
import { Router } from 'express';
const userRouter = Router();
userRouter.get('/', (req, res) => { /* alle Users */ });
userRouter.get('/:id', (req, res) => { /* ein User */ });
userRouter.post('/', (req, res) => { /* User anlegen */ });
userRouter.put('/:id', (req, res) => { /* User update */ });
userRouter.delete('/:id', (req, res) => { /* User löschen */ });
app.use('/users', userRouter); // mountet unter /users/*
```
---
<!-- _class: lead -->
# Fetch in Node
---
# fetch — global ab Node 18
```javascript
// GET
const res = await fetch('https://api.github.com/users/torvalds');
const data = await res.json();
console.log(data.public_repos);
// POST
const post = await fetch('https://api.example.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Hallo' })
});
```
Genau wie im Browser. **Kein extra Package** (vorher: `node-fetch`, `axios`).
---
# Error-Handling
```javascript
try {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const data = await res.json();
return data;
} catch (error) {
console.error('API call failed:', error.message);
throw error; // re-throw für caller
}
```
`res.ok` ist `true` für 2xx-Statuscodes.
---
# Environment Variables
```javascript
// .env (gitignored!)
DATABASE_URL=postgres://...
API_KEY=sk-...
PORT=3000
// src/config.js
import 'dotenv/config';
export const config = {
port: process.env.PORT || 3000,
dbUrl: process.env.DATABASE_URL,
apiKey: process.env.API_KEY,
// utils.js — default export
export default {
add,
greet
};
```
**Niemals** API-Keys ins Repo committen.
```javascript
// nutzen
import { add, greet } from "./utils.js"; // named
import utils from "./utils.js"; // default
import utils, { add } from "./utils.js"; // beides
```
---
<small>**Legacy CJS:** `module.exports = { add, greet }` + `const { add } = require("./utils")`.</small>
<!-- _class: aufgabe -->
# Selbstlernen — Mini-API
1. **Projekt initialisieren:** `npm init -y`, ESM aktivieren
2. **Express installieren**
3. **REST-API** für eine Ressource (Books / Movies / TODO)
- `GET /items`, `GET /items/:id`, `POST /items`, `DELETE /items/:id`
4. **In-Memory-Store** als Array (echte DB kommt Kap 4)
5. **Mit Hoppscotch oder curl** testen
**Bonus:** `npm run dev` mit `--watch`-Flag.
---
# Zusammenfassung
**Heute gelernt:**
- Node.js als JS-Runtime außerhalb Browser
- **fnm + Node 24 LTS** als Versions-Setup
- **npm init**, package.json, scripts, dependencies
- **ESM** (import/export) als modernes Modul-System
- Built-in HTTP-Server + **Express** für REST
- **fetch** global ab Node 18
- **.env + dotenv** für Secrets
**Nächste Stunde:** async/await, Filesystem, Datenbank, Auth.