Wie die Größe des Codes ist, hängt vom Minifier, Collector und der Sprache ab. Unerwartetes Webpack-Update

Mein Name ist Ilya Goldfarb, ich bin Entwickler von Yandex-Schnittstellen. Ich bin daran interessiert zu verfolgen, wie sich die Tools zum Erstellen des Frontends entwickeln, daher versuche ich, die Änderungen in jeder Version beliebter Lösungen zu untersuchen.

In Erwartung der fünften Version von Webpack möchte ich über die scheinbar geringfügige Version 4.26.0 vom 19. November 2018 sprechen, in der unerwartet und ohne Kriegserklärung die Standardversion des Minifier geändert wurde. Früher war es ein UglifyJS-Paket, jetzt verwendet es Terser, einen Zweig von UglifyES, einem Zweig von UglifyJS, der sowohl ES5- als auch ES6-Code komprimieren kann. Terser erschien, als der Hauptbetreuer sich weigerte, UglifyES zu unterstützen und weiterzuentwickeln. UglifyJS stoppte jedoch auch seine Entwicklung im August 2018, als die letzte Version veröffentlicht wurde. In einer neuen Abzweigung haben wir einige Fehler behoben und den Code ein wenig überarbeitet.

Die API dieser Minifier ist kompatibel, führt jedoch zu unterschiedlichen Komprimierungsergebnissen. Normalerweise treten Änderungen dieser Stufe nur bei größeren, nicht bei kleineren Aktualisierungen auf. Aus diesem Grund achten viele Entwickler möglicherweise nicht auf die Innovation. Natürlich wird in den meisten Fällen alles funktionieren, aber niemand möchte derjenige werden, der aufgrund des Build- und Minimierungssystems bei der Produktion seines Projekts Fehler bekommt.

Diese ganze Geschichte veranlasste mich, ein wenig persönlich über Komprimierung zu recherchieren. Hier sind die Fragen, die ich gestellt habe:

  • Was komprimiert ES5, TerSer oder UglifyJS besser?
  • Was wird schneller geladen: eine komprimierte Version von ES5 von Terser oder von UglifyJS?
  • Welche Version wiegt mehr: ES5 oder ES6? Und wie wirkt sich TypeScript darauf aus?
  • Gibt es einen großen Unterschied zwischen Standardeinstellungen und manuellen Einstellungen?
  • Und wenn nicht Webpack? Wer produziert eine kleinere Baugruppe, ein Rollup oder ein Webpack?

Für die Forschung habe ich eine kleine React 16-Anwendung erstellt, die eine Vue 2-Anwendung rendert, die eine Angular 7-Anwendung mit einer ganzen Schaltfläche rendert.

Insgesamt wurden 3 529 695 Bytes nicht minimierten Codes (720 393 gzip-Bytes) freigegeben.

Was komprimiert ES5, TerSer oder UglifyJS besser?


Ich habe das letzte verfügbare UglifyJS genommen und das Terser-Webpack mit der ES5-Option verwendet und die gleichen Komprimierungseinstellungen verwendet.

Größe in Bytes
Größe in Bytes (gzip)
UglifyJS
1.050.376
285,290
Terser
1,089,282
292 678
Fazit: UglifyJS komprimiert besser um 3,5% (2,5% gzip).

Was wird schneller geladen: eine komprimierte Version von ES5 von Terser oder von UglifyJS?


Ich habe die Leistung mit dem Standard DevTools Yandex Browser gemessen. Ich habe die Seite 12 Mal geladen und den Wert Scripting (Laufzeit des Skripts) verwendet, wobei die ersten drei Dimensionen verworfen wurden.
UglifyJS - 221 ms (Fehler 2,8%).
Terser - 226 ms (Fehler 2,7%).
Fazit: Die Werte sind zu klein für einen solchen Fehler, wir können sie als gleich betrachten. Wir schließen auch, dass diese Methode nicht zur Messung der Ladezeit geeignet ist.
Ich habe die Geschwindigkeit des Codes nicht gemessen und verglichen, da unterschiedlicher Code unterschiedlich funktioniert. Die Entwickler jedes Projekts sollten dieses Problem unabhängig untersuchen.

Welche Version wiegt mehr: ES6 oder ES5? Und wie wirkt sich TypeScript darauf aus?


