Mi informacion de contacto
Correo[email protected]
2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Además del proceso principal, también explicaremos en detalle varios conceptos vagos:
Al frente Inicializar, hacer y sellar"En", hemos introducido que la lógica de construcción subyacente de Webpack se puede dividir aproximadamente en: "Inicialización, construcción, embalaje."tres fases:
en,"Construir"La fase se encarga de analizar las dependencias entre módulos y establecer las Gráfico de dependencia(ModuleGraph); luego, en "EncapsulaciónEn la etapa, según el gráfico de dependencia, los módulos se encapsulan por separado en varios objetos Chunk y las relaciones de dependencia padre-hijo entre Chunks se clasifican en ChunkGraph y varios objetos ChunkGroup.
El objetivo más importante de la fase de "encapsulación" es construir el gráfico de relaciones ChunkGraph basado en el gráfico de relaciones ModuleGraph recopilado en la fase de "construcción". La lógica de este proceso es relativamente compleja:
Analicemos brevemente la lógica de implementación de varios pasos importantes aquí.
El primer paso es muy crítico: transferirseal()
Después de la función, atraviesaentry
Configuración, crea uno vacío para cada entradaChunk
yPunto de entrada objeto (un especialChunkGroup
), y configurar inicialmente el básico ChunkGraph
Relación estructural, prepárese para el siguiente paso, código clave:
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);
// 触发各种优化钩子
// ...
}
}
Una vez completada la ejecución, se forma la siguiente estructura de datos:
En segundo lugar, si está configurado en este momento entry.runtime
Webpack también proporcionará código de tiempo de ejecución en esta etapa. crear El Chunk correspondiente y directamentedistribuir Darentry
correspondienteChunkGroup
objeto.Llamado cuando todo está listo.ConstruirChunkGraph función, vaya al siguiente paso.
Segundo paso: existirbuildChunkGraph
dentro de la funcióntransferir visitModules
Función, atraviesa ModuleGraph y asigna todos los módulos a diferentes módulos según sus dependencias.Chunk
Objeto; si se encuentra durante este proceso;módulo asíncrono, entonces el módulo crearnuevo ChunkGroup
yChunk
Objeto, que finalmente forma la siguiente estructura de datos:
tercer paso: existirbuildChunkGraph
en funcióntransferir connectChunkGroups
método, construirChunkGroup
entre,Chunk
dependencias entre sí para generar una completaChunkGraph
Objeto, que finalmente forma la siguiente estructura de datos:
el cuarto paso: existirbuildChunkGraph
en funcióntransferir cleanupUnconnectedGroups
Método, la limpieza no es válidaChunkGroup
, juega principalmente un papel en la optimización del rendimiento.
Después de seguir estos cuatro pasos de arriba a abajo,ModuleGraph
Los módulos almacenados se asignarán a tres objetos Chunk diferentes: Entry, Async y Runtime según la naturaleza del módulo en sí, y las dependencias entre Chunks se almacenarán en las colecciones ChunkGraph y ChunkGroup. Puede continuar en función de estos objetos. en el futuro modificar las políticas de subcontratación (p. ej.SplitChunksPlugin
), logra la optimización de la subcontratación reorganizando y asignando la propiedad de los objetos Módulo y Chunk.
El proceso de construcción anterior involucra tres objetos clave: Chunk, ChunkGroup y ChunkGraph. Primero resumamos sus conceptos y funciones para profundizar nuestra comprensión:
Chunk
: El módulo se utiliza para leer el contenido del módulo, registrar dependencias entre módulos, etc.; mientras que Chunk fusiona varios módulos en función de las dependencias del módulo y los genera en archivos de activos (la lógica de fusionar y generar productos se explicará en el siguiente capítulo):ChunkGroup
:uno ChunkGroup
contiene uno o másChunk
objeto;ChunkGroup
yChunkGroup
Se forma una relación de dependencia padre-hijo entre:ChunkGraph
: Finalmente, Webpack almacenará las dependencias entre Chunks y ChunkGroups en compilation.chunkGraph
En el objeto se forman las siguientes relaciones de tipo:Lo anterior ChunkGraph
En última instancia, el proceso de construcción organizará el módulo en tres tipos diferentes de fragmentos:
entry
Los módulos alcanzados por el toque inferior se organizan en un Chunk;entry.runtime
Cuando no está vacío, el módulo de ejecución se organizará en un fragmento.Esto está integrado en Webpack, si no se usa splitChunks
En el caso de otros complementos, las reglas predeterminadas para asignar la entrada del módulo a la salida son uno de los principios subyacentes clave de Webpack, por lo que es necesario introducir las reglas específicas de cada Chunk.
Fragmento de entrada:
Comenzando con Entry Chunk, Webpack primero entry
crearChunk
Objeto, por ejemplo, la siguiente configuración:
module.exports = {
entry: {
main: "./src/main",
home: "./src/home",
}
};
atravesar entry
propiedades del objeto y crearchunk[main]
、chunk[home]
Dos objetos, en este momento los dos trozos contienen respectivamentemain
、home
Módulo:
Una vez completada la inicialización, Webpack ModuleGraph
datos de dependencia,entry
Todos los módulos tocados por lo siguiente se insertan en el Chunk (que ocurre enVisitaMódulos método), por ejemplo, para las siguientes dependencias de archivos:
main.js
Si se hace referencia directa o indirectamente a los cuatro archivos a/b/c/d de forma sincrónica, Webpack primeromain.js
El módulo crea objetos Chunk y EntryPoint y luego agrega gradualmente módulos a/b/c/d achunk[main]
, formando finalmente:
Fragmento asincrónico:
En segundo lugar, Webpack compilará cada declaración de importación asincrónica (import(xxx)
yrequire.ensure
) se procesa como un objeto Chunk separado y todos sus submódulos se agregan a este Chunk; lo llamamos Async Chunk. Por ejemplo, para el siguiente ejemplo:
// index.js
import './sync-a.js'
import './sync-b.js'
import('./async-a.js')
// async-a.js
import './sync-c.js'
En el módulo de entrada index.js
En, sync-a y sync-b se introducen de forma sincrónica; el módulo async-a se introduce de forma asincrónica; en async-a, el módulo async-a se introduce de forma sincrónica;sync-c
módulo, formando el siguiente diagrama de dependencia del módulo:
En este punto, Webpack será el punto de entrada. index.js
, módulo asíncrono async-a.js
Cree subpaquetes por separado para formar la siguiente estructura de fragmentos:
y chunk[index]
ychunk[async-a]
Se forma una dependencia unidireccional entre ellos y Webpack guardará esta dependencia enChunkGroup._parents
、ChunkGroup._children
en propiedades.
Fragmento de tiempo de ejecución:
Finalmente, excepto entry
Además de los módulos asincrónicos, Webpack5 también admite la extracción de código de tiempo de ejecución por separado en fragmentos. El código de tiempo de ejecución mencionado aquí se refiere a una serie de códigos de marco básicos inyectados por Webpack para garantizar que el producto empaquetado pueda ejecutarse normalmente. Por ejemplo, la estructura común del producto empaquetado de Webpack es la siguiente:
La gran sección de código rodeada en el cuadro rojo en la imagen de arriba es el código de tiempo de ejecución generado dinámicamente por Webpack. Al compilar, Webpack decidirá qué código de tiempo de ejecución generar según el código comercial (según.Dependency
subclase), por ejemplo:
__webpack_require__.f
、__webpack_require__.r
y otras funciones para lograr un soporte modular mínimo;__webpack_require__.e
función;__webpack_require__.o
función;Aunque cada fragmento de código de tiempo de ejecución puede ser pequeño, a medida que aumentan las funciones, el resultado final será cada vez más grande. Especialmente para aplicaciones de múltiples entradas, es un poco derrochador empaquetar repetidamente un tiempo de ejecución similar en cada entrada. entry.runtime
Los elementos de configuración se utilizan para declarar cómo se empaqueta el código de ejecución.Para su uso, simplemente useentry
Agregar forma de cadena al artículoruntime
valor, por ejemplo:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
}
};
existir compilation.seal
En la función, Webpack primero esentry
crearEntryPoint
, entonces juzga entry
¿La configuración contieneruntime
propiedades, si las hay, créalas conruntime
El valor es el nombre del fragmento. Por lo tanto, la configuración del ejemplo anterior generará dos fragmentos:chunk[index.js]
、chunk[solid-runtime]
, y en base a esto, finalmente se generan dos archivos:
index.js
documento;solid-runtime.js
documento.en muchos entry
En el escenario, solo para cadaentry
Todos configurados igualruntime
valor, el código de tiempo de ejecución de Webpack se fusionará y escribirá en el mismo Runtime Chunk, logrando en última instancia la optimización del rendimiento del producto. Por ejemplo, para la siguiente configuración:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
home: { import: "./src/home", runtime: "solid-runtime" },
}
};
Entrada index
、home
compartir el mismoruntime
valor y finalmente generar tres fragmentos, respectivamente:
Entrada en este momento chunk[index]
、chunk[home]
con tiempo de ejecuciónchunk[solid-runtime]
También se formará una relación de dependencia entre padres e hijos.
El mayor problema con las reglas de subempaquetado predeterminadas es que no pueden resolver la duplicación de módulos. Si varios fragmentos contienen el mismo módulo al mismo tiempo, este módulo se empaquetará repetidamente en estos fragmentos sin restricciones. Por ejemplo, supongamos que tenemos dos entradas main/index y ambas dependen del mismo módulo:
De forma predeterminada, Webpack no realizará procesamiento adicional sobre esto, sino que simplemente empaquetará el módulo c en los fragmentos principal/índice al mismo tiempo, formando finalmente:
puede ser visto chunk
están aislados entre sí, el módulo c se empaqueta repetidamente, lo que puede causar una pérdida innecesaria de rendimiento en el producto final.
Para resolver este problema, se introdujo Webpack 3. CommonChunkPlugin
El complemento intenta extraer dependencias comunes entre entradas en separadochunk
,pero CommonChunkPlugin
Básicamente, se implementa en base a una simple cadena de relaciones padre-hijo entre fragmentos. Es difícil inferir que el tercer paquete extraído deba usarse como tal.entry
padrechunk
todavía un niñochunk
,CommonChunkPlugin
procesamiento unificado como padrechunk
, en algunos casos tiene un impacto negativo considerable en el rendimiento.
Por esta razón, se introdujeron específicamente estructuras de datos más complejas después de Webpack 4—— ChunkGroup
Especializados en realizar gestión de cadenas de relaciones y cooperación.SplitChunksPlugin
se puede implementar de manera más eficiente e inteligenteSubcontratación heurística.
En resumen, la fase "Construir" es responsable de construir ModuleGraph según la relación de referencia del módulo; la fase "Encapsulación" es responsable de construir una serie de objetos Chunk basados en ModuleGraph y organizar las dependencias entre Chunks (referencias asincrónicas, tiempo de ejecución). ) en ChunkGraph: objeto gráfico de dependencia de fragmentos. Al igual que ModuleGraph, la introducción de la estructura ChunkGraph también puede desacoplar la lógica de gestión de dependencias entre Chunks, lo que hace que la lógica de la arquitectura general sea más razonable y más fácil de expandir.
Sin embargo, aunque parezca muy complicado, el objetivo más importante de la etapa de "empaquetado" sigue siendo determinar cuántos fragmentos hay y qué módulos se incluyen en cada fragmento; estos son los factores clave que realmente afectan el resultado final del empaquetado.
Para este punto, debemos comprender las tres reglas de subempaquetado integradas de Webpack5: Entry Chunk, Async Chunk y Runtime Chunk. Estas son la lógica de subempaquetado más original. complemento splitChunks) se basan todos en esto, con la ayuda de buildChunkGraph
Varios ganchos activados posteriormente dividieron, fusionaron y optimizaron aún más la estructura Chunk para lograr efectos de subcontratación ampliados.
pensar Chunk
¿Se producirá sólo un archivo de producto? ¿Por qué?mini-css-extract-plugin
、file-loader
¿Cómo se implementa este tipo de componente que puede escribir archivos adicionales en la parte inferior?