refactor: standardize HTML and JavaScript formatting; improve readability

This commit is contained in:
Sascha 2026-03-26 21:19:58 +01:00
parent bdbce1c3ad
commit 1fbc500c19
2 changed files with 78 additions and 54 deletions

View File

@ -1,14 +1,22 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Primary Meta Tags --> <!-- Primary Meta Tags -->
<title>Sascha Bach | Freelance Software Developer Accessible Web Development</title> <title>
<meta name="description" content="Freelance software developer in Germany specializing in accessible web development. I build inclusive websites compliant with the Accessibility Act using React, TypeScript, and modern frameworks." /> Sascha Bach | Freelance Software Developer Accessible Web Development
</title>
<meta
name="description"
content="Freelance software developer in Germany specializing in accessible web development. I build inclusive websites compliant with the Accessibility Act using React, TypeScript, and modern frameworks."
/>
<meta name="author" content="Sascha Bach" /> <meta name="author" content="Sascha Bach" />
<meta name="keywords" content="freelance software developer, accessible web development, barrierefreie Webentwicklung, React developer, TypeScript, web accessibility, BFSG, Germany" /> <meta
name="keywords"
content="freelance software developer, accessible web development, barrierefreie Webentwicklung, React developer, TypeScript, web accessibility, BFSG, Germany"
/>
<link rel="canonical" href="https://sascha-bach.de/" /> <link rel="canonical" href="https://sascha-bach.de/" />
<!-- Hreflang for multi-language --> <!-- Hreflang for multi-language -->
@ -19,16 +27,28 @@
<!-- Open Graph / Facebook --> <!-- Open Graph / Facebook -->
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://sascha-bach.de/" /> <meta property="og:url" content="https://sascha-bach.de/" />
<meta property="og:title" content="Sascha Bach | Freelance Software Developer" /> <meta
<meta property="og:description" content="Freelance software developer in Germany specializing in accessible web development. Building inclusive websites compliant with the Accessibility Act." /> property="og:title"
content="Sascha Bach | Freelance Software Developer"
/>
<meta
property="og:description"
content="Freelance software developer in Germany specializing in accessible web development. Building inclusive websites compliant with the Accessibility Act."
/>
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:locale:alternate" content="de_DE" /> <meta property="og:locale:alternate" content="de_DE" />
<meta property="og:site_name" content="Sascha Bach Portfolio" /> <meta property="og:site_name" content="Sascha Bach Portfolio" />
<!-- Twitter --> <!-- Twitter -->
<meta name="twitter:card" content="summary" /> <meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Sascha Bach | Freelance Software Developer" /> <meta
<meta name="twitter:description" content="Freelance software developer in Germany specializing in accessible web development. Building inclusive websites compliant with the Accessibility Act." /> name="twitter:title"
content="Sascha Bach | Freelance Software Developer"
/>
<meta
name="twitter:description"
content="Freelance software developer in Germany specializing in accessible web development. Building inclusive websites compliant with the Accessibility Act."
/>
<!-- JSON-LD Structured Data --> <!-- JSON-LD Structured Data -->
<script type="application/ld+json"> <script type="application/ld+json">
@ -77,7 +97,11 @@
<div id="root"></div> <div id="root"></div>
<noscript> <noscript>
<h1>Sascha Bach Freelance Software Developer</h1> <h1>Sascha Bach Freelance Software Developer</h1>
<p>Freelance software developer in Germany specializing in accessible web development. Building inclusive websites compliant with the Accessibility Act using React, TypeScript, and modern frameworks.</p> <p>
Freelance software developer in Germany specializing in accessible web
development. Building inclusive websites compliant with the
Accessibility Act using React, TypeScript, and modern frameworks.
</p>
<p>Contact: freelancer [at] sascha-bach.de</p> <p>Contact: freelancer [at] sascha-bach.de</p>
<p>Visit with JavaScript enabled for the full experience.</p> <p>Visit with JavaScript enabled for the full experience.</p>
</noscript> </noscript>

View File