Um die beiden Versionen zu vergleichen und mich ausschließlich auf die Technologie zu konzentrieren, habe ich Babel-Plugins verwendet und vier Assemblys erstellt:

  • ES5: alle als es2016 gekennzeichneten Plugins, + Plugin für Object.assign + Plugins für spätere Versionen + experimentelle Plugins, Ziel in tsconfig in ES5 installiert;
  • ES5 (ts esnext): alle als es2016 gekennzeichneten Plugins, + Plugin für Object.assign + alle Plugins für spätere Versionen + experimentelle Plugins, Ziel in tsconfig ist auf esnext gesetzt;
  • ES6: nur Plug-Ins für es2017 und höher + experimentelle Plug-Ins, Ziel in tsconfig ist auf ES6 gesetzt;
  • ES6 (ts esnext): Nur Plugins für es2017 und höher + experimentelle Plugins, Ziel in tsconfig ist auf esnext gesetzt.


Größe in Bytes
Größe in Bytes (gzip)
ES5
1 186 520
322 071
ES5 (ts esnext)
1,089,282
292 678
ES6
1,087,220
292 232
ES6 (ts esnext)
1,087,220
292 232
Fazit: Die von Babel mit Kompilierungs-Timecode unter esnext komprimierte Version wiegt 97.238 Bytes (8,2%) weniger. Dies ist unerwartet häufig passiert, da der Winkel in TypeScript geschrieben ist und Vue und React in JavaScript Terser wie Uglify beim Erstellen mit einem Webpack keinen nicht verwendeten Code kompilieren kann, der aus dem Winkel mit einem Web-Skript geliefert wird. Dies ist ein Kompilierungsfehler für dieses Beispiel. In der Baugruppe eines anderen Projekts ist dies möglicherweise nicht der Fall, und der Unterschied ist viel geringer.

Es ist auch ersichtlich, dass das Volumen des ES6-Codes nur um 2062 Bytes kleiner als ES5 ist. Beim Haustierprojekt habe ich ein völlig anderes Ergebnis erzielt: Der ES6-Code ist 3-6% höher als der ES5-Code. Dies ist auf mehrere Faktoren zurückzuführen, von denen zwei Hauptfaktoren sind:
1. Der Babel-Helfer für die Klassenvererbung wird einmal eingefügt und kostet dann vier Bytes (e (a, b)), und ES6 verwendet die native Vererbung zum Preis von 15 Bytes (Klasse a erweitert b).
2. Die Methode zum Deklarieren von Variablen. In ES5 sind dies Vars, und sie werden perfekt komprimiert. In ES6 sind dies jedoch let und const, die die Initialisierungsreihenfolge beibehalten und nicht miteinander kombiniert werden.

Unsichere aggressive Minimierungen wie erzwungene Pfeilfunktionen oder die Verwendung der losen Einstellung tragen dazu bei, die Größe des ES6-Codes zu verringern. Seien Sie vorsichtig und berücksichtigen Sie die Feinheiten. In Firefox sind die Pfeilfunktionen beispielsweise viermal langsamer als gewöhnlich, in Chromium gibt es jedoch keinen Unterschied.

Daher ist es unmöglich, die Frage eindeutig zu beantworten: Das Ergebnis hängt stark vom Code und der Ziellaufzeit ab.

Gibt es einen großen Unterschied zwischen Standardeinstellungen und manuellen Einstellungen?


Vergleichen Sie, ob es möglich ist, eine kleinere Dateigröße zu erhalten, wenn Sie die Einstellungen ein wenig anpassen. Zum Beispiel weisen wir darauf hin, dass die Minifizierung fünfmal wiederholt werden muss. Standardmäßig wird es nur einmal übergeben.

