Tree Shaking: ce este, mecanismul eliminării codului mort și instrumente

Autor: IT Sectr Publicat: 2026-05-18 Timp de citire: 8 min

Tree Shaking — mecanism de eliminare a codului neutilizat (dead code elimination) în etapa de build a aplicației. Tree Shaking analizează structura statică a modulelor ES și exclude funcțiile, clasele și variabilele exportate care nu sunt importate nicăieri. Conform Webpack Documentation, configurarea corectă a Tree Shaking poate reduce dimensiunea bundle-ului cu 30–60% fără a modifica funcționalitatea aplicației.

Principalele

  • Tree Shaking — eliminarea exporturilor neutilizate din modulele ES pe baza analizei statice import/export
  • Modulele ES (import/export) — singurul format care suportă Tree Shaking; CommonJS nu este suportat
  • Webpack și Rollup — principalele bundlere cu suport Tree Shaking prin pluginuri
  • Side effects — efectele secundare în module blochează Tree Shaking; flag-ul sideEffects: false în package.json rezolvă problema
  • Used exports — analiza utilizării exporturilor în modul production Webpack pentru eliminarea precisă a codului mort

Ce este Tree Shaking?

Tree Shaking (scuturarea copacului) — tehnică de optimizare a codului prin care modulele și funcțiile neutilizate sunt excluse din bundle-ul final. Termenul a fost introdus de echipa Rollup în 2015 și descrie metaforic procesul: copacul dependențelor este scuturat, iar ramurile neutilizate cad. Spre deosebire de optimizarea manuală, Tree Shaking se execută automat în etapa de build.

Tree Shaking funcționează numai cu modulele ES (ECMAScript Modules), unde dependențele sunt definite static prin import și export. CommonJS (require/module.exports) nu suportă Tree Shaking deoarece require se execută dinamic — bundlerul nu poate determina dinainte care funcții sunt utilizate efectiv. Bibliotecile moderne (Lodash, Moment.js, RxJS) lansează versiuni ES pentru suport Tree Shaking.

Rollup: pionierul Tree Shaking

Rollup — primul bundler care a implementat Tree Shaking în 2015. Spre deosebire de Webpack, Rollup a fost proiectat de la început pentru modulele ES și execută o eliminare mai agresivă a codului mort. Rollup analizează nu numai exporturile individuale, ci și modulele întregi: dacă un modul nu are efecte secundare și niciun export nu este utilizat, Rollup exclude întregul modul din bundle.

Rollup este deosebit de eficient pentru biblioteci și SDK-uri, unde fiecare kilobyte contează. Framework-ul Vue.js folosește Rollup pentru build-ul versiunii de producție. React a trecut la Rollup în 2020. Pentru aplicații se folosește mai des Webpack datorită ecosistemului mai bogat de pluginuri (Hot Module Replacement, code splitting, CSS modules), dar pentru Tree Shaking maxim la build-ul bibliotecilor, Rollup rămâne standardul industriei.

Economia de la Tree Shaking depinde puternic de arhitectura proiectului. Într-o aplicație React cu biblioteca Ant Design, Tree Shaking poate elimina până la 70% din codul componentelor UI. Într-un proiect unde toate importurile sunt specifice și punctuale, economia va fi de 5–15%. Economia medie conform cercetărilor Webpack este de 30–40% din dimensiunea bundle-ului.

Ce este codul mort

Tip de cod mortExempluDetectare de Tree Shaking
Export neutilizatexport function unusedHelper()Da
Import neutilizatimport { unused } from "lib"Da
Ramură moartă de condițieif (false) { ... }Nu (eliminat de minificator)
Funcție neapelată după DCEfunction a(){} a() unde a nu e apelatăParțial

Cum funcționează Tree Shaking: analiza statică a modulelor

Mecanismul Tree Shaking se bazează pe graful de dependențe (dependency graph) pe care bundlerul îl construiește din toate import/export-urile din proiect. În prima etapă, bundlerul parcurge toate fișierele de la punctul de intrare (entry point) și colectează arborele de module. În a doua etapă, se analizează care exporturi din fiecare modul sunt efectiv importate în alte module.

