Artikel

JavaScript bundle-optimering — Code splitting, tree shaking og analyse

JavaScript er dyrt: download, parse, kompilering og eksekvering. Code splitting sender kun den nødvendige kode til brugeren. Tree shaking fjerner ubrugt kode. Bundle-analyse afslører hvad der fylder.

JavaScript er den dyreste ressource per byte på nettet: det skal downloades, dekomprimeres, parses, kompileres og eksekveres — alt på main thread. Et 500 KB JavaScript-bundle kan blokere interaktivitet i 2-5 sekunder på en middel Android-telefon. Bundle-optimering handler om at sende så lidt JavaScript som muligt, og kun det der er nødvendigt.

Tree shaking

Tree shaking er bundlerens evne til at fjerne ubrugt kode (dead code elimination). Det kræver ESM-imports (ikke CommonJS require):

// ✅ Tree shakeable — kun `formatDate` inkluderes i bundle
import { formatDate } from './utils';

// ❌ Ikke tree shakeable — hele utils-modulet inkluderes
const utils = require('./utils');

Mange npm-pakker eksponerer ikke tree-shakeable ESM. lodash er et klassisk eksempel — import _ from 'lodash' inkluderer hele biblioteket (70+ KB). Alternativet: import debounce from 'lodash/debounce' eller lodash-es.

Sidecar bundles: Vite og Rollup er fremragende til tree shaking af ESM. Webpack kræver mode: 'production' og sideEffects: false i package.json for optimal tree shaking.

Code splitting

Code splitting opdeler ét monolitisk bundle i chunks der loades on-demand:

Route-baseret splitting (React, Next.js):

// React.lazy — chunk loades kun når komponenten renderes
const CheckoutPage = React.lazy(() => import('./CheckoutPage'));
const BlogPost = React.lazy(() => import('./BlogPost'));

Dynamiske imports (alle bundlers):

// Kode loades kun ved klik
button.addEventListener('click', async () => {
  const { initChart } = await import('./chart-library');
  initChart(data);
});

Vendor splitting — adskil tredjeparts-biblioteker fra applikationskode. Biblioteker ændres sjældnere og caches længere:

// vite.config.js
build: {
  rollupOptions: {
    output: {
      manualChunks: {
        vendor: ['react', 'react-dom'],
        charts: ['chart.js'],
      }
    }
  }
}

Bundle-analyse

Webpack Bundle Analyzer visualiserer hvad der fylder:

npm install --save-dev webpack-bundle-analyzer
# Kør med npx webpack-bundle-analyzer stats.json

Vite bundle visualizer:

npx vite-bundle-visualizer

source-map-explorer analyserer en compiled bundle via source maps:

npx source-map-explorer dist/main.js

Kig efter: duplikeret kode, unødvendigt store biblioteker, og kode der burde lazy-loades.

Komprimering

Alle moderne servere og CDN’er understøtter komprimering. Gzip reducerer typisk JavaScript med 60-70%. Brotli reducerer 15-25% mere end Gzip for tekstfiler:

# Nginx — aktiver Brotli og Gzip
brotli on;
brotli_comp_level 6;
gzip on;
gzip_types text/javascript application/javascript;

Vite og Webpack genererer .gz og .br filer ved build — serveren sender den komprimerede version automatisk.

Moderne JavaScript med browsermål

Bundling til ES2015 (default for mange tools) inkluderer polyfills der er unødvendige for moderne browsere. Specificér et moderne browsermål for at eliminere unødvendige polyfills:

// vite.config.js
build: {
  target: 'es2020'
}
// .browserslistrc — moderne browsere only
last 2 Chrome versions
last 2 Firefox versions
last 2 Safari versions

En moderne target reducerer typisk bundle-størrelse med 10-20% ved at eliminere transpilerings-overhead.

Import cost og editor-integration

VS Code extension Import Cost viser størrelsen af hvert import direkte i editoren — tidlig feedback inden bundling. Det er det nemmeste tool til at fange dyre biblioteker før de når produktion. → Denne artikel er en del af Web Performance — Core Web Vitals og teknisk hastighed.

Andre artikler i samme emne

Ofte stillede spørgsmål

Hvad er forskellen på code splitting og tree shaking?
Code splitting opdeler bundlet i chunks der loades on-demand — brugere downloader kun kode til de sider de besøger. Tree shaking fjerner ubrugt kode fra bundlet ved build-time — hvis du importerer én funktion fra et bibliotek, inkluderes kun den funktion. De er komplementære: tree shaking reducerer chunk-størrelse, code splitting reducerer hvad der loades.
Hvad er et godt JavaScript-budget for mobilbrugere?
Google anbefaler under 150 KB komprimeret JavaScript for den kritiske eksekverings-sti (kode der kræves for at siden er interaktiv). Total JavaScript-budget varierer med kontekst, men 300-400 KB komprimeret er en praktisk grænse for de fleste sites. Husk at 300 KB komprimeret JavaScript kan være 1 MB+ ukomprimeret eksekvering.
Hvordan analyserer jeg hvad der fylder i mit JavaScript-bundle?
Bundle-analyse kræver et visualiseringsværktøj der viser bundle-indholdet som et interaktivt treemap. Til Vite bruges vite-bundle-visualizer eller rollup-plugin-visualizer. Til Webpack bruges webpack-bundle-analyzer. Source map explorer analyserer den producerede kode via source maps. Typiske synder: store tredjeparts-biblioteker (moment.js, lodash) der importeres i sin helhed, duplicate dependencies og vendor chunks der er for store til at cache effektivt.
Hvad er dynamic import og hvornår bør det bruges?
Dynamic import (import()) er JavaScript-syntaks der loader et modul asynkront og on-demand frem for ved startup. Det er mekanismen bag route-based code splitting i frameworks og lazy-loading af komponenter. Brug dynamic import til kode der kun behøves ved brugerinteraktion (fx en modal, en chart-komponent eller et rigt tekstfelt), kode der kun bruges på specifikke sider, og store biblioteker som kun en lille del af brugerne når. Det reducerer initial bundle-størrelse og forbedrer Time to Interactive.
Hvad er preload og prefetch til JavaScript og hvornår bruges hvad?
Preload (<link rel=preload as=script>) fortæller browseren at fetche en ressource med høj prioritet — bruges til scripts der er kritiske for sideindlæsning men opdages sent i HTML. Prefetch (<link rel=prefetch>) fetcher ressourcer med lav prioritet til fremtidig brug — bruges til scripts der sandsynligvis behøves på næste side i brugerens navigation. For JavaScript-chunks: brug preload til kritisk JavaScript der er nødvendigt for den aktuelle sides interaktivitet, og prefetch til route-chunks for sandsynlige næste sider.

Placering i ordbogen

JavaScript bundle-optimering — Code splitting, tree shaking og analyse