Größe in Bytes
Größe in Bytes (gzip)
Terser (Standard) ES5
1.097.141
294 306
Terser (besteht 5) ES5
1 089 312
292,408
Uglify (Standard) ES5
1 091 350
294.845
Uglify (besteht 5) ES5
1.050.363
284 618
Fazit: Uglify mit fünffacher Minimierung ist standardmäßig um 3,7% (3,4% gzip) geringer als Uglify. Daher müssen Sie die Komprimierungseinstellungen immer verschärfen. Eine fünffache Verkleinerung bedeutet übrigens nicht, dass die Montage fünfmal länger dauert. In diesem Testprojekt dauert eine einzelne Minifizierung beispielsweise 18 Sekunden, fünfmal - 38 und zehnmal - 49. Ich empfehle, experimentell den idealen Wert für Ihr Projekt zu finden. Danach wird die Minimierung gestoppt und der Code ändert sich nicht. Normalerweise ist es zwischen 5 und 10. Es gibt auch eine Reihe anderer Optionen: Kommentare: false schneidet alle Kommentare zu Lizenzen aus (obwohl dies ein rechtliches Problem ist) und hoist_funs: true groups funktioniert an einem Ort, wodurch eine bessere Optimierung von vars ermöglicht wird. Im Idealfall müssen Sie alle Einstellungen durchgehen.

Wer produziert eine kleinere Baugruppe, ein Rollup oder ein Webpack?


Rollup ist ein alternativer Sammler mit einem eingebauten Baumschüttelmechanismus. Für den Test habe ich ein Rollup 0.67.4 mit den gleichen Einstellungen wie das Webpack erstellt.

Größe in Bytes
Größe in Bytes (gzip)
Rollup ES5 (Uglify)
990 497
274 105
Rollup ES5 (Terser)
995 318
272 532
Webpack ES5 (Uglify)
1.050.363
284 618
Webpack ES5 (Terser)
1 089 312
292,408
Fazit: Das Ergebnis von Rollup und Uglify ist 5,6% (3,6% gzip) weniger.

Dies geschah aus mehreren Gründen:

1. Webpack enthält Krücken für Grenzfälle. Dieser Code umschließt beispielsweise jeden Funktionsaufruf eines anderen Moduls in Object (). Dies geschieht, um die Kontextübertragung für Module ohne strikte Verwendung zu Modulen mit strikter Verwendung zu verhindern. Gut geschriebene Projekte ohne Abhängigkeiten von Drittanbietern benötigen keinen Wrapper, aber manchmal ist nicht nur gut geschriebener Code an der Assembly beteiligt. In dieser Hinsicht sieht das Webpack zuverlässiger aus. Rollap wiederum glaubt, dass alle Module ES6-Module sind und immer strikt im Gebrauch ausgeführt werden, so dass dieses Problem für ihn einfach nicht besteht.

Eine wichtige Frage ist, wie sich solche Webpack-Krücken auf die Leistung auswirken. Stellen Sie sich vor, wir haben den perfekten Code geschrieben, für den keine zusätzlichen Wrapper erforderlich sind, aber dennoch wird jeder Funktionsaufruf diese durchlaufen. Dies führt zu einem geringen Leistungsaufwand: ungefähr eine Hundertstel Mikrosekunde pro Funktionsaufruf in Chromium (ein Zehntel in Firefox).

2. Das Webpack verfügt über einen kleinen Bootstrap, der die Initialisierung und das Laden von Modulen steuert. Rollup verwendet keine Wrapper, sondern legt den Code aller Module einfach in einem einzigen Bereich ab. Das Webpack hat eine ähnliche Optimierung, funktioniert jedoch nicht mit allen Modulen.

Zusammenfassung der Studie


Ich hoffe, dass viele nach dem Lesen des Artikels ihre Build-Systeme überprüfen und sicherstellen, dass sie alle möglichen Tricks für die beste Komprimierung verwenden. Es ist schnell und einfach.

Richten Sie zunächst eine Reihe von TypeScript und Babel richtig ein. Lassen Sie jede Komponente der Baugruppe ihr eigenes Ding machen: Eine überprüft die Typen und die zweite ist für die Konvertierung in veraltete Standards verantwortlich.

Zweitens können Sie bei Verwendung von ES5 den Minifier wieder in UglifyJS ändern. Beachten Sie jedoch, dass er nicht mehr unterstützt wird.

Drittens ist es vorzuziehen, Rollup für die Montage zu wählen. Dies ist jedoch nicht in allen Fällen möglich, da einige Plugins fehlen. Vergessen Sie nach dem Zusammenbau nicht, die Funktionalität durch Funktionstests zu überprüfen. Wenn Sie sie nicht haben, ist es Zeit, sie zu schreiben.

Source: https://habr.com/ru/post/de438022/


All Articles