Pentru fiecare modul, Webpack sau Rollup marchează exporturile ca utilizate sau neutilizate. Exporturile neutilizate sunt excluse din bundle. Cu toate acestea, modulul însuși rămâne în bundle dacă cel puțin un export al său este utilizat. Excluderea completă a unui modul este posibilă numai prin flag-ul sideEffects sau dacă modulul nu conține niciun efect secundar.

Exemplu: înainte și după Tree Shaking

js
// utils.js — modul cu funcții
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 — punct de intrare
import { formatDate } from "./utils";

const today = formatDate(new Date());
console.log(today);
js
// După Tree Shaking — în bundle doar formatDate
function formatDate(date) {
  return date.toISOString().slice(0, 10);
}
const today = formatDate(new Date());
console.log(today);

Tree Shaking a exclus formatCurrency și slugify din bundle-ul final, deoarece nu sunt importate în app.js. Dimensiunea modulului utils.js s-a redus de la 3 funcții la 1. Dacă utils.js conține side effects (de exemplu, inițializare globală), Tree Shaking nu va putea elimina nici măcar exporturile neutilizate.

Tree Shaking în Webpack: configurare și optimizare

Webpack include suport încorporat pentru Tree Shaking prin pluginul TerserPlugin în modul production. Pentru activarea Tree Shaking sunt suficiente două condiții: mode setat la production (mode: "production") și modulele care folosesc sintaxa ES (import/export). Webpack marchează automat exporturile neutilizate și le transmite lui Terser pentru eliminare.

Configurarea suplimentară usedExports: true în optimization.webpack.config.js activează analiza detaliată a utilizării exporturilor în interiorul modulului. Această opțiune determină care exporturi sunt efectiv utilizate (used) și care sunt doar exportate (provided). Combinația usedExports și Terser oferă eficiență maximă de eliminare a codului mort.

Configurarea Webpack pentru Tree Shaking

js
// webpack.config.js — configurare Tree Shaking
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 }],
            ],
          },
        },
      },
    ],
  },
};

Parametrul cheie — modules: false în @babel/preset-env. Babel transformă implicit modulele ES în CommonJS, ceea ce distruge Tree Shaking. modules: false interzice Babel să transforme import/export, păstrând sintaxa ES pentru Webpack. concatenateModules combină suplimentar modulele într-un domeniu comun de vizibilitate, reducând numărul de IIFE și dimensiunea bundle-ului.

Problema side effects și flag-ul sideEffects

Side effects (efecte secundare) — acțiunile modulului la importul său, care nu sunt legate de valorile exportate: stiluri globale (import "./styles.css"), polyfill-uri (import "core-js/stable"), inițializarea variabilelor globale sau înregistrarea Service Worker. Dacă un modul conține side effects, bundlerul nu poate să-l elimine în siguranță din bundle, chiar dacă niciun export nu este utilizat.

Flag-ul sideEffects din package.json informează bundlerul care module din pachet nu au efecte secundare. Pentru un pachet unde toate modulele sunt pure (doar export de funcții), trebuie setat "sideEffects": false. Pentru pachete cu CSS sau polyfill-uri — o matrice de căi către fișiere cu efecte secundare: "sideEffects": ["*.css"]. Fără acest flag, Tree Shaking nu va elimina nici măcar funcțiile neutilizate.

Cum să identifici side effects în propriul cod

Pentru a verifica dacă un modul are efecte secundare, puneți întrebarea: va executa acest import vreo acțiune care nu are legătură cu exportul de valori? import "./styles.css" adaugă CSS în DOM — este un side effect. import { throttle } from "lodash-es" nu are side effects — doar face funcția throttle disponibilă. Polyfill-urile (import "core-js/stable") au side effects — modifică prototipurile globale.

Pentru propriile module se recomandă: mutarea stilurilor și polyfill-urilor în puncte de intrare separate, separarea utilităților pure (funcții fără side effects) de modulele cu efecte secundare (inițializare, logare, înregistrare Service Worker). În package.json al proiectului de nivel superior, setați "sideEffects": false numai dacă toate modulele sunt pure. Dacă există stiluri — setați "sideEffects": ["*.css"] exact.

