Tree Shaking: vad är det, mekanism för borttagning av död kod och verktyg

Författare: IT Sectr Publicerad: 2026-05-18 Lästid: 8 min

Tree Shaking — mekanism för borttagning av oanvänd kod (dead code elimination) i applikationens byggfas. Tree Shaking analyserar den statiska strukturen hos ES-moduler och exkluderar exporterade funktioner, klasser och variabler som inte importeras någonstans. Enligt Webpack Documentation kan korrekt konfiguration av Tree Shaking minska storleken på bundle med 30–60% utan att ändra applikationens funktionalitet.

Huvudpunkter

  • Tree Shaking — borttagning av oanvända export från ES-moduler baserat på statisk analys av import/export
  • ES-moduler (import/export) — det enda formatet som stöder Tree Shaking; CommonJS stöds inte
  • Webpack och Rollup — de huvudsakliga byggverktygen med Tree Shaking-stöd via plugins
  • Side effects — biverkningar i moduler blockerar Tree Shaking; flaggan sideEffects: false i package.json löser problemet
  • Used exports — analys av exportanvändning i Webpacks produktionsläge för exakt borttagning av död kod

Vad är Tree Shaking?

Tree Shaking (skaka trädet) — en kodoptimeringsmetod där moduler och funktioner som inte används i applikationen exkluderas från den slutliga bundle. Termen introducerades av Rollup-teamet 2015 och beskriver metaforiskt processen: beroendeträdet skakas och oanvända grenar faller av. Till skillnad från manuell optimering utförs Tree Shaking automatiskt i byggfasen.

Tree Shaking fungerar bara med ES-moduler (ECMAScript Modules), där beroenden definieras statiskt via import och export. CommonJS (require/module.exports) stöder inte Tree Shaking eftersom require körs dynamiskt — byggverktyget kan inte i förväg avgöra vilka funktioner som faktiskt används. Moderna bibliotek (Lodash, Moment.js, RxJS) släpper ES-versioner för att stödja Tree Shaking.

Rollup: pionjär inom Tree Shaking

Rollup — det första byggverktyget som implementerade Tree Shaking 2015. Till skillnad från Webpack var Rollup från början designat för ES-moduler och utför en mer aggressiv borttagning av död kod. Rollup analyserar inte bara enskilda export, utan hela moduler: om en modul inte har några biverkningar och ingen export används, exkluderar Rollup hela modulen från bundle.

Rollup är särskilt effektivt för bibliotek och SDK, där varje kilobyte räknas. Ramverket Vue.js använder Rollup för att bygga produktionsversionen. React bytte till Rollup 2020. För applikationer används oftare Webpack på grund av det rikare plugin-ekosystemet (Hot Module Replacement, code splitting, CSS modules), men för maximal Tree Shaking vid byggande av bibliotek förblir Rollup industristandarden.

Besparingen från Tree Shaking beror starkt på projektarkitekturen. I en React-applikation med Ant Design-biblioteket kan Tree Shaking ta bort upp till 70% av UI-komponenternas kod. I ett projekt där alla import är specifika och träffsäkra blir besparingen 5–15%. Den genomsnittliga besparingen enligt Webpacks forskning är 30–40% av bundle-storleken.

Vad är död kod

Typ av död kodExempelUpptäckt av Tree Shaking
Oanvänd exportexport function unusedHelper()Ja
Oanvänd importimport { unused } from "lib"Ja
Död gren av villkorif (false) { ... }Nej (tas bort av minifierare)
Ej anropad funktion efter DCEfunction a(){} a() där a inte anropasDelvis

Hur fungerar Tree Shaking: statisk analys av moduler

Mekanismen för Tree Shaking är baserad på beroendegrafen (dependency graph) som byggverktyget skapar från alla import/export i projektet. I den första fasen går byggverktyget igenom alla filer från startpunkten (entry point) och samlar in modulträdet. I den andra fasen analyseras vilka export från varje modul som faktiskt importeras i andra moduler.

För varje modul markerar Webpack eller Rollup export som använda eller oanvända. Oanvända export exkluderas från bundle. Själva modulen finns dock kvar i bundle om minst en export används. Att helt exkludera en modul är endast möjligt via sideEffects-flaggan eller om modulen inte innehåller några biverkningar.

