Sven Wagner
14.02.2019 Sven Wagner, Leitung Frontend

Tree Shaking, eine Einführung

Was ist Tree Shaking und warum ist Tree Shaking wichtig und nützlich?

Der Begriff Tree Shaking kommt aus der JavaScript-Welt und ist eine Form der sogenannten Dead Code Elimination: durch Tree Shaking reduziert man die Menge an JavaScript-Code auf das, was letztendlich wirklich benötigt wird. Der Begriff wurde von Rollup eingeführt.

Die Idee hinter Tree Shaking ist, dass man sich die diversen Abhängigkeiten seines Codes als einen Baum vorstellen soll. Dieser Baum wird von Zeit zu Zeit immer größer, komplexer, verzweigter, weil immer mehr Abhängigkeiten in Form von weiteren Paketen dazu kommen. Auf der anderen Seite werden nach und nach aber auch ältere Abhängigkeiten ggf. nicht mehr eingebunden bzw. verwendet. Das Paket ist zwar noch da, aber nicht mehr „angebunden“.

Wenn man an diesem Baum „schüttelt“, fällt alles ab, was nicht fest verbunden ist mit dem Stamm bzw. den Ästen – es fallen nun die Pakete herunter, die nicht mehr fest angebunden sind und damit nicht mehr benötigt werden.

Tree Shaking ist neben dem Minifizieren und Komprimieren von JavaScript-Code das wohl wichtigste Tool, um die Ladezeit einer Web-App zu beschleunigen. Nicht zuletzt deswegen, weil es die Menge des Codes direkt beeinflusst.

Wieso ist das wichtig? 170 KB !== 170 KB

Vergleichen wir einmal 170 KB JavaScript-Code (komprimiert) mit der gleichen Menge an Bytes für ein JPEG-Bild, exemplarisch gemessen an einem 3–4 Jahre alten Smartphone mit einer 3G-Verbindung.

Für beides benötigt der Browser dieselbe Zeit, um diese herunterzuladen, da es dieselbe Menge an Daten darstellt.

Betrachtet man aber die Zeiten, die der Browser für die weitere Verarbeitung dieser jeweiligen Daten benötigt, dann wird deutlich wie kostenintensiv JavaScript-Code ist. Für das Anzeigen des Bildes benötigt der Browser noch ca. 0,1 s. Der JavaScript-Code hingegen wird erstmal auf ca. 500 KB Code entpackt. Dieser Code benötigt dann noch ca. 3,5 s zum Parsen/Kompilieren und zur Ausführung: das 35-fache!

JavaScript-Bytes !== JPEG-Bytes

Wie schreib ich meinen Code?

Der Mechanismus hinter Tree Shaking baut auf statische Code-Analyse, die durch die EMS-Schreibweise (import/export) ermöglicht wird:

import { foo } from './bar.js'

Durch spezifisches Importieren von Variablen bzw. Funktionen sagen wir bereits, welche Teile des Codes wir benötigen und welche nicht:

module/index.js:

export { Foo, Bar }

myProject.js:

import { Foo } from 'module' // `Bar` wird nicht verwendet und wird daher durch Tree Shaking später aus dem Bundle entfernt

Auf Basis dessen markiert webpack diese Code-Stellen, damit diese dann von Tools wie UglifyJS entfernt werden.

Es ist allerdings erforderlich, dass die Quelle, also in diesem Fall „bar.js“, im EMS-Format geschrieben wurde. In der CommonJS-Schreibweise ist es bspw. webpack oder Rollup nicht möglich, auf Basis dieses Formats eine statische Code-Analyse durchzuführen. In der Regel hat man bei eigens erstellen Dateien damit keine Probleme, wenn man dort das EMS-Format verwendet.

Vorsicht bei Dependencies

Es ist anhand des import-Statements nicht zu erkennen, ob die Quelle im EMS-Format geschrieben ist. Hierfür ist ein Blick in die package.json der Dependency notwendig.

Bekannterweise wird die Dependency mit der Datei aufgelöst, die unter dem Feld „main“ steht. Bundler wie webpack oder Rollup halten jedoch zunächst Ausschau nach dem Feld „module“, um eine EMS-Version der Dependency ausfindig zu machen.

Bekannte Dependencies, bei denen der Code nicht im EMS-Format vorliegt, sind:

Je nach Dependency gibt es ggf. Möglichkeiten, wie man dennoch diese Tree-Shaking-freundlich einsetzen kann. Siehe dazu:

Vorsicht auch bei Babel

Wenn wir also durch unsere import-Schreibweise und die Schreibweise der Dependency sichergestellt haben, dass die Bedingungen für Tree Shaking erfüllt sind, kann einem nur noch Babel in die Quere kommen.

Sollte man „babel-preset-env“ verwenden, dann wird es in den Standard-Einstellungen das EMS-Format in CommonJS umwandeln. Um dies zu verhindern, setzt man die Option „modules“ auf false.

Zusammenfassung

  • Nutze webpack
  • Benutze die ES2015-Module-Syntax (import und export)
  • Stelle sicher, dass Tools wie Babel bzw. preset-env deinen EMS-Code nicht in CommonJS umwandeln
  • Nutze Tools wie Uglify oder Terser über den Production Build von webpack, um das Tree Shaking auch auszuführen

Quellen