Exemplu de configurare sideEffects

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"] înseamnă: toate fișierele CSS au efecte secundare (nu pot fi eliminate) și polyfills.js de asemenea. Toate celelalte fișiere JS din pachet sunt pure — pot fi shake-uite în siguranță. Câmpul module indică calea către versiunea ES a pachetului pe care bundlerul trebuie să o folosească în locul versiunii CommonJS (main) pentru Tree Shaking.

Tree Shaking în React Native și Metro

React Native cu Metro Bundler suportă o versiune limitată de Tree Shaking. Metro nu efectuează o analiză statică completă a exporturilor utilizate (usedExports) ca Webpack. În schimb, Metro se bazează pe Terser pentru eliminarea părții neutilizate a modulelor în etapa de minificare. Eficiența acestei abordări este mai mică decât Tree Shaking-ul complet din Webpack.

Pentru optimizarea maximă a proiectelor React Native se recomandă: utilizarea bibliotecilor cu module ES (câmpul module în package.json), conectarea pluginurilor babel-plugin-transform-remove-console pentru eliminarea codului de debug și configurarea Metro transformer.minifierConfig pentru Terser. Suplimentar, Ram Bundle (împărțirea bundle-ului în module) reduce încărcarea ecranelor neutilizate.

Întrebări frecvente

De ce Tree Shaking nu funcționează cu CommonJS?

CommonJS (require/module.exports) nu suportă analiza statică — require poate fi apelat dinamic în interiorul condițiilor și funcțiilor. Bundlerul nu poate determina care părți ale modulului sunt efectiv utilizate. Numai modulele ES cu import/export static permit Tree Shaking.

Se poate folosi Tree Shaking cu TypeScript?

TypeScript este complet compatibil cu Tree Shaking cu condiția ca tsconfig.json să fie configurat pentru module ES: "module": "esnext". Compilatorul TypeScript trebuie să păstreze import/export fără transformare în CommonJS. Babel cu @babel/preset-typescript și modules: false transmite corect modulele ES către Webpack.

Cum verific dacă Tree Shaking a funcționat?

Webpack Bundle Analyzer — plugin care vizualizează compoziția bundle-ului sub formă de diagramă interactivă. Dacă o bibliotecă este prezentă în bundle, dar funcțiile sale nu sunt utilizate, Tree Shaking nu a funcționat. De asemenea, puteți analiza fișierul de ieșire: găsiți exportul neutilizat în textul bundle-ului prin grep.

De ce Lodash nu este tree-shake-uit implicit?

Lodash v4 este distribuit ca pachet CommonJS. Pentru Tree Shaking trebuie să folosiți lodash-es — versiunea ES a bibliotecii. Înlocuiți import throttle from "lodash/throttle" cu import { throttle } from "lodash-es" și configurați resolve.alias în Webpack pentru înlocuirea lodash cu lodash-es.

Tree Shaking afectează timpul de build?

Tree Shaking crește ușor timpul de build (cu 5–15%), deoarece adaugă etapa de analiză a grafului de dependențe și marcarea exporturilor utilizate. În modul development, Tree Shaking este de obicei dezactivat pentru viteză. În production, timpul suplimentar este justificat de reducerea semnificativă a dimensiunii bundle-ului.

Rezumat

  • Tree Shaking — eliminarea automată a exporturilor ES neutilizate în etapa de build, reducând dimensiunea bundle-ului cu 30–60%
  • Modulele ES — singurul format care suportă analiza statică; CommonJS nu este potrivit pentru Tree Shaking
  • Webpack și Rollup asigură Tree Shaking prin usedExports și Terser în modul production
  • Side effects blochează eliminarea modulului; flag-ul sideEffects: false în package.json rezolvă problema pentru bibliotecile pure
  • Babel trebuie configurat cu modules: false pentru a nu transforma modulele ES în CommonJS
  • React Native Metro are Tree Shaking limitat, bazându-se pe Terser în etapa de minificare

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și