minhas informações de contato
Correspondência[email protected]
2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Além do processo principal, também explicaremos detalhadamente vários conceitos vagos:
em frente Iniciar、Fazer、Selar"Em ", introduzimos que a lógica de construção subjacente do Webpack pode ser dividida em: "Inicialização, construção, embalagem"três fases:
em,"Construir“A fase é responsável por analisar as dependências entre os módulos e estabelecer as Gráfico de dependência(MóduloGraph); então, em "encapsulamento”Estágio, com base no gráfico de dependência, os módulos são encapsulados separadamente em vários objetos Chunk, e os relacionamentos de dependência pai-filho entre Chunks são classificados em ChunkGraph e vários objetos ChunkGroup.
O objetivo mais importante da fase de "encapsulação" é construir o gráfico de relacionamento ChunkGraph com base no gráfico de relacionamento ModuleGraph coletado na fase de "construção". A lógica deste processo é relativamente complexa:
Vamos analisar brevemente a lógica de implementação de várias etapas importantes aqui.
O primeiro passo é muito crítico: transferirseal()
Após a função, percorraentry
Configuração, crie uma vazia para cada entradaChunk
ePonto de entrada objeto (um especialChunkGroup
) e inicialmente configurei o básico ChunkGraph
Relacionamento estrutural, prepare-se para a próxima etapa, código-chave:
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);
// 触发各种优化钩子
// ...
}
}
Após a conclusão da execução, a seguinte estrutura de dados é formada:
Em segundo lugar, se configurado neste momento entry.runtime
, o Webpack também fornecerá código de tempo de execução nesta fase criar O pedaço correspondente e diretamentedistribuir Darentry
correspondenteChunkGroup
objeto.Chamado quando tudo estiver prontoconstruirChunkGraph função, vá para a próxima etapa.
Passo dois: existirbuildChunkGraph
dentro da funçãotransferir visitModules
Função, percorra o ModuleGraph e atribua todos os Módulos a módulos diferentes de acordo com suas dependências.Chunk
Objeto; se encontrado durante este processomódulo assíncrono, então o módulo criarnovo ChunkGroup
eChunk
Objeto, formando em última análise a seguinte estrutura de dados:
terceiro passo: existirbuildChunkGraph
em funçãotransferir connectChunkGroups
método, estabelecerChunkGroup
entre,Chunk
dependências entre si para gerar um completoChunkGraph
Objeto, formando em última análise a seguinte estrutura de dados:
o quarto passo: existirbuildChunkGraph
em funçãotransferir cleanupUnconnectedGroups
Método, a limpeza é inválidaChunkGroup
, desempenha principalmente um papel na otimização do desempenho.
Depois de passar por essas quatro etapas de cima para baixo,ModuleGraph
Os módulos armazenados serão atribuídos a três objetos Chunk diferentes: Entry, Async e Runtime de acordo com a natureza do próprio módulo, e as dependências entre os Chunks serão armazenadas nas coleções ChunkGraph e ChunkGroup. Você pode continuar com base nesses objetos. mais tarde. Modificar as políticas de subcontratação (por exemplo,SplitChunksPlugin
), realize a otimização da subcontratação reorganizando e alocando a propriedade dos objetos Module e Chunk.
O processo de construção acima envolve três objetos principais: Chunk, ChunkGroup e ChunkGraph. Vamos primeiro resumir seus conceitos e funções para aprofundar nossa compreensão:
Chunk
: o módulo é usado para ler o conteúdo do módulo, registrar dependências entre módulos, etc.; enquanto o Chunk mescla vários módulos com base nas dependências do módulo e os gera em arquivos de ativos (a lógica de mesclagem e saída de produtos será explicada no próximo capítulo):ChunkGroup
:um ChunkGroup
contém um ou maisChunk
objeto;ChunkGroup
eChunkGroup
Uma relação de dependência pai-filho é formada entre:ChunkGraph
: Finalmente, o Webpack armazenará as dependências entre Chunks e ChunkGroups em compilation.chunkGraph
No objeto, os seguintes relacionamentos de tipo são formados:O de cima ChunkGraph
O processo de construção organizará o Módulo em três tipos diferentes de Pedaços:
entry
Os módulos alcançados pelo toque inferior são organizados em um Chunk;entry.runtime
Quando não estiver vazio, o módulo de tempo de execução será organizado em um Chunk.Isso está embutido no Webpack, se não for usado splitChunks
No caso de outros plug-ins, as regras padrão para mapear a entrada do módulo para a saída são um dos principais princípios subjacentes do Webpack, por isso é necessário introduzir as regras específicas de cada Chunk.
Bloco de entrada:
Começando com o Entry Chunk, o Webpack irá primeiro entry
criarChunk
Objeto, por exemplo, a seguinte configuração:
module.exports = {
entry: {
main: "./src/main",
home: "./src/home",
}
};
Atravessar entry
propriedades do objeto e criarchunk[main]
、chunk[home]
Dois objetos, neste momento os dois Chunks contêm respectivamentemain
、home
Módulo:
Após a conclusão da inicialização, o Webpack irá ModuleGraph
dados de dependência, seráentry
Todos os módulos tocados a seguir são inseridos no Chunk (ocorrendo emvisitMódulos método), por exemplo, para as seguintes dependências de arquivo:
main.js
Se os quatro arquivos a/b/c/d forem referenciados direta ou indiretamente de forma síncrona, o Webpack primeiromain.js
O módulo cria objetos Chunk e EntryPoint e, em seguida, adiciona gradualmente módulos a/b/c/d achunk[main]
, finalmente formando:
Pedaço assíncrono:
Em segundo lugar, o Webpack irá compilar cada instrução de importação assíncrona (import(xxx)
erequire.ensure
) é processado como um objeto Chunk separado e todos os seus submódulos são adicionados a esse Chunk - nós o chamamos de Async Chunk. Por exemplo, para o exemplo a seguir:
// index.js
import './sync-a.js'
import './sync-b.js'
import('./async-a.js')
// async-a.js
import './sync-c.js'
No módulo de entrada index.js
Em, sync-a e sync-b são introduzidos de maneira síncrona; o módulo async-a é introduzido de maneira assíncrona; em async-a, o módulo async-a é introduzido de maneira síncrona;sync-c
módulo, formando o seguinte diagrama de dependência do módulo:
Neste ponto, o Webpack será o ponto de entrada index.js
, módulo assíncrono async-a.js
Crie subpacotes separadamente para formar a seguinte estrutura Chunk:
e chunk[index]
echunk[async-a]
Uma dependência unidirecional é formada entre eles, e o Webpack salvará essa dependência emChunkGroup._parents
、ChunkGroup._children
em propriedades.
Pedaço de tempo de execução:
Finalmente, exceto entry
, Além dos módulos assíncronos, o Webpack5 também oferece suporte à extração de código de tempo de execução separadamente em Chunks. O código de tempo de execução mencionado aqui refere-se a uma série de códigos de estrutura básicos injetados pelo Webpack para garantir que o produto empacotado possa ser executado normalmente. Por exemplo, a estrutura comum do produto empacotado do Webpack é a seguinte:
A grande seção de código circulada na caixa vermelha na imagem acima é o código de tempo de execução gerado dinamicamente pelo Webpack. Ao compilar, o Webpack decidirá qual código de tempo de execução será gerado com base no código de negócios (com base em).Dependency
subclasse), por exemplo:
__webpack_require__.f
、__webpack_require__.r
e outras funções para obter suporte modular mínimo;__webpack_require__.e
função;__webpack_require__.o
função;Embora cada parte do código de tempo de execução possa ser pequena, à medida que os recursos aumentam, o resultado final se tornará cada vez maior. Especialmente para aplicativos com várias entradas, é um desperdício empacotar repetidamente um tempo de execução semelhante em cada entrada. entry.runtime
Os itens de configuração são usados para declarar como o código de tempo de execução é empacotado.Para uso, basta usarentry
Adicionar formato de string ao itemruntime
valor, por exemplo:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
}
};
existir compilation.seal
Na função, Webpack primeiro éentry
criarEntryPoint
, então julgue entry
A configuração contémruntime
propriedades, se houver, crie-as comruntime
O valor é o nome do Chunk. Portanto, a configuração do exemplo acima irá gerar dois Chunks:chunk[index.js]
、chunk[solid-runtime]
, e com base nisso, dois arquivos são finalmente gerados:
index.js
documento;solid-runtime.js
documento.em muitos entry
No cenário, apenas para cadaentry
Tudo definido da mesma formaruntime
valor, o código de tempo de execução do Webpack será mesclado e gravado no mesmo Runtime Chunk, alcançando, em última análise, a otimização do desempenho do produto. Por exemplo, para a seguinte configuração:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
home: { import: "./src/home", runtime: "solid-runtime" },
}
};
Entrada index
、home
compartilhe o mesmoruntime
valor e, finalmente, gerar três pedaços, respectivamente:
Entrada neste horário chunk[index]
、chunk[home]
com tempo de execuçãochunk[solid-runtime]
Uma relação de dependência entre pais e filhos também será formada.
O maior problema com as regras de subempacotamento padrão é que elas não podem resolver a duplicação de módulos. Se vários pedaços contiverem o mesmo módulo ao mesmo tempo, então este módulo será repetidamente empacotado nesses pedaços sem restrição. Por exemplo, suponha que temos duas entradas main/index que dependem do mesmo módulo:
Por padrão, o Webpack não fará processamento adicional nisso, mas simplesmente empacotará o módulo c nos dois pedaços principal/índice ao mesmo tempo, formando em última análise:
pode ser visto chunk
são isolados um do outro, o módulo c é embalado repetidamente, o que pode causar perda desnecessária de desempenho no produto final!
Para resolver este problema, o Webpack 3 introduziu CommonChunkPlugin
O plugin tenta extrair dependências comuns entre entradas em separadochunk
,mas CommonChunkPlugin
É essencialmente implementado com base na simples cadeia de relacionamento pai-filho entre Chunks. É difícil inferir que o terceiro pacote extraído deva ser usado como.entry
paichunk
Ainda uma criançachunk
,CommonChunkPlugin
processamento unificado como paichunk
, em alguns casos tem um impacto negativo considerável no desempenho.
Por esta razão, estruturas de dados mais complexas foram introduzidas especificamente após o Webpack 4—— ChunkGroup
Especializada em realizar gestão e cooperação da cadeia de relacionamentoSplitChunksPlugin
pode ser implementado de forma mais eficiente e inteligenteSubcontratação heurística.
Em resumo, a fase “Build” é responsável por construir o ModuleGraph com base no relacionamento de referência do módulo; a fase “Encapsulation” é responsável por construir uma série de objetos Chunk baseados no ModuleGraph e organizar as dependências entre os Chunks (referências assíncronas, tempo de execução). ) em ChunkGraph - objeto gráfico de dependência de Chunk. Semelhante ao ModuleGraph, a introdução da estrutura ChunkGraph também pode dissociar a lógica de gerenciamento de dependências entre os Chunks, tornando a lógica geral da arquitetura mais razoável e mais fácil de expandir.
No entanto, embora pareça muito complicado, o objetivo mais importante da etapa de “empacotamento” ainda é determinar quantos Chunks existem e quais Módulos estão incluídos em cada Chunk – esses são os fatores-chave que realmente afetam o resultado final do empacotamento.
Para este ponto, precisamos entender as três regras de subcontratação integradas do Webpack5: Entry Chunk, Async Chunk e Runtime Chunk. Essas são as lógicas de subcontratação mais originais. splitChunksPlugin) são todos baseados nisso, com a ajuda de buildChunkGraph
Vários ganchos acionados posteriormente dividem, mesclam e otimizam a estrutura do Chunk para obter efeitos de subcontratação expandidos.
pensar Chunk
Será produzido apenas um arquivo de produto? Por que?mini-css-extract-plugin
、file-loader
Como esse tipo de componente que pode gravar arquivos adicionais é implementado na parte inferior?