Exempel: före och efter Tree Shaking

js
// utils.js — modul med funktioner
export function formatDate(date) {
  return date.toISOString().slice(0, 10);
}

export function formatCurrency(amount) {
  return "$" + amount.toFixed(2);
}

export function slugify(text) {
  return text.toLowerCase().replace(/\s+/g, "-");
}
js
// app.js — startpunkt
import { formatDate } from "./utils";

const today = formatDate(new Date());
console.log(today);
js
// Efter Tree Shaking — i bundle endast formatDate
function formatDate(date) {
  return date.toISOString().slice(0, 10);
}
const today = formatDate(new Date());
console.log(today);

Tree Shaking exkluderade formatCurrency och slugify från den slutliga bundle eftersom de inte importeras i app.js. Storleken på modulen utils.js minskade från 3 funktioner till 1. Om utils.js innehåller side effects (t.ex. global initiering) kan Tree Shaking inte ta bort ens oanvända export.

Tree Shaking i Webpack: konfiguration och optimering

Webpack har inbyggt stöd för Tree Shaking via plugin TerserPlugin i produktionsläge. För att aktivera Tree Shaking räcker två villkor: mode inställt på production (mode: "production") och moduler som använder ES-syntax (import/export). Webpack markerar automatiskt oanvända export och skickar dem till Terser för borttagning.

Ytterligare konfiguration usedExports: true i optimization.webpack.config.js aktiverar detaljerad analys av exportanvändning inuti modulen. Detta alternativ avgör vilka export som faktiskt används (used) och vilka som endast exporteras (provided). Kombinationen av usedExports och Terser ger maximal effektivitet vid borttagning av död kod.

Webpack-konfiguration för Tree Shaking

js
// webpack.config.js — Tree Shaking-konfiguration
module.exports = {
  mode: "production",
  entry: "./src/app.js",
  output: {
    filename: "bundle.js",
  },
  optimization: {
    usedExports: true,
    minimize: true,
    concatenateModules: true,
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules\/(?!(my-lib)\/).*/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              ["@babel/preset-env", { modules: false }],
            ],
          },
        },
      },
    ],
  },
};

Nyckelparametern — modules: false i @babel/preset-env. Babel konverterar som standard ES-moduler till CommonJS, vilket dödar Tree Shaking. modules: false förbjuder Babel att konvertera import/export och bevarar ES-syntaxen för Webpack. concatenateModules slår dessutom samman moduler i ett gemensamt synlighetsområde, vilket minskar antalet IIFE och bundle-storleken.

Problemet med side effects och flaggan sideEffects

Side effects (biverkningar) — en moduls handlingar vid import som inte är relaterade till exporterade värden: globala stilar (import "./styles.css"), polyfills (import "core-js/stable"), initiering av globala variabler eller registrering av Service Worker. Om en modul innehåller side effects kan byggverktyget inte säkert ta bort den från bundle, även om ingen export används.

Flaggan sideEffects i package.json informerar byggverktyget om vilka moduler i paketet som inte har biverkningar. För ett paket där alla moduler är rena (endast export av funktioner) ska "sideEffects": false ställas in. För paket med CSS eller polyfills — en array med sökvägar till filer med biverkningar: "sideEffects": ["*.css"]. Utan denna flagga kommer Tree Shaking inte att ta bort ens oanvända funktioner.

Hur man identifierar side effects i sin egen kod

För att kontrollera om en modul har biverkningar, ställ frågan: kommer denna import att utföra några handlingar som inte är relaterade till export av värden? import "./styles.css" lägger till CSS i DOM — detta är en side effect. import { throttle } from "lodash-es" har inga side effects — det gör bara funktionen throttle tillgänglig. Polyfills (import "core-js/stable") har side effects — de modifierar globala prototyper.

För egna moduler rekommenderas: flytta stilar och polyfills till separata startpunkter, separera rena verktyg (funktioner utan side effects) från moduler med biverkningar (initiering, loggning, Service Worker-registrering). I package.json för det överordnade projektet, ställ in "sideEffects": false endast om alla moduler är rena. Om det finns stilar — ställ in "sideEffects": ["*.css"] exakt.

