2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Neben dem Hauptprozess werden wir auch einige vage Konzepte im Detail erläutern:
vorne Initialisieren, Erstellen, Versiegeln„In“ haben wir eingeführt, dass die zugrunde liegende Konstruktionslogik von Webpack grob unterteilt werden kann in: „Initialisierung, Konstruktion, Verpackung„drei Phasen:
In,"Bauen„Die Phase ist dafür verantwortlich, die Abhängigkeiten zwischen Modulen zu analysieren und festzulegen Abhängigkeitsdiagramm(ModuleGraph); dann in „VerkapselungIn dieser Phase werden die Module basierend auf dem Abhängigkeitsdiagramm separat in mehrere Chunk-Objekte gekapselt und die Eltern-Kind-Abhängigkeitsbeziehungen zwischen Chunks werden in ChunkGraph und mehrere ChunkGroup-Objekte sortiert.
Das wichtigste Ziel der „Kapselungs“-Phase besteht darin, das ChunkGraph-Beziehungsdiagramm basierend auf dem in der „Build“-Phase gesammelten ModuleGraph-Beziehungsdiagramm zu erstellen. Die Logik dieses Prozesses ist relativ komplex:
Lassen Sie uns hier kurz die Implementierungslogik einiger wichtiger Schritte analysieren.
Der erste Schritt ist sehr kritisch: überweisenseal()
Nach der Funktion durchlaufenentry
Konfiguration, erstellen Sie für jeden Eintrag eine leereChunk
UndEinstiegspunkt Objekt (ein besonderesChunkGroup
) und richtete zunächst die Basis ein ChunkGraph
Strukturelle Beziehung, bereiten Sie sich auf den nächsten Schritt vor, Schlüsselcode:
class Compilation {
seal(callback) {
// ...
const chunkGraphInit = new Map();
// 遍历入口模块列表
for (const [name, { dependencies, includeDependencies, options }] of this
.entries) {
// 为每一个 entry 创建对应的 Chunk 对象
const chunk = this.addChunk(name);
// 为每一个 entry 创建对应的 ChunkGroup 对象
const entrypoint = new Entrypoint(options);
// 关联 Chunk 与 ChunkGroup
connectChunkGroupAndChunk(entrypoint, chunk);
// 遍历 entry Dependency 列表
for (const dep of [...this.globalEntry.dependencies, ...dependencies]) {
// 为每一个 EntryPoint 关联入口依赖对象,以便下一步从入口依赖开始遍历其它模块
entrypoint.addOrigin(null, { name }, /** @type {any} */ (dep).request);
const module = this.moduleGraph.getModule(dep);
if (module) {
// 在 ChunkGraph 中记录入口模块与 Chunk 关系
chunkGraph.connectChunkAndEntryModule(chunk, module, entrypoint);
// ...
}
}
}
// 调用 buildChunkGraph 方法,开始构建 ChunkGraph
buildChunkGraph(this, chunkGraphInit);
// 触发各种优化钩子
// ...
}
}
Nach Abschluss der Ausführung wird die folgende Datenstruktur gebildet:
Zweitens, falls zu diesem Zeitpunkt konfiguriert entry.runtime
, Webpack stellt zu diesem Zeitpunkt auch Laufzeitcode bereit erstellen Den entsprechenden Chunk und direktverteilen Gebenentry
dazugehörigenChunkGroup
Objekt.Wird angerufen, wenn alles fertig istErstellen Sie einen ChunkGraph Funktion, gehen Sie zum nächsten Schritt.
Schritt zwei: existierenbuildChunkGraph
innerhalb der Funktionüberweisen visitModules
Funktion: Durchlaufen Sie den ModuleGraph und weisen Sie alle Module entsprechend ihren Abhängigkeiten verschiedenen Modulen zu.Chunk
Objekt; falls während dieses Vorgangs angetroffenAsync-Modul, dann das Modul erstellenneu ChunkGroup
UndChunk
Objekt, das letztendlich die folgende Datenstruktur bildet:
dritter Schritt: existierenbuildChunkGraph
in Funktionüberweisen connectChunkGroups
Methode, etablierenChunkGroup
zwischen,Chunk
Abhängigkeiten untereinander, um ein Gesamtbild zu erzeugenChunkGraph
Objekt, das letztendlich die folgende Datenstruktur bildet:
der vierte Schritt: existierenbuildChunkGraph
in Funktionüberweisen cleanupUnconnectedGroups
Methode, Bereinigung ist ungültigChunkGroup
, spielt hauptsächlich eine Rolle bei der Leistungsoptimierung.
Nachdem Sie diese vier Schritte von oben nach unten durchlaufen haben,ModuleGraph
Die in gespeicherten Module werden entsprechend der Art des Moduls selbst drei verschiedenen Chunk-Objekten zugewiesen: Entry, Async und Runtime, und die Abhängigkeiten zwischen Chunks werden in den Sammlungen ChunkGraph und ChunkGroup gespeichert. Sie können basierend auf diesen Objekten fortfahren später ändern. Richtlinien zur Unterauftragsvergabe ändern (z. B.SplitChunksPlugin
), realisieren Sie eine Optimierung der Unterauftragsvergabe, indem Sie den Besitz von Modul- und Chunk-Objekten neu organisieren und zuweisen.
Der obige Konstruktionsprozess umfasst drei Schlüsselobjekte: Chunk, ChunkGroup und ChunkGraph. Fassen wir zunächst ihre Konzepte und Funktionen zusammen, um unser Verständnis zu vertiefen:
Chunk
: Modul wird verwendet, um Modulinhalte zu lesen, Abhängigkeiten zwischen Modulen aufzuzeichnen usw.; während Chunk mehrere Module basierend auf Modulabhängigkeiten zusammenführt und in Asset-Dateien ausgibt (die Logik der Zusammenführung und Ausgabe von Produkten wird im nächsten Kapitel erläutert):ChunkGroup
:eins ChunkGroup
enthält eine oder mehrereChunk
Objekt;ChunkGroup
UndChunkGroup
Eine Eltern-Kind-Abhängigkeitsbeziehung entsteht zwischen:ChunkGraph
: Schließlich speichert Webpack die Abhängigkeiten zwischen Chunks und ChunkGroups in compilation.chunkGraph
Im Objekt werden folgende Typbeziehungen gebildet:Obenstehendes ChunkGraph
Der Build-Prozess organisiert das Modul letztendlich in drei verschiedene Arten von Chunks:
entry
Die durch die untere Berührung erreichten Module sind in einem Chunk organisiert;entry.runtime
Wenn es nicht leer ist, wird das Laufzeitmodul in einem Chunk organisiert.Dies ist in Webpack integriert, sofern es nicht verwendet wird splitChunks
Bei anderen Plug-Ins sind die Standardregeln für die Zuordnung der Moduleingabe zur Ausgabe eines der wichtigsten Grundprinzipien von Webpack. Daher ist es erforderlich, die spezifischen Regeln jedes Chunks einzuführen.
Eintragsblock:
Beginnend mit dem Entry Chunk wird zunächst Webpack ausgeführt entry
erstellenChunk
Objekt, zum Beispiel die folgende Konfiguration:
module.exports = {
entry: {
main: "./src/main",
home: "./src/home",
}
};
Traverse entry
Objekteigenschaften und erstellenchunk[main]
、chunk[home]
Zwei Objekte, die zu diesem Zeitpunkt jeweils zwei Chunks enthaltenmain
、home
Modul:
Nach Abschluss der Initialisierung wird Webpack dies tun ModuleGraph
Abhängigkeitsdaten, Willeentry
Alle im Folgenden berührten Module werden in den Chunk (vorkommend in) gestopftBesuchsmodule Methode), zum Beispiel für die folgenden Dateiabhängigkeiten:
main.js
Wenn die vier Dateien a/b/c/d direkt oder indirekt synchron referenziert werden, wird Webpack dies zuerst tunmain.js
Das Modul erstellt Chunk- und EntryPoint-Objekte und fügt dann nach und nach a/b/c/d-Module hinzuchunk[main]
, schließlich bilden:
Asynchroner Block:
Zweitens kompiliert Webpack jede asynchrone Importanweisung (import(xxx)
Undrequire.ensure
) wird als separates Chunk-Objekt verarbeitet und alle seine Submodule werden diesem Chunk hinzugefügt – wir nennen ihn Async Chunk. Zum Beispiel für das folgende Beispiel:
// index.js
import './sync-a.js'
import './sync-b.js'
import('./async-a.js')
// async-a.js
import './sync-c.js'
Im Einstiegsmodul index.js
In werden sync-a und sync-b auf synchrone Weise eingeführt; das async-a-Modul wird gleichzeitig auf asynchrone Weise eingeführt; in async-a wird das async-a-Modul auf synchrone Weise eingeführt.sync-c
Modul, das das folgende Modulabhängigkeitsdiagramm bildet:
Zu diesem Zeitpunkt wird Webpack der Einstiegspunkt sein index.js
, asynchrones Modul async-a.js
Erstellen Sie Unterpakete separat, um die folgende Chunk-Struktur zu bilden:
Und chunk[index]
Undchunk[async-a]
Zwischen ihnen wird eine einseitige Abhängigkeit gebildet, und Webpack speichert diese Abhängigkeit inChunkGroup._parents
、ChunkGroup._children
in Immobilien.
Laufzeit-Chunk:
Endlich, außer entry
Zusätzlich zu asynchronen Modulen unterstützt Webpack5 auch das separate Extrahieren von Laufzeitcode in Chunks. Der hier erwähnte Laufzeitcode bezieht sich auf eine Reihe grundlegender Framework-Codes, die von Webpack eingefügt werden, um sicherzustellen, dass das verpackte Produkt normal ausgeführt werden kann. Die allgemeine Struktur des verpackten Webpack-Produkts lautet beispielsweise wie folgt:
Der große Codeabschnitt, der im roten Feld im obigen Bild eingekreist ist, ist der von Webpack dynamisch generierte Laufzeitcode. Beim Kompilieren entscheidet Webpack basierend auf dem Geschäftscode (basierend auf).Dependency
Unterklasse), zum Beispiel:
__webpack_require__.f
、__webpack_require__.r
und andere Funktionen, um eine minimale modulare Unterstützung zu erreichen;__webpack_require__.e
Funktion;__webpack_require__.o
Funktion;Obwohl jeder Teil des Laufzeitcodes klein sein kann, wird das Endergebnis immer größer. Insbesondere bei Anwendungen mit mehreren Einträgen ist es etwas verschwenderisch, bei jedem Eintrag wiederholt eine ähnliche Laufzeit zu packen entry.runtime
Konfigurationselemente werden verwendet, um zu deklarieren, wie Laufzeitcode gepackt wird.Zur Verwendung einfach verwendenentry
Fügen Sie dem Element eine Zeichenfolgenform hinzuruntime
Wert, zum Beispiel:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
}
};
existieren compilation.seal
In der Funktion steht Webpack an erster Stelleentry
erstellenEntryPoint
, dann urteilen entry
Enthält die Konfigurationruntime
Eigenschaften, falls vorhanden, erstellen Sie sie mitruntime
Der Wert ist der Name des Chunks. Daher generiert die obige Beispielkonfiguration zwei Chunks:chunk[index.js]
、chunk[solid-runtime]
, und darauf basierend werden schließlich zwei Dateien ausgegeben:
index.js
dokumentieren;solid-runtime.js
dokumentieren.in vielen entry
Im Szenario nur für jedenentry
Alle gleich eingestelltruntime
Wert wird der Webpack-Laufzeitcode zusammengeführt und in denselben Laufzeitblock geschrieben, wodurch letztendlich eine Optimierung der Produktleistung erreicht wird. Zum Beispiel für die folgende Konfiguration:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
home: { import: "./src/home", runtime: "solid-runtime" },
}
};
Eingang index
、home
das Gleiche teilenruntime
Wert und generieren schließlich jeweils drei Chunks:
Einlass zu dieser Zeit chunk[index]
、chunk[home]
mit Laufzeitchunk[solid-runtime]
Es entsteht auch ein Eltern-Kind-Abhängigkeitsverhältnis.
Das größte Problem mit den Standard-Unterverpackungsregeln besteht darin, dass Modulduplizierungen nicht behoben werden können. Wenn mehrere Chunks gleichzeitig dasselbe Modul enthalten, wird dieses Modul ohne Einschränkung wiederholt in diese Chunks gepackt. Angenommen, wir haben zwei Einträge main/index, die beide vom selben Modul abhängen:
Standardmäßig führt Webpack hierfür keine zusätzliche Verarbeitung durch, sondern packt das C-Modul einfach gleichzeitig in die beiden Haupt-/Index-Chunks, wodurch letztendlich Folgendes entsteht:
kann gesehen werden chunk
Sind sie voneinander isoliert, wird Modul c wiederholt verpackt, was zu unnötigen Leistungseinbußen beim Endprodukt führen kann!
Um dieses Problem zu lösen, wurde Webpack 3 eingeführt CommonChunkPlugin
Das Plugin versucht, gemeinsame Abhängigkeiten zwischen Einträgen in separate zu extrahierenchunk
,Aber CommonChunkPlugin
Es basiert im Wesentlichen auf der einfachen Eltern-Kind-Beziehungskette zwischen Chunks. Es ist schwierig, daraus zu schließen, dass das extrahierte dritte Paket verwendet werden sollteentry
Vaterchunk
Immer noch ein Kindchunk
,CommonChunkPlugin
einheitliche Verarbeitung als übergeordnetes Elementchunk
, in einigen Fällen hat es erhebliche negative Auswirkungen auf die Leistung.
Aus diesem Grund wurden nach Webpack 4 gezielt komplexere Datenstrukturen eingeführt. ChunkGroup
Spezialisiert auf die Umsetzung von Beziehungskettenmanagement und ZusammenarbeitSplitChunksPlugin
effizienter und intelligenter umgesetzt werden könnenHeuristische Unterauftragsvergabe.
Zusammenfassend ist die Phase „Build“ für den Aufbau des ModuleGraphs basierend auf der Referenzbeziehung des Moduls verantwortlich; die Phase „Encapsulation“ ist für den Aufbau einer Reihe von Chunk-Objekten basierend auf dem ModuleGraph und die Organisation der Abhängigkeiten zwischen Chunks (asynchrone Referenzen, Laufzeit) verantwortlich ) in ChunkGraph – Chunk-Abhängigkeitsdiagrammobjekt. Ähnlich wie bei ModuleGraph kann die Einführung der ChunkGraph-Struktur auch die Verwaltungslogik von Abhängigkeiten zwischen Chunks entkoppeln, wodurch die Gesamtarchitekturlogik vernünftiger und einfacher erweiterbar wird.
Auch wenn es sehr kompliziert aussieht, besteht das wichtigste Ziel der „Verpackungs“-Phase immer noch darin, zu bestimmen, wie viele Chunks vorhanden sind und welche Module in jedem Chunk enthalten sind – das sind die Schlüsselfaktoren, die das endgültige Verpackungsergebnis wirklich beeinflussen.
Für diesen Punkt müssen wir die drei integrierten Unterauftragsregeln von Webpack5 verstehen: Entry Chunk, Async Chunk und Runtime Chunk. Dies sind die originellsten Unterauftragslogiken (z. B splitChunksPlugin) basieren alle darauf, mit Hilfe von buildChunkGraph
Verschiedene Hooks lösten später eine weitere Aufteilung, Zusammenführung und Optimierung der Chunk-Struktur aus, um erweiterte Unterauftragseffekte zu erzielen.
denken Chunk
Wird nur eine Produktdatei erstellt? Warum?mini-css-extract-plugin
、file-loader
Wie wird diese Art von Komponente, die zusätzliche Dateien schreiben kann, unten implementiert?