Tree Shaking: cos’è, meccanismo di eliminazione del codice morto e strumenti

Autore: IT Sectr Pubblicato: 2026-05-18 Tempo di lettura: 8 min

Tree Shaking è un meccanismo per rimuovere il codice non utilizzato (dead code elimination) nella fase di build dell’applicazione. Tree Shaking analizza la struttura statica dei moduli ES ed esclude funzioni, classi e variabili esportate che non vengono importate da nessuna parte. Secondo la Documentazione Webpack, una corretta configurazione di Tree Shaking può ridurre la dimensione del bundle del 30–60% senza modificare la funzionalità dell’applicazione.

Punti chiave

  • Tree Shaking — rimozione delle esportazioni inutilizzate dai moduli ES basata sull’analisi statica di import/export
  • Moduli ES (import/export) — l’unico formato che supporta Tree Shaking; CommonJS non è supportato
  • Webpack e Rollup — i principali bundler con supporto Tree Shaking tramite plugin
  • Side effects — gli effetti collaterali nei moduli bloccano Tree Shaking; il flag sideEffects: false in package.json risolve il problema
  • Used exports — analisi dell’utilizzo delle esportazioni in modalità production di Webpack per la rimozione precisa del codice morto

Cos’è Tree Shaking?

Tree Shaking è una tecnica di ottimizzazione del codice che esclude moduli e funzioni inutilizzati dal bundle finale. Il termine è stato introdotto dal team di Rollup nel 2015 e descrive metaforicamente il processo: l’albero delle dipendenze viene scosso e i rami inutilizzati cadono. A differenza dell’ottimizzazione manuale, Tree Shaking viene eseguito automaticamente nella fase di build.

Tree Shaking funziona solo con i moduli ES (ECMAScript Modules), dove le dipendenze sono determinate staticamente tramite import ed export. CommonJS (require/module.exports) non supporta Tree Shaking perché require viene eseguito dinamicamente — il bundler non può determinare in anticipo quali funzioni sono effettivamente utilizzate. Le librerie moderne (Lodash, Moment.js, RxJS) pubblicano versioni ES per supportare Tree Shaking.

Rollup: pioniere di Tree Shaking

Rollup è stato il primo bundler a implementare Tree Shaking nel 2015. A differenza di Webpack, Rollup è stato progettato fin dall’inizio per i moduli ES ed esegue una rimozione del codice morto più aggressiva. Rollup analizza non solo le singole esportazioni ma interi moduli: se un modulo non ha effetti collaterali e nessuna esportazione viene utilizzata, Rollup esclude l’intero modulo dal bundle.

Rollup è particolarmente efficace per librerie e SDK dove ogni kilobyte conta. Il framework Vue.js utilizza Rollup per compilare la sua versione di produzione. React è passato a Rollup nel 2020. Per le applicazioni, Webpack è più comunemente utilizzato grazie al suo ecosistema di plugin più ricco (Hot Module Replacement, code splitting, CSS modules), ma per il massimo Tree Shaking durante la creazione di librerie, Rollup rimane lo standard del settore.

Il risparmio di Tree Shaking dipende fortemente dall’architettura del progetto. In un’applicazione React con la libreria Ant Design, Tree Shaking può rimuovere fino al 70% del codice dei componenti UI. In un progetto dove tutte le importazioni sono specifiche e mirate, il risparmio sarà del 5–15%. Secondo le ricerche di Webpack, il risparmio medio è del 30–40% della dimensione del bundle.

Cos’è il codice morto

Tipo di codice mortoEsempioRilevamento Tree Shaking
Esportazione inutilizzataexport function unusedHelper()
Importazione inutilizzataimport { unused } from "lib"
Ramo di condizione mortoif (false) { ... }No (rimosso dal minifier)
Funzione non chiamata dopo DCEfunction a(){} a() dove a non è chiamataParzialmente

Come funziona Tree Shaking: analisi statica dei moduli

