Kann jemand das CommonsChunkPlugin von Webpack erklären?

82

Ich verstehe allgemein, dass CommonsChunkPluginalle Einstiegspunkte überprüft werden, ob gemeinsame Pakete / Abhängigkeiten zwischen ihnen bestehen, und sie in ein eigenes Bundle aufteilen.

Nehmen wir also an, ich habe die folgende Konfiguration:

...
enrty : {
    entry1 : 'entry1.js', //which has 'jquery' as a dependency
    entry2 : 'entry2.js', //which has 'jquery as a dependency
    vendors : [
        'jquery',
        'some_jquery_plugin' //which has 'jquery' as a dependency
    ]
},
output: {
    path: PATHS.build,
    filename: '[name].bundle.js'
}
...

Wenn ich ohne Verwendung bündle CommonsChunkPlugin

Ich werde mit 3 neuen Bundle-Dateien enden:

  • entry1.bundle.jsdie enthält den vollständigen Code aus entry1.jsund jqueryund enthält eine eigene Laufzeit
  • entry2.bundle.jsdie enthält den vollständigen Code aus entry2.jsund jqueryund enthält eine eigene Laufzeit
  • vendors.bundle.jsdie enthält den vollständigen Code aus jqueryund some_jquery_pluginund enthält eine eigene Laufzeit

Das ist offensichtlich schlecht, weil ich möglicherweise jquerydreimal auf die Seite laden werde , also wollen wir das nicht.

Wenn ich mit bündle CommonsChunkPlugin

Abhängig davon, welche Argumente ich an CommonsChunkPlugineines der folgenden Argumente weitergebe, geschieht Folgendes:

  • FALL 1: Wenn ich bestanden habe, erhalte { name : 'commons' }ich die folgenden Bundle-Dateien:

    • entry1.bundle.jsDies enthält den vollständigen Code von entry1.js, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • entry2.bundle.jsDies enthält den vollständigen Code von entry2.js, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • vendors.bundle.jsDies enthält den vollständigen Code von some_jquery_plugin, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • commons.bundle.jswelches den vollständigen Code von jqueryund die Laufzeit enthält

    Auf diese Weise erhalten wir insgesamt einige kleinere Bundles und die Laufzeit ist im commonsBundle enthalten. Ziemlich ok, aber nicht ideal.

  • FALL 2: Wenn ich bestanden habe, erhalte { name : 'vendors' }ich die folgenden Bundle-Dateien:

    • entry1.bundle.jsDies enthält den vollständigen Code von entry1.js, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • entry2.bundle.jsDies enthält den vollständigen Code von entry2.js, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • vendors.bundle.jsdie enthält den vollständigen Code aus jqueryund some_jquery_pluginund enthält die Laufzeit.

    Auf diese Weise erhalten wir wieder einige kleinere Bundles insgesamt, aber die Laufzeit ist jetzt im vendorsBundle enthalten. Es ist etwas schlimmer als im vorherigen Fall, da die Laufzeit jetzt im vendorsBundle enthalten ist.

  • FALL 3: Wenn ich bestanden habe, erhalte { names : ['vendors', 'manifest'] }ich die folgenden Bundle-Dateien:

    • entry1.bundle.jsDies enthält den vollständigen Code von entry1.js, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • entry2.bundle.jsDies enthält den vollständigen Code von entry2.js, eine Anforderung für jqueryund enthält nicht die Laufzeit
    • vendors.bundle.jswelches den vollständigen Code von jqueryund enthält some_jquery_pluginund nicht die Laufzeit enthält
    • manifest.bundle.js Dies enthält Anforderungen für jedes andere Bundle und die Laufzeit

    Auf diese Weise erhalten wir insgesamt einige kleinere Bundles und die Laufzeit ist im manifestBundle enthalten. Dies ist der Idealfall.

