le mie informazioni di contatto
Posta[email protected]
2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Oltre al processo principale, spiegheremo in dettaglio anche alcuni concetti vaghi:
davanti Init, Crea, Sigilla"In ", abbiamo introdotto che la logica costruttiva sottostante a Webpack può essere grossolanamente suddivisa in: "Inizializzazione, costruzione, confezionamento"tre fasi:
In,"Costruire"La fase è responsabile dell'analisi delle dipendenze tra i moduli e della definizione del file Grafico delle dipendenze(Grafico Modulo); quindi, in "Incapsulamento", in base al grafico delle dipendenze, i moduli vengono incapsulati separatamente in diversi oggetti Chunk e le relazioni di dipendenza padre-figlio tra Chunk vengono ordinate in ChunkGraph e diversi oggetti ChunkGroup.
L'obiettivo più importante della fase di "incapsulamento" è costruire il grafico delle relazioni ChunkGraph basato sul grafico delle relazioni ModuleGraph raccolto nella fase di "costruzione". La logica di questo processo è relativamente complessa:
Analizziamo qui brevemente la logica di implementazione di alcuni passaggi importanti.
Il primo passo è molto critico: trasferimentoseal()
Dopo la funzione, traversaentry
Configurazione, creane uno vuoto per ogni voceChunk
EPunto d'entrata oggetto (uno specialeChunkGroup
) e inizialmente impostare il file basic ChunkGraph
Relazione strutturale, prepararsi per il passaggio successivo, codice chiave:
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);
// 触发各种优化钩子
// ...
}
}
Al termine dell'esecuzione, viene formata la seguente struttura dati:
In secondo luogo, se configurato in questo momento entry.runtime
, Webpack fornirà anche il codice runtime in questa fase creare Il Chunk corrispondente e direttamentedistribuire Dareentry
corrispondenteChunkGroup
oggetto.Chiamato quando tutto è prontocostruireChunkGraph funzione, andare al passaggio successivo.
Passo due: esisterebuildChunkGraph
all'interno della funzionetrasferimento visitModules
Funzione, attraversa il ModuleGraph e assegna tutti i moduli a diversi moduli in base alle loro dipendenze.Chunk
Oggetto; se incontrato durante questo processomodulo asincrono, quindi il modulo crearenuovo ChunkGroup
EChunk
Oggetto, che in definitiva forma la seguente struttura dati:
terzo passo: esisterebuildChunkGraph
in funzionetrasferimento connectChunkGroups
metodo, costruireChunkGroup
fra,Chunk
dipendenze tra loro per generare un file completoChunkGraph
Oggetto, che in definitiva forma la seguente struttura dati:
il quarto passo: esisterebuildChunkGraph
in funzionetrasferimento cleanupUnconnectedGroups
Metodo, la pulizia non è validaChunkGroup
, svolge principalmente un ruolo nell'ottimizzazione delle prestazioni.
Dopo aver eseguito questi quattro passaggi dall'alto verso il basso,ModuleGraph
I moduli archiviati verranno assegnati a tre diversi oggetti Chunk: Entry, Async e Runtime in base alla natura del modulo stesso e le dipendenze tra Chunk verranno archiviate nelle raccolte ChunkGraph e ChunkGroup. È possibile continuare in base a questi oggetti in futuro modificare le politiche di subappalto (es.SplitChunksPlugin
), realizzare l'ottimizzazione del conto lavoro riorganizzando e assegnando la proprietà degli oggetti Modulo e Blocco.
Il processo di costruzione di cui sopra coinvolge tre oggetti chiave: Chunk, ChunkGroup e ChunkGraph Riassumiamo innanzitutto i loro concetti e funzioni per approfondire la nostra comprensione:
Chunk
: Il modulo viene utilizzato per leggere il contenuto del modulo, registrare le dipendenze tra moduli, ecc.; mentre Chunk unisce più moduli in base alle dipendenze del modulo e li genera in file di risorse (la logica dell'unione e dell'output dei prodotti verrà spiegata nel capitolo successivo):ChunkGroup
:uno ChunkGroup
ne contiene uno o piùChunk
oggetto;ChunkGroup
EChunkGroup
Si forma una relazione di dipendenza genitore-figlio tra:ChunkGraph
: Infine, Webpack memorizzerà le dipendenze tra Chunks e ChunkGroups in compilation.chunkGraph
Nell'oggetto si formano le seguenti relazioni di tipo:Quanto sopra ChunkGraph
Il processo di creazione organizzerà infine il modulo in tre diversi tipi di blocchi:
entry
I moduli raggiunti dal touch inferiore sono organizzati in Chunk;entry.runtime
Quando non è vuoto, il modulo runtime sarà organizzato in un Chunk.Questo è integrato in Webpack, se non utilizzato splitChunks
Nel caso di altri plug-in, le regole predefinite per la mappatura dell'input del modulo all'output sono uno dei principi chiave alla base di Webpack, quindi è necessario introdurre le regole specifiche di ciascun Chunk.
Frammento di ingresso:
A partire da Entry Chunk, Webpack lo farà per primo entry
creareChunk
Oggetto, ad esempio, la seguente configurazione:
module.exports = {
entry: {
main: "./src/main",
home: "./src/home",
}
};
Attraversare entry
proprietà dell'oggetto e crearechunk[main]
、chunk[home]
Due oggetti, in questo momento i due Chunk contengono rispettivamentemain
、home
Modulo:
Una volta completata l'inizializzazione, Webpack lo farà ModuleGraph
dati sulla dipendenza, volontàentry
Tutti i moduli toccati da quanto segue vengono inseriti nel Chunk (che si verifica invisitaModuli metodo), ad esempio, per le seguenti dipendenze file:
main.js
Se si fa riferimento direttamente o indirettamente ai quattro file a/b/c/d in modo sincrono, Webpack lo farà per primomain.js
Il modulo crea oggetti Chunk e EntryPoint, quindi aggiunge gradualmente moduli a/b/c/dchunk[main]
, formando infine:
Blocco asincrono:
In secondo luogo, Webpack compilerà ogni istruzione di importazione asincrona (import(xxx)
Erequire.ensure
) viene elaborato come un oggetto Chunk separato e tutti i suoi sottomoduli vengono aggiunti a questo Chunk: lo chiamiamo Async Chunk. Ad esempio, per il seguente esempio:
// index.js
import './sync-a.js'
import './sync-b.js'
import('./async-a.js')
// async-a.js
import './sync-c.js'
Nel modulo di inserimento index.js
In, sync-a e sync-b vengono introdotti in modo sincrono; il modulo async-a viene introdotto in modo asincrono; allo stesso tempo, in async-a, il modulo async-a viene introdotto in modo sincrono;sync-c
modulo, formando il seguente diagramma delle dipendenze del modulo:
A questo punto, Webpack sarà il punto di ingresso index.js
, modulo asincrono async-a.js
Crea sottopacchetti separatamente per formare la seguente struttura Chunk:
E chunk[index]
Echunk[async-a]
Tra loro si forma una dipendenza unidirezionale e Webpack salverà questa dipendenzaChunkGroup._parents
、ChunkGroup._children
nelle proprietà.
Frammento di runtime:
Infine, tranne entry
, Oltre ai moduli asincroni, Webpack5 supporta anche l'estrazione del codice runtime separatamente in blocchi. Il codice runtime menzionato qui si riferisce a una serie di codici framework di base inseriti da Webpack per garantire che il prodotto in pacchetto possa essere eseguito normalmente. Ad esempio, la struttura comune del prodotto in pacchetto Webpack è la seguente:
La grande sezione di codice cerchiata nel riquadro rosso nell'immagine sopra è il codice runtime generato dinamicamente da Webpack Durante la compilazione, Webpack deciderà quale codice runtime generare in base al codice aziendale (basato suDependency
sottoclasse), ad esempio:
__webpack_require__.f
、__webpack_require__.r
e altre funzioni per ottenere un supporto modulare minimo;__webpack_require__.e
funzione;__webpack_require__.o
funzione;Anche se ogni pezzo di codice runtime può essere piccolo, man mano che le funzionalità aumentano, il risultato finale diventerà sempre più grande. Soprattutto per le applicazioni a più voci, è un po' uno spreco confezionare ripetutamente un runtime simile per ogni voce fornita da questo Webpack5 entry.runtime
Gli elementi di configurazione vengono utilizzati per dichiarare la modalità di confezionamento del codice runtime.Per l'utilizzo, basta usareentry
Aggiungi il formato stringa all'elementoruntime
valore, ad esempio:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
}
};
esistere compilation.seal
Nella funzione, Webpack è innanzituttoentry
creareEntryPoint
, poi giudica entry
La configurazione contieneruntime
proprietà, se ce ne sono, creale conruntime
Il valore è il nome del Chunk Pertanto, la configurazione dell'esempio precedente genererà due Chunk:chunk[index.js]
、chunk[solid-runtime]
e in base a ciò vengono infine emessi due file:
index.js
documento;solid-runtime.js
documento.in molti entry
Nello scenario, solo per ciascunoentry
Tutto impostato allo stesso modoruntime
valore, il codice runtime di Webpack verrà unito e scritto nello stesso blocco runtime, ottenendo infine l'ottimizzazione delle prestazioni del prodotto. Ad esempio, per la seguente configurazione:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
home: { import: "./src/home", runtime: "solid-runtime" },
}
};
Entrata index
、home
condividere lo stessoruntime
valore, e infine generare tre Chunk, rispettivamente:
Ingresso in questo momento chunk[index]
、chunk[home]
con tempo di esecuzionechunk[solid-runtime]
Si formerà anche una relazione di dipendenza genitore-figlio.
Il problema più grande con le regole di sub-packaging predefinite è che non possono risolvere la duplicazione del modulo. Se più blocchi contengono lo stesso modulo contemporaneamente, questo modulo verrà ripetutamente impacchettato in questi blocchi senza restrizioni. Ad esempio, supponiamo di avere due voci main/index che dipendono entrambe dallo stesso modulo:
Per impostazione predefinita, Webpack non eseguirà ulteriori elaborazioni su questo, ma semplicemente impacchetterà il modulo c nei blocchi principale/indice allo stesso tempo, formando infine:
si può vedere chunk
sono isolati l'uno dall'altro, il modulo c viene confezionato ripetutamente, il che potrebbe causare un'inutile perdita di prestazioni del prodotto finale!
Per risolvere questo problema, è stato introdotto Webpack 3 CommonChunkPlugin
Il plugin tenta di estrarre le dipendenze comuni tra le voci in file separatichunk
,Ma CommonChunkPlugin
È essenzialmente implementato sulla base della semplice catena di relazioni genitore-figlio tra Chunks. È difficile dedurre che il terzo pacchetto estratto debba essere utilizzato comeentry
padrechunk
Ancora un ragazzinochunk
,CommonChunkPlugin
elaborazione unificata come genitorechunk
, in alcuni casi ha un notevole impatto negativo sulle prestazioni.
Per questo motivo, dopo il Webpack 4 sono state introdotte strutture dati più complesse—— ChunkGroup
Specializzato nella realizzazione di gestione e cooperazione della catena di relazioniSplitChunksPlugin
possono essere implementati in modo più efficiente e intelligenteSubappalto euristico.
In sintesi, la fase "Build" è responsabile della costruzione del ModuleGraph in base alla relazione di riferimento del modulo, la fase "Encapsulation" è responsabile della costruzione di una serie di oggetti Chunk basati sul ModuleGraph e dell'organizzazione delle dipendenze tra i Chunk (riferimenti asincroni, runtime); ) in ChunkGraph - Oggetto grafico Chunk Dependency. Similmente a ModuleGraph, l'introduzione della struttura ChunkGraph può anche disaccoppiare la logica di gestione delle dipendenze tra Chunk, rendendo la logica dell'architettura complessiva più ragionevole e più facile da espandere.
Tuttavia, anche se sembra molto complicato, l'obiettivo più importante della fase di "confezionamento" è comunque determinare quanti Chunk ci sono e quali Moduli sono inclusi in ciascun Chunk: questi sono i fattori chiave che influenzano realmente il risultato finale del packaging.
A questo punto, dobbiamo comprendere le tre regole di sotto-packaging integrate di Webpack5: Entry Chunk, Async Chunk e Runtime Chunk. Queste sono la logica del sotto-packaging più originale. Altri plug-in (come Plugin di suddivisione dei pezzi) sono tutti basati su questo, con l'aiuto di buildChunkGraph
Vari hook attivati successivamente dividono, uniscono e ottimizzano ulteriormente la struttura Chunk per ottenere effetti di subappalto ampliati.
pensare Chunk
Verrà prodotto un solo file di prodotto? Perché?mini-css-extract-plugin
、file-loader
Come viene implementato in basso questo tipo di componente che può scrivere file aggiuntivi?