Il meccanismo di Tree Shaking si basa su un grafo delle dipendenze che il bundler costruisce da tutte le dichiarazioni import/export nel progetto. Nella prima fase, il bundler attraversa tutti i file dal punto di ingresso (entry point) e raccoglie l’albero dei moduli. Nella seconda fase, analizza quali esportazioni da ciascun modulo vengono effettivamente importate in altri moduli.

Per ogni modulo, Webpack o Rollup contrassegna le esportazioni come utilizzate o inutilizzate. Le esportazioni inutilizzate vengono escluse dal bundle. Tuttavia, il modulo stesso rimane nel bundle se almeno una delle sue esportazioni viene utilizzata. Un modulo può essere completamente escluso solo tramite il flag sideEffects o se il modulo non contiene effetti collaterali.

Esempio: prima e dopo Tree Shaking

js
// utils.js — modulo con funzioni
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 — punto di ingresso
import { formatDate } from "./utils";

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

Tree Shaking ha escluso formatCurrency e slugify dal bundle finale perché non sono importati in app.js. La dimensione del modulo utils.js è passata da 3 funzioni a 1. Se utils.js contiene effetti collaterali (ad esempio, inizializzazione globale), Tree Shaking non può rimuovere nemmeno le esportazioni inutilizzate.

Tree Shaking in Webpack: configurazione e ottimizzazione

Webpack include il supporto integrato di Tree Shaking tramite TerserPlugin in modalità production. Per abilitare Tree Shaking, due condizioni sono sufficienti: mode è impostato su production (mode: "production") e i moduli utilizzano la sintassi ES (import/export). Webpack contrassegna automaticamente le esportazioni inutilizzate e le passa a Terser per la rimozione.

La configurazione aggiuntiva di usedExports: true in optimization.webpack.config.js consente un’analisi dettagliata dell’utilizzo delle esportazioni all’interno di un modulo. Questa opzione determina quali esportazioni sono effettivamente utilizzate e quali sono solo esportate (provided). La combinazione di usedExports e Terser offre la massima efficienza di rimozione del codice morto.

Configurazione Webpack per Tree Shaking

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

Il parametro chiave è modules: false in @babel/preset-env. Per impostazione predefinita, Babel trasforma i moduli ES in CommonJS, il che uccide Tree Shaking. modules: false impedisce a Babel di trasformare import/export, preservando la sintassi ES per Webpack. concatenateModules inoltre unisce i moduli in un ambito condiviso, riducendo il numero di IIFE e diminuendo la dimensione del bundle.

Il problema dei side effects e il flag sideEffects

I side effects (effetti collaterali) sono azioni che un modulo esegue quando viene importato e che non sono correlate ai valori esportati: stili globali (import "./styles.css"), polyfill (import "core-js/stable"), inizializzazione di variabili globali o registrazione di Service Worker. Se un modulo contiene effetti collaterali, il bundler non può rimuoverlo in modo sicuro dal bundle, anche se nessuna delle sue esportazioni viene utilizzata.

Il flag sideEffects in package.json dice al bundler quali moduli nel pacchetto non hanno effetti collaterali. Per un pacchetto in cui tutti i moduli sono puri (solo esportazioni di funzioni), è necessario specificare "sideEffects": false. Per i pacchetti con CSS o polyfill — un array di percorsi verso file con effetti collaterali: "sideEffects": ["*.css"]. Senza questo flag, Tree Shaking non rimuoverà nemmeno le funzioni inutilizzate.

Come identificare gli effetti collaterali nel proprio codice

Per verificare se un modulo ha effetti collaterali, chiediti: questa importazione eseguirà azioni non correlate all’esportazione di valori? import "./styles.css" aggiunge CSS al DOM — questo è un effetto collaterale. import { throttle } from "lodash-es" non ha effetti collaterali — rende semplicemente disponibile la funzione throttle. I polyfill (import "core-js/stable") hanno effetti collaterali — modificano i prototipi globali.

