내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-08
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
주요 프로세스 외에도 몇 가지 모호한 개념을 자세히 설명합니다.
앞에 초기화、만들기、봉인"에서 우리는 Webpack의 기본 구성 논리를 대략 다음과 같이 나눌 수 있음을 소개했습니다. "초기화, 구성, 패키징"3단계:
안에,"건설하다"이 단계는 모듈 간의 종속성을 분석하고 종속성 그래프(ModuleGraph)에서 "캡슐화” 단계에서는 종속성 그래프를 기반으로 모듈을 여러 Chunk 개체로 개별적으로 캡슐화하고 Chunk 간의 부모-자식 종속 관계를 ChunkGraph와 여러 ChunkGroup 개체로 정렬합니다.
"캡슐화" 단계의 가장 중요한 목표는 "빌드" 단계에서 수집된 ModuleGraph 관계 그래프를 기반으로 ChunkGraph 관계 그래프를 구성하는 것입니다. 이 프로세스의 논리는 비교적 복잡합니다.
여기서 몇 가지 중요한 단계의 구현 논리를 간략하게 분석해 보겠습니다.
첫 번째 단계는 매우 중요합니다. 옮기다seal()
함수 후 트래버스entry
구성, 각 항목에 대해 빈 항목을 만듭니다.Chunk
그리고진입 지점 객체(특수ChunkGroup
), 처음에는 기본을 설정합니다. ChunkGraph
구조적 관계, 다음 단계 준비, 키 코드:
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);
// 触发各种优化钩子
// ...
}
}
실행이 완료되면 다음과 같은 데이터 구조가 형성됩니다.
둘째, 이때 구성하면 entry.runtime
, Webpack은 이 단계에서 런타임 코드도 제공합니다. 만들다 해당 Chunk와 직접적으로분배하다 주다entry
동ChunkGroup
물체.모든 것이 준비되면 호출됩니다.빌드 청크 그래프 기능을 사용하려면 다음 단계로 이동하세요.
2단계: 존재하다buildChunkGraph
기능 내에서옮기다 visitModules
함수를 사용하여 ModuleGraph를 탐색하고 종속성에 따라 모든 모듈을 다른 모듈에 할당합니다.Chunk
이 과정에서 객체가 발견되면;비동기 모듈, 그 다음 모듈 만들다새로운 ChunkGroup
그리고Chunk
객체는 궁극적으로 다음과 같은 데이터 구조를 형성합니다.
세 번째 단계: 존재하다buildChunkGraph
기능상옮기다 connectChunkGroups
방법, 확립하다ChunkGroup
사이,Chunk
완전한 생성을 위해 서로 간의 종속성ChunkGraph
객체는 궁극적으로 다음과 같은 데이터 구조를 형성합니다.
네 번째 단계: 존재하다buildChunkGraph
기능상옮기다 cleanupUnconnectedGroups
방법, 정리가 잘못되었습니다.ChunkGroup
, 주로 성능 최적화에 역할을 합니다.
위의 4가지 단계를 거쳐 아래로 이동한 후,ModuleGraph
에 저장된 모듈은 모듈 자체의 특성에 따라 Entry, Async 및 Runtime의 세 가지 다른 청크 개체에 할당되며 청크 간의 종속성은 ChunkGraph 및 ChunkGroup 컬렉션에 저장됩니다. 나중에 하도급 정책을 수정합니다(예:SplitChunksPlugin
), Module 및 Chunk 객체의 소유권을 재구성하고 할당하여 하도급 최적화를 실현합니다.
위의 구성 프로세스에는 Chunk, ChunkGroup 및 ChunkGraph의 세 가지 주요 개체가 포함됩니다. 먼저 이해를 돕기 위해 해당 개념과 기능을 요약하겠습니다.
Chunk
: 모듈은 모듈 내용을 읽고 모듈 간 종속성을 기록하는 데 사용되며 Chunk는 모듈 종속성을 기반으로 여러 모듈을 병합하여 자산 파일로 출력합니다(제품 병합 및 출력 논리는 다음 장에서 설명됩니다).ChunkGroup
:하나 ChunkGroup
하나 이상 포함Chunk
물체;ChunkGroup
그리고ChunkGroup
부모-자식 종속 관계는 다음 사이에 형성됩니다.ChunkGraph
: 마지막으로 Webpack은 Chunk와 ChunkGroup 간의 종속성을 저장합니다. compilation.chunkGraph
객체에서는 다음과 같은 유형 관계가 형성됩니다.위의 ChunkGraph
빌드 프로세스는 궁극적으로 모듈을 세 가지 유형의 청크로 구성합니다.
entry
아래쪽 터치로 도달한 모듈은 청크로 구성됩니다.entry.runtime
비어 있지 않으면 런타임 모듈이 청크로 구성됩니다.사용하지 않는 경우 Webpack에 내장되어 있습니다. splitChunks
다른 플러그인의 경우 모듈 입력을 출력으로 매핑하는 기본 규칙은 Webpack의 주요 기본 원칙 중 하나이므로 각 청크에 대한 구체적인 규칙을 도입해야 합니다.
엔트리 청크:
Entry Chunk부터 시작하여 Webpack은 먼저 entry
만들다Chunk
객체(예: 다음 구성):
module.exports = {
entry: {
main: "./src/main",
home: "./src/home",
}
};
횡단 entry
객체 속성 및 생성chunk[main]
、chunk[home]
두 개의 개체, 이때 두 개의 청크에는 각각 다음이 포함됩니다.main
、home
기준 치수:
초기화가 완료되면 Webpack은 ModuleGraph
종속성 데이터는entry
다음에 의해 접촉된 모든 모듈은 청크에 채워집니다(다음에서 발생).방문모듈 메서드) 예를 들어 다음 파일 종속성의 경우:
main.js
4개의 파일 a/b/c/d가 동기적으로 직접 또는 간접적으로 참조되는 경우 Webpack은 먼저main.js
모듈은 Chunk 및 EntryPoint 개체를 생성한 다음 점차적으로 a/b/c/d 모듈을 추가합니다.chunk[main]
, 최종적으로 다음과 같이 형성됩니다.
비동기 청크:
둘째, Webpack은 각 비동기 import 문(import(xxx)
그리고require.ensure
)은 별도의 청크 객체로 처리되며 모든 하위 모듈이 이 청크에 추가됩니다. 이를 비동기 청크라고 부릅니다. 예를 들어, 다음 예의 경우:
// index.js
import './sync-a.js'
import './sync-b.js'
import('./async-a.js')
// async-a.js
import './sync-c.js'
엔트리 모듈에서는 index.js
sync-a 및 sync-b는 동기식으로 도입되고, async-a 모듈은 동시에 비동기식으로 도입됩니다. async-a 모듈은 동기식으로 도입됩니다.sync-c
모듈을 사용하여 다음과 같은 모듈 종속성 다이어그램을 구성합니다.
이 시점에서 Webpack이 진입점이 됩니다. index.js
, 비동기 모듈 async-a.js
다음 청크 구조를 형성하기 위해 별도로 하위 패키지를 생성합니다.
그리고 chunk[index]
그리고chunk[async-a]
이들 사이에는 단방향 종속성이 형성되며 Webpack은 이 종속성을 다음 위치에 저장합니다.ChunkGroup._parents
、ChunkGroup._children
속성에서.
런타임 청크:
마지막으로 제외 entry
, 비동기 모듈 외에도 Webpack5는 런타임 코드를 청크로 별도로 추출하는 기능도 지원합니다. 여기에 언급된 런타임 코드는 패키지 제품이 정상적으로 실행될 수 있도록 Webpack에서 삽입한 일련의 기본 프레임워크 코드를 나타냅니다. 예를 들어 일반적인 Webpack 패키지 제품 구조는 다음과 같습니다.
위 그림에서 빨간색 상자 안의 큰 원으로 표시된 코드 부분은 Webpack이 동적으로 생성한 런타임 코드입니다. 컴파일 시 Webpack은 비즈니스 코드를 기반으로 출력할 런타임 코드를 결정합니다.Dependency
하위 클래스) 예를 들면 다음과 같습니다.
__webpack_require__.f
、__webpack_require__.r
최소한의 모듈 지원을 달성하기 위한 기타 기능;__webpack_require__.e
기능;__webpack_require__.o
기능;각 런타임 코드 조각은 작을 수 있지만 기능이 증가함에 따라 최종 결과는 점점 더 커질 것입니다. 특히 다중 항목 응용 프로그램의 경우 각 항목마다 유사한 런타임을 반복적으로 패키징하는 것은 약간 낭비입니다. entry.runtime
구성 항목은 런타임 코드가 패키징되는 방법을 선언하는 데 사용됩니다.사용법은 다음과 같습니다.entry
항목에 문자열 형식 추가runtime
값은 다음과 같습니다.
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
}
};
존재하다 compilation.seal
함수에서 Webpack은 먼저entry
만들다EntryPoint
, 그럼 판단해 entry
구성에 다음이 포함되어 있습니까?runtime
속성이 있는 경우 다음을 사용하여 생성합니다.runtime
값은 청크의 이름입니다. 따라서 위의 예제 구성에서는 두 개의 청크를 생성합니다.chunk[index.js]
、chunk[solid-runtime]
, 이를 기반으로 최종적으로 두 개의 파일이 출력됩니다.
index.js
문서;solid-runtime.js
문서.많은 entry
시나리오에서는 각각에 대해서만entry
모두 동일하게 설정됨runtime
값을 지정하면 Webpack 런타임 코드가 병합되어 동일한 런타임 청크에 기록되어 궁극적으로 제품 성능 최적화를 달성합니다. 예를 들어 다음 구성의 경우:
module.exports = {
entry: {
index: { import: "./src/index", runtime: "solid-runtime" },
home: { import: "./src/home", runtime: "solid-runtime" },
}
};
입구 index
、home
같은 것을 공유하다runtime
값을 입력하고 마지막으로 각각 3개의 청크를 생성합니다.
이때 입장 chunk[index]
、chunk[home]
런타임 포함chunk[solid-runtime]
부모-자식 의존 관계도 형성됩니다.
기본 하위 패키징 규칙의 가장 큰 문제는 모듈 중복을 해결할 수 없다는 것입니다. 여러 청크에 동시에 동일한 모듈이 포함되어 있으면 이 모듈은 제한 없이 반복적으로 이러한 청크로 패키징됩니다. 예를 들어, 동일한 모듈에 의존하는 두 개의 항목 main/index가 있다고 가정해 보겠습니다.
기본적으로 Webpack은 이에 대한 추가 처리를 수행하지 않고 단순히 c 모듈을 동시에 두 개의 청크/메인/인덱스로 패키징하여 궁극적으로 다음을 형성합니다.
볼 수 있다 chunk
서로 분리되어 모듈 c가 반복적으로 패키징되므로 최종 제품에 불필요한 성능 손실이 발생할 수 있습니다!
이 문제를 해결하기 위해 Webpack 3에서는 CommonChunkPlugin
플러그인은 항목 간의 공통 종속성을 별도의 항목으로 추출하려고 시도합니다.chunk
,하지만 CommonChunkPlugin
본질적으로 Chunk 간의 단순한 부모-자식 관계 체인을 기반으로 구현됩니다. 추출된 세 번째 패키지를 다음과 같이 사용해야 한다고 유추하기는 어렵습니다.entry
아버지chunk
아직 어린아이야chunk
,CommonChunkPlugin
상위로 통합 처리chunk
, 어떤 경우에는 성능에 상당한 부정적인 영향을 미칩니다.
이러한 이유로 Webpack 4 이후에는 더욱 복잡한 데이터 구조가 특별히 도입되었습니다. ChunkGroup
관계사슬 관리 및 협력 실현 전문SplitChunksPlugin
보다 효율적이고 지능적으로 구현할 수 있습니다.경험적 하도급.
요약하면, "빌드" 단계는 모듈의 참조 관계를 기반으로 ModuleGraph를 구축하는 역할을 담당하고, "캡슐화" 단계는 ModuleGraph를 기반으로 일련의 청크 개체를 구축하고 청크(비동기 참조, 런타임) 간의 종속성을 구성하는 역할을 담당합니다. )을 ChunkGraph - 청크 종속성 그래프 개체로 변환합니다. ModuleGraph와 유사하게 ChunkGraph 구조의 도입으로 청크 간의 종속성 관리 로직을 분리할 수 있어 전체 아키텍처 로직을 더욱 합리적이고 쉽게 확장할 수 있습니다.
그러나 매우 복잡해 보이지만 "패키징" 단계의 가장 중요한 목표는 여전히 청크 수와 각 청크에 어떤 모듈이 포함되어 있는지 결정하는 것입니다. 이것이 최종 패키징 결과에 실제로 영향을 미치는 핵심 요소입니다.
이를 위해서는 Webpack5에 내장된 세 가지 하도급 규칙인 Entry Chunk, Async Chunk 및 Runtime Chunk를 이해해야 합니다. 이는 가장 독창적인 하도급 로직입니다(예: splitChunks플러그인)는 모두 다음의 도움으로 이를 기반으로 합니다. buildChunkGraph
나중에 다양한 후크가 발생하여 청크 구조를 추가로 분할, 병합 및 최적화하여 확장된 하도급 효과를 달성합니다.
생각하다 Chunk
제품 파일은 하나만 생성되나요? 왜?mini-css-extract-plugin
、file-loader
하단에 추가 파일을 작성할 수 있는 이런 컴포넌트는 어떻게 구현되어 있나요?