[{"data":1,"prerenderedAt":53},["ShallowReactive",2],{"article-building-with-nuxt4":3},{"slug":4,"date":5,"tags":6,"coverImage":11,"url":11,"translations":12},"building-with-nuxt4","2026-05-01",[7,8,9,10],"dev","nuxt","web","firebase",null,{"en":13,"fr":17,"de":21,"es":25,"it":29,"nl":33,"no":37,"pl":41,"pt":45,"tr":49},{"title":14,"summary":15,"body":16},"How I rebuilt my personal site with Nuxt 4 and Firebase","My old site was a single static HTML file. Here's how and why I rebuilt it with Nuxt 4, Tailwind CSS, Firebase Hosting, and a fully custom multilingual system covering 10 languages.","## The old site\n\nFor a long time, my personal site was a single `index.html` file. Minimal, fast, and easy to maintain. It did the job — but as I started building more projects and wanted a proper news feed, it wasn't going to scale.\n\nI decided to do a full rebuild.\n\n## Why Nuxt 4\n\nI chose **Nuxt 4** for a few specific reasons:\n\n- **Static generation** — `nuxt generate` produces a fully static output compatible with Firebase Hosting\n- **File-based routing** — Article pages at `/news/[slug]` just work with zero configuration\n- **TypeScript-first** — The entire codebase is typed, from server routes to composables\n- **SSR + hydration** — Pages are pre-rendered on the server and hydrated on the client, which is ideal for SEO\n\n## The stack\n\n- **Nuxt 4** (compatibility version 4) — App directory structure, SSR with static generation\n- **Tailwind CSS** — Utility-first styling with no component library overhead\n- **Firebase Hosting** — Global CDN, near-zero config deploys with `firebase deploy`\n- **Custom i18n** — A hand-rolled composable using `vue-i18n` directly, no module needed\n- **Nitro server routes** — Articles are stored as local JSON files and served via `server/api/` endpoints\n\n## The multilingual system\n\nThe site supports 10 languages: English, French, German, Spanish, Italian, Dutch, Norwegian, Polish, Portuguese, and Turkish.\n\nI deliberately avoided `@nuxtjs/i18n`. For a personal site with this scope, the module brings too much weight and complexity. Instead, I wrote a `useI18n()` composable that wraps `vue-i18n` directly and reads from a `locale` cookie. Switching languages is instant and doesn't require a page reload.\n\n## Articles as local JSON\n\nEach article is a single JSON file in `content/articles/`. The schema is simple:\n\n- `slug` — the URL key\n- `date` — ISO date string\n- `tags` — array of strings\n- `url` — optional external link\n- `translations` — an object with one entry per locale, each containing `title`, `summary`, and `body` (Markdown text)\n\nThis means every article is fully translated at the content layer. The page component just picks the right translation based on the current locale — no external service, no API call.\n\n## SEO and prerendering\n\nFor each article to be properly indexed, it needs its own static HTML file. A `nitro:config` hook reads the `content/articles/` directory before the Vite build and adds every `/news/[slug]` route to the prerender list.\n\nEach article page uses `useSeoMeta()` for meta tags and `useHead()` for canonical + hreflang links across all 10 locales. Google can index every article in every language from a single URL.\n\n## What I'd do differently\n\nThe main thing I underestimated was hydration. With SSR, any mismatch between what the server renders and what the client expects causes Vue hydration warnings. The most common culprit: conditional rendering based on client-only state (like a cookie or `localStorage`). The fix is wrapping those blocks in `\u003CClientOnly>` or initializing state carefully from the server.\n\n## What's next\n\nThe rebuild is complete. The site now has proper routing, a news feed, and full multilingual support. I plan to keep publishing here — new Reloadium launches, product thinking, and the occasional technical deep-dive.",{"title":18,"summary":19,"body":20},"Comment j'ai reconstruit mon site personnel avec Nuxt 4 et Firebase","Mon ancien site était un simple fichier HTML statique. Voici comment et pourquoi je l'ai reconstruit avec Nuxt 4, Tailwind CSS, Firebase Hosting, et un système multilingue personnalisé couvrant 10 langues.","## L'ancien site\n\nPendant longtemps, mon site personnel était un seul fichier `index.html`. Minimal, rapide et facile à maintenir — mais pas extensible. J'ai décidé de faire une reconstruction complète.\n\n## Pourquoi Nuxt 4\n\nJ'ai choisi **Nuxt 4** pour plusieurs raisons précises :\n\n- **Génération statique** — `nuxt generate` produit une sortie statique compatible avec Firebase Hosting\n- **Routage basé sur les fichiers** — Les pages d'articles à `/news/[slug]` fonctionnent sans configuration\n- **TypeScript natif** — Toute la codebase est typée\n- **SSR + hydratation** — Idéal pour le SEO\n\n## La stack\n\n- **Nuxt 4** avec structure de répertoire `app/`, SSR avec génération statique\n- **Tailwind CSS** — Styles utilitaires sans surcharge de bibliothèque de composants\n- **Firebase Hosting** — CDN mondial, déploiements en une commande\n- **i18n personnalisé** — Un composable maison utilisant directement `vue-i18n`\n- **Routes serveur Nitro** — Articles stockés en JSON local servis via `server/api/`\n\n## Le système multilingue\n\nLe site supporte 10 langues. J'ai délibérément évité `@nuxtjs/i18n`. À la place, j'ai écrit un composable `useI18n()` qui lit depuis un cookie `locale`. Le changement de langue est instantané sans rechargement de page.\n\n## Articles comme JSON local\n\nChaque article est un fichier JSON dans `content/articles/` avec un objet `translations` — une entrée par locale avec `title`, `summary` et `body` en Markdown.\n\n## SEO et prérendu\n\nUn hook `nitro:config` lit le répertoire `content/articles/` avant le build Vite et ajoute chaque route `/news/[slug]` à la liste de prérendu. Chaque page utilise `useSeoMeta()` et `useHead()` avec des liens hreflang pour toutes les 10 locales.\n\n## La suite\n\nLe site dispose maintenant d'un routage approprié, d'un fil d'actualités et d'un support multilingue complet.",{"title":22,"summary":23,"body":24},"Wie ich meine persönliche Website mit Nuxt 4 und Firebase neu aufgebaut habe","Meine alte Website war eine einzelne statische HTML-Datei. So und warum ich sie mit Nuxt 4, Tailwind CSS, Firebase Hosting und einem vollständig angepassten Mehrsprachsystem für 10 Sprachen neu aufgebaut habe.","## Die alte Website\n\nLange Zeit war meine persönliche Website eine einzelne `index.html`-Datei. Minimal und schnell — aber nicht skalierbar. Ich entschied mich für einen vollständigen Neuaufbau.\n\n## Warum Nuxt 4\n\n- **Statische Generierung** — `nuxt generate` erzeugt statische Ausgabe für Firebase Hosting\n- **Dateibasiertes Routing** — Artikelseiten unter `/news/[slug]` funktionieren ohne Konfiguration\n- **TypeScript-first** — Die gesamte Codebasis ist typisiert\n- **SSR + Hydration** — Ideal für SEO\n\n## Der Stack\n\n- **Nuxt 4** — App-Verzeichnisstruktur, SSR mit statischer Generierung\n- **Tailwind CSS** — Utility-first Styling\n- **Firebase Hosting** — Globales CDN, einfache Deployments\n- **Eigenes i18n** — Ein handgeschriebenes Composable mit `vue-i18n`\n- **Nitro Server-Routen** — Artikel als lokale JSON-Dateien\n\n## Das Mehrsprachsystem\n\nDie Website unterstützt 10 Sprachen. Ich habe `@nuxtjs/i18n` bewusst vermieden und stattdessen ein `useI18n()`-Composable geschrieben, das aus einem `locale`-Cookie liest.\n\n## Artikel als lokales JSON\n\nJeder Artikel ist eine JSON-Datei mit einem `translations`-Objekt — ein Eintrag pro Locale mit `title`, `summary` und `body` in Markdown.\n\n## SEO und Pre-Rendering\n\nEin `nitro:config`-Hook liest das `content/articles/`-Verzeichnis vor dem Vite-Build und fügt jede `/news/[slug]`-Route zur Pre-Render-Liste hinzu.\n\n## Ausblick\n\nDie Website hat jetzt ordentliches Routing, einen News-Feed und vollständige Mehrsprachunterstützung.",{"title":26,"summary":27,"body":28},"Cómo reconstruí mi sitio personal con Nuxt 4 y Firebase","Mi antiguo sitio era un único archivo HTML estático. Así es cómo y por qué lo reconstruí con Nuxt 4, Tailwind CSS, Firebase Hosting y un sistema multilingüe personalizado que cubre 10 idiomas.","## El sitio antiguo\n\nDurante mucho tiempo, mi sitio personal fue un único archivo `index.html`. Mínimo y rápido — pero no escalable. Decidí hacer una reconstrucción completa.\n\n## Por qué Nuxt 4\n\n- **Generación estática** — `nuxt generate` produce salida estática compatible con Firebase Hosting\n- **Enrutamiento basado en archivos** — Las páginas de artículos en `/news/[slug]` funcionan sin configuración\n- **TypeScript primero** — Todo el código base está tipado\n- **SSR + hidratación** — Ideal para SEO\n\n## El stack\n\n- **Nuxt 4** con estructura de directorio `app/`, SSR con generación estática\n- **Tailwind CSS** — Estilos utility-first\n- **Firebase Hosting** — CDN global, despliegues sencillos\n- **i18n personalizado** — Un composable propio usando `vue-i18n`\n- **Rutas de servidor Nitro** — Artículos como archivos JSON locales\n\n## El sistema multilingüe\n\nEl sitio soporta 10 idiomas. Evité deliberadamente `@nuxtjs/i18n` y escribí un composable `useI18n()` que lee desde una cookie `locale`.\n\n## Artículos como JSON local\n\nCada artículo es un archivo JSON con un objeto `translations` — una entrada por locale con `title`, `summary` y `body` en Markdown.\n\n## SEO y prerrenderizado\n\nUn hook `nitro:config` lee el directorio `content/articles/` antes del build y añade cada ruta `/news/[slug]` a la lista de prerrenderizado.\n\n## Lo que sigue\n\nEl sitio tiene ahora enrutamiento adecuado, un feed de noticias y soporte multilingüe completo.",{"title":30,"summary":31,"body":32},"Come ho ricostruito il mio sito personale con Nuxt 4 e Firebase","Il mio vecchio sito era un singolo file HTML statico. Ecco come e perché l'ho ricostruito con Nuxt 4, Tailwind CSS, Firebase Hosting e un sistema multilingua personalizzato per 10 lingue.","## Il vecchio sito\n\nPer molto tempo, il mio sito personale era un singolo file `index.html`. Minimale e veloce — ma non scalabile. Ho deciso di fare una ricostruzione completa.\n\n## Perché Nuxt 4\n\n- **Generazione statica** — `nuxt generate` produce output statico compatibile con Firebase Hosting\n- **Routing basato sui file** — Le pagine degli articoli a `/news/[slug]` funzionano senza configurazione\n- **TypeScript-first** — L'intero codebase è tipizzato\n- **SSR + idratazione** — Ideale per la SEO\n\n## Lo stack\n\n- **Nuxt 4** con struttura di directory `app/`, SSR con generazione statica\n- **Tailwind CSS** — Stili utility-first\n- **Firebase Hosting** — CDN globale, deploy semplici\n- **i18n personalizzato** — Un composable artigianale con `vue-i18n`\n- **Route server Nitro** — Articoli come file JSON locali\n\n## Il sistema multilingua\n\nIl sito supporta 10 lingue. Ho evitato `@nuxtjs/i18n` e scritto un composable `useI18n()` che legge da un cookie `locale`.\n\n## Articoli come JSON locale\n\nOgni articolo è un file JSON con un oggetto `translations` — una voce per locale con `title`, `summary` e `body` in Markdown.\n\n## SEO e prerendering\n\nUn hook `nitro:config` legge la directory `content/articles/` prima del build e aggiunge ogni route `/news/[slug]` alla lista di prerendering.\n\n## Prossimi passi\n\nIl sito ha ora routing appropriato, un feed di notizie e supporto multilingua completo.",{"title":34,"summary":35,"body":36},"Hoe ik mijn persoonlijke website herbouwde met Nuxt 4 en Firebase","Mijn oude site was een enkel statisch HTML-bestand. Dit is hoe en waarom ik het herbouwde met Nuxt 4, Tailwind CSS, Firebase Hosting en een volledig aangepast meertalig systeem voor 10 talen.","## De oude site\n\nLang was mijn persoonlijke website een enkel `index.html`-bestand. Minimaal en snel — maar niet schaalbaar. Ik besloot een volledige herbouw te doen.\n\n## Waarom Nuxt 4\n\n- **Statische generatie** — `nuxt generate` produceert statische uitvoer voor Firebase Hosting\n- **Bestandsgebaseerde routering** — Artikelpagina's op `/news/[slug]` werken zonder configuratie\n- **TypeScript-first** — De volledige codebase is getypeerd\n- **SSR + hydratatie** — Ideaal voor SEO\n\n## De stack\n\n- **Nuxt 4** met `app/`-directorystructuur, SSR met statische generatie\n- **Tailwind CSS** — Utility-first styling\n- **Firebase Hosting** — Globaal CDN, eenvoudige deploys\n- **Aangepaste i18n** — Een zelfgemaakt composable met `vue-i18n`\n- **Nitro serverroutes** — Artikelen als lokale JSON-bestanden\n\n## Het meertalige systeem\n\nDe site ondersteunt 10 talen. Ik heb `@nuxtjs/i18n` bewust vermeden en een `useI18n()`-composable geschreven die uit een `locale`-cookie leest.\n\n## Artikelen als lokale JSON\n\nElk artikel is een JSON-bestand met een `translations`-object — één vermelding per locale met `title`, `summary` en `body` in Markdown.\n\n## SEO en prerendering\n\nEen `nitro:config`-hook leest de `content/articles/`-directory vóór de Vite-build en voegt elke `/news/[slug]`-route toe aan de prerenderlijst.\n\n## Wat volgt\n\nDe site heeft nu proper routing, een nieuwsfeed en volledige meertalige ondersteuning.",{"title":38,"summary":39,"body":40},"Hvordan jeg gjenbygget min personlige nettside med Nuxt 4 og Firebase","Min gamle nettside var en enkelt statisk HTML-fil. Slik og hvorfor gjenbygget jeg den med Nuxt 4, Tailwind CSS, Firebase Hosting og et fullt tilpasset flerspråklig system for 10 språk.","## Den gamle nettsiden\n\nI lang tid var min personlige nettside en enkelt `index.html`-fil. Minimal og rask — men ikke skalerbar. Jeg bestemte meg for en fullstendig gjenbygging.\n\n## Hvorfor Nuxt 4\n\n- **Statisk generering** — `nuxt generate` produserer statisk utdata for Firebase Hosting\n- **Filbasert ruting** — Artikelsider på `/news/[slug]` fungerer uten konfigurasjon\n- **TypeScript-first** — Hele kodebasen er typet\n- **SSR + hydrering** — Ideelt for SEO\n\n## Stakken\n\n- **Nuxt 4** med `app/`-katalogstruktur, SSR med statisk generering\n- **Tailwind CSS** — Utility-first styling\n- **Firebase Hosting** — Globalt CDN, enkle deploys\n- **Tilpasset i18n** — Et håndlaget composable med `vue-i18n`\n- **Nitro serverruter** — Artikler som lokale JSON-filer\n\n## Det flerspråklige systemet\n\nNettsiden støtter 10 språk. Jeg unngikk bevisst `@nuxtjs/i18n` og skrev et `useI18n()`-composable som leser fra en `locale`-informasjonskapsel.\n\n## Artikler som lokal JSON\n\nHver artikkel er en JSON-fil med et `translations`-objekt — én oppføring per locale med `title`, `summary` og `body` i Markdown.\n\n## SEO og forhåndsrendering\n\nEn `nitro:config`-hook leser `content/articles/`-katalogen før Vite-bygget og legger til hver `/news/[slug]`-rute i forhåndsrenderingslisten.\n\n## Hva er neste\n\nNettsiden har nå ordentlig ruting, en nyhetsfeed og full flerspråklig støtte.",{"title":42,"summary":43,"body":44},"Jak przebudowałem swój osobisty serwis z Nuxt 4 i Firebase","Mój stary serwis to był jeden statyczny plik HTML. Oto jak i dlaczego przebudowałem go z Nuxt 4, Tailwind CSS, Firebase Hosting i w pełni niestandardowym systemem wielojęzycznym obsługującym 10 języków.","## Stary serwis\n\nPrzez długi czas mój osobisty serwis był pojedynczym plikiem `index.html`. Minimalny i szybki — ale nie skalowalny. Zdecydowałem się na pełną przebudowę.\n\n## Dlaczego Nuxt 4\n\n- **Generowanie statyczne** — `nuxt generate` produkuje statyczne wyjście kompatybilne z Firebase Hosting\n- **Routing oparty na plikach** — Strony artykułów pod `/news/[slug]` działają bez konfiguracji\n- **TypeScript jako standard** — Cała baza kodu jest typowana\n- **SSR + hydratacja** — Idealne dla SEO\n\n## Stack\n\n- **Nuxt 4** ze strukturą katalogu `app/`, SSR z generowaniem statycznym\n- **Tailwind CSS** — Stylowanie utility-first\n- **Firebase Hosting** — Globalne CDN, proste wdrożenia\n- **Niestandardowe i18n** — Własny composable używający bezpośrednio `vue-i18n`\n- **Trasy serwera Nitro** — Artykuły jako lokalne pliki JSON\n\n## System wielojęzyczny\n\nSerwis obsługuje 10 języków. Celowo unikałem `@nuxtjs/i18n` i napisałem composable `useI18n()` czytający z ciasteczka `locale`.\n\n## Artykuły jako lokalny JSON\n\nKażdy artykuł to plik JSON z obiektem `translations` — jeden wpis na locale z `title`, `summary` i `body` w Markdown.\n\n## SEO i prerenderowanie\n\nHook `nitro:config` odczytuje katalog `content/articles/` przed buildem Vite i dodaje każdą trasę `/news/[slug]` do listy prerenderowania.\n\n## Co dalej\n\nSerwis ma teraz właściwy routing, feed z aktualnościami i pełne wsparcie wielojęzyczne.",{"title":46,"summary":47,"body":48},"Como reconstruí o meu site pessoal com Nuxt 4 e Firebase","O meu antigo site era um único ficheiro HTML estático. Aqui está como e porquê o reconstruí com Nuxt 4, Tailwind CSS, Firebase Hosting e um sistema multilingue personalizado cobrindo 10 idiomas.","## O site antigo\n\nDurante muito tempo, o meu site pessoal foi um único ficheiro `index.html`. Mínimo e rápido — mas não escalável. Decidi fazer uma reconstrução completa.\n\n## Porquê Nuxt 4\n\n- **Geração estática** — `nuxt generate` produz saída estática compatível com Firebase Hosting\n- **Roteamento baseado em ficheiros** — Páginas de artigos em `/news/[slug]` funcionam sem configuração\n- **TypeScript-first** — Toda a base de código está tipada\n- **SSR + hidratação** — Ideal para SEO\n\n## O stack\n\n- **Nuxt 4** com estrutura de diretório `app/`, SSR com geração estática\n- **Tailwind CSS** — Estilos utility-first\n- **Firebase Hosting** — CDN global, deploys simples\n- **i18n personalizado** — Um composable feito à mão com `vue-i18n`\n- **Rotas de servidor Nitro** — Artigos como ficheiros JSON locais\n\n## O sistema multilingue\n\nO site suporta 10 idiomas. Evitei deliberadamente `@nuxtjs/i18n` e escrevi um composable `useI18n()` que lê a partir de um cookie `locale`.\n\n## Artigos como JSON local\n\nCada artigo é um ficheiro JSON com um objeto `translations` — uma entrada por locale com `title`, `summary` e `body` em Markdown.\n\n## SEO e pré-renderização\n\nUm hook `nitro:config` lê o diretório `content/articles/` antes do build do Vite e adiciona cada rota `/news/[slug]` à lista de pré-renderização.\n\n## O que vem a seguir\n\nO site tem agora roteamento adequado, um feed de notícias e suporte multilingue completo.",{"title":50,"summary":51,"body":52},"Kişisel sitemi Nuxt 4 ve Firebase ile nasıl yeniden inşa ettim","Eski sitem tek bir statik HTML dosyasıydı. Nuxt 4, Tailwind CSS, Firebase Hosting ve 10 dili kapsayan tamamen özel çok dilli bir sistemle nasıl ve neden yeniden inşa ettiğimi anlıyorum.","## Eski site\n\nUzun süre boyunca kişisel sitem tek bir `index.html` dosyasıydı. Minimal ve hızlı — ama ölçeklenemez. Tam bir yeniden inşa yapmaya karar verdim.\n\n## Neden Nuxt 4\n\n- **Statik oluşturma** — `nuxt generate`, Firebase Hosting ile uyumlu tamamen statik çıktı üretir\n- **Dosya tabanlı yönlendirme** — `/news/[slug]` altındaki makale sayfaları yapılandırma gerektirmeden çalışır\n- **TypeScript-öncelikli** — Tüm kod tabanı tiplenmiş\n- **SSR + hidrasyon** — SEO için ideal\n\n## Stack\n\n- **Nuxt 4** — `app/` dizin yapısı, statik oluşturma ile SSR\n- **Tailwind CSS** — Utility-first stil\n- **Firebase Hosting** — Global CDN, kolay deploy\n- **Özel i18n** — `vue-i18n` kullanan el yapımı composable\n- **Nitro sunucu rotaları** — Yerel JSON dosyaları olarak makaleler\n\n## Çok dilli sistem\n\nSite 10 dili destekliyor. `@nuxtjs/i18n`'den kaçınarak `locale` çerezini okuyan bir `useI18n()` composable yazdım.\n\n## Yerel JSON olarak makaleler\n\nHer makale, `translations` nesnesi olan bir JSON dosyasıdır — her locale için `title`, `summary` ve Markdown'da `body` içeren bir giriş.\n\n## SEO ve ön işleme\n\nBir `nitro:config` hook'u, Vite build'inden önce `content/articles/` dizinini okur ve her `/news/[slug]` rotasını ön işleme listesine ekler.\n\n## Sonraki adımlar\n\nSite artık uygun yönlendirmeye, bir haber akışına ve tam çok dilli desteğe sahip.",1780530996836]