Was ich nicht verstehe / Ich bin nicht sicher, ob ich es verstehe

  • Warum haben wir in FALL 2 das vendorsBundle erhalten, das sowohl den gemeinsamen Code ( jquery) als auch alles enthält, was vom vendorsEintrag ( some_jquery_plugin) übrig geblieben ist ? Nach meinem Verständnis hat das CommonsChunkPluginhier den gemeinsamen Code ( jquery) gesammelt , und da wir ihn gezwungen haben, ihn in das vendorsBundle auszugeben , hat es den gemeinsamen Code in das vendorsBundle "zusammengeführt" (das jetzt nur den Code von enthält) some_jquery_plugin). Bitte bestätigen oder erklären.

  • In Fall 3 verstehe ich nicht, was passiert ist, als wir { names : ['vendors', 'manifest'] }zum Plugin übergegangen sind . Warum / wie wurde das vendorsBundle intakt gehalten, das beides enthielt, jqueryund some_jquery_pluginwann jqueryist eindeutig eine gemeinsame Abhängigkeit, und warum wurde die generierte manifest.bundle.jsDatei so erstellt, wie sie erstellt wurde (alle anderen Bundles erforderlich und die Laufzeit enthalten)?

Dimitris Karagiannis
quelle
Für Fall 1 sollten Sie die Eigenschaft minChunks angeben.
Marko
10
Ich habe so viel aus Ihrer Frage gelernt, vielen Dank!
Rafael Eyng
1
Vielen Dank, dass Sie dies gefragt und meine Verwirrungen die ganze Zeit über auf diesem Plugin ausgeräumt haben
Glenn
Vielleicht weiß jemand, wie dieses Beispiel in Webpack 4 aussehen wird?
StalkAlex

Antworten:

105

So funktioniert das CommonsChunkPlugin.

Ein gemeinsamer Block "empfängt" die Module, die von mehreren Eintragsblöcken gemeinsam genutzt werden. Ein gutes Beispiel für eine komplexe Konfiguration finden Sie im Webpack-Repository .

Das CommonsChunkPluginwird während der Optimierungsphase von Webpack ausgeführt, was bedeutet, dass es im Speicher ausgeführt wird, kurz bevor die Chunks versiegelt und auf die Festplatte geschrieben werden.

Wenn mehrere gemeinsame Blöcke definiert sind, werden sie der Reihe nach verarbeitet. In Ihrem Fall 3 ist es so, als würde man das Plugin zweimal ausführen. Beachten Sie jedoch, dass die CommonsChunkPluginKonfiguration komplexer sein kann (minSize, minChunks usw.), was sich auf die Art und Weise auswirkt, wie Module verschoben werden.

FALL 1:

  1. Es gibt 3 entryStücke ( entry1, entry2und vendors).
  2. Die Konfiguration legt den commonsBlock als gemeinsamen Block fest.
  3. Das Plugin verarbeitet den commonsallgemeinen Block (da der Block nicht vorhanden ist, wird er erstellt):
    1. Er sammelt die Module , die mehr verwendet werden , als einmal in den anderen Stücken: entry1, entry2und vendorsVerwendung jqueryso das Modul aus diesen Brocken entfernt ist und mit dem zusätzlichen commonsBrocken.
    2. Der commonsKlumpen wird als markiert entryBrocken , während die entry1, entry2und vendorsStücke wie unmarkierte werden entry.
  4. Da der commonsChunk ein entryChunk ist, enthält er schließlich die Laufzeit und das jqueryModul.

FALL 2:

  1. Es gibt 3 entryStücke ( entry1, entry2und vendors).
  2. Die Konfiguration legt den vendorsBlock als gemeinsamen Block fest.
  3. Das Plugin verarbeitet den vendorsgemeinsamen Block:
    1. Es sammelt die Module, die mehr als einmal in den anderen Chunks verwendet werden: entry1und entry2verwendet, jquerydamit das Modul aus diesen Chunks entfernt wird (beachten Sie, dass es nicht zum vendorsChunk hinzugefügt wird, da der vendorsChunk es bereits enthält).
    2. Der vendorsKlumpen wird als markiert entryBrocken , während die entry1und entry2Brocken als unmarkierte werden entry.
  4. Da der vendorsBlock ein entryBlock ist, enthält er schließlich die Laufzeit und die jquery/ jquery_pluginModule.

