Forside/Blog/Vi genopbyggede vores side i Next.js 16 — her er hvad vi lærte
Webudvikling18. februar 20268 min read

Vi genopbyggede vores side i Next.js 16 — her er hvad vi lærte

En teknisk bygge-log: Next.js 16, Turbopack-fælder, tosproget routing uden biblioteker, og den CSS-fejl der kostede os to dage.

Next.js 16 udviklingsmiljø med kodeeditor og browser preview

Hvorfor vi byggede om fra bunden

Build444's tidligere side fungerede. Den virkede. Men den havde opsamlet den slags teknisk gæld der gør at hver ny funktion tager tre gange så lang tid som den burde.

Vi havde brug for tosproget support (engelsk og dansk). Vi ville sælge ydelser direkte gennem siden med Stripe. Og ærligt talt ville vi bruge vores egen stak. Hvis vi fortæller kunder at de skal investere i hurtige, moderne websites, bør vores egen side være et.

Så i starten af 2026 rev vi den ned og byggede op på Next.js 16, React 19, Tailwind CSS v4 og Turbopack. Det her er bygge-loggen. Gevinsterne, fejlene og de ting vi ville gøre anderledes.

Stakken

Next.js 16.1.6 med App Router. Vi gik all-in på server components. De fleste af vores sider har nul client-side JavaScript medmindre de har brug for interaktivitet. Shop-, checkout- og formularsider er client components. Alt andet er server-renderet.

React 19. Den nye use hook og server actions simplificerede meget af vores data fetching. Vi bruger stadig useEffect et par steder, men langt mindre end før.

Tailwind CSS v4.1.18. Den nye CSS-first konfiguration er renere end den gamle JavaScript-config. Men migrationen var ikke gnidningsfri. Mere om det nedenfor.

Turbopack. Next.js 16 bruger Turbopack som standard til dev-serveren. Hot module replacement er hurtig. Byggetider faldt fra 12 sekunder til under 2. Men Turbopack har edge cases der kostede os reel debugging-tid.

Stripe SDK 20.3.1. Vi håndterer checkout server-side med Stripes seneste SDK. Moms-ID indsamling og automatisk fakturaoprettelse er bygget ind. Webhook-handleren videresender events til vores n8n automatiserings-workflows.

Turbopack: hurtig, men pas på kanterne

Turbopack erstattede Webpack som standard dev-bundler i Next.js 16. For det meste virker det bare. Sider genindlæses på millisekunder. Udvikleroplevelsen er mærkbart bedre.

Så ramte vi CSS-fejlen.

CSS-strippings-problemet

Da vi tilføjede nye CSS-klasser til vores globals.css, forsvandt multi-line formaterede regler lydløst. Ingen fejl. Ingen advarsel. Stilene var bare ikke der.

Vi brugte to dage på det her. Tjekkede browser-inspektøren. Tjekkede build-outputtet. Tilføjede !important i desperation. Ingenting.

Løsningen viste sig at være absurd: skriv nye CSS-regler som enkeltlinje-deklarationer.

/* Dette bliver strippet af Turbopack */
.dropdown-overlay {
  display: flex;
  gap: 8px;
  background: #faf9f6;
}

