Zum Hauptinhalt springen




Erfahren Sie, wie sich CommonJS-Module auf die Änderung Ihres Anwendungsbaums auswirken


Aktualisiert

Es erscheint in:
Schnelle Ladezeiten

En esta publicación, veremos qué es CommonJS y por qué hace que sus paquetes de JavaScript sean más grandes de lo necesario.

Zusammenfassung: Para asegurarse de que el empaquetador pueda optimieren con éxito su aplicación, evite depender de los módulos CommonJS y utilice la sintaxis del módulo ECMAScript en toda su aplicación.

Was ist CommonJS?

CommonJS es un estándar de 2009 que estableció convenciones para módulos JavaScript. Inicialmente estaba destinado a ser utilizado fuera del Browser Netz, principalmente para aplicaciones del lado del Server.

Mit CommonJS können Sie Module definieren, deren Funktionalität exportieren und in andere Module importieren. Das folgende Snippet definiert beispielsweise ein Modul, das fünf Funktionen exportiert: hinzufügen, subtrahieren, multiplizieren, Teileny max:


const { maxBy } = benötigen('lodash-es');
const fns = {
hinzufügen: (zu, b) => zu + b,
subtrahieren: (zu, b) => zu - b,
multiplizieren: (zu, b) => zu * b,
Teilen: (zu, b) => zu / b,
max: arr => maxBy(arr)
};

Object.keys(fns).forEach(fnName => Modul.Exporte[fnName] = fns[fnName]);

Später kann ein anderes Modul einige oder alle dieser Funktionen importieren und verwenden:


const { hinzufügen } = benötigen('./utils');
console.Log(hinzufügen(1, 2));

Aufrufen Index.js mit Gib nicht gibt die Nummer aus 3 auf der Konsole.

Debido a la falta de un sistema de módulos estandarizado en el navegador a principios de la década de 2010, CommonJS también se convirtió en un formato de módulo popular para las bibliotecas del lado del Klient de JavaScript.

Wie wirkt sich CommonJS auf die endgültige Größe Ihres Pakets aus?

Die Größe Ihrer serverseitigen JavaScript-Anwendung ist nicht so kritisch wie im Browser. Aus diesem Grund wurde CommonJS nicht entwickelt, um die Größe des Produktionspakets zu reduzieren. Gleichzeitig, Analyse zeigt, dass die JavaScript-Paketgröße immer noch der Hauptgrund für die Verlangsamung von Browseranwendungen ist.

JavaScript-Zackenbarsche und Minifier, wie z Webpack y terser, realice diferentes optimizaciones para reducir el tamaño de su aplicación. Al analizar su aplicación en el momento de la compilación, intentan eliminar tanto como Sein posible del Quellcode que no está utilizando.

Im obigen Snippet sollte Ihr endgültiges Paket beispielsweise nur das enthalten hinzufügen Funktion, da dies das einzige Symbol von ist utils.js Worin bist du wichtig? index.js.

Lassen Sie uns die Anwendung wie folgt erstellen Webpack Rahmen:

const path = benötigen('path');
Modul.Exporte = {
entry: 'index.js',
output: {
filename: 'out.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'production',
};

Hier geben wir an, dass wir Produktionsmodusoptimierungen verwenden und verwenden möchten index.js als Einstiegspunkt. Nach dem Aufrufen Webpack, wenn wir das erkunden Ausfahrt Größe, wir werden so etwas sehen:

$ CD dist && ls -lah
625K Apr 13 13:04 out.js

Realisieren Paket ist 625KB. Wenn wir uns die Ausgabe ansehen, finden wir alle Funktionen von utils.js plus viele Module von lodash. Obwohl wir nicht verwenden lodash im index.js ist Teil der AusgabeDies erhöht unser Produktionsvermögen erheblich.

Ändern wir nun das Modulformat in ECMAScript-Module und versuche es erneut. Diesmal, utils.js es würde so aussehen:

Export const hinzufügen = (zu, b) => zu + b;
Export const subtrahieren = (zu, b) => zu - b;
Export const multiplizieren = (zu, b) => zu * b;
Export const Teilen = (zu, b) => zu / b;

importieren { maxBy } desde 'lodash-es';

Export const max = arr => maxBy(arr);

Y. index.js würde stören utils.js Verwenden der Syntax des ECMAScript-Moduls:

importieren { hinzufügen } desde './utils';

console.Log(hinzufügen(1, 2));

Mit dem gleichen Webpack Konfiguration können wir unsere Anwendung erstellen und die Ausgabedatei öffnen. Jetzt sind es 40 Bytes mit den folgenden Ausfahrt:

(()=>{"use strict";console.Log(1+2)})();

Beachten Sie, dass das endgültige Paket keine der Funktionen von enthält utils.js dass wir nicht verwenden, und es gibt keine Spur von lodash! Sogar mehr, terser (der JavaScript-Minifier, der Webpack verwendet) in der hinzufügen lauf weiter console.log.

Eine faire Frage, die Sie stellen könnten, ist: Warum macht die Verwendung von CommonJS das Ausgabepaket fast 16.000-mal größer?? Natürlich ist dies ein Spielzeugbeispiel, tatsächlich ist der Größenunterschied möglicherweise nicht so groß, aber CommonJS wird höchstwahrscheinlich Ihrem Produktionsaufbau ein erhebliches Gewicht hinzufügen.

CommonJS-Module sind im allgemeinen Fall schwieriger zu optimieren, da sie viel dynamischer als ES-Module sind. Um sicherzustellen, dass Ihr Stitcher und Minifier Ihre Anwendung erfolgreich optimieren kann, sollten Sie sich nicht auf CommonJS-Module verlassen und die Syntax des ECMAScript-Moduls in Ihrer gesamten Anwendung verwenden.

Beachten Sie, dass auch wenn Sie ECMAScript-Module in verwenden index.jsWenn das von Ihnen verwendete Modul ein CommonJS-Modul ist, wird die Paketgröße Ihrer Anwendung beeinflusst.

Warum erweitert CommonJS seine Anwendung?

Um diese Frage zu beantworten, werden wir uns das Verhalten von ansehen ModuleConcatenationPlugin im Webpack y, después de eso, discutir la analizabilidad estática. Este complemento concatena el Umfang de todos sus módulos en un solo cierre y permite que su código tenga un tiempo de ejecución más rápido en el navegador. Veamos un ejemplo:


Export const hinzufügen = (zu, b) => zu + b;
Export const subtrahieren = (zu, b) => zu - b;


importieren { hinzufügen } desde './utils';
const subtrahieren = (zu, b) => zu - b;

console.Log(hinzufügen(1, 2));

Oben haben wir ein ECMAScript-Modul, in das wir importieren index.js. Wir definieren auch a subtrahieren Funktion. Wir können das Projekt damit erstellen Webpack Konfiguration wie oben, aber dieses Mal werden wir die Minimierung deaktivieren:

const path = benötigen('path');

Modul.Exporte = {
entry: 'index.js',
output: {
filename: 'out.js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
minimize: falsch
},
mode: 'production',
};

Sehen wir uns die Ausgabe an:

 (() => { 
"use strict";


const hinzufügen = (zu, b) => zu + b;
const subtrahieren = (zu, b) => zu - b;


const index_subtract = (zu, b) => zu - b;**
console.Log(hinzufügen(1, 2));**

})();

In der obigen Ausgabe befinden sich alle Funktionen im selben Namespace. Um Kollisionen zu vermeiden, wurde das Webpack umbenannt subtrahieren lauf weiter index.js zu index_subtract.

Wenn ein Minifier den obigen Quellcode verarbeitet, führt er Folgendes aus:

  • Löschen Sie nicht verwendete Funktionen subtrahieren y index_subtract
  • Entfernen Sie alle Kommentare und redundanten Leerzeichen
  • Kippen Sie den Körper des hinzufügen Funktion in der console.log Anruf

Dies wird häufig von Entwicklern erwähnt Entfernung nicht verwendeter Importe wie Baumschütteln. Das Schütteln von Bäumen war nur möglich, weil das Webpaket (zur Kompilierungszeit) statisch verstehen konnte, welche Symbole wir importieren utils.js und welche Symbole es exportiert.

Dieses Verhalten ist standardmäßig für aktiviert ES-Module Weil sie sind statisch analysierbarerim Vergleich zu CommonJS.

Schauen wir uns genau das gleiche Beispiel an, aber diesmal ändern Sie sich utils.js So verwenden Sie CommonJS anstelle von ES-Modulen:


const { maxBy } = benötigen('lodash-es');

const fns = {
hinzufügen: (zu, b) => zu + b,
subtrahieren: (zu, b) => zu - b,
multiplizieren: (zu, b) => zu * b,
Teilen: (zu, b) => zu / b,
max: arr => maxBy(arr)
};

Object.keys(fns).forEach(fnName => Modul.Exporte[fnName] = fns[fnName]);

Dieses kleine Update wird die Ausgabe erheblich verändern. Da das Einfügen auf dieser Seite zu lang ist, habe ich nur einen kleinen Teil geteilt:

...
(() => {

"use strict";
var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(288);
const subtrahieren = (zu, b) => zu - b;
console.Log((0,_utils__WEBPACK_IMPORTED_MODULE_0__ .IH)(1, 2));

})();

Beachten Sie, dass das endgültige Paket einige enthält Webpack "Runtime": injizierter Code, der für den Import / Export der Funktionalität der gepackten Module verantwortlich ist. Diesmal, anstatt alle Symbole von zu platzieren utils.js y index.js Unter demselben Namespace benötigen wir zur Laufzeit dynamisch die hinzufügen Funktion mit __webpack_require__.

Dies ist notwendig, da wir mit CommonJS den Exportnamen aus einem beliebigen Ausdruck abrufen können. Der folgende Code ist beispielsweise ein absolut gültiges Konstrukt:

Modul.Exporte[localStorage.getItem(Math.random())] = () => {};

No hay forma de que el empaquetador sepa en el tiempo de compilación cuál es el nombre del símbolo exportado, ya que esto requiere información que solo está disponible en tiempo de ejecución, en el contexto del navegador del Nutzername.

Auf diese Weise kann der Minifier nicht verstehen, was genau ist index.js verwendet seine Abhängigkeiten, damit Sie es nicht loswerden können. Wir werden das exakt gleiche Verhalten auch für Module von Drittanbietern beobachten. Wenn wir ein CommonJS-Modul aus importieren KnotenmoduleIhre Build-Toolchain kann sie nicht richtig optimieren.

Bäume mit CommonJS schütteln

CommonJS-Module sind viel schwieriger zu analysieren, da sie per Definition dynamisch sind. Beispielsweise ist der Importspeicherort in ES-Modulen im Vergleich zu CommonJS, wo es sich um einen Ausdruck handelt, immer ein Zeichenfolgenliteral.

In einigen Fällen können nicht verwendete Exporte beim Erstellen mithilfe eines Drittanbieters entfernt werden, wenn die von Ihnen verwendete Bibliothek bestimmten Konventionen zur Verwendung von CommonJS entspricht Webpack Stecker. Dieses Plugin bietet zwar Unterstützung für das Schütteln von Bäumen, deckt jedoch nicht alle Möglichkeiten ab, wie Ihre Abhängigkeiten CommonJS verwenden. Dies bedeutet, dass Sie nicht die gleichen Garantien wie bei ES-Modulen erhalten. Fügen Sie im Rahmen Ihres Erstellungsprozesses zusätzlich zu den Standardeinstellungen zusätzliche Kosten hinzu Webpack Verhalten.

Fazit

Um sicherzustellen, dass der Packager Ihre Anwendung erfolgreich optimieren kann, sollten Sie sich nicht auf CommonJS-Module verlassen und die ECMAScript-Modulsyntax in Ihrer gesamten Anwendung verwenden.

Hier sind einige praktische Tipps, um sicherzustellen, dass Sie auf dem optimalen Weg sind:

  • Verwenden Sie Rollup.js NodeJS Auflösung
    Plugin und stellen Sie die ModuleNur Häkchen, um anzugeben, dass Sie nur von ECMAScript-Modulen abhängig sein möchten.
  • Verwenden Sie das Paket is-esm

    um zu überprüfen, ob ein npm-Paket ECMAScript-Module verwendet.

  • Wenn Sie Angular verwenden, erhalten Sie standardmäßig eine Warnung, wenn dies von Modulen abhängt, die nicht vom Baum geschüttelt werden können.