@ -6,17 +6,17 @@
* Usage: node prerender.js (run after `vite build`) * Usage: node prerender.js (run after `vite build`)
*/ */
import { createServer } from 'http'; import { createServer } from 'http'
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'; import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'
import { join, dirname } from 'path'; import { join, dirname } from 'path'
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url'
import puppeteer from 'puppeteer'; import puppeteer from 'puppeteer'
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url))
const DIST = join(__dirname, 'dist'); const DIST = join(__dirname, 'dist')
const PORT = 4173; const PORT = 4173
const ROUTES = ['/', '/technical', '/imprint', '/privacy-policy']; const ROUTES = ['/', '/technical', '/imprint', '/privacy-policy']
/** Minimal static file server that falls back to index.html (SPA). */ /** Minimal static file server that falls back to index.html (SPA). */
function startServer() { function startServer() {
@ -31,71 +31,71 @@ function startServer() {
'.pdf': 'application/pdf', '.pdf': 'application/pdf',
'.woff2': 'font/woff2', '.woff2': 'font/woff2',
'.woff': 'font/woff', '.woff': 'font/woff',
}; }
const server = createServer((req, res) => { const server = createServer((req, res) => {
let filePath = join(DIST, req.url === '/' ? '/index.html' : req.url); let filePath = join(DIST, req.url === '/' ? '/index.html' : req.url)
if (!existsSync(filePath) || !filePath.includes('.')) { if (!existsSync(filePath) || !filePath.includes('.')) {
filePath = join(DIST, 'index.html'); filePath = join(DIST, 'index.html')
} }
const ext = '.' + filePath.split('.').pop(); const ext = '.' + filePath.split('.').pop()
const contentType = mimeTypes[ext] || 'application/octet-stream'; const contentType = mimeTypes[ext] || 'application/octet-stream'
try { try {
const content = readFileSync(filePath); const content = readFileSync(filePath)
res.writeHead(200, { 'Content-Type': contentType }); res.writeHead(200, { 'Content-Type': contentType })
res.end(content); res.end(content)
} catch { } catch {
res.writeHead(404); res.writeHead(404)
res.end('Not found'); res.end('Not found')
} }
}); })
return new Promise((resolve) => { return new Promise((resolve) => {
server.listen(PORT, () => { server.listen(PORT, () => {
console.log(` Server running on http://localhost:${PORT}`); console.log(` Server running on http://localhost:${PORT}`)
resolve(server); resolve(server)
}); })
}); })
} }
async function prerender() { async function prerender() {
console.log('\n🔍 Prerendering routes...\n'); console.log('\n🔍 Prerendering routes...\n')
const server = await startServer(); const server = await startServer()
const browser = await puppeteer.launch({ headless: true }); const browser = await puppeteer.launch({ headless: true })
for (const route of ROUTES) { for (const route of ROUTES) {
const page = await browser.newPage(); const page = await browser.newPage()
const url = `http://localhost:${PORT}${route}`; const url = `http://localhost:${PORT}${route}`
console.log(` Rendering ${route} ...`); console.log(` Rendering ${route} ...`)
await page.goto(url, { waitUntil: 'networkidle0', timeout: 15000 }); await page.goto(url, { waitUntil: 'networkidle0', timeout: 15000 })
// Wait a bit for React to finish any async rendering // Wait a bit for React to finish any async rendering
await new Promise((r) => setTimeout(r, 1500)); await new Promise((r) => setTimeout(r, 1500))
const html = await page.content(); const html = await page.content()
await page.close(); await page.close()
// Write to dist/<route>/index.html // Write to dist/<route>/index.html
const outDir = route === '/' ? DIST : join(DIST, route); const outDir = route === '/' ? DIST : join(DIST, route)
if (!existsSync(outDir)) { if (!existsSync(outDir)) {
mkdirSync(outDir, { recursive: true }); mkdirSync(outDir, { recursive: true })
} }
const outFile = join(outDir, 'index.html'); const outFile = join(outDir, 'index.html')
writeFileSync(outFile, html, 'utf-8'); writeFileSync(outFile, html, 'utf-8')
console.log(` ✓ Saved ${outFile.replace(DIST, 'dist')}`); console.log(` ✓ Saved ${outFile.replace(DIST, 'dist')}`)
} }
await browser.close(); await browser.close()
server.close(); server.close()
console.log('\n✅ Prerendering complete!\n'); console.log('\n✅ Prerendering complete!\n')
} }
prerender().catch((err) => { prerender().catch((err) => {
console.error('Prerendering failed:', err); console.error('Prerendering failed:', err)
process.exit(1); process.exit(1)
}); })