Exempel på sideEffects-konfiguration

json
{
  "name": "my-ui-lib",
  "version": "2.1.0",
  "sideEffects": [
    "*.css",
    "polyfills.js"
  ],
  "module": "dist/index.esm.js",
  "main": "dist/index.cjs.js"
}

"sideEffects": ["*.css", "polyfills.js"] betyder: alla CSS-filer har biverkningar (kan inte tas bort) och polyfills.js också. Alla andra JS-filer i paketet är rena — de kan säkert shake-as. Fältet module anger sökvägen till ES-versionen av paketet som byggverktyget ska använda istället för CommonJS-versionen (main) för Tree Shaking.

Tree Shaking i React Native och Metro

React Native med Metro Bundler stöder en begränsad version av Tree Shaking. Metro utför inte fullständig statisk analys av använda export (usedExports) som Webpack. Istället förlitar sig Metro på Terser för att ta bort oanvända delar av moduler i minifieringsfasen. Effektiviteten hos detta tillvägagångssätt är lägre än fullständig Tree Shaking i Webpack.

För maximal optimering av React Native-projekt rekommenderas: använd bibliotek med ES-moduler (fältet module i package.json), anslut plugins babel-plugin-transform-remove-console för borttagning av felsökningskod och konfigurera Metro transformer.minifierConfig för Terser. Dessutom minskar Ram Bundle (uppdelning av bundle i moduler) laddningen av oanvända skärmar.

Vanliga frågor

Varför fungerar inte Tree Shaking med CommonJS?

CommonJS (require/module.exports) stöder inte statisk analys — require kan anropas dynamiskt inuti villkor och funktioner. Byggverktyget kan inte avgöra vilka delar av modulen som faktiskt används. Endast ES-moduler med statisk import/export möjliggör Tree Shaking.

Kan Tree Shaking användas med TypeScript?

TypeScript är fullt kompatibelt med Tree Shaking förutsatt att tsconfig.json är konfigurerat för ES-moduler: "module": "esnext". TypeScript-kompilatorn måste bevara import/export utan konvertering till CommonJS. Babel med @babel/preset-typescript och modules: false överför också korrekt ES-moduler till Webpack.

Hur kontrollerar man om Tree Shaking fungerade?

Webpack Bundle Analyzer — ett plugin som visualiserar bundle-sammansättningen som ett interaktivt diagram. Om ett bibliotek finns i bundle men dess funktioner inte används, fungerade inte Tree Shaking. Man kan också analysera utdatafilen: hitta oanvänd export i bundle-texten via grep.

Varför tree-shake-as inte Lodash som standard?

Lodash v4 distribueras som CommonJS-paket. För Tree Shaking måste lodash-es användas — ES-versionen av biblioteket. Byt ut import throttle from "lodash/throttle" mot import { throttle } from "lodash-es" och konfigurera resolve.alias i Webpack för att ersätta lodash med lodash-es.

Påverkar Tree Shaking byggtiden?

Tree Shaking ökar byggtiden något (med 5–15%), eftersom det lägger till en fas för analys av beroendegrafen och markering av använda export. I utvecklingsläge är Tree Shaking vanligtvis avstängt för hastighet. I produktion motiveras den extra tiden av en betydande minskning av bundle-storleken.

Sammanfattning

  • Tree Shaking — automatisk borttagning av oanvända ES-export i byggfasen, minskning av bundle-storleken med 30–60%
  • ES-moduler — det enda formatet som stöder statisk analys; CommonJS lämpar sig inte för Tree Shaking
  • Webpack och Rollup tillhandahåller Tree Shaking via usedExports och Terser i produktionsläge
  • Side effects blockerar borttagning av moduler; flaggan sideEffects: false i package.json löser problemet för rena bibliotek
  • Babel måste konfigureras med modules: false för att inte konvertera ES-moduler till CommonJS
  • React Native Metro har begränsad Tree Shaking och förlitar sig på Terser i minifieringsfasen

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också