123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
- const asyncLib = require("neo-async");
- const util = require("util");
- const { CachedSource } = require("webpack-sources");
- const {
- Tapable,
- SyncHook,
- SyncBailHook,
- SyncWaterfallHook,
- AsyncSeriesHook
- } = require("tapable");
- const EntryModuleNotFoundError = require("./EntryModuleNotFoundError");
- const ModuleNotFoundError = require("./ModuleNotFoundError");
- const ModuleDependencyWarning = require("./ModuleDependencyWarning");
- const ModuleDependencyError = require("./ModuleDependencyError");
- const ChunkGroup = require("./ChunkGroup");
- const Chunk = require("./Chunk");
- const Entrypoint = require("./Entrypoint");
- const MainTemplate = require("./MainTemplate");
- const ChunkTemplate = require("./ChunkTemplate");
- const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate");
- const ModuleTemplate = require("./ModuleTemplate");
- const RuntimeTemplate = require("./RuntimeTemplate");
- const ChunkRenderError = require("./ChunkRenderError");
- const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError");
- const Stats = require("./Stats");
- const Semaphore = require("./util/Semaphore");
- const createHash = require("./util/createHash");
- const Queue = require("./util/Queue");
- const SortableSet = require("./util/SortableSet");
- const GraphHelpers = require("./GraphHelpers");
- const ModuleDependency = require("./dependencies/ModuleDependency");
- const compareLocations = require("./compareLocations");
- /** @typedef {import("./Module")} Module */
- /** @typedef {import("./Compiler")} Compiler */
- /** @typedef {import("webpack-sources").Source} Source */
- /** @typedef {import("./WebpackError")} WebpackError */
- /** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */
- /** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */
- /** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */
- /** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
- /** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
- /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
- /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
- /** @typedef {import("./Dependency")} Dependency */
- /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
- /** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */
- /** @typedef {import("./util/createHash").Hash} Hash */
- // TODO use @callback
- /** @typedef {{[assetName: string]: Source}} CompilationAssets */
- /** @typedef {(err: Error|null, result?: Module) => void } ModuleCallback */
- /** @typedef {(err?: Error|null, result?: Module) => void } ModuleChainCallback */
- /** @typedef {(module: Module) => void} OnModuleCallback */
- /** @typedef {(err?: Error|null) => void} Callback */
- /** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */
- /** @typedef {new (...args: any[]) => Dependency} DepConstructor */
- /** @typedef {{apply: () => void}} Plugin */
- /**
- * @typedef {Object} ModuleFactoryCreateDataContextInfo
- * @property {string} issuer
- * @property {string} compiler
- */
- /**
- * @typedef {Object} ModuleFactoryCreateData
- * @property {ModuleFactoryCreateDataContextInfo} contextInfo
- * @property {any=} resolveOptions
- * @property {string} context
- * @property {Dependency[]} dependencies
- */
- /**
- * @typedef {Object} ModuleFactory
- * @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create
- */
- /**
- * @typedef {Object} SortedDependency
- * @property {ModuleFactory} factory
- * @property {Dependency[]} dependencies
- */
- /**
- * @typedef {Object} DependenciesBlockLike
- * @property {Dependency[]} dependencies
- * @property {AsyncDependenciesBlock[]} blocks
- * @property {DependenciesBlockVariable[]} variables
- */
- /**
- * @param {Chunk} a first chunk to sort by id
- * @param {Chunk} b second chunk to sort by id
- * @returns {-1|0|1} sort value
- */
- const byId = (a, b) => {
- if (typeof a.id !== typeof b.id) {
- return typeof a.id < typeof b.id ? -1 : 1;
- }
- if (a.id < b.id) return -1;
- if (a.id > b.id) return 1;
- return 0;
- };
- /**
- * @param {Module} a first module to sort by
- * @param {Module} b second module to sort by
- * @returns {-1|0|1} sort value
- */
- const byIdOrIdentifier = (a, b) => {
- if (typeof a.id !== typeof b.id) {
- return typeof a.id < typeof b.id ? -1 : 1;
- }
- if (a.id < b.id) return -1;
- if (a.id > b.id) return 1;
- const identA = a.identifier();
- const identB = b.identifier();
- if (identA < identB) return -1;
- if (identA > identB) return 1;
- return 0;
- };
- /**
- * @param {Module} a first module to sort by
- * @param {Module} b second module to sort by
- * @returns {-1|0|1} sort value
- */
- const byIndexOrIdentifier = (a, b) => {
- if (a.index < b.index) return -1;
- if (a.index > b.index) return 1;
- const identA = a.identifier();
- const identB = b.identifier();
- if (identA < identB) return -1;
- if (identA > identB) return 1;
- return 0;
- };
- /**
- * @param {Compilation} a first compilation to sort by
- * @param {Compilation} b second compilation to sort by
- * @returns {-1|0|1} sort value
- */
- const byNameOrHash = (a, b) => {
- if (a.name < b.name) return -1;
- if (a.name > b.name) return 1;
- if (a.fullHash < b.fullHash) return -1;
- if (a.fullHash > b.fullHash) return 1;
- return 0;
- };
- /**
- * @template T
- * @param {Set<T>} a first set
- * @param {Set<T>} b second set
- * @returns {number} cmp
- */
- const bySetSize = (a, b) => {
- return a.size - b.size;
- };
- /**
- * @param {DependenciesBlockVariable[]} variables DepBlock Variables to iterate over
- * @param {DepBlockVarDependenciesCallback} fn callback to apply on iterated elements
- * @returns {void}
- */
- const iterationBlockVariable = (variables, fn) => {
- for (
- let indexVariable = 0;
- indexVariable < variables.length;
- indexVariable++
- ) {
- const varDep = variables[indexVariable].dependencies;
- for (let indexVDep = 0; indexVDep < varDep.length; indexVDep++) {
- fn(varDep[indexVDep]);
- }
- }
- };
- /**
- * @template T
- * @param {T[]} arr array of elements to iterate over
- * @param {function(T): void} fn callback applied to each element
- * @returns {void}
- */
- const iterationOfArrayCallback = (arr, fn) => {
- for (let index = 0; index < arr.length; index++) {
- fn(arr[index]);
- }
- };
- /**
- * @template T
- * @param {Set<T>} set set to add items to
- * @param {Set<T>} otherSet set to add items from
- * @returns {void}
- */
- const addAllToSet = (set, otherSet) => {
- for (const item of otherSet) {
- set.add(item);
- }
- };
- class Compilation extends Tapable {
- /**
- * Creates an instance of Compilation.
- * @param {Compiler} compiler the compiler which created the compilation
- */
- constructor(compiler) {
- super();
- this.hooks = {
- /** @type {SyncHook<Module>} */
- buildModule: new SyncHook(["module"]),
- /** @type {SyncHook<Module>} */
- rebuildModule: new SyncHook(["module"]),
- /** @type {SyncHook<Module, Error>} */
- failedModule: new SyncHook(["module", "error"]),
- /** @type {SyncHook<Module>} */
- succeedModule: new SyncHook(["module"]),
- /** @type {SyncHook<Dependency, string>} */
- addEntry: new SyncHook(["entry", "name"]),
- /** @type {SyncHook<Dependency, string, Error>} */
- failedEntry: new SyncHook(["entry", "name", "error"]),
- /** @type {SyncHook<Dependency, string, Module>} */
- succeedEntry: new SyncHook(["entry", "name", "module"]),
- /** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
- dependencyReference: new SyncWaterfallHook([
- "dependencyReference",
- "dependency",
- "module"
- ]),
- /** @type {SyncHook<Module[]>} */
- finishModules: new SyncHook(["modules"]),
- /** @type {SyncHook<Module>} */
- finishRebuildingModule: new SyncHook(["module"]),
- /** @type {SyncHook} */
- unseal: new SyncHook([]),
- /** @type {SyncHook} */
- seal: new SyncHook([]),
- /** @type {SyncHook} */
- beforeChunks: new SyncHook([]),
- /** @type {SyncHook<Chunk[]>} */
- afterChunks: new SyncHook(["chunks"]),
- /** @type {SyncBailHook<Module[]>} */
- optimizeDependenciesBasic: new SyncBailHook(["modules"]),
- /** @type {SyncBailHook<Module[]>} */
- optimizeDependencies: new SyncBailHook(["modules"]),
- /** @type {SyncBailHook<Module[]>} */
- optimizeDependenciesAdvanced: new SyncBailHook(["modules"]),
- /** @type {SyncBailHook<Module[]>} */
- afterOptimizeDependencies: new SyncHook(["modules"]),
- /** @type {SyncHook} */
- optimize: new SyncHook([]),
- /** @type {SyncBailHook<Module[]>} */
- optimizeModulesBasic: new SyncBailHook(["modules"]),
- /** @type {SyncBailHook<Module[]>} */
- optimizeModules: new SyncBailHook(["modules"]),
- /** @type {SyncBailHook<Module[]>} */
- optimizeModulesAdvanced: new SyncBailHook(["modules"]),
- /** @type {SyncHook<Module[]>} */
- afterOptimizeModules: new SyncHook(["modules"]),
- /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
- optimizeChunksBasic: new SyncBailHook(["chunks", "chunkGroups"]),
- /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
- optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
- /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
- optimizeChunksAdvanced: new SyncBailHook(["chunks", "chunkGroups"]),
- /** @type {SyncHook<Chunk[], ChunkGroup[]>} */
- afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),
- /** @type {AsyncSeriesHook<Chunk[], Module[]>} */
- optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
- /** @type {SyncHook<Chunk[], Module[]>} */
- afterOptimizeTree: new SyncHook(["chunks", "modules"]),
- /** @type {SyncBailHook<Chunk[], Module[]>} */
- optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]),
- /** @type {SyncBailHook<Chunk[], Module[]>} */
- optimizeChunkModules: new SyncBailHook(["chunks", "modules"]),
- /** @type {SyncBailHook<Chunk[], Module[]>} */
- optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]),
- /** @type {SyncHook<Chunk[], Module[]>} */
- afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
- /** @type {SyncBailHook} */
- shouldRecord: new SyncBailHook([]),
- /** @type {SyncHook<Module[], any>} */
- reviveModules: new SyncHook(["modules", "records"]),
- /** @type {SyncHook<Module[]>} */
- optimizeModuleOrder: new SyncHook(["modules"]),
- /** @type {SyncHook<Module[]>} */
- advancedOptimizeModuleOrder: new SyncHook(["modules"]),
- /** @type {SyncHook<Module[]>} */
- beforeModuleIds: new SyncHook(["modules"]),
- /** @type {SyncHook<Module[]>} */
- moduleIds: new SyncHook(["modules"]),
- /** @type {SyncHook<Module[]>} */
- optimizeModuleIds: new SyncHook(["modules"]),
- /** @type {SyncHook<Module[]>} */
- afterOptimizeModuleIds: new SyncHook(["modules"]),
- /** @type {SyncHook<Chunk[], any>} */
- reviveChunks: new SyncHook(["chunks", "records"]),
- /** @type {SyncHook<Chunk[]>} */
- optimizeChunkOrder: new SyncHook(["chunks"]),
- /** @type {SyncHook<Chunk[]>} */
- beforeChunkIds: new SyncHook(["chunks"]),
- /** @type {SyncHook<Chunk[]>} */
- optimizeChunkIds: new SyncHook(["chunks"]),
- /** @type {SyncHook<Chunk[]>} */
- afterOptimizeChunkIds: new SyncHook(["chunks"]),
- /** @type {SyncHook<Module[], any>} */
- recordModules: new SyncHook(["modules", "records"]),
- /** @type {SyncHook<Chunk[], any>} */
- recordChunks: new SyncHook(["chunks", "records"]),
- /** @type {SyncHook} */
- beforeHash: new SyncHook([]),
- /** @type {SyncHook<Chunk>} */
- contentHash: new SyncHook(["chunk"]),
- /** @type {SyncHook} */
- afterHash: new SyncHook([]),
- /** @type {SyncHook<any>} */
- recordHash: new SyncHook(["records"]),
- /** @type {SyncHook<Compilation, any>} */
- record: new SyncHook(["compilation", "records"]),
- /** @type {SyncHook} */
- beforeModuleAssets: new SyncHook([]),
- /** @type {SyncBailHook} */
- shouldGenerateChunkAssets: new SyncBailHook([]),
- /** @type {SyncHook} */
- beforeChunkAssets: new SyncHook([]),
- /** @type {SyncHook<Chunk[]>} */
- additionalChunkAssets: new SyncHook(["chunks"]),
- /** @type {AsyncSeriesHook} */
- additionalAssets: new AsyncSeriesHook([]),
- /** @type {AsyncSeriesHook<Chunk[]>} */
- optimizeChunkAssets: new AsyncSeriesHook(["chunks"]),
- /** @type {SyncHook<Chunk[]>} */
- afterOptimizeChunkAssets: new SyncHook(["chunks"]),
- /** @type {AsyncSeriesHook<CompilationAssets>} */
- optimizeAssets: new AsyncSeriesHook(["assets"]),
- /** @type {SyncHook<CompilationAssets>} */
- afterOptimizeAssets: new SyncHook(["assets"]),
- /** @type {SyncBailHook} */
- needAdditionalSeal: new SyncBailHook([]),
- /** @type {AsyncSeriesHook} */
- afterSeal: new AsyncSeriesHook([]),
- /** @type {SyncHook<Chunk, Hash>} */
- chunkHash: new SyncHook(["chunk", "chunkHash"]),
- /** @type {SyncHook<Module, string>} */
- moduleAsset: new SyncHook(["module", "filename"]),
- /** @type {SyncHook<Chunk, string>} */
- chunkAsset: new SyncHook(["chunk", "filename"]),
- /** @type {SyncWaterfallHook<string, TODO>} */
- assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate
- /** @type {SyncBailHook} */
- needAdditionalPass: new SyncBailHook([]),
- /** @type {SyncHook<Compiler, string, number>} */
- childCompiler: new SyncHook([
- "childCompiler",
- "compilerName",
- "compilerIndex"
- ]),
- // TODO the following hooks are weirdly located here
- // TODO move them for webpack 5
- /** @type {SyncHook<object, Module>} */
- normalModuleLoader: new SyncHook(["loaderContext", "module"]),
- /** @type {SyncBailHook<Chunk[]>} */
- optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]),
- /** @type {SyncBailHook<Chunk[]>} */
- optimizeExtractedChunks: new SyncBailHook(["chunks"]),
- /** @type {SyncBailHook<Chunk[]>} */
- optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]),
- /** @type {SyncHook<Chunk[]>} */
- afterOptimizeExtractedChunks: new SyncHook(["chunks"])
- };
- this._pluginCompat.tap("Compilation", options => {
- switch (options.name) {
- case "optimize-tree":
- case "additional-assets":
- case "optimize-chunk-assets":
- case "optimize-assets":
- case "after-seal":
- options.async = true;
- break;
- }
- });
- /** @type {string=} */
- this.name = undefined;
- /** @type {Compiler} */
- this.compiler = compiler;
- this.resolverFactory = compiler.resolverFactory;
- this.inputFileSystem = compiler.inputFileSystem;
- this.requestShortener = compiler.requestShortener;
- const options = compiler.options;
- this.options = options;
- this.outputOptions = options && options.output;
- /** @type {boolean=} */
- this.bail = options && options.bail;
- this.profile = options && options.profile;
- this.performance = options && options.performance;
- this.mainTemplate = new MainTemplate(this.outputOptions);
- this.chunkTemplate = new ChunkTemplate(this.outputOptions);
- this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(
- this.outputOptions
- );
- this.runtimeTemplate = new RuntimeTemplate(
- this.outputOptions,
- this.requestShortener
- );
- this.moduleTemplates = {
- javascript: new ModuleTemplate(this.runtimeTemplate, "javascript"),
- webassembly: new ModuleTemplate(this.runtimeTemplate, "webassembly")
- };
- this.semaphore = new Semaphore(options.parallelism || 100);
- this.entries = [];
- /** @private @type {{name: string, request: string, module: Module}[]} */
- this._preparedEntrypoints = [];
- this.entrypoints = new Map();
- /** @type {Chunk[]} */
- this.chunks = [];
- /** @type {ChunkGroup[]} */
- this.chunkGroups = [];
- /** @type {Map<string, ChunkGroup>} */
- this.namedChunkGroups = new Map();
- /** @type {Map<string, Chunk>} */
- this.namedChunks = new Map();
- /** @type {Module[]} */
- this.modules = [];
- /** @private @type {Map<string, Module>} */
- this._modules = new Map();
- this.cache = null;
- this.records = null;
- /** @type {string[]} */
- this.additionalChunkAssets = [];
- /** @type {CompilationAssets} */
- this.assets = {};
- /** @type {WebpackError[]} */
- this.errors = [];
- /** @type {WebpackError[]} */
- this.warnings = [];
- /** @type {Compilation[]} */
- this.children = [];
- /** @type {Map<DepConstructor, ModuleFactory>} */
- this.dependencyFactories = new Map();
- /** @type {Map<DepConstructor, DependencyTemplate>} */
- this.dependencyTemplates = new Map();
- // TODO refactor this in webpack 5 to a custom DependencyTemplates class with a hash property
- // @ts-ignore
- this.dependencyTemplates.set("hash", "");
- this.childrenCounters = {};
- /** @type {Set<number|string>} */
- this.usedChunkIds = null;
- /** @type {Set<number>} */
- this.usedModuleIds = null;
- /** @type {Map<string, number>=} */
- this.fileTimestamps = undefined;
- /** @type {Map<string, number>=} */
- this.contextTimestamps = undefined;
- /** @type {Set<string>=} */
- this.compilationDependencies = undefined;
- /** @private @type {Map<Module, Callback[]>} */
- this._buildingModules = new Map();
- /** @private @type {Map<Module, Callback[]>} */
- this._rebuildingModules = new Map();
- }
- getStats() {
- return new Stats(this);
- }
- /**
- * @typedef {Object} AddModuleResult
- * @property {Module} module the added or existing module
- * @property {boolean} issuer was this the first request for this module
- * @property {boolean} build should the module be build
- * @property {boolean} dependencies should dependencies be walked
- */
- /**
- * @param {Module} module module to be added that was created
- * @param {any=} cacheGroup cacheGroup it is apart of
- * @returns {AddModuleResult} returns meta about whether or not the module had built
- * had an issuer, or any dependnecies
- */
- addModule(module, cacheGroup) {
- const identifier = module.identifier();
- const alreadyAddedModule = this._modules.get(identifier);
- if (alreadyAddedModule) {
- return {
- module: alreadyAddedModule,
- issuer: false,
- build: false,
- dependencies: false
- };
- }
- const cacheName = (cacheGroup || "m") + identifier;
- if (this.cache && this.cache[cacheName]) {
- const cacheModule = this.cache[cacheName];
- if (typeof cacheModule.updateCacheModule === "function") {
- cacheModule.updateCacheModule(module);
- }
- let rebuild = true;
- if (this.fileTimestamps && this.contextTimestamps) {
- rebuild = cacheModule.needRebuild(
- this.fileTimestamps,
- this.contextTimestamps
- );
- }
- if (!rebuild) {
- cacheModule.disconnect();
- this._modules.set(identifier, cacheModule);
- this.modules.push(cacheModule);
- for (const err of cacheModule.errors) {
- this.errors.push(err);
- }
- for (const err of cacheModule.warnings) {
- this.warnings.push(err);
- }
- return {
- module: cacheModule,
- issuer: true,
- build: false,
- dependencies: true
- };
- }
- cacheModule.unbuild();
- module = cacheModule;
- }
- this._modules.set(identifier, module);
- if (this.cache) {
- this.cache[cacheName] = module;
- }
- this.modules.push(module);
- return {
- module: module,
- issuer: true,
- build: true,
- dependencies: true
- };
- }
- /**
- * Fetches a module from a compilation by its identifier
- * @param {Module} module the module provided
- * @returns {Module} the module requested
- */
- getModule(module) {
- const identifier = module.identifier();
- return this._modules.get(identifier);
- }
- /**
- * Attempts to search for a module by its identifier
- * @param {string} identifier identifier (usually path) for module
- * @returns {Module|undefined} attempt to search for module and return it, else undefined
- */
- findModule(identifier) {
- return this._modules.get(identifier);
- }
- /**
- * @param {Module} module module with its callback list
- * @param {Callback} callback the callback function
- * @returns {void}
- */
- waitForBuildingFinished(module, callback) {
- let callbackList = this._buildingModules.get(module);
- if (callbackList) {
- callbackList.push(() => callback());
- } else {
- process.nextTick(callback);
- }
- }
- /**
- * Builds the module object
- *
- * @param {Module} module module to be built
- * @param {boolean} optional optional flag
- * @param {Module=} origin origin module this module build was requested from
- * @param {Dependency[]=} dependencies optional dependencies from the module to be built
- * @param {TODO} thisCallback the callback
- * @returns {TODO} returns the callback function with results
- */
- buildModule(module, optional, origin, dependencies, thisCallback) {
- let callbackList = this._buildingModules.get(module);
- if (callbackList) {
- callbackList.push(thisCallback);
- return;
- }
- this._buildingModules.set(module, (callbackList = [thisCallback]));
- const callback = err => {
- this._buildingModules.delete(module);
- for (const cb of callbackList) {
- cb(err);
- }
- };
- this.hooks.buildModule.call(module);
- module.build(
- this.options,
- this,
- this.resolverFactory.get("normal", module.resolveOptions),
- this.inputFileSystem,
- error => {
- const errors = module.errors;
- for (let indexError = 0; indexError < errors.length; indexError++) {
- const err = errors[indexError];
- err.origin = origin;
- err.dependencies = dependencies;
- if (optional) {
- this.warnings.push(err);
- } else {
- this.errors.push(err);
- }
- }
- const warnings = module.warnings;
- for (
- let indexWarning = 0;
- indexWarning < warnings.length;
- indexWarning++
- ) {
- const war = warnings[indexWarning];
- war.origin = origin;
- war.dependencies = dependencies;
- this.warnings.push(war);
- }
- const originalMap = module.dependencies.reduce((map, v, i) => {
- map.set(v, i);
- return map;
- }, new Map());
- module.dependencies.sort((a, b) => {
- const cmp = compareLocations(a.loc, b.loc);
- if (cmp) return cmp;
- return originalMap.get(a) - originalMap.get(b);
- });
- if (error) {
- this.hooks.failedModule.call(module, error);
- return callback(error);
- }
- this.hooks.succeedModule.call(module);
- return callback();
- }
- );
- }
- /**
- * @param {Module} module to be processed for deps
- * @param {ModuleCallback} callback callback to be triggered
- * @returns {void}
- */
- processModuleDependencies(module, callback) {
- const dependencies = new Map();
- const addDependency = dep => {
- const resourceIdent = dep.getResourceIdentifier();
- if (resourceIdent) {
- const factory = this.dependencyFactories.get(dep.constructor);
- if (factory === undefined) {
- throw new Error(
- `No module factory available for dependency type: ${
- dep.constructor.name
- }`
- );
- }
- let innerMap = dependencies.get(factory);
- if (innerMap === undefined) {
- dependencies.set(factory, (innerMap = new Map()));
- }
- let list = innerMap.get(resourceIdent);
- if (list === undefined) innerMap.set(resourceIdent, (list = []));
- list.push(dep);
- }
- };
- const addDependenciesBlock = block => {
- if (block.dependencies) {
- iterationOfArrayCallback(block.dependencies, addDependency);
- }
- if (block.blocks) {
- iterationOfArrayCallback(block.blocks, addDependenciesBlock);
- }
- if (block.variables) {
- iterationBlockVariable(block.variables, addDependency);
- }
- };
- try {
- addDependenciesBlock(module);
- } catch (e) {
- callback(e);
- }
- const sortedDependencies = [];
- for (const pair1 of dependencies) {
- for (const pair2 of pair1[1]) {
- sortedDependencies.push({
- factory: pair1[0],
- dependencies: pair2[1]
- });
- }
- }
- this.addModuleDependencies(
- module,
- sortedDependencies,
- this.bail,
- null,
- true,
- callback
- );
- }
- /**
- * @param {Module} module module to add deps to
- * @param {SortedDependency[]} dependencies set of sorted dependencies to iterate through
- * @param {(boolean|null)=} bail whether to bail or not
- * @param {TODO} cacheGroup optional cacheGroup
- * @param {boolean} recursive whether it is recursive traversal
- * @param {function} callback callback for when dependencies are finished being added
- * @returns {void}
- */
- addModuleDependencies(
- module,
- dependencies,
- bail,
- cacheGroup,
- recursive,
- callback
- ) {
- const start = this.profile && Date.now();
- const currentProfile = this.profile && {};
- asyncLib.forEach(
- dependencies,
- (item, callback) => {
- const dependencies = item.dependencies;
- const errorAndCallback = err => {
- err.origin = module;
- err.dependencies = dependencies;
- this.errors.push(err);
- if (bail) {
- callback(err);
- } else {
- callback();
- }
- };
- const warningAndCallback = err => {
- err.origin = module;
- this.warnings.push(err);
- callback();
- };
- const semaphore = this.semaphore;
- semaphore.acquire(() => {
- const factory = item.factory;
- factory.create(
- {
- contextInfo: {
- issuer: module.nameForCondition && module.nameForCondition(),
- compiler: this.compiler.name
- },
- resolveOptions: module.resolveOptions,
- context: module.context,
- dependencies: dependencies
- },
- (err, dependentModule) => {
- let afterFactory;
- const isOptional = () => {
- return dependencies.every(d => d.optional);
- };
- const errorOrWarningAndCallback = err => {
- if (isOptional()) {
- return warningAndCallback(err);
- } else {
- return errorAndCallback(err);
- }
- };
- if (err) {
- semaphore.release();
- return errorOrWarningAndCallback(
- new ModuleNotFoundError(module, err)
- );
- }
- if (!dependentModule) {
- semaphore.release();
- return process.nextTick(callback);
- }
- if (currentProfile) {
- afterFactory = Date.now();
- currentProfile.factory = afterFactory - start;
- }
- const iterationDependencies = depend => {
- for (let index = 0; index < depend.length; index++) {
- const dep = depend[index];
- dep.module = dependentModule;
- dependentModule.addReason(module, dep);
- }
- };
- const addModuleResult = this.addModule(
- dependentModule,
- cacheGroup
- );
- dependentModule = addModuleResult.module;
- iterationDependencies(dependencies);
- const afterBuild = () => {
- if (currentProfile) {
- const afterBuilding = Date.now();
- currentProfile.building = afterBuilding - afterFactory;
- }
- if (recursive && addModuleResult.dependencies) {
- this.processModuleDependencies(dependentModule, callback);
- } else {
- return callback();
- }
- };
- if (addModuleResult.issuer) {
- if (currentProfile) {
- dependentModule.profile = currentProfile;
- }
- dependentModule.issuer = module;
- } else {
- if (this.profile) {
- if (module.profile) {
- const time = Date.now() - start;
- if (
- !module.profile.dependencies ||
- time > module.profile.dependencies
- ) {
- module.profile.dependencies = time;
- }
- }
- }
- }
- if (addModuleResult.build) {
- this.buildModule(
- dependentModule,
- isOptional(),
- module,
- dependencies,
- err => {
- if (err) {
- semaphore.release();
- return errorOrWarningAndCallback(err);
- }
- if (currentProfile) {
- const afterBuilding = Date.now();
- currentProfile.building = afterBuilding - afterFactory;
- }
- semaphore.release();
- afterBuild();
- }
- );
- } else {
- semaphore.release();
- this.waitForBuildingFinished(dependentModule, afterBuild);
- }
- }
- );
- });
- },
- err => {
- // In V8, the Error objects keep a reference to the functions on the stack. These warnings &
- // errors are created inside closures that keep a reference to the Compilation, so errors are
- // leaking the Compilation object.
- if (err) {
- // eslint-disable-next-line no-self-assign
- err.stack = err.stack;
- return callback(err);
- }
- return process.nextTick(callback);
- }
- );
- }
- /**
- *
- * @param {string} context context string path
- * @param {Dependency} dependency dependency used to create Module chain
- * @param {OnModuleCallback} onModule function invoked on modules creation
- * @param {ModuleChainCallback} callback callback for when module chain is complete
- * @returns {void} will throw if dependency instance is not a valid Dependency
- */
- _addModuleChain(context, dependency, onModule, callback) {
- const start = this.profile && Date.now();
- const currentProfile = this.profile && {};
- const errorAndCallback = this.bail
- ? err => {
- callback(err);
- }
- : err => {
- err.dependencies = [dependency];
- this.errors.push(err);
- callback();
- };
- if (
- typeof dependency !== "object" ||
- dependency === null ||
- !dependency.constructor
- ) {
- throw new Error("Parameter 'dependency' must be a Dependency");
- }
- const Dep = /** @type {DepConstructor} */ (dependency.constructor);
- const moduleFactory = this.dependencyFactories.get(Dep);
- if (!moduleFactory) {
- throw new Error(
- `No dependency factory available for this dependency type: ${
- dependency.constructor.name
- }`
- );
- }
- this.semaphore.acquire(() => {
- moduleFactory.create(
- {
- contextInfo: {
- issuer: "",
- compiler: this.compiler.name
- },
- context: context,
- dependencies: [dependency]
- },
- (err, module) => {
- if (err) {
- this.semaphore.release();
- return errorAndCallback(new EntryModuleNotFoundError(err));
- }
- let afterFactory;
- if (currentProfile) {
- afterFactory = Date.now();
- currentProfile.factory = afterFactory - start;
- }
- const addModuleResult = this.addModule(module);
- module = addModuleResult.module;
- onModule(module);
- dependency.module = module;
- module.addReason(null, dependency);
- const afterBuild = () => {
- if (currentProfile) {
- const afterBuilding = Date.now();
- currentProfile.building = afterBuilding - afterFactory;
- }
- if (addModuleResult.dependencies) {
- this.processModuleDependencies(module, err => {
- if (err) return callback(err);
- callback(null, module);
- });
- } else {
- return callback(null, module);
- }
- };
- if (addModuleResult.issuer) {
- if (currentProfile) {
- module.profile = currentProfile;
- }
- }
- if (addModuleResult.build) {
- this.buildModule(module, false, null, null, err => {
- if (err) {
- this.semaphore.release();
- return errorAndCallback(err);
- }
- if (currentProfile) {
- const afterBuilding = Date.now();
- currentProfile.building = afterBuilding - afterFactory;
- }
- this.semaphore.release();
- afterBuild();
- });
- } else {
- this.semaphore.release();
- this.waitForBuildingFinished(module, afterBuild);
- }
- }
- );
- });
- }
- /**
- *
- * @param {string} context context path for entry
- * @param {Dependency} entry entry dependency being created
- * @param {string} name name of entry
- * @param {ModuleCallback} callback callback function
- * @returns {void} returns
- */
- addEntry(context, entry, name, callback) {
- this.hooks.addEntry.call(entry, name);
- const slot = {
- name: name,
- // TODO webpack 5 remove `request`
- request: null,
- module: null
- };
- if (entry instanceof ModuleDependency) {
- slot.request = entry.request;
- }
- // TODO webpack 5: merge modules instead when multiple entry modules are supported
- const idx = this._preparedEntrypoints.findIndex(slot => slot.name === name);
- if (idx >= 0) {
- // Overwrite existing entrypoint
- this._preparedEntrypoints[idx] = slot;
- } else {
- this._preparedEntrypoints.push(slot);
- }
- this._addModuleChain(
- context,
- entry,
- module => {
- this.entries.push(module);
- },
- (err, module) => {
- if (err) {
- this.hooks.failedEntry.call(entry, name, err);
- return callback(err);
- }
- if (module) {
- slot.module = module;
- } else {
- const idx = this._preparedEntrypoints.indexOf(slot);
- if (idx >= 0) {
- this._preparedEntrypoints.splice(idx, 1);
- }
- }
- this.hooks.succeedEntry.call(entry, name, module);
- return callback(null, module);
- }
- );
- }
- /**
- * @param {string} context context path string
- * @param {Dependency} dependency dep used to create module
- * @param {ModuleCallback} callback module callback sending module up a level
- * @returns {void}
- */
- prefetch(context, dependency, callback) {
- this._addModuleChain(
- context,
- dependency,
- module => {
- module.prefetched = true;
- },
- callback
- );
- }
- /**
- * @param {Module} module module to be rebuilt
- * @param {Callback} thisCallback callback when module finishes rebuilding
- * @returns {void}
- */
- rebuildModule(module, thisCallback) {
- let callbackList = this._rebuildingModules.get(module);
- if (callbackList) {
- callbackList.push(thisCallback);
- return;
- }
- this._rebuildingModules.set(module, (callbackList = [thisCallback]));
- const callback = err => {
- this._rebuildingModules.delete(module);
- for (const cb of callbackList) {
- cb(err);
- }
- };
- this.hooks.rebuildModule.call(module);
- const oldDependencies = module.dependencies.slice();
- const oldVariables = module.variables.slice();
- const oldBlocks = module.blocks.slice();
- module.unbuild();
- this.buildModule(module, false, module, null, err => {
- if (err) {
- this.hooks.finishRebuildingModule.call(module);
- return callback(err);
- }
- this.processModuleDependencies(module, err => {
- if (err) return callback(err);
- this.removeReasonsOfDependencyBlock(module, {
- dependencies: oldDependencies,
- variables: oldVariables,
- blocks: oldBlocks
- });
- this.hooks.finishRebuildingModule.call(module);
- callback();
- });
- });
- }
- finish() {
- const modules = this.modules;
- this.hooks.finishModules.call(modules);
- for (let index = 0; index < modules.length; index++) {
- const module = modules[index];
- this.reportDependencyErrorsAndWarnings(module, [module]);
- }
- }
- unseal() {
- this.hooks.unseal.call();
- this.chunks.length = 0;
- this.chunkGroups.length = 0;
- this.namedChunks.clear();
- this.namedChunkGroups.clear();
- this.additionalChunkAssets.length = 0;
- this.assets = {};
- for (const module of this.modules) {
- module.unseal();
- }
- }
- /**
- * @param {Callback} callback signals when the seal method is finishes
- * @returns {void}
- */
- seal(callback) {
- this.hooks.seal.call();
- while (
- this.hooks.optimizeDependenciesBasic.call(this.modules) ||
- this.hooks.optimizeDependencies.call(this.modules) ||
- this.hooks.optimizeDependenciesAdvanced.call(this.modules)
- ) {
- /* empty */
- }
- this.hooks.afterOptimizeDependencies.call(this.modules);
- this.hooks.beforeChunks.call();
- for (const preparedEntrypoint of this._preparedEntrypoints) {
- const module = preparedEntrypoint.module;
- const name = preparedEntrypoint.name;
- const chunk = this.addChunk(name);
- const entrypoint = new Entrypoint(name);
- entrypoint.setRuntimeChunk(chunk);
- entrypoint.addOrigin(null, name, preparedEntrypoint.request);
- this.namedChunkGroups.set(name, entrypoint);
- this.entrypoints.set(name, entrypoint);
- this.chunkGroups.push(entrypoint);
- GraphHelpers.connectChunkGroupAndChunk(entrypoint, chunk);
- GraphHelpers.connectChunkAndModule(chunk, module);
- chunk.entryModule = module;
- chunk.name = name;
- this.assignDepth(module);
- }
- this.processDependenciesBlocksForChunkGroups(this.chunkGroups.slice());
- this.sortModules(this.modules);
- this.hooks.afterChunks.call(this.chunks);
- this.hooks.optimize.call();
- while (
- this.hooks.optimizeModulesBasic.call(this.modules) ||
- this.hooks.optimizeModules.call(this.modules) ||
- this.hooks.optimizeModulesAdvanced.call(this.modules)
- ) {
- /* empty */
- }
- this.hooks.afterOptimizeModules.call(this.modules);
- while (
- this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) ||
- this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) ||
- this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups)
- ) {
- /* empty */
- }
- this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups);
- this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => {
- if (err) {
- return callback(err);
- }
- this.hooks.afterOptimizeTree.call(this.chunks, this.modules);
- while (
- this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) ||
- this.hooks.optimizeChunkModules.call(this.chunks, this.modules) ||
- this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules)
- ) {
- /* empty */
- }
- this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules);
- const shouldRecord = this.hooks.shouldRecord.call() !== false;
- this.hooks.reviveModules.call(this.modules, this.records);
- this.hooks.optimizeModuleOrder.call(this.modules);
- this.hooks.advancedOptimizeModuleOrder.call(this.modules);
- this.hooks.beforeModuleIds.call(this.modules);
- this.hooks.moduleIds.call(this.modules);
- this.applyModuleIds();
- this.hooks.optimizeModuleIds.call(this.modules);
- this.hooks.afterOptimizeModuleIds.call(this.modules);
- this.sortItemsWithModuleIds();
- this.hooks.reviveChunks.call(this.chunks, this.records);
- this.hooks.optimizeChunkOrder.call(this.chunks);
- this.hooks.beforeChunkIds.call(this.chunks);
- this.applyChunkIds();
- this.hooks.optimizeChunkIds.call(this.chunks);
- this.hooks.afterOptimizeChunkIds.call(this.chunks);
- this.sortItemsWithChunkIds();
- if (shouldRecord) {
- this.hooks.recordModules.call(this.modules, this.records);
- this.hooks.recordChunks.call(this.chunks, this.records);
- }
- this.hooks.beforeHash.call();
- this.createHash();
- this.hooks.afterHash.call();
- if (shouldRecord) {
- this.hooks.recordHash.call(this.records);
- }
- this.hooks.beforeModuleAssets.call();
- this.createModuleAssets();
- if (this.hooks.shouldGenerateChunkAssets.call() !== false) {
- this.hooks.beforeChunkAssets.call();
- this.createChunkAssets();
- }
- this.hooks.additionalChunkAssets.call(this.chunks);
- this.summarizeDependencies();
- if (shouldRecord) {
- this.hooks.record.call(this, this.records);
- }
- this.hooks.additionalAssets.callAsync(err => {
- if (err) {
- return callback(err);
- }
- this.hooks.optimizeChunkAssets.callAsync(this.chunks, err => {
- if (err) {
- return callback(err);
- }
- this.hooks.afterOptimizeChunkAssets.call(this.chunks);
- this.hooks.optimizeAssets.callAsync(this.assets, err => {
- if (err) {
- return callback(err);
- }
- this.hooks.afterOptimizeAssets.call(this.assets);
- if (this.hooks.needAdditionalSeal.call()) {
- this.unseal();
- return this.seal(callback);
- }
- return this.hooks.afterSeal.callAsync(callback);
- });
- });
- });
- });
- }
- /**
- * @param {Module[]} modules the modules array on compilation to perform the sort for
- * @returns {void}
- */
- sortModules(modules) {
- // TODO webpack 5: this should only be enabled when `moduleIds: "natural"`
- // TODO move it into a plugin (NaturalModuleIdsPlugin) and use this in WebpackOptionsApply
- // TODO remove this method
- modules.sort(byIndexOrIdentifier);
- }
- /**
- * @param {Module} module moulde to report from
- * @param {DependenciesBlock[]} blocks blocks to report from
- * @returns {void}
- */
- reportDependencyErrorsAndWarnings(module, blocks) {
- for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
- const block = blocks[indexBlock];
- const dependencies = block.dependencies;
- for (let indexDep = 0; indexDep < dependencies.length; indexDep++) {
- const d = dependencies[indexDep];
- const warnings = d.getWarnings();
- if (warnings) {
- for (let indexWar = 0; indexWar < warnings.length; indexWar++) {
- const w = warnings[indexWar];
- const warning = new ModuleDependencyWarning(module, w, d.loc);
- this.warnings.push(warning);
- }
- }
- const errors = d.getErrors();
- if (errors) {
- for (let indexErr = 0; indexErr < errors.length; indexErr++) {
- const e = errors[indexErr];
- const error = new ModuleDependencyError(module, e, d.loc);
- this.errors.push(error);
- }
- }
- }
- this.reportDependencyErrorsAndWarnings(module, block.blocks);
- }
- }
- /**
- * @param {TODO} groupOptions options for the chunk group
- * @param {Module} module the module the references the chunk group
- * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
- * @param {string} request the request from which the the chunk group is referenced
- * @returns {ChunkGroup} the new or existing chunk group
- */
- addChunkInGroup(groupOptions, module, loc, request) {
- if (typeof groupOptions === "string") {
- groupOptions = { name: groupOptions };
- }
- const name = groupOptions.name;
- if (name) {
- const chunkGroup = this.namedChunkGroups.get(name);
- if (chunkGroup !== undefined) {
- chunkGroup.addOptions(groupOptions);
- if (module) {
- chunkGroup.addOrigin(module, loc, request);
- }
- return chunkGroup;
- }
- }
- const chunkGroup = new ChunkGroup(groupOptions);
- if (module) chunkGroup.addOrigin(module, loc, request);
- const chunk = this.addChunk(name);
- GraphHelpers.connectChunkGroupAndChunk(chunkGroup, chunk);
- this.chunkGroups.push(chunkGroup);
- if (name) {
- this.namedChunkGroups.set(name, chunkGroup);
- }
- return chunkGroup;
- }
- /**
- * This method first looks to see if a name is provided for a new chunk,
- * and first looks to see if any named chunks already exist and reuse that chunk instead.
- *
- * @param {string=} name optional chunk name to be provided
- * @returns {Chunk} create a chunk (invoked during seal event)
- */
- addChunk(name) {
- if (name) {
- const chunk = this.namedChunks.get(name);
- if (chunk !== undefined) {
- return chunk;
- }
- }
- const chunk = new Chunk(name);
- this.chunks.push(chunk);
- if (name) {
- this.namedChunks.set(name, chunk);
- }
- return chunk;
- }
- /**
- * @param {Module} module module to assign depth
- * @returns {void}
- */
- assignDepth(module) {
- const queue = new Set([module]);
- let depth;
- module.depth = 0;
- /**
- * @param {Module} module module for processeing
- * @returns {void}
- */
- const enqueueJob = module => {
- const d = module.depth;
- if (typeof d === "number" && d <= depth) return;
- queue.add(module);
- module.depth = depth;
- };
- /**
- * @param {Dependency} dependency dependency to assign depth to
- * @returns {void}
- */
- const assignDepthToDependency = dependency => {
- if (dependency.module) {
- enqueueJob(dependency.module);
- }
- };
- /**
- * @param {DependenciesBlock} block block to assign depth to
- * @returns {void}
- */
- const assignDepthToDependencyBlock = block => {
- if (block.variables) {
- iterationBlockVariable(block.variables, assignDepthToDependency);
- }
- if (block.dependencies) {
- iterationOfArrayCallback(block.dependencies, assignDepthToDependency);
- }
- if (block.blocks) {
- iterationOfArrayCallback(block.blocks, assignDepthToDependencyBlock);
- }
- };
- for (module of queue) {
- queue.delete(module);
- depth = module.depth;
- depth++;
- assignDepthToDependencyBlock(module);
- }
- }
- /**
- * @param {Module} module the module containing the dependency
- * @param {Dependency} dependency the dependency
- * @returns {DependencyReference} a reference for the dependency
- */
- getDependencyReference(module, dependency) {
- // TODO remove dep.getReference existence check in webpack 5
- if (typeof dependency.getReference !== "function") return null;
- const ref = dependency.getReference();
- if (!ref) return null;
- return this.hooks.dependencyReference.call(ref, dependency, module);
- }
- /**
- * This method creates the Chunk graph from the Module graph
- * @private
- * @param {TODO[]} inputChunkGroups chunk groups which are processed
- * @returns {void}
- */
- processDependenciesBlocksForChunkGroups(inputChunkGroups) {
- // Process is splitting into two parts:
- // Part one traverse the module graph and builds a very basic chunks graph
- // in chunkDependencies.
- // Part two traverse every possible way through the basic chunk graph and
- // tracks the available modules. While traversing it connects chunks with
- // eachother and Blocks with Chunks. It stops traversing when all modules
- // for a chunk are already available. So it doesn't connect unneeded chunks.
- /** @type {Map<ChunkGroup, {block: AsyncDependenciesBlock, chunkGroup: ChunkGroup, couldBeFiltered: boolean}[]>} */
- const chunkDependencies = new Map();
- const allCreatedChunkGroups = new Set();
- // PREPARE
- /** @type {Map<DependenciesBlock, { modules: Module[], blocks: AsyncDependenciesBlock[]}>} */
- const blockInfoMap = new Map();
- /**
- * @param {Dependency} d dependency to iterate over
- * @returns {void}
- */
- const iteratorDependency = d => {
- // We skip Dependencies without Reference
- const ref = this.getDependencyReference(currentModule, d);
- if (!ref) {
- return;
- }
- // We skip Dependencies without Module pointer
- const refModule = ref.module;
- if (!refModule) {
- return;
- }
- // We skip weak Dependencies
- if (ref.weak) {
- return;
- }
- blockInfoModules.add(refModule);
- };
- /**
- * @param {AsyncDependenciesBlock} b blocks to prepare
- * @returns {void}
- */
- const iteratorBlockPrepare = b => {
- blockInfoBlocks.push(b);
- blockQueue.push(b);
- };
- /** @type {Module} */
- let currentModule;
- /** @type {DependenciesBlock} */
- let block;
- /** @type {DependenciesBlock[]} */
- let blockQueue;
- /** @type {Set<Module>} */
- let blockInfoModules;
- /** @type {AsyncDependenciesBlock[]} */
- let blockInfoBlocks;
- for (const module of this.modules) {
- blockQueue = [module];
- currentModule = module;
- while (blockQueue.length > 0) {
- block = blockQueue.pop();
- blockInfoModules = new Set();
- blockInfoBlocks = [];
- if (block.variables) {
- iterationBlockVariable(block.variables, iteratorDependency);
- }
- if (block.dependencies) {
- iterationOfArrayCallback(block.dependencies, iteratorDependency);
- }
- if (block.blocks) {
- iterationOfArrayCallback(block.blocks, iteratorBlockPrepare);
- }
- const blockInfo = {
- modules: Array.from(blockInfoModules),
- blocks: blockInfoBlocks
- };
- blockInfoMap.set(block, blockInfo);
- }
- }
- // PART ONE
- /** @type {Map<ChunkGroup, { index: number, index2: number }>} */
- const chunkGroupCounters = new Map();
- for (const chunkGroup of inputChunkGroups) {
- chunkGroupCounters.set(chunkGroup, { index: 0, index2: 0 });
- }
- let nextFreeModuleIndex = 0;
- let nextFreeModuleIndex2 = 0;
- /** @type {Map<DependenciesBlock, ChunkGroup>} */
- const blockChunkGroups = new Map();
- /** @type {Set<DependenciesBlock>} */
- const blocksWithNestedBlocks = new Set();
- const ADD_AND_ENTER_MODULE = 0;
- const ENTER_MODULE = 1;
- const PROCESS_BLOCK = 2;
- const LEAVE_MODULE = 3;
- /**
- * @typedef {Object} QueueItem
- * @property {number} action
- * @property {DependenciesBlock} block
- * @property {Module} module
- * @property {Chunk} chunk
- * @property {ChunkGroup} chunkGroup
- */
- /**
- * @param {ChunkGroup} chunkGroup chunk group
- * @returns {QueueItem} queue item
- */
- const chunkGroupToQueueItem = chunkGroup => ({
- action: ENTER_MODULE,
- block: chunkGroup.chunks[0].entryModule,
- module: chunkGroup.chunks[0].entryModule,
- chunk: chunkGroup.chunks[0],
- chunkGroup
- });
- // Start with the provided modules/chunks
- /** @type {QueueItem[]} */
- let queue = inputChunkGroups.map(chunkGroupToQueueItem).reverse();
- /** @type {QueueItem[]} */
- let queueDelayed = [];
- /** @type {Module} */
- let module;
- /** @type {Chunk} */
- let chunk;
- /** @type {ChunkGroup} */
- let chunkGroup;
- // For each async Block in graph
- /**
- * @param {AsyncDependenciesBlock} b iterating over each Async DepBlock
- * @returns {void}
- */
- const iteratorBlock = b => {
- // 1. We create a chunk for this Block
- // but only once (blockChunkGroups map)
- let c = blockChunkGroups.get(b);
- if (c === undefined) {
- c = this.namedChunkGroups.get(b.chunkName);
- if (c && c.isInitial()) {
- this.errors.push(
- new AsyncDependencyToInitialChunkError(b.chunkName, module, b.loc)
- );
- c = chunkGroup;
- } else {
- c = this.addChunkInGroup(
- b.groupOptions || b.chunkName,
- module,
- b.loc,
- b.request
- );
- chunkGroupCounters.set(c, { index: 0, index2: 0 });
- blockChunkGroups.set(b, c);
- allCreatedChunkGroups.add(c);
- }
- } else {
- // TODO webpack 5 remove addOptions check
- if (c.addOptions) c.addOptions(b.groupOptions);
- c.addOrigin(module, b.loc, b.request);
- }
- // 2. We store the Block+Chunk mapping as dependency for the chunk
- let deps = chunkDependencies.get(chunkGroup);
- if (!deps) chunkDependencies.set(chunkGroup, (deps = []));
- deps.push({
- block: b,
- chunkGroup: c,
- couldBeFiltered: true
- });
- // 3. We enqueue the DependenciesBlock for traversal
- queueDelayed.push({
- action: PROCESS_BLOCK,
- block: b,
- module: module,
- chunk: c.chunks[0],
- chunkGroup: c
- });
- };
- // Iterative traversal of the Module graph
- // Recursive would be simpler to write but could result in Stack Overflows
- while (queue.length) {
- while (queue.length) {
- const queueItem = queue.pop();
- module = queueItem.module;
- block = queueItem.block;
- chunk = queueItem.chunk;
- chunkGroup = queueItem.chunkGroup;
- switch (queueItem.action) {
- case ADD_AND_ENTER_MODULE: {
- // We connect Module and Chunk when not already done
- if (chunk.addModule(module)) {
- module.addChunk(chunk);
- } else {
- // already connected, skip it
- break;
- }
- }
- // fallthrough
- case ENTER_MODULE: {
- if (chunkGroup !== undefined) {
- const index = chunkGroup.getModuleIndex(module);
- if (index === undefined) {
- chunkGroup.setModuleIndex(
- module,
- chunkGroupCounters.get(chunkGroup).index++
- );
- }
- }
- if (module.index === null) {
- module.index = nextFreeModuleIndex++;
- }
- queue.push({
- action: LEAVE_MODULE,
- block,
- module,
- chunk,
- chunkGroup
- });
- }
- // fallthrough
- case PROCESS_BLOCK: {
- // get prepared block info
- const blockInfo = blockInfoMap.get(block);
- // Traverse all referenced modules
- for (let i = blockInfo.modules.length - 1; i >= 0; i--) {
- const refModule = blockInfo.modules[i];
- if (chunk.containsModule(refModule)) {
- // skip early if already connected
- continue;
- }
- // enqueue the add and enter to enter in the correct order
- // this is relevant with circular dependencies
- queue.push({
- action: ADD_AND_ENTER_MODULE,
- block: refModule,
- module: refModule,
- chunk,
- chunkGroup
- });
- }
- // Traverse all Blocks
- iterationOfArrayCallback(blockInfo.blocks, iteratorBlock);
- if (blockInfo.blocks.length > 0 && module !== block) {
- blocksWithNestedBlocks.add(block);
- }
- break;
- }
- case LEAVE_MODULE: {
- if (chunkGroup !== undefined) {
- const index = chunkGroup.getModuleIndex2(module);
- if (index === undefined) {
- chunkGroup.setModuleIndex2(
- module,
- chunkGroupCounters.get(chunkGroup).index2++
- );
- }
- }
- if (module.index2 === null) {
- module.index2 = nextFreeModuleIndex2++;
- }
- break;
- }
- }
- }
- const tempQueue = queue;
- queue = queueDelayed.reverse();
- queueDelayed = tempQueue;
- }
- // PART TWO
- /** @type {Set<Module>} */
- let newAvailableModules;
- /**
- * @typedef {Object} ChunkGroupInfo
- * @property {Set<Module>} minAvailableModules current minimal set of modules available at this point
- * @property {Set<Module>[]} availableModulesToBeMerged enqueued updates to the minimal set of available modules
- */
- /** @type {Map<ChunkGroup, ChunkGroupInfo>} */
- const chunkGroupInfoMap = new Map();
- /** @type {Queue<ChunkGroup>} */
- const queue2 = new Queue(inputChunkGroups);
- for (const chunkGroup of inputChunkGroups) {
- chunkGroupInfoMap.set(chunkGroup, {
- minAvailableModules: undefined,
- availableModulesToBeMerged: [new Set()]
- });
- }
- /**
- * Helper function to check if all modules of a chunk are available
- *
- * @param {ChunkGroup} chunkGroup the chunkGroup to scan
- * @param {Set<Module>} availableModules the comparitor set
- * @returns {boolean} return true if all modules of a chunk are available
- */
- const areModulesAvailable = (chunkGroup, availableModules) => {
- for (const chunk of chunkGroup.chunks) {
- for (const module of chunk.modulesIterable) {
- if (!availableModules.has(module)) return false;
- }
- }
- return true;
- };
- // For each edge in the basic chunk graph
- /**
- * @param {TODO} dep the dependency used for filtering
- * @returns {boolean} used to filter "edges" (aka Dependencies) that were pointing
- * to modules that are already available. Also filters circular dependencies in the chunks graph
- */
- const filterFn = dep => {
- const depChunkGroup = dep.chunkGroup;
- if (!dep.couldBeFiltered) return true;
- if (blocksWithNestedBlocks.has(dep.block)) return true;
- if (areModulesAvailable(depChunkGroup, newAvailableModules)) {
- return false; // break all modules are already available
- }
- dep.couldBeFiltered = false;
- return true;
- };
- // Iterative traversing of the basic chunk graph
- while (queue2.length) {
- chunkGroup = queue2.dequeue();
- const info = chunkGroupInfoMap.get(chunkGroup);
- const availableModulesToBeMerged = info.availableModulesToBeMerged;
- let minAvailableModules = info.minAvailableModules;
- // 1. Get minimal available modules
- // It doesn't make sense to traverse a chunk again with more available modules.
- // This step calculates the minimal available modules and skips traversal when
- // the list didn't shrink.
- availableModulesToBeMerged.sort(bySetSize);
- let changed = false;
- for (const availableModules of availableModulesToBeMerged) {
- if (minAvailableModules === undefined) {
- minAvailableModules = new Set(availableModules);
- info.minAvailableModules = minAvailableModules;
- changed = true;
- } else {
- for (const m of minAvailableModules) {
- if (!availableModules.has(m)) {
- minAvailableModules.delete(m);
- changed = true;
- }
- }
- }
- }
- availableModulesToBeMerged.length = 0;
- if (!changed) continue;
- // 2. Get the edges at this point of the graph
- const deps = chunkDependencies.get(chunkGroup);
- if (!deps) continue;
- if (deps.length === 0) continue;
- // 3. Create a new Set of available modules at this points
- newAvailableModules = new Set(minAvailableModules);
- for (const chunk of chunkGroup.chunks) {
- for (const m of chunk.modulesIterable) {
- newAvailableModules.add(m);
- }
- }
- // 4. Foreach remaining edge
- const nextChunkGroups = new Set();
- for (let i = 0; i < deps.length; i++) {
- const dep = deps[i];
- // Filter inline, rather than creating a new array from `.filter()`
- if (!filterFn(dep)) {
- continue;
- }
- const depChunkGroup = dep.chunkGroup;
- const depBlock = dep.block;
- // 5. Connect block with chunk
- GraphHelpers.connectDependenciesBlockAndChunkGroup(
- depBlock,
- depChunkGroup
- );
- // 6. Connect chunk with parent
- GraphHelpers.connectChunkGroupParentAndChild(chunkGroup, depChunkGroup);
- nextChunkGroups.add(depChunkGroup);
- }
- // 7. Enqueue further traversal
- for (const nextChunkGroup of nextChunkGroups) {
- let nextInfo = chunkGroupInfoMap.get(nextChunkGroup);
- if (nextInfo === undefined) {
- nextInfo = {
- minAvailableModules: undefined,
- availableModulesToBeMerged: []
- };
- chunkGroupInfoMap.set(nextChunkGroup, nextInfo);
- }
- nextInfo.availableModulesToBeMerged.push(newAvailableModules);
- // As queue deduplicates enqueued items this makes sure that a ChunkGroup
- // is not enqueued twice
- queue2.enqueue(nextChunkGroup);
- }
- }
- // Remove all unconnected chunk groups
- for (const chunkGroup of allCreatedChunkGroups) {
- if (chunkGroup.getNumberOfParents() === 0) {
- for (const chunk of chunkGroup.chunks) {
- const idx = this.chunks.indexOf(chunk);
- if (idx >= 0) this.chunks.splice(idx, 1);
- chunk.remove("unconnected");
- }
- chunkGroup.remove("unconnected");
- }
- }
- }
- /**
- *
- * @param {Module} module module relationship for removal
- * @param {DependenciesBlockLike} block //TODO: good description
- * @returns {void}
- */
- removeReasonsOfDependencyBlock(module, block) {
- const iteratorDependency = d => {
- if (!d.module) {
- return;
- }
- if (d.module.removeReason(module, d)) {
- for (const chunk of d.module.chunksIterable) {
- this.patchChunksAfterReasonRemoval(d.module, chunk);
- }
- }
- };
- if (block.blocks) {
- iterationOfArrayCallback(block.blocks, block =>
- this.removeReasonsOfDependencyBlock(module, block)
- );
- }
- if (block.dependencies) {
- iterationOfArrayCallback(block.dependencies, iteratorDependency);
- }
- if (block.variables) {
- iterationBlockVariable(block.variables, iteratorDependency);
- }
- }
- /**
- * @param {Module} module module to patch tie
- * @param {Chunk} chunk chunk to patch tie
- * @returns {void}
- */
- patchChunksAfterReasonRemoval(module, chunk) {
- if (!module.hasReasons()) {
- this.removeReasonsOfDependencyBlock(module, module);
- }
- if (!module.hasReasonForChunk(chunk)) {
- if (module.removeChunk(chunk)) {
- this.removeChunkFromDependencies(module, chunk);
- }
- }
- }
- /**
- *
- * @param {DependenciesBlock} block block tie for Chunk
- * @param {Chunk} chunk chunk to remove from dep
- * @returns {void}
- */
- removeChunkFromDependencies(block, chunk) {
- const iteratorDependency = d => {
- if (!d.module) {
- return;
- }
- this.patchChunksAfterReasonRemoval(d.module, chunk);
- };
- const blocks = block.blocks;
- for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
- const asyncBlock = blocks[indexBlock];
- // Grab all chunks from the first Block's AsyncDepBlock
- const chunks = asyncBlock.chunkGroup.chunks;
- // For each chunk in chunkGroup
- for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
- const iteratedChunk = chunks[indexChunk];
- asyncBlock.chunkGroup.removeChunk(iteratedChunk);
- asyncBlock.chunkGroup.removeParent(iteratedChunk);
- // Recurse
- this.removeChunkFromDependencies(block, iteratedChunk);
- }
- }
- if (block.dependencies) {
- iterationOfArrayCallback(block.dependencies, iteratorDependency);
- }
- if (block.variables) {
- iterationBlockVariable(block.variables, iteratorDependency);
- }
- }
- applyModuleIds() {
- const unusedIds = [];
- let nextFreeModuleId = 0;
- const usedIds = new Set();
- if (this.usedModuleIds) {
- for (const id of this.usedModuleIds) {
- usedIds.add(id);
- }
- }
- const modules1 = this.modules;
- for (let indexModule1 = 0; indexModule1 < modules1.length; indexModule1++) {
- const module1 = modules1[indexModule1];
- if (module1.id !== null) {
- usedIds.add(module1.id);
- }
- }
- if (usedIds.size > 0) {
- let usedIdMax = -1;
- for (const usedIdKey of usedIds) {
- if (typeof usedIdKey !== "number") {
- continue;
- }
- usedIdMax = Math.max(usedIdMax, usedIdKey);
- }
- let lengthFreeModules = (nextFreeModuleId = usedIdMax + 1);
- while (lengthFreeModules--) {
- if (!usedIds.has(lengthFreeModules)) {
- unusedIds.push(lengthFreeModules);
- }
- }
- }
- const modules2 = this.modules;
- for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
- const module2 = modules2[indexModule2];
- if (module2.id === null) {
- if (unusedIds.length > 0) {
- module2.id = unusedIds.pop();
- } else {
- module2.id = nextFreeModuleId++;
- }
- }
- }
- }
- applyChunkIds() {
- /** @type {Set<number>} */
- const usedIds = new Set();
- // Get used ids from usedChunkIds property (i. e. from records)
- if (this.usedChunkIds) {
- for (const id of this.usedChunkIds) {
- if (typeof id !== "number") {
- continue;
- }
- usedIds.add(id);
- }
- }
- // Get used ids from existing chunks
- const chunks = this.chunks;
- for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
- const chunk = chunks[indexChunk];
- const usedIdValue = chunk.id;
- if (typeof usedIdValue !== "number") {
- continue;
- }
- usedIds.add(usedIdValue);
- }
- // Calculate maximum assigned chunk id
- let nextFreeChunkId = -1;
- for (const id of usedIds) {
- nextFreeChunkId = Math.max(nextFreeChunkId, id);
- }
- nextFreeChunkId++;
- // Determine free chunk ids from 0 to maximum
- /** @type {number[]} */
- const unusedIds = [];
- if (nextFreeChunkId > 0) {
- let index = nextFreeChunkId;
- while (index--) {
- if (!usedIds.has(index)) {
- unusedIds.push(index);
- }
- }
- }
- // Assign ids to chunk which has no id
- for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
- const chunk = chunks[indexChunk];
- if (chunk.id === null) {
- if (unusedIds.length > 0) {
- chunk.id = unusedIds.pop();
- } else {
- chunk.id = nextFreeChunkId++;
- }
- }
- if (!chunk.ids) {
- chunk.ids = [chunk.id];
- }
- }
- }
- sortItemsWithModuleIds() {
- this.modules.sort(byIdOrIdentifier);
- const modules = this.modules;
- for (let indexModule = 0; indexModule < modules.length; indexModule++) {
- modules[indexModule].sortItems(false);
- }
- const chunks = this.chunks;
- for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
- chunks[indexChunk].sortItems();
- }
- chunks.sort((a, b) => a.compareTo(b));
- }
- sortItemsWithChunkIds() {
- for (const chunkGroup of this.chunkGroups) {
- chunkGroup.sortItems();
- }
- this.chunks.sort(byId);
- for (
- let indexModule = 0;
- indexModule < this.modules.length;
- indexModule++
- ) {
- this.modules[indexModule].sortItems(true);
- }
- const chunks = this.chunks;
- for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
- chunks[indexChunk].sortItems();
- }
- /**
- * Used to sort errors and warnings in compilation. this.warnings, and
- * this.errors contribute to the compilation hash and therefore should be
- * updated whenever other references (having a chunk id) are sorted. This preserves the hash
- * integrity
- *
- * @param {WebpackError} a first WebpackError instance (including subclasses)
- * @param {WebpackError} b second WebpackError instance (including subclasses)
- * @returns {-1|0|1} sort order index
- */
- const byMessage = (a, b) => {
- const ma = `${a.message}`;
- const mb = `${b.message}`;
- if (ma < mb) return -1;
- if (mb < ma) return 1;
- return 0;
- };
- this.errors.sort(byMessage);
- this.warnings.sort(byMessage);
- this.children.sort(byNameOrHash);
- }
- summarizeDependencies() {
- this.fileDependencies = new SortableSet(this.compilationDependencies);
- this.contextDependencies = new SortableSet();
- this.missingDependencies = new SortableSet();
- for (
- let indexChildren = 0;
- indexChildren < this.children.length;
- indexChildren++
- ) {
- const child = this.children[indexChildren];
- addAllToSet(this.fileDependencies, child.fileDependencies);
- addAllToSet(this.contextDependencies, child.contextDependencies);
- addAllToSet(this.missingDependencies, child.missingDependencies);
- }
- for (
- let indexModule = 0;
- indexModule < this.modules.length;
- indexModule++
- ) {
- const module = this.modules[indexModule];
- if (module.buildInfo.fileDependencies) {
- addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies);
- }
- if (module.buildInfo.contextDependencies) {
- addAllToSet(
- this.contextDependencies,
- module.buildInfo.contextDependencies
- );
- }
- }
- for (const error of this.errors) {
- if (
- typeof error.missing === "object" &&
- error.missing &&
- error.missing[Symbol.iterator]
- ) {
- addAllToSet(this.missingDependencies, error.missing);
- }
- }
- this.fileDependencies.sort();
- this.contextDependencies.sort();
- this.missingDependencies.sort();
- }
- createHash() {
- const outputOptions = this.outputOptions;
- const hashFunction = outputOptions.hashFunction;
- const hashDigest = outputOptions.hashDigest;
- const hashDigestLength = outputOptions.hashDigestLength;
- const hash = createHash(hashFunction);
- if (outputOptions.hashSalt) {
- hash.update(outputOptions.hashSalt);
- }
- this.mainTemplate.updateHash(hash);
- this.chunkTemplate.updateHash(hash);
- for (const key of Object.keys(this.moduleTemplates).sort()) {
- this.moduleTemplates[key].updateHash(hash);
- }
- for (const child of this.children) {
- hash.update(child.hash);
- }
- for (const warning of this.warnings) {
- hash.update(`${warning.message}`);
- }
- for (const error of this.errors) {
- hash.update(`${error.message}`);
- }
- const modules = this.modules;
- for (let i = 0; i < modules.length; i++) {
- const module = modules[i];
- const moduleHash = createHash(hashFunction);
- module.updateHash(moduleHash);
- module.hash = moduleHash.digest(hashDigest);
- module.renderedHash = module.hash.substr(0, hashDigestLength);
- }
- // clone needed as sort below is inplace mutation
- const chunks = this.chunks.slice();
- /**
- * sort here will bring all "falsy" values to the beginning
- * this is needed as the "hasRuntime()" chunks are dependent on the
- * hashes of the non-runtime chunks.
- */
- chunks.sort((a, b) => {
- const aEntry = a.hasRuntime();
- const bEntry = b.hasRuntime();
- if (aEntry && !bEntry) return 1;
- if (!aEntry && bEntry) return -1;
- return byId(a, b);
- });
- for (let i = 0; i < chunks.length; i++) {
- const chunk = chunks[i];
- const chunkHash = createHash(hashFunction);
- try {
- if (outputOptions.hashSalt) {
- chunkHash.update(outputOptions.hashSalt);
- }
- chunk.updateHash(chunkHash);
- const template = chunk.hasRuntime()
- ? this.mainTemplate
- : this.chunkTemplate;
- template.updateHashForChunk(
- chunkHash,
- chunk,
- this.moduleTemplates.javascript,
- this.dependencyTemplates
- );
- this.hooks.chunkHash.call(chunk, chunkHash);
- chunk.hash = chunkHash.digest(hashDigest);
- hash.update(chunk.hash);
- chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
- this.hooks.contentHash.call(chunk);
- } catch (err) {
- this.errors.push(new ChunkRenderError(chunk, "", err));
- }
- }
- this.fullHash = hash.digest(hashDigest);
- this.hash = this.fullHash.substr(0, hashDigestLength);
- }
- /**
- * @param {string} update extra information
- * @returns {void}
- */
- modifyHash(update) {
- const outputOptions = this.outputOptions;
- const hashFunction = outputOptions.hashFunction;
- const hashDigest = outputOptions.hashDigest;
- const hashDigestLength = outputOptions.hashDigestLength;
- const hash = createHash(hashFunction);
- hash.update(this.fullHash);
- hash.update(update);
- this.fullHash = hash.digest(hashDigest);
- this.hash = this.fullHash.substr(0, hashDigestLength);
- }
- createModuleAssets() {
- for (let i = 0; i < this.modules.length; i++) {
- const module = this.modules[i];
- if (module.buildInfo.assets) {
- for (const assetName of Object.keys(module.buildInfo.assets)) {
- const fileName = this.getPath(assetName);
- this.assets[fileName] = module.buildInfo.assets[assetName];
- this.hooks.moduleAsset.call(module, fileName);
- }
- }
- }
- }
- createChunkAssets() {
- const outputOptions = this.outputOptions;
- const cachedSourceMap = new Map();
- /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
- const alreadyWrittenFiles = new Map();
- for (let i = 0; i < this.chunks.length; i++) {
- const chunk = this.chunks[i];
- chunk.files = [];
- let source;
- let file;
- let filenameTemplate;
- try {
- const template = chunk.hasRuntime()
- ? this.mainTemplate
- : this.chunkTemplate;
- const manifest = template.getRenderManifest({
- chunk,
- hash: this.hash,
- fullHash: this.fullHash,
- outputOptions,
- moduleTemplates: this.moduleTemplates,
- dependencyTemplates: this.dependencyTemplates
- }); // [{ render(), filenameTemplate, pathOptions, identifier, hash }]
- for (const fileManifest of manifest) {
- const cacheName = fileManifest.identifier;
- const usedHash = fileManifest.hash;
- filenameTemplate = fileManifest.filenameTemplate;
- file = this.getPath(filenameTemplate, fileManifest.pathOptions);
- // check if the same filename was already written by another chunk
- const alreadyWritten = alreadyWrittenFiles.get(file);
- if (alreadyWritten !== undefined) {
- if (alreadyWritten.hash === usedHash) {
- if (this.cache) {
- this.cache[cacheName] = {
- hash: usedHash,
- source: alreadyWritten.source
- };
- }
- chunk.files.push(file);
- this.hooks.chunkAsset.call(chunk, file);
- continue;
- } else {
- throw new Error(
- `Conflict: Multiple chunks emit assets to the same filename ${file}` +
- ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
- );
- }
- }
- if (
- this.cache &&
- this.cache[cacheName] &&
- this.cache[cacheName].hash === usedHash
- ) {
- source = this.cache[cacheName].source;
- } else {
- source = fileManifest.render();
- // Ensure that source is a cached source to avoid additional cost because of repeated access
- if (!(source instanceof CachedSource)) {
- const cacheEntry = cachedSourceMap.get(source);
- if (cacheEntry) {
- source = cacheEntry;
- } else {
- const cachedSource = new CachedSource(source);
- cachedSourceMap.set(source, cachedSource);
- source = cachedSource;
- }
- }
- if (this.cache) {
- this.cache[cacheName] = {
- hash: usedHash,
- source
- };
- }
- }
- if (this.assets[file] && this.assets[file] !== source) {
- throw new Error(
- `Conflict: Multiple assets emit to the same filename ${file}`
- );
- }
- this.assets[file] = source;
- chunk.files.push(file);
- this.hooks.chunkAsset.call(chunk, file);
- alreadyWrittenFiles.set(file, {
- hash: usedHash,
- source,
- chunk
- });
- }
- } catch (err) {
- this.errors.push(
- new ChunkRenderError(chunk, file || filenameTemplate, err)
- );
- }
- }
- }
- /**
- * @param {string} filename used to get asset path with hash
- * @param {TODO=} data // TODO: figure out this param type
- * @returns {string} interpolated path
- */
- getPath(filename, data) {
- data = data || {};
- data.hash = data.hash || this.hash;
- return this.mainTemplate.getAssetPath(filename, data);
- }
- /**
- * This function allows you to run another instance of webpack inside of webpack however as
- * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins
- * from parent (or top level compiler) and creates a child Compilation
- *
- * @param {string} name name of the child compiler
- * @param {TODO} outputOptions // Need to convert config schema to types for this
- * @param {Plugin[]} plugins webpack plugins that will be applied
- * @returns {Compiler} creates a child Compiler instance
- */
- createChildCompiler(name, outputOptions, plugins) {
- const idx = this.childrenCounters[name] || 0;
- this.childrenCounters[name] = idx + 1;
- return this.compiler.createChildCompiler(
- this,
- name,
- idx,
- outputOptions,
- plugins
- );
- }
- checkConstraints() {
- /** @type {Set<number|string>} */
- const usedIds = new Set();
- const modules = this.modules;
- for (let indexModule = 0; indexModule < modules.length; indexModule++) {
- const moduleId = modules[indexModule].id;
- if (moduleId === null) continue;
- if (usedIds.has(moduleId)) {
- throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
- }
- usedIds.add(moduleId);
- }
- const chunks = this.chunks;
- for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
- const chunk = chunks[indexChunk];
- if (chunks.indexOf(chunk) !== indexChunk) {
- throw new Error(
- `checkConstraints: duplicate chunk in compilation ${chunk.debugId}`
- );
- }
- }
- for (const chunkGroup of this.chunkGroups) {
- chunkGroup.checkConstraints();
- }
- }
- }
- // TODO remove in webpack 5
- Compilation.prototype.applyPlugins = util.deprecate(
- /**
- * @deprecated
- * @param {string} name Name
- * @param {any[]} args Other arguments
- * @returns {void}
- * @this {Compilation}
- */
- function(name, ...args) {
- this.hooks[
- name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase())
- ].call(...args);
- },
- "Compilation.applyPlugins is deprecated. Use new API on `.hooks` instead"
- );
- // TODO remove in webpack 5
- Object.defineProperty(Compilation.prototype, "moduleTemplate", {
- configurable: false,
- get: util.deprecate(
- /**
- * @deprecated
- * @this {Compilation}
- * @returns {TODO} module template
- */
- function() {
- return this.moduleTemplates.javascript;
- },
- "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead"
- ),
- set: util.deprecate(
- /**
- * @deprecated
- * @param {ModuleTemplate} value Template value
- * @this {Compilation}
- * @returns {void}
- */
- function(value) {
- this.moduleTemplates.javascript = value;
- },
- "Compilation.moduleTemplate: Use Compilation.moduleTemplates.javascript instead."
- )
- });
- module.exports = Compilation;
|