Per i propri moduli, si raccomanda di: estrarre stili e polyfill in punti di ingresso separati, separare le utilità pure (funzioni senza effetti collaterali) dai moduli con effetti collaterali (inizializzazione, registrazione, registrazione di Service Worker). Nel package.json del progetto di livello superiore, specificare "sideEffects": false solo se tutti i moduli sono puri. Se ci sono stili, specificare "sideEffects": ["*.css"] con precisione.

Esempio di configurazione 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"] significa: tutti i file CSS hanno effetti collaterali (non possono essere rimossi) e polyfills.js anche. Tutti gli altri file JS nel pacchetto sono puri — possono essere scossi in modo sicuro. Il campo module specifica il percorso della versione ES del pacchetto che il bundler deve utilizzare al posto della versione CommonJS (main) per Tree Shaking.

Tree Shaking in React Native e Metro

React Native con Metro Bundler supporta una versione limitata di Tree Shaking. Metro non esegue un’analisi statica completa delle esportazioni utilizzate (usedExports) come Webpack. Invece, Metro si affida a Terser per rimuovere le parti inutilizzate dei moduli durante la minificazione. L’efficacia di questo approccio è inferiore al Tree Shaking completo in Webpack.

Per la massima ottimizzazione dei progetti React Native, si raccomanda di: utilizzare librerie con moduli ES (campo module in package.json), aggiungere babel-plugin-transform-remove-console per rimuovere il codice di debug e configurare Metro transformer.minifierConfig per Terser. Inoltre, Ram Bundle (divisione del bundle in moduli) riduce il caricamento delle schermate inutilizzate.

Domande frequenti

Perché Tree Shaking non funziona con CommonJS?

CommonJS (require/module.exports) non supporta l’analisi statica — require può essere chiamato dinamicamente all’interno di condizioni e funzioni. Il bundler non può determinare quali parti del modulo vengono effettivamente utilizzate. Solo i moduli ES con import/export statici consentono Tree Shaking.

Si può usare Tree Shaking con TypeScript?

TypeScript è completamente compatibile con Tree Shaking a condizione che tsconfig.json sia configurato per i moduli ES: "module": "esnext". Il compilatore TypeScript deve preservare import/export senza convertirli in CommonJS. Babel con @babel/preset-typescript e modules: false trasmette correttamente i moduli ES a Webpack.

Come verificare se Tree Shaking ha funzionato?

Webpack Bundle Analyzer è un plugin che visualizza la composizione del bundle come diagramma interattivo. Se una libreria è presente nel bundle ma le sue funzioni non vengono utilizzate, Tree Shaking non ha funzionato. Puoi anche analizzare il file di output: cerca le esportazioni inutilizzate nel testo del bundle tramite grep.

Perché Lodash non fa tree-shake di default?

Lodash v4 viene distribuito come pacchetto CommonJS. Per Tree Shaking, è necessario usare lodash-es — la versione ES della libreria. Sostituisci import throttle from "lodash/throttle" con import { throttle } from "lodash-es" e configura resolve.alias in Webpack per sostituire lodash con lodash-es.

Tree Shaking influisce sui tempi di build?

Tree Shaking aumenta leggermente i tempi di build (del 5–15%) perché aggiunge una fase di analisi del grafo delle dipendenze e marcatura delle esportazioni utilizzate. In modalità development, Tree Shaking è solitamente disabilitato per velocità. In produzione, il tempo aggiuntivo è giustificato da una significativa riduzione delle dimensioni del bundle.

Riepilogo

  • Tree Shaking — rimozione automatica delle esportazioni ES inutilizzate al momento della build, riducendo la dimensione del bundle del 30–60%
  • Moduli ES — l’unico formato che supporta l’analisi statica; CommonJS non è adatto a Tree Shaking
  • Webpack e Rollup forniscono Tree Shaking tramite usedExports e Terser in modalità production
  • Gli effetti collaterali bloccano la rimozione dei moduli; il flag sideEffects: false in package.json risolve il problema per le librerie pure
  • Babel deve essere configurato con modules: false per evitare la conversione dei moduli ES in CommonJS
  • React Native Metro ha un Tree Shaking limitato, affidandosi a Terser nella fase di minificazione

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche