App-Übersicht
Ich habe „Own Info App" veröffentlicht, eine kleine Webanwendung, mit der Sie schnell Netzwerkinformationen (z. B. Ihre globale IP-Adresse) sowie Browser-/Geräteinformationen überprüfen und sofort kopieren/teilen können.
https://x.com/Sloth255000/status/1986792593569763395- Quelltechnologie (Teilkonfiguration): Next.js 15 (App Router), React 19, TypeScript, Tailwind CSS
- Distribution: S3 + CloudFront (Static Export)
- Mehrsprachig: Englisch/Japanisch/Chinesisch/Koreanisch/Deutsch/Französisch/Spanisch/Portugiesisch
- Analytics: Firebase Analytics
Seitenübergänge und UI sind so einfach wie möglich gehalten. Einfach öffnen, die benötigten Informationen „kopieren" oder „teilen" und schließen – das ist alles.
Tech-Stack und Design-Punkte
1) Next.js 15 App Router × Static Export
- Vollständig statische Ausgabe (SSG) mit
output: 'export' - Ausgabedateien haben eine flache Struktur mit
index.html,en.html,ja.htmlusw. direkt im out-Verzeichnis
Diese Konfiguration macht CDN-Distribution und Caching einfach und erzeugt eine schnelle App ohne dynamische Server oder SSR.
2) URL-Rewriting mit CloudFront Functions
Verwendung von CloudFront Functions (cloudfront-js-2.0) für leichtgewichtiges URL → Datei-Mapping.
/→/index.html/ja→/ja.html(Trailing Slash wird ähnlich behandelt)/contact,/privacy,/licenses→ jeweilige*.html-Dateien- URIs mit Erweiterungen (.svg, .js, .css, ...) werden ohne Rewriting durchgelassen
- Nicht unterstützte Locales werden zu
/en/_not-foundweitergeleitet
3) i18n und Routing
- Unterstützte Sprachen:
en, ja, zh, ko, de, fr, es, pt - Übersetzungen getrennt in
src/locales/*.json, SSG für jede Locale im App Router - Root
/rendert die Standardsprache (en) äquivalent zu SSR für SEO & Bots, während bei Browser-Besuchen eine einmalige Client-Weiterleitung zur Locale-Seite basierend aufnavigator.languagesdurchgeführt wird
4) SEO und OGP/Twitter Cards (pro Locale)
generateMetadata()für jede Seite implementiert, um „canonical / og:url / og:image / og:locale" pro Sprache korrekt auszugeben- OGP-Bilder (
public/og-*.png) für jede Sprache vorbereitet, mit Beschreibungstext in Bildern aus Übersetzungstexten erstellt - Strukturierte Daten (JSON-LD) pro Locale in Server-Komponenten ausgegeben (
application/ld+json). Alle 8 Sprachen explizit ininLanguageangegeben
// Beispiel: Ausgabe strukturierter Daten (Auszug)
export default function StructuredData({ title, description, siteUrl }: Props) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'WebApplication',
name: title,
description,
url: siteUrl || '/',
applicationCategory: 'UtilityApplication',
operatingSystem: 'Web Browser',
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
inLanguage: [
{ '@type': 'Language', name: 'English', alternateName: 'en' },
{ '@type': 'Language', name: 'Japanese', alternateName: 'ja' },
{ '@type': 'Language', name: 'Chinese', alternateName: 'zh' },
{ '@type': 'Language', name: 'Korean', alternateName: 'ko' },
{ '@type': 'Language', name: 'German', alternateName: 'de' },
{ '@type': 'Language', name: 'French', alternateName: 'fr' },
{ '@type': 'Language', name: 'Spanish', alternateName: 'es' },
{ '@type': 'Language', name: 'Portuguese', alternateName: 'pt' },
],
};
return <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />;
}
5) Korrekte <html lang>-Angabe pro Locale
Im App Router gibt es die Einschränkung, dass „das <html> des Root-Layouts allen Seiten gemeinsam ist", was dazu führt, dass <html lang="en"> zum Build-Zeitpunkt bestehen bleibt.
Diesmal habe ich eine schlanke Komponente eingebaut, die „<html lang> clientseitig überschreibt" – sowohl im Locale-Layout als auch auf der Root-Seite –, um während der tatsächlichen Nutzung auf das korrekte Sprach-Tag zu aktualisieren.
'use client'
import { useEffect } from 'react'
export default function HtmlLangSetterClient({ lang }: { lang: string }) {
useEffect(() => {
document.documentElement.setAttribute('lang', lang)
}, [lang])
return null
}
Den Unterschied zwischen statischem HTML zur Build-Zeit und dem tatsächlich von Benutzern gesehenen DOM so gering wie möglich haltend, habe ich eine praktische Implementierung unter den Static-Export-Einschränkungen erreicht.
Deployment/Betrieb
Infrastruktur
- S3 (statisches Hosting) + CloudFront (Origin ist S3s Website-Endpunkt)
- CloudFront Functions separat deployed (SAM-Template für Ressourcenerstellung, Code-Updates auf CI-Seite)
CI/CD (GitHub Actions)
- Ausgelöst durch Push auf
main:- Next.js Build (Static Export)
- S3-Sync
/_next/staticmitmax-age=31536000, immutable- HTML mit
max-age=300, must-revalidate
- CloudFront Function Code-Update (
update-function→publish-function) - CloudFront Invalidation (
/*) bei Bedarf
AWS-Credentials, S3-Bucket, CloudFront Distribution ID und NEXT_PUBLIC_* sind als Secrets/Vars konfiguriert.
Manuelle Updates über CLI sind möglich, aber grundsätzlich dem CI überlassen.
Zusammenfassung
- Lokalisierung
- Minimales SEO
- Minimale Infrastrukturkonfiguration
- CI/CD & IaC
Als ich mit der persönlichen Entwicklung begann, wollte ich den gesamten Prozess der Veröffentlichung einer App durchlaufen – irgendetwas –, so wurde es diese Art von einfacher, kostengünstiger App.
Ich freue mich, dass ich zum ersten Mal Next.js ausprobieren konnte. Als Nächstes werde ich versuchen, auf Vercel mit SSR statt SSG zu deployen.