/* Dette virker fint */
.dropdown-overlay { display: flex; gap: 8px; background: #faf9f6; }

Eksisterende multi-line regler var ikke påvirket. Kun nye tilføjede under hot module replacement. @keyframes blokke og font-family: var(...) i nye regler forårsagede også stripping. Vi skiftede til hardkodede værdier i stedet for CSS-variabler i nye overlay- og dropdown-regler.

Genstart af dev-serveren løste det ikke. Kun enkeltlinje-formatet virkede. Vi indberettede en issue. Per februar 2026 er den stadig åben.

Modulopløsnings-problemet

Tailwind v4 bruger @import "tailwindcss" som entry point. Det virker med Webpack. Med Turbopack fejler det. Turbopacks enhanced-resolve understøtter ikke style-betingelsen i package exports.

Løsningen: brug @import "tailwindcss/index.css" i stedet. Simpelt, når man ved det. Frustrerende når man ikke gør.

Tosproget arkitektur uden i18n-bibliotek

Vi havde brug for engelsk og dansk. De fleste guider anbefaler next-intl eller next-i18next. Vi prøvede begge. De tilføjede kompleksitet, bundle-størrelse og konfigurationsoverhead der ikke matchede vores use case.

Vi har to sprog. Ikke tyve. Så vi byggede det selv.

Middleware rewrites

En lille middleware-fil fanger indkommende requests og omskriver stier baseret på en sprogcookie eller Accept-Language headeren:

  • /about serverer engelsk
  • /da/about serverer dansk
  • Førstegangsbesøgende detekteres via browsersprog

Middlewaren er 47 linjer. Den håndterer alt. Intet bibliotek nødvendigt.

Data-lang CSS-tilgangen

For komponenter der har brug for forskellig styling per sprog (danske ord er længere end engelske), bruger vi en data-lang attribut på HTML-elementet og targeter det i CSS:

[data-lang="da"] .hero-title { font-size: 2.2rem; }
[data-lang="en"] .hero-title { font-size: 2.5rem; }

Ingen JavaScript. Ingen re-renders. Bare CSS der gør hvad CSS gør.

Indholdsfiler per sprog

Blogindlæg, servicebeskrivelser og produkttekster ligger i separate filer per sprog: en.mdx og da.mdx. Blogsystemet læser den rigtige fil baseret på URL-sproget. Ingen oversættelsesnøgler. Ingen JSON-ordbøger. Bare skriv indholdet på hvert sprog.

Denne tilgang ville ikke skalere til 10 sprog. For to er den simplere end noget bibliotek vi prøvede.

Performance-resultater

Vi kørte Lighthouse-audits før og efter genopbygningen. Tallene taler for sig selv.

| Metrik | Gammel side | Ny side | |--------|-------------|---------| | Performance | 67 | 98 | | Accessibility | 82 | 100 | | Best Practices | 78 | 100 | | SEO | 89 | 100 | | LCP | 3,8s | 1,1s | | CLS | 0,18 | 0,01 | | INP | 380ms | 45ms |

Largest Contentful Paint faldt fra 3,8 sekunder til 1,1. Det er et direkte resultat af server components. Den gamle side indlæste en 240KB JavaScript-bundle før den kunne rendere hero-sektionen. Den nye side sender HTML.

Cumulative Layout Shift gik fra 0,18 (fejlende) til 0,01 (godkendt med god margin). Vi opnåede det ved at sætte eksplicitte dimensioner på hvert billede og bruge CSS aspect-ratio til responsive containere.

Interaction to Next Paint blev bedre fordi de fleste sider slet ikke har client-side JavaScript. Der er ingenting der blokerer main thread.

Shoppen: 30+ produkter, ét checkout-flow

Vi byggede en shop med 30+ produkter fordelt på 7 kategorier. Hver kategori har et farvesystem defineret i en enkelt TypeScript-fil. Produkter spænder fra engangs SEO-analyser til månedlige aftaler.

Checkout-flowet bruger Stripes server-side SDK. Ingen Stripe.js på klienten. Kunden klikker "Køb," vi opretter en Checkout Session server-side og redirecter til Stripes hosted side. Det holder vores bundle lille og vores PCI-compliance simpel.

Efter betaling sender Stripe en webhook til vores API-route, som videresender eventet til n8n for automatiseret levering. SEO-rapport produktet udløser et 48-node workflow der kører automatiseret analyse og leverer en PDF-rapport via email.

Hvad vi ville gøre anderledes

Start med Turbopack-test fra dag ét. Vi byggede det meste af CSS'en med Webpack og skiftede til Turbopack sent i projektet. Det var der CSS-fejlene dukkede op. Hvis vi havde startet med Turbopack, ville vi have opdaget enkeltlinje-workarounden tidligere og sparet to dage.

Brug CSS modules i stedet for globale klasser til nye komponenter. Vores globals.css er 800+ linjer. CSS modules ville have givet os bedre scoping og helt undgået Turbopack-strippings-problemet.

Sæt visuel regressionstest op. Vi fangede de fleste layout-fejl manuelt. Et værktøj som Playwrights screenshot-sammenligning ville have fanget CLS-problemerne hurtigere, især på tværs af de to sprogvarianter hvor tekstlængden er forskellig.

Planlæg den tosprogede indholdspipeline tidligere. At skrive indhold på to sprog tager dobbelt så lang tid som ét sprog. Vi undervurderede tiden til de danske versioner. Næste gang ville vi budgettere for oversættelse fra start, ikke bolte det på efter det engelske indhold er færdigt.

Var det det værd?

Next.js 16 med React 19 og Turbopack er en reel performance-opgradering. Vores Lighthouse-scores gik fra middelmådige til næsten perfekte. Server components eliminerede det meste af vores client-side JavaScript. Udvikleroplevelsen er hurtigere.

Men toolingen er stadig ung. Turbopack har reelle fejl. Tailwind v4's import-syntaks virker ikke ud af boksen. Man rammer edge cases der endnu ikke er dokumenteret.

Hvis du starter et nyt projekt i 2026, er denne stak det rigtige valg. Hvis du migrerer et eksisterende, skal du budgettere ekstra tid til Turbopack-særhederne. De kan løses, men de er ikke indlysende.

Vores side er nu hurtig, tosproget og sælger produkter direkte gennem Stripe. Genopbygningen tog seks uger. For hvad vi fik ud af det, var det tid godt brugt.

Daniel Dalgaard

Daniel Dalgaard

Grundlægger af Build444. Bygger hjemmesider, automatiseringer og SEO-systemer for virksomheder der vil vokse online.

Læs mere

Vil du vide, hvor din hjemmeside står?

Få en komplet SEO-analyse med AI-parathedsscore på under 5 minutter.

Få din SEO-analyse