Fall 3:

  1. Es gibt 3 entryStücke ( entry1, entry2und vendors).
  2. Die Konfiguration legt den vendorsBlock und den manifestBlock als allgemeine Blöcke fest.
  3. Das Plugin erstellt den manifestChunk, da er nicht vorhanden ist.
  4. Das Plugin verarbeitet den vendorsgemeinsamen Block:
    1. Es sammelt die Module, die mehr als einmal in den anderen Chunks verwendet werden: entry1und entry2verwendet, jquerydamit das Modul aus diesen Chunks entfernt wird (beachten Sie, dass es nicht zum vendorsChunk hinzugefügt wird, da der vendorsChunk es bereits enthält).
    2. Der vendorsKlumpen wird als markiert entryBrocken , während die entry1und entry2Brocken als unmarkierte werden entry.
  5. Das Plugin verarbeitet den manifestallgemeinen Block (da der Block nicht vorhanden ist, wird er erstellt):
    1. Es sammelt die Module, die mehr als einmal in den anderen Blöcken verwendet werden: Da keine Module mehr als einmal verwendet werden, wird kein Modul verschoben.
    2. Der Block wird als Block manifestmarkiert, entrywährend der entry1, entry2und vendorsist nicht markiert als entry.
  6. Da der manifestBlock ein entryBlock ist, enthält er schließlich die Laufzeit.

Ich hoffe es hilft.

Laurent Etiemble
quelle
Ein paar Dinge, die ich fragen / klären möchte, fügen Sie bitte auch diese Punkte zu Ihrer Antwort hinzu: 1) Können Sie die gleiche schrittweise Erklärung für FALL 1 machen, nur damit die Antwort zu 1000% vollständig ist? 2) Das Plugin mit auszuführen { names : ['vendors', 'manifest'] }ist wie es zweimal auszuführen, einmal mit { name : 'vendors' }und einmal mit { name : 'manifest' }, richtig? 3) Wenn wir sagen "Das Plugin verarbeitet einen gemeinsamen Block", meinen wir, dass es den Inhalt erstellt, den es in die bundle.jsDatei spuckt , in den Speicher, richtig? 4) Bis es "alle gängigen Chunks verarbeitet" hat, hat es überhaupt keine Ausgabe in eine Datei geschrieben, es ist alles im Speicher
Dimitris Karagiannis
2
Ich habe noch eine Frage, wenn Sie antworten möchten. Nehmen wir an, wir nennen es in meinem Beispiel von oben entry1.jsund entry2.jshatten eine andere gemeinsame Datei als die jqueryDatei ownLib.js. ownLib.jsWürde in FALL 2 und FALL 3 das vendors.bundle.jsRichtige landen ? Wie würden Sie es schaffen, dass andere gängige Dateien als Herstellerdateien, abgesehen vom Block, in ihren eigenen Block getrennt werden vendors? Tut mir leid, dass ich Sie gestört habe, aber ich lerne immer noch, wie man Webpack benutzt
Dimitris Karagiannis
7
Ja das ist richtig: ownLib.jswürde in den ersten gemeinsamen Chunck gelegt werden. Wenn Sie allgemeine Abhängigkeiten in einem anderen Chunck sammeln möchten, müssen Sie Folgendes übergeben : { names : ['common', 'vendors', 'manifest'] }.
Laurent Etiemble
6
Tolle Frage, tolle Antwort, tolle Diskussion. Scheint, als würde ich es endlich verstehen.
Oluckyman
3
Ich habe den letzten Tag damit verbracht, CommonsChunkPlugin-Dokumente zu lesen, und dies ist der erste Ort, an dem ich gelesen habe, dass die verarbeiteten Blöcke nach der Ausführung "als Eintrag nicht gekennzeichnet" sind. Das erklärt im Grunde alles, womit ich Probleme hatte - wenn ich mehr als einmal abstimmen könnte, würde ich es tun.
Coderer