RuntimeTemplate.js 154 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { CachedSource, ReplaceSource } = require("webpack-sources");
  7. const APIPlugin = require("./APIPlugin");
  8. const InitFragment = require("./InitFragment");
  9. const {
  10. ASSET_TYPE,
  11. ASSET_URL_TYPE,
  12. CSS_TYPE,
  13. HTML_TYPE,
  14. JAVASCRIPT_TYPE,
  15. RUNTIME_TYPE
  16. } = require("./ModuleSourceTypeConstants");
  17. const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("./ModuleTypeConstants");
  18. const RuntimeGlobals = require("./RuntimeGlobals");
  19. const Template = require("./Template");
  20. const {
  21. getOutgoingAsyncModules
  22. } = require("./async-modules/AsyncModuleHelpers");
  23. const HarmonyImportDependency = require("./dependencies/HarmonyImportDependency");
  24. const ImportDependency = require("./dependencies/ImportDependency");
  25. const { ImportPhaseUtils } = require("./dependencies/ImportPhase");
  26. const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
  27. const { InlinedUsedName } = require("./optimize/InlineExports");
  28. const {
  29. getDeferredCycleModuleIds,
  30. getDeferredCycleModules,
  31. getMakeDeferredNamespaceModeFromExportsType,
  32. getOptimizedDeferredModule
  33. } = require("./runtime/MakeDeferredNamespaceObjectRuntime");
  34. const {
  35. isAbsoluteBaseUri,
  36. isChunkRelativeBaseUri
  37. } = require("./runtime/baseUri");
  38. const { equals } = require("./util/ArrayHelpers");
  39. const { getScheme } = require("./util/URLAbsoluteSpecifier");
  40. const { compareIds } = require("./util/comparators");
  41. const compileBooleanMatcher = require("./util/compileBooleanMatcher");
  42. const { getUndoPath, toJsStringLiteral } = require("./util/identifier");
  43. const memoize = require("./util/memoize");
  44. const { propertyAccess, propertyName } = require("./util/property");
  45. const {
  46. forEachRuntime,
  47. getRuntimeKey,
  48. intersectRuntime,
  49. subtractRuntime
  50. } = require("./util/runtime");
  51. const getCssModulesPlugin = memoize(() => require("./css/CssModulesPlugin"));
  52. // `Compilation` requires this module, so its stage constants are read lazily.
  53. const getCompilation = memoize(() => require("./Compilation"));
  54. /**
  55. * @typedef {object} ChunkAssetNaming
  56. * @property {(chunk: Chunk, outputOptions: OutputOptions) => ChunkFilenameTemplate} template what names the asset
  57. * @property {SpecifierPartKind} standIn the stand-in kind that spells it once the hashes exist
  58. */
  59. /**
  60. * What names the asset a chunk emits for one source type. Keyed rather than branched
  61. * on, so a type nothing here answers for keeps the runtime form instead of silently
  62. * taking another type's name and hash. A plugin emitting a new kind of chunk asset
  63. * registers it here to have its urls baked.
  64. * @type {Map<string, ChunkAssetNaming>}
  65. */
  66. const CHUNK_ASSET_NAMING = new Map([
  67. [
  68. JAVASCRIPT_TYPE,
  69. {
  70. template: (chunk, outputOptions) =>
  71. JavascriptModulesPlugin.getChunkFilenameTemplate(chunk, outputOptions),
  72. standIn: "chunk"
  73. }
  74. ],
  75. [
  76. CSS_TYPE,
  77. {
  78. template: (chunk, outputOptions) =>
  79. getCssModulesPlugin().getChunkFilenameTemplate(chunk, outputOptions),
  80. standIn: "cssChunk"
  81. }
  82. ]
  83. ]);
  84. const getTemplatedPathPlugin = memoize(() => require("./TemplatedPathPlugin"));
  85. const getConcatenatedModule = memoize(() =>
  86. require("./optimize/ConcatenatedModule")
  87. );
  88. // Any `[hash]`/`[fullhash]`/`[chunkhash]`/`[contenthash]` token, incl. a `:<length>`
  89. // or `:<digest>[:<length>]` suffix (e.g. `[contenthash:base64:8]`). Its value is only
  90. // resolved after code generation, so a filename using one can't be an inline literal.
  91. const HASH_IN_FILENAME = /\[(?:full|chunk|content)?hash(?::[^\]]+)?\]/;
  92. // Two stand-ins for every hash a filename function might read: a name built from one
  93. // is hash-dependent exactly when the two calls disagree.
  94. const HASH_PROBE = "0123456789abcdef0123";
  95. // Reversed, so the two differ at every position and no slice of one equals the other.
  96. const HASH_PROBE_ALTERNATE = "3210fedcba9876543210";
  97. const HASH_IN_FILENAME_GLOBAL = /\[(?:full|chunk|content)?hash(?::[^\]]+)?\]/g;
  98. /**
  99. * @param {SpecifierPart} part one piece of a reserved name
  100. * @returns {boolean} true when it is text the deferred pass adds nothing to
  101. */
  102. const isLiteralPart = (part) => part[0] === "literal";
  103. /**
  104. * The text these parts spell, or `null` when one of them is a stand-in that only
  105. * the deferred pass can fill in.
  106. * @param {SpecifierPart[] | null} parts pieces of a name
  107. * @returns {string | null} the text, or `null` when they are not all literal
  108. */
  109. const literalText = (parts) => {
  110. if (parts === null) return null;
  111. // Built in one pass rather than tested and then joined: every specifier asks, and
  112. // a stand-in in the first part answers without reading the rest.
  113. let text = "";
  114. for (const part of parts) {
  115. if (!isLiteralPart(part)) return null;
  116. text += part[1];
  117. }
  118. return text;
  119. };
  120. /**
  121. * Whether a public path reaches the same place from any base. A relative one does
  122. * not, and is equivalent only behind the `../` path back to the output root.
  123. * @param {string} publicPath the resolved public path, or the shape of one
  124. * @returns {boolean} true when no base is needed
  125. */
  126. const isBaseIndependent = (publicPath) =>
  127. publicPath.startsWith("/") || getScheme(publicPath) !== undefined;
  128. /**
  129. * Drops the `./` a public path may open with: what follows it is already walked back
  130. * to the output root, so it would only lengthen the name.
  131. * @param {SpecifierPart[]} parts a public path's pieces
  132. * @returns {SpecifierPart[]} them, without that `./`
  133. */
  134. const rootedParts = (parts) =>
  135. parts.length > 0 &&
  136. isLiteralPart(parts[0]) &&
  137. /** @type {string} */ (parts[0][1]).startsWith("./")
  138. ? [
  139. /** @type {SpecifierPart} */ ([
  140. "literal",
  141. /** @type {string} */ (parts[0][1]).slice(2)
  142. ]),
  143. ...parts.slice(1)
  144. ]
  145. : parts;
  146. // Types that ride the chunk itself or render their own asset, so no `.f` handler
  147. // fetches them; every other type may install one, so the map has to exist for it.
  148. /** @type {Set<string>} */
  149. const TYPES_WITHOUT_CHUNK_HANDLER = new Set([
  150. JAVASCRIPT_TYPE,
  151. RUNTIME_TYPE,
  152. ASSET_TYPE,
  153. ASSET_URL_TYPE,
  154. HTML_TYPE
  155. ]);
  156. // Why a name only the deferred pass could settle was not deferred.
  157. const DEFER_BAILOUT =
  158. "a hashed name needs optimization.realContentHash, or no emitted javascript named by its content";
  159. /**
  160. * Where a literal is read from — the `../` path back to the output root, and whether
  161. * the chunk loader fetched the chunk it sits in through `output.publicPath`.
  162. * @typedef {object} Placement
  163. * @property {string | null} undo the path back to the output root
  164. * @property {boolean | null} loaded whether the chunk loader fetched the chunk
  165. */
  166. // A reference in no chunk at all: nothing is known about where it is read from.
  167. /** @type {Placement} */
  168. const NO_PLACEMENT = { undo: null, loaded: null };
  169. /**
  170. * Which of `createHash`'s four rounds settles this chunk's hash. A hash may only be
  171. * read from an earlier round, which is what lets one chunk's name be folded into
  172. * another's hash.
  173. * @param {Chunk} chunk the chunk
  174. * @param {ChunkGraph} chunkGraph the chunk graph
  175. * @returns {number} the round, ascending
  176. */
  177. const hashRound = (chunk, chunkGraph) => {
  178. if (chunk.hasRuntime()) return 2;
  179. if (chunkGraph.getNumberOfEntryModules(chunk) > 0) return 3;
  180. return chunk.canBeInitial() ? 1 : 0;
  181. };
  182. // The round runtime chunks are settled in, ordered by references between them rather
  183. // than by id, so id says nothing about the order inside it.
  184. const RUNTIME_HASH_ROUND = 2;
  185. // Why a public path needing a base could not be spelled from the chunk holding it.
  186. const SERVED_BAILOUT =
  187. "this module is in a chunk webpack loads through output.publicPath and in one it does not, so no one path back to the output root fits both";
  188. /**
  189. * @import {
  190. * OutputNormalizedWithDefaults as OutputOptions
  191. * } from "./config/defaults"
  192. */
  193. /** @import { PublicPath, WasmLoading } from "../declarations/WebpackOptions" */
  194. /** @import ModuleDependency from "./dependencies/ModuleDependency" */
  195. /**
  196. * @import Module, {
  197. * ReadOnlyRuntimeRequirements,
  198. * BuildMeta,
  199. * RuntimeRequirements
  200. * } from "./Module"
  201. */
  202. /** @typedef {"import" | "url" | "url-runtime" | "url-inline" | "wasm" | "wasm-relative"} AnalyzableForm */
  203. /**
  204. * One piece of a name only the deferred pass can spell: text as it stands, the `../`
  205. * path from the asset it sits in to the output root, a template or `output.publicPath`
  206. * resolved once the hashes exist, one of the assets the chunk with this id emits, or
  207. * the base everything else is resolved against once it is spelled.
  208. * @typedef {"literal" | "undo" | "template" | "publicPath" | "unserved" | "chunk" | "cssChunk" | "base"} SpecifierPartKind
  209. */
  210. /** @typedef {[SpecifierPartKind, string | number]} SpecifierPart */
  211. const SPECIFIER_PART_KINDS = new Set([
  212. "literal",
  213. "undo",
  214. "template",
  215. "publicPath",
  216. "unserved",
  217. "base",
  218. "chunk",
  219. "cssChunk"
  220. ]);
  221. // Only these carry a chunk id, which is the one part value that may be a number.
  222. const CHUNK_SPECIFIER_PART_KINDS = new Set(["chunk", "cssChunk"]);
  223. // What the deferred pass scans for — the other half of what the class spells.
  224. const ANALYZABLE_TOKEN_REGEXP = /\.\/@@webpackAnalyzableChunk:([\w-]+)@@/g;
  225. // Stands in for the compilation hash inside an otherwise resolved filename, with the
  226. // requested length when the placeholder asked for one.
  227. const FULL_HASH_TOKEN_REGEXP = /@@webpackFullHash(?:-(\d+))?@@/g;
  228. const FULL_HASH_TOKEN_PREFIX = "@@webpackFullHash";
  229. /**
  230. * @param {number=} length how many characters the placeholder asked for
  231. * @returns {string} the stand-in to emit
  232. */
  233. const reserveFullHash = (length) =>
  234. `${FULL_HASH_TOKEN_PREFIX}${length === undefined ? "" : `-${length}`}@@`;
  235. // `getPath` data that leaves every compilation-hash placeholder as a stand-in while the
  236. // rest of the name resolves — a module's own hash and id are settled during code
  237. // generation, the compilation's is not. Shared: it closes over nothing.
  238. const DEFERRED_FULL_HASH_PATH_DATA = {
  239. hash: reserveFullHash(),
  240. hashWithLength: reserveFullHash
  241. };
  242. // The same table read by stand-in, for the pass that spells one: a chunk's content hash
  243. // is keyed by source type, so the type it is keyed under here is the hash to read.
  244. const CHUNK_ASSET_NAMING_BY_STAND_IN = new Map(
  245. [...CHUNK_ASSET_NAMING].map(([contentHashType, naming]) => [
  246. naming.standIn,
  247. { template: naming.template, contentHashType }
  248. ])
  249. );
  250. /**
  251. * first character, last character, replacement.
  252. * @typedef {[number, number, string]} Replacement
  253. */
  254. const PASS_NAME = "analyzableChunkNaming";
  255. /** @import AsyncDependenciesBlock from "./AsyncDependenciesBlock" */
  256. /** @import { Source } from "webpack-sources" */
  257. /** @import Compiler from "./Compiler" */
  258. /** @import Chunk, { ChunkFilenameTemplate, ChunkId } from "./Chunk" */
  259. /** @import ChunkGroup from "./ChunkGroup" */
  260. /** @import ChunkGraph from "./ChunkGraph" */
  261. /** @import Compilation from "./Compilation" */
  262. /** @import Dependency from "./Dependency" */
  263. /** @import ModuleGraph from "./ModuleGraph" */
  264. /** @import RequestShortener from "./RequestShortener" */
  265. /** @import Hash from "./util/Hash" */
  266. /** @import CodeGenerationResults from "./CodeGenerationResults" */
  267. /** @import { RuntimeSpec } from "./util/runtime" */
  268. /**
  269. * A stand-in whose every hash reads back as `hash`. Which content hashes a chunk
  270. * carries is settled after code generation, so `present` makes the two probes disagree
  271. * about that too — a name built by enumerating them then reads as hash-dependent.
  272. * Shadows the chunk rather than mutating it, so a filename function still reads every
  273. * other field and method straight off it.
  274. * @param {Chunk} chunk the chunk being referenced
  275. * @param {string} hash the stand-in hash
  276. * @param {boolean} present whether the chunk is claimed to carry content hashes
  277. * @returns {Chunk} the stand-in chunk
  278. */
  279. const createHashProbeChunk = (chunk, hash, present) => {
  280. const probeChunk = Object.create(chunk);
  281. probeChunk.hash = hash;
  282. probeChunk.renderedHash = hash;
  283. probeChunk.contentHash = new Proxy(
  284. present ? { [JAVASCRIPT_TYPE]: hash } : {},
  285. {
  286. // Any content-hash type, not only the ones this chunk happens to carry.
  287. get: (target, key) => (typeof key === "string" ? hash : undefined),
  288. has: () => present,
  289. getOwnPropertyDescriptor: () =>
  290. present
  291. ? {
  292. value: hash,
  293. writable: true,
  294. enumerable: true,
  295. configurable: true
  296. }
  297. : undefined
  298. }
  299. );
  300. return probeChunk;
  301. };
  302. /**
  303. * No module id error message.
  304. * @param {Module} module the module
  305. * @param {ChunkGraph} chunkGraph the chunk graph
  306. * @returns {string} error message
  307. */
  308. const noModuleIdErrorMessage = (
  309. module,
  310. chunkGraph
  311. ) => `Module ${module.identifier()} has no id assigned.
  312. This should not happen.
  313. It's in these chunks: ${
  314. Array.from(
  315. chunkGraph.getModuleChunksIterable(module),
  316. (c) => c.name || c.id || c.debugId
  317. ).join(", ") || "none"
  318. } (If module is in no chunk this indicates a bug in some chunk/module optimization logic)
  319. Module has these incoming connections: ${Array.from(
  320. chunkGraph.moduleGraph.getIncomingConnections(module),
  321. (connection) =>
  322. `\n - ${connection.originModule && connection.originModule.identifier()} ${
  323. connection.dependency && connection.dependency.type
  324. } ${
  325. (connection.explanations && [...connection.explanations].join(", ")) || ""
  326. }`
  327. ).join("")}`;
  328. // `this` as a value, not as a property name or part of a longer identifier
  329. // (identifier characters per `getGlobalObject` below, so `globalThis` is not one)
  330. const THIS_REFERENCE_REGEXP = /(?:^|[^\p{L}\p{N}_$.])this(?![\p{L}\p{N}_$])/u;
  331. /**
  332. * Gets global object.
  333. * @param {string | undefined} definition global object definition
  334. * @returns {string | undefined} save to use global object
  335. */
  336. function getGlobalObject(definition) {
  337. if (!definition) return definition;
  338. const trimmed = definition.trim();
  339. if (
  340. // identifier, we do not need real identifier regarding ECMAScript/Unicode
  341. /^[_\p{L}][_0-9\p{L}]*$/iu.test(trimmed) ||
  342. // iife
  343. // call expression
  344. // expression in parentheses
  345. /^(?:[_\p{L}][_0-9\p{L}]*)?\(.*\)$/iu.test(trimmed)
  346. ) {
  347. return trimmed;
  348. }
  349. return `Object(${trimmed})`;
  350. }
  351. class RuntimeTemplate {
  352. /**
  353. * Creates an instance of RuntimeTemplate.
  354. * @param {Compilation} compilation the compilation
  355. * @param {OutputOptions} outputOptions the compilation output options
  356. * @param {RequestShortener} requestShortener the request shortener
  357. */
  358. constructor(compilation, outputOptions, requestShortener) {
  359. /** @type {Compilation} */
  360. this.compilation = compilation;
  361. this.outputOptions = /** @type {OutputOptions} */ (outputOptions || {});
  362. /** @type {RequestShortener} */
  363. this.requestShortener = requestShortener;
  364. /** @type {string} */
  365. this.globalObject =
  366. /** @type {string} */
  367. (getGlobalObject(outputOptions.globalObject));
  368. /** @type {string} */
  369. this.contentHashReplacement = "X".repeat(outputOptions.hashDigestLength);
  370. /** @type {boolean | undefined} */
  371. this._javascriptNamedWithoutContent = undefined;
  372. /** @type {WeakMap<Chunk, boolean>} */
  373. this._chunkNamedWithoutContent = new WeakMap();
  374. /** @type {WeakMap<Chunk, string>} */
  375. this._foldedAnalyzableNames = new WeakMap();
  376. /** @type {WeakMap<Chunk, Map<string, string>>} */
  377. this._analyzableAssetNames = new WeakMap();
  378. /** @type {Map<Chunk, Set<string>> | undefined} */
  379. this._namesBakedInto = undefined;
  380. /** @type {Map<string, Chunk> | undefined} */
  381. this._chunksByIdForFold = undefined;
  382. /** @type {Set<Chunk> | undefined} */
  383. this._chunksBakingFullHash = undefined;
  384. /** @type {string | false | undefined} */
  385. this._publicPathShapeText = undefined;
  386. /** @type {string | null | undefined} */
  387. this._publicPathClimbText = undefined;
  388. /** @type {WeakMap<Chunk, Placement>} */
  389. this._placementByChunk = new WeakMap();
  390. /** @type {Map<string, string | null | undefined>} */
  391. this._entryBaseUriByRuntime = new Map();
  392. /** @type {Map<string, string> | undefined} */
  393. this._wasmRuntimeGroupsByKey = undefined;
  394. /** @type {Set<string> | false | undefined} */
  395. this._wasmFetchingGroupSet = undefined;
  396. /** @type {Map<string, boolean> | undefined} */
  397. this._wasmAnchorKnownByGroup = undefined;
  398. /** @type {Map<string, boolean> | undefined} */
  399. this._wasmGroupOnlyFetchesMap = undefined;
  400. }
  401. isIIFE() {
  402. return this.outputOptions.iife;
  403. }
  404. /**
  405. * Whether the global object expression reads the `this` binding, which only
  406. * refers to the global object outside of strict mode.
  407. * @returns {boolean} true, when it reads `this`
  408. */
  409. globalObjectUsesThis() {
  410. return THIS_REFERENCE_REGEXP.test(this.globalObject);
  411. }
  412. isModule() {
  413. return this.outputOptions.module;
  414. }
  415. isNeutralPlatform() {
  416. return (
  417. !this.compilation.compiler.platform.web &&
  418. !this.compilation.compiler.platform.node
  419. );
  420. }
  421. /**
  422. * Whether the bundle targets node and web at once (universal `["node", "web"]` + `output.module`), like `isUniversalTarget` in `WebpackOptionsApply`.
  423. * @returns {boolean} true for a universal target
  424. */
  425. isUniversalTarget() {
  426. const { platform } = this.compilation.compiler;
  427. return (
  428. Boolean(this.outputOptions.module) &&
  429. platform.node === null &&
  430. platform.web === null
  431. );
  432. }
  433. /**
  434. * Runtime expression that is truthy in browser-like environments (a DOM
  435. * `document` or a worker `self`) and falsy in Node.js. Single source of
  436. * truth for branching a universal ("node-or-web") target at runtime.
  437. * @returns {string} runtime condition expression
  438. */
  439. isWebLikePlatformExpression() {
  440. return "typeof document !== 'undefined' || typeof self !== 'undefined'";
  441. }
  442. /**
  443. * Expression for the global registry that collects CSS server-side when there
  444. * is no DOM (SSR). Read it with `__webpack_css_server_styles__`; it is keyed
  445. * by the style/chunk identifier and namespaced by `output.uniqueName`.
  446. * Targets without `globalThis` go through the `__webpack_require__.g`
  447. * polyfill, so consumers must also require `RuntimeGlobals.global`.
  448. * @returns {string} runtime expression evaluating to the registry object
  449. */
  450. cssServerStyleRegistry() {
  451. const name = this.outputOptions.uniqueName;
  452. const key = JSON.stringify(
  453. name ? `__webpack_css__${name}` : "__webpack_css__"
  454. );
  455. const global = this.outputOptions.environment.globalThis
  456. ? "globalThis"
  457. : RuntimeGlobals.global;
  458. return `(${this.assignOr(`${global}[${key}]`, "{}")})`;
  459. }
  460. supportsConst() {
  461. return this.outputOptions.environment.const;
  462. }
  463. supportsLet() {
  464. return this.outputOptions.environment.let;
  465. }
  466. supportsMethodShorthand() {
  467. return this.outputOptions.environment.methodShorthand;
  468. }
  469. supportsLogicalAssignment() {
  470. return this.outputOptions.environment.logicalAssignment;
  471. }
  472. supportsArrowFunction() {
  473. return this.outputOptions.environment.arrowFunction;
  474. }
  475. supportsAsyncFunction() {
  476. return this.outputOptions.environment.asyncFunction;
  477. }
  478. supportsGenerator() {
  479. return this.outputOptions.environment.generator;
  480. }
  481. supportsOptionalChaining() {
  482. return this.outputOptions.environment.optionalChaining;
  483. }
  484. supportsSpread() {
  485. return this.outputOptions.environment.spread;
  486. }
  487. supportsObjectHasOwn() {
  488. return this.outputOptions.environment.hasOwn;
  489. }
  490. supportsSymbol() {
  491. return this.outputOptions.environment.symbol;
  492. }
  493. supportsForOf() {
  494. return this.outputOptions.environment.forOf;
  495. }
  496. supportsDestructuring() {
  497. return this.outputOptions.environment.destructuring;
  498. }
  499. supportsBigIntLiteral() {
  500. return this.outputOptions.environment.bigIntLiteral;
  501. }
  502. supportsDynamicImport() {
  503. return this.outputOptions.environment.dynamicImport;
  504. }
  505. supportsEcmaScriptModuleSyntax() {
  506. return this.outputOptions.environment.module;
  507. }
  508. supportsDeferImport() {
  509. return this.outputOptions.environment.deferImport;
  510. }
  511. supportsSourceImport() {
  512. return this.outputOptions.environment.sourceImport;
  513. }
  514. supportsModulePreload() {
  515. return this.outputOptions.environment.modulePreload;
  516. }
  517. /**
  518. * Whether a reference a foreign bundler can follow without running webpack's runtime
  519. * may be emitted — the one question every caller asks, in the form it is asking for:
  520. *
  521. * - `"import"` — a literal `import("./chunk.js")` in place of `ensureChunk(id)`
  522. * - `"url"` — a literal `new URL(<file>, import.meta.url)`
  523. * - `"url-runtime"` — the same, written into a runtime module rather than a module
  524. * - `"url-inline"` — whether such a reference names the file at the call site
  525. * - `"wasm"` — the same, fully baked for a wasm binary the runtime would name
  526. * - `"wasm-relative"` — a wasm path built at runtime under an `import.meta.url` base
  527. *
  528. * `"url-inline"` differs from `"url"` only in taking the `.p + <file>` fallback as
  529. * an answer too — both name the file where it is used rather than through the
  530. * asset's javascript wrapper, which is what decides whether that wrapper is emitted.
  531. *
  532. * A name code generation cannot settle may still be baked, through a stand-in the
  533. * deferred pass fills in. Not covered here, because only the reference can tell: a
  534. * chunk with no id, and one this compilation emits no javascript for.
  535. * @param {AnalyzableForm} form which reference is being emitted
  536. * @param {ChunkGraph=} chunkGraph the chunk graph, to place `module` in its runtimes
  537. * @param {Module=} module the module the reference is emitted into
  538. * @param {RuntimeSpec=} runtime the runtime the reference is emitted for; the wasm forms answer for the loader it shares rather than for every loader in the compilation
  539. * @returns {boolean} true when the literal form may be emitted
  540. */
  541. supportsAnalyzable(form, chunkGraph, module, runtime) {
  542. // Analyzable output is ESM output — anything else is a different feature.
  543. if (!this.isModule()) return false;
  544. // Build-time execution keeps the runtime form — `import.meta` does not parse in its
  545. // vm wrapper. Unreported on purpose: its chunk graph shares the real module graph.
  546. if (chunkGraph && chunkGraph.buildTimeExecution) return false;
  547. const { outputOptions } = this;
  548. // One loader per runtime serves every wasm module in it, so the answer has to
  549. // hold compilation-wide — else a baked url reaches the id-and-hash signature.
  550. const scoped = form !== "wasm" && form !== "wasm-relative";
  551. // Resolved once: concatenation may have absorbed the module that wrote the
  552. // reference, and both the scope below and the worker loop ask about the same one.
  553. const placedModule =
  554. scoped && module !== undefined
  555. ? getConcatenatedModule().getChunkGraphModule(this.compilation, module)
  556. : undefined;
  557. // A reassigned `__webpack_public_path__` cannot reach a baked literal, and `.p`
  558. // belongs to a runtime, so only the runtimes it reaches keep the runtime form.
  559. // `url-inline` is unaffected: that form falls back to `.p + <file>`, which reads
  560. // the reassigned value at the call site rather than through the wrapper.
  561. if (
  562. form !== "url-inline" &&
  563. APIPlugin.runtimeUsesPublicPathOverride(
  564. this.compilation,
  565. scoped ? chunkGraph : undefined,
  566. placedModule
  567. )
  568. ) {
  569. this._analyzableBailout(
  570. module,
  571. "__webpack_public_path__ is reassigned in a runtime this module belongs to"
  572. );
  573. return false;
  574. }
  575. if (form === "import") {
  576. // Read through a native `import()`, or it is not this feature at all.
  577. if (outputOptions.chunkFormat !== "module") {
  578. this._analyzableBailout(
  579. module,
  580. `output.chunkFormat is ${JSON.stringify(outputOptions.chunkFormat)}, so chunks are not read through a native import()`
  581. );
  582. return false;
  583. }
  584. if (outputOptions.importFunctionName !== "import") {
  585. this._analyzableBailout(
  586. module,
  587. `output.importFunctionName is ${JSON.stringify(outputOptions.importFunctionName)}, so the call site is not a native import()`
  588. );
  589. return false;
  590. }
  591. // A worker loading its own chunks some other way keeps that runtime; one on
  592. // `import` uses the same ESM loader as the main graph, so it can be analyzable.
  593. for (const originChunk of /** @type {ChunkGraph} */ (
  594. chunkGraph
  595. ).getModuleChunksIterable(/** @type {Module} */ (placedModule))) {
  596. const entryOptions = originChunk.getEntryOptions();
  597. if (!entryOptions || !entryOptions.worker) continue;
  598. // `WorkerAndWorkletPlugin` always seeds this from `output.workerChunkLoading`.
  599. if (entryOptions.chunkLoading !== "import") {
  600. this._analyzableBailout(
  601. module,
  602. `this worker loads its chunks with ${JSON.stringify(entryOptions.chunkLoading)}, not "import"`
  603. );
  604. return false;
  605. }
  606. }
  607. return true;
  608. }
  609. // `url-inline` asks whether the file can be named at the call site at all, and
  610. // its `.p + <file>` fallback spells that without `import.meta` — so neither gate
  611. // below rules it out, and the asset's javascript wrapper stays dropped.
  612. if (form === "url-inline") return true;
  613. // `import.meta` is ESM syntax the target has to read. A chunk `import()` is
  614. // emitted by the module chunk loader either way, so only the url forms check.
  615. if (!this.supportsEcmaScriptModuleSyntax()) {
  616. this._analyzableBailout(
  617. module,
  618. "output.environment.module is false, so the target does not read the import.meta this form needs"
  619. );
  620. return false;
  621. }
  622. // `eval` devtool wraps each module in `eval(...)`, where `import.meta` is a
  623. // syntax error. Runtime modules are emitted beside them, never wrapped.
  624. const { devtool } = this.compilation.options;
  625. if (
  626. form !== "url-runtime" &&
  627. typeof devtool === "string" &&
  628. devtool.includes("eval")
  629. ) {
  630. this._analyzableBailout(
  631. module,
  632. `devtool ${JSON.stringify(devtool)} wraps the module in eval(), where import.meta does not parse`
  633. );
  634. return false;
  635. }
  636. if (form === "url" || form === "url-runtime") return true;
  637. // A bare relative URL is what `__webpack_require__.p + path` means only under an
  638. // `auto` public path; anything else has to be baked, which is the "wasm" form.
  639. if (form === "wasm-relative") {
  640. if (outputOptions.publicPath === "auto") return true;
  641. this._analyzableBailout(
  642. module,
  643. "output.publicPath is set, so a bare relative url no longer means what the public path would have resolved to"
  644. );
  645. return false;
  646. }
  647. // The rest is the `"wasm"` form: whether the whole binary url can be spelled
  648. // here, rather than built at runtime under an `import.meta.url` base.
  649. const { publicPath, webassemblyModuleFilename } = outputOptions;
  650. if (publicPath !== "auto") {
  651. // A public path that needs no base names the same place from the chunk as from
  652. // the document, so a literal spells what `fetch` would have reached.
  653. if (this._publicPathNeedsNoBase()) {
  654. // Settled no earlier than the hash it reads or is called with, so it is
  655. // baked only where the deferred pass may finish it.
  656. if (this._resolvePublicPathPrefix(publicPath, module) === null) {
  657. return false;
  658. }
  659. } else if (
  660. this._anyWasmChunkFetches(runtime) &&
  661. !this._wasmFetchAnchorIsKnown(runtime)
  662. ) {
  663. this._analyzableBailout(
  664. module,
  665. "output.publicPath needs a base, and no one path back to the document fits every chunk `fetch` reads it from"
  666. );
  667. return false;
  668. }
  669. }
  670. // The compilation hash is settled after code generation, so a name carrying one
  671. // is baked only where the deferred pass can fill it in. `[hash]` is the module's
  672. // own here, which code generation already knows.
  673. if (
  674. getTemplatedPathPlugin()
  675. .getPresentKinds(/** @type {string} */ (webassemblyModuleFilename))
  676. .has("fullhash") &&
  677. !this._canDeferOrBakeFullHash(true, undefined, module)
  678. ) {
  679. return false;
  680. }
  681. return true;
  682. }
  683. /**
  684. * Records why a reference kept the runtime form, on the module that wrote it —
  685. * the channel `ModuleConcatenationPlugin` already reports through, so it reaches
  686. * `stats.optimizationBailout`. Silent unless the build asked for ESM output, where
  687. * alone the answer is actionable; deduplicated because a module may write many.
  688. * @param {Module | undefined} module the module the reference is emitted into
  689. * @param {string} reason why no literal could be baked
  690. * @returns {void}
  691. */
  692. _analyzableBailout(module, reason) {
  693. if (module === undefined || !this.outputOptions.module) return;
  694. const text = `Analyzable ESM bailout: ${reason}`;
  695. const bailouts =
  696. this.compilation.moduleGraph.getOptimizationBailout(module);
  697. for (const existing of bailouts) {
  698. if (existing === text) return;
  699. }
  700. bailouts.push(text);
  701. }
  702. /**
  703. * Whether a name that code generation cannot settle may be reserved as a stand-in
  704. * and filled in once the hashes exist. Substituting rewrites a chunk after its own
  705. * content hash was taken, so either `RealContentHashPlugin` has to bring the two
  706. * back in line, or no emitted javascript may be named by its content in the first
  707. * place — with a name like `[name].js` there is nothing to go stale. Asked of the
  708. * names the chunks actually carry rather than of `output`, so a template nothing is
  709. * emitted under does not rule the rewrite out and a `chunk.filenameTemplate` does
  710. * not slip past it.
  711. * @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into; omit
  712. * where the answer has to hold for the whole compilation, as it does for a gate a
  713. * runtime module asks from the other end
  714. * @returns {boolean} true when deferring is safe
  715. */
  716. _canDeferAnalyzableName(chunks) {
  717. if (chunks === undefined) {
  718. // Memoized: the chunk graph is settled before any caller asks compilation-wide.
  719. if (this._javascriptNamedWithoutContent === undefined) {
  720. this._javascriptNamedWithoutContent = this._canDeferAnalyzableName(
  721. this.compilation.chunks
  722. );
  723. }
  724. return this._javascriptNamedWithoutContent;
  725. }
  726. let found = false;
  727. for (const chunk of chunks) {
  728. found = true;
  729. if (!this._chunkNameIndependentOfContent(chunk)) return false;
  730. }
  731. // None at all names nothing to reason about — the asset is unknown, not safe.
  732. return found;
  733. }
  734. /**
  735. * `_canDeferAnalyzableName`, recording why not when the answer is no — what every
  736. * caller with a module to report against does with it.
  737. * @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into
  738. * @param {Module=} module the module the reference is emitted into
  739. * @returns {boolean} true when deferring is safe
  740. */
  741. _canDeferOrBail(chunks, module) {
  742. if (this._canDeferAnalyzableName(chunks)) return true;
  743. this._analyzableBailout(module, DEFER_BAILOUT);
  744. return false;
  745. }
  746. /**
  747. * These parts as a quoted specifier: the text itself where they spell one already,
  748. * and a stand-in for the deferred pass where they do not.
  749. * @param {SpecifierPart[]} parts the whole specifier
  750. * @param {Iterable<Chunk>} chunks the chunks it is written into
  751. * @param {Module=} module the module the reference is emitted into
  752. * @returns {string | null} it already quoted, or `null` when no stand-in may be
  753. * reserved
  754. */
  755. _specifierOf(parts, chunks, module) {
  756. const text = literalText(parts);
  757. if (text !== null) return toJsStringLiteral(text);
  758. if (
  759. !this._canDeferOrBakeFullHash(
  760. this._partsBakeFullHash(parts),
  761. chunks,
  762. module
  763. )
  764. ) {
  765. return null;
  766. }
  767. return toJsStringLiteral(this._reserveAnalyzableSpecifier(parts));
  768. }
  769. /**
  770. * `_canDeferOrBail` for a name the fill builds out of the compilation hash. Such a
  771. * stand-in settles the name it lands in for us: `_markChunksBakingFullHash` reads it
  772. * back and moves that chunk into the round after that hash, which is the same place a
  773. * chunk reaching for `__webpack_require__.p` ends up without asking.
  774. * @param {boolean} carriesFullHash whether the fill builds this one out of that hash
  775. * @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into
  776. * @param {Module=} module the module the reference is emitted into
  777. * @returns {boolean} true when deferring is safe
  778. */
  779. _canDeferOrBakeFullHash(carriesFullHash, chunks, module) {
  780. return carriesFullHash || this._canDeferOrBail(chunks, module);
  781. }
  782. /**
  783. * Whether the fill will build these parts out of the compilation hash — the same
  784. * question `_markChunksBakingFullHash` asks of what was generated, so a stand-in this
  785. * says yes to is one that moves its chunk into the round after that hash.
  786. * @param {SpecifierPart[]} parts what the stand-in resolves to
  787. * @returns {boolean} true when that hash reaches the text
  788. */
  789. _partsBakeFullHash(parts) {
  790. for (const [kind, value] of parts) {
  791. if (kind === "publicPath" || kind === "template" || kind === "unserved") {
  792. return true;
  793. }
  794. if (kind === "literal" && this._hasReservedFullHash(String(value))) {
  795. return true;
  796. }
  797. }
  798. return false;
  799. }
  800. /**
  801. * Whether the name this chunk is emitted under is settled before its own content
  802. * is, which is what leaves it right after a later rewrite. A filename function is
  803. * asked rather than assumed to read a hash — the same two probes the chunk
  804. * specifier is resolved with. Memoized per chunk: answering calls that function
  805. * twice, and a reference asks once for every chunk it is written into.
  806. * @param {Chunk} chunk a chunk the stand-in is written into
  807. * @returns {boolean} true when the name does not move with the content
  808. */
  809. _chunkNameIndependentOfContent(chunk) {
  810. const cached = this._chunkNamedWithoutContent.get(chunk);
  811. if (cached !== undefined) return cached;
  812. const template = this._resolveChunkFilenameTemplate(
  813. JavascriptModulesPlugin.getChunkFilenameTemplate(
  814. chunk,
  815. this.outputOptions
  816. ),
  817. chunk,
  818. JAVASCRIPT_TYPE
  819. );
  820. let independent = false;
  821. if (typeof template === "string") {
  822. const kinds = getTemplatedPathPlugin().getPresentKinds(template);
  823. // `[chunkhash]` is taken from this chunk's own modules and nothing repairs it
  824. // afterwards, so such a name stays put while the reference it holds moves.
  825. independent =
  826. !kinds.has("chunkhash") &&
  827. (!kinds.has("contenthash") ||
  828. Boolean(this.compilation.options.optimization.realContentHash));
  829. }
  830. this._chunkNamedWithoutContent.set(chunk, independent);
  831. return independent;
  832. }
  833. /**
  834. * Builds the analyzable `new URL(specifier, import.meta.url)` expression the ESM
  835. * wasm/asset loader backends use to reference an emitted binary relative to the
  836. * current module (via `output.importMetaName`) instead of the runtime public-path
  837. * global — the form other bundlers and webpack itself can statically follow.
  838. * @param {string} specifier already-rendered URL argument (a literal or expression)
  839. * @returns {string} the `new URL(...)` expression
  840. */
  841. importMetaUrl(specifier) {
  842. return `new URL(${specifier}, ${this.outputOptions.importMetaName}.url)`;
  843. }
  844. /**
  845. * Whether a baked asset url resolves against the entry `baseUri` at all. A public
  846. * path that reaches the same place from any base never reads `.b` — and `auto`
  847. * resolves to an absolute url too — while output with no baked form has nothing to
  848. * resolve. Where this is false, what `baseUri` is set to cannot reach the generated
  849. * code, so it must not reach the module hash either: `URLDependency.updateHash`
  850. * asks this before contributing one.
  851. * @returns {boolean} true when the base can change what is generated
  852. */
  853. analyzableUrlReadsBaseUri() {
  854. if (!this.isModule()) return false;
  855. const { publicPath } = this.outputOptions;
  856. if (publicPath === "auto") return false;
  857. return !this._publicPathNeedsNoBase();
  858. }
  859. /**
  860. * Whether `output.publicPath` reaches the same place from any base, so a literal may
  861. * carry it without walking back to the output root first. One whose shape nothing
  862. * answers needs a base as far as anything here can tell. Never asked of `auto`,
  863. * which is no path of its own.
  864. * @returns {boolean} true when no base is needed
  865. */
  866. _publicPathNeedsNoBase() {
  867. const shape = this._publicPathShape();
  868. return shape !== undefined && isBaseIndependent(shape);
  869. }
  870. /**
  871. * Static literal specifier (already quoted) for the `new URL(<here>, import.meta.url)`
  872. * an asset reference bakes to, or `null` to keep the runtime form. Unlike a wasm
  873. * binary, the runtime resolves an asset url against `__webpack_require__.b` — the
  874. * output root, or an entry `baseUri` where one is set — so that base is settled here
  875. * before the rest of the name is.
  876. * @param {Module} module the module the reference is emitted into
  877. * @param {ChunkGraph} chunkGraph the chunk graph
  878. * @param {string} filename the asset's name, relative to the output root
  879. * @param {RuntimeSpec} runtime the runtime the code is generated for
  880. * @returns {string | null} a quoted literal, or `null` to fall back
  881. */
  882. getAnalyzableAssetUrl(module, chunkGraph, filename, runtime) {
  883. const { publicPath } = this.outputOptions;
  884. const base = this.analyzableUrlReadsBaseUri()
  885. ? this.entryBaseUri(runtime)
  886. : undefined;
  887. if (base !== undefined) {
  888. if (base === null) {
  889. this._analyzableBailout(
  890. module,
  891. "the entries this module is generated for set different baseUri values, so no one url resolves for all of them"
  892. );
  893. return null;
  894. }
  895. // A relative one is no base of its own: the runtime reads it against the
  896. // chunk, so the literal spells it there rather than resolving against it.
  897. if (isChunkRelativeBaseUri(base)) {
  898. return this._getAnalyzableFileSpecifier(
  899. module,
  900. chunkGraph,
  901. [["literal", filename]],
  902. true,
  903. base
  904. );
  905. }
  906. const chunks = this._moduleChunks(module, chunkGraph);
  907. // A protocol-relative base names a host but no scheme, and the runtime reads it
  908. // against the chunk's own url to get one — the very url this literal is
  909. // resolved against — so it may stay protocol-relative instead of being settled
  910. // here. Nothing walks back to the output root first: the base replaces it.
  911. if (base.startsWith("//")) {
  912. const relative = this._resolvePublicPathPrefix(
  913. publicPath,
  914. module,
  915. chunks
  916. );
  917. return relative === null
  918. ? null
  919. : this._specifierOf(
  920. [
  921. ["literal", base],
  922. ...rootedParts(relative),
  923. ["literal", filename]
  924. ],
  925. chunks,
  926. module
  927. );
  928. }
  929. if (!isAbsoluteBaseUri(base)) {
  930. this._analyzableBailout(
  931. module,
  932. `an entry sets a baseUri of ${JSON.stringify(base)}, whose scheme names no base anything can be resolved against`
  933. );
  934. return null;
  935. }
  936. const parts = this._resolvePublicPathPrefix(publicPath, module, chunks);
  937. if (parts === null) return null;
  938. // Resolved here rather than against the output root, and only an absolute base
  939. // settles it — a relative one has no base of its own to be read against.
  940. const spelled = literalText(parts);
  941. // A hash the deferred pass still has to fill in cannot be resolved against the
  942. // base here: the fill would land inside an already-resolved url, where a hash
  943. // opening with a letter reads as a scheme and drops the base entirely.
  944. const text =
  945. spelled !== null && !this._hasReservedFullHash(spelled)
  946. ? spelled
  947. : null;
  948. /** @type {URL} */
  949. let resolved;
  950. try {
  951. // Empty where only the deferred pass can spell the rest, which still settles
  952. // whether the base itself is one anything may be resolved against.
  953. resolved = new URL(text === null ? "" : text + filename, base);
  954. } catch (_error) {
  955. this._analyzableBailout(
  956. module,
  957. `an entry sets a baseUri of ${JSON.stringify(base)}, which is not absolute, so no url can be resolved against it here`
  958. );
  959. return null;
  960. }
  961. if (text !== null) return toJsStringLiteral(resolved.href);
  962. if (!this._canDeferOrBail(chunks, module)) return null;
  963. return toJsStringLiteral(
  964. this._reserveAnalyzableSpecifier([
  965. ["base", base],
  966. ...parts,
  967. ["literal", filename]
  968. ])
  969. );
  970. }
  971. return this._getAnalyzableFileSpecifier(
  972. module,
  973. chunkGraph,
  974. [["literal", filename]],
  975. true
  976. );
  977. }
  978. /**
  979. * The `baseUri` the entries this code runs under agree on, which replaces the output
  980. * root an asset url resolves against. Asked per runtime, because that is what the
  981. * module is generated for: two entries with different bases each get their own
  982. * source. `undefined` when none of them sets one, `null` when they disagree — an
  983. * entry that omits it disagrees with one that sets it.
  984. * @param {RuntimeSpec} runtime the runtime the code is generated for
  985. * @returns {string | null | undefined} the base those entries agree on
  986. */
  987. entryBaseUri(runtime) {
  988. const key = getRuntimeKey(runtime);
  989. if (this._entryBaseUriByRuntime.has(key)) {
  990. return this._entryBaseUriByRuntime.get(key);
  991. }
  992. /** @type {string | null | undefined} */
  993. let base;
  994. let found = false;
  995. for (const chunk of this.compilation.chunks) {
  996. // What a literal has to agree with is the one value `BaseUriRuntimeModule`
  997. // writes out, and it reads the entry options off the chunk it is emitted into
  998. // — so only a chunk carrying a runtime has a say. Entries sharing one runtime
  999. // chunk already share the base it sets, however their descriptors differ.
  1000. if (!chunk.hasRuntime()) continue;
  1001. const entryOptions = chunk.getEntryOptions();
  1002. // An entry this code cannot run under has no say in the base it resolves to.
  1003. if (
  1004. !entryOptions ||
  1005. intersectRuntime(chunk.runtime, runtime) === undefined
  1006. ) {
  1007. continue;
  1008. }
  1009. if (found && base !== entryOptions.baseUri) {
  1010. base = null;
  1011. break;
  1012. }
  1013. base = entryOptions.baseUri;
  1014. found = true;
  1015. }
  1016. this._entryBaseUriByRuntime.set(key, base);
  1017. return base;
  1018. }
  1019. /**
  1020. * `output.publicPath` as the constant it will be, for code that would otherwise read
  1021. * `__webpack_require__.p` for a value that never changes. `undefined` when only the
  1022. * hash could say, or when a runtime reassigns `__webpack_public_path__` — then the
  1023. * global is the only thing that knows.
  1024. * @returns {string | undefined} the settled public path
  1025. */
  1026. constantPublicPath() {
  1027. const { publicPath } = this.outputOptions;
  1028. if (
  1029. publicPath === "auto" ||
  1030. APIPlugin.usesRuntimePublicPathOverride(this.compilation)
  1031. ) {
  1032. return undefined;
  1033. }
  1034. if (typeof publicPath === "function") {
  1035. const resolved = this._resolveHashIndependent(
  1036. publicPath,
  1037. this._publicPathShape()
  1038. );
  1039. return resolved === null ? undefined : resolved;
  1040. }
  1041. return publicPath.includes("[") ? undefined : publicPath;
  1042. }
  1043. /**
  1044. * Whether a chunk loads WebAssembly through `fetch`, which is the only loader the
  1045. * public path reaches: `readFile` resolves the binary's name against the chunk it is
  1046. * read from, exactly as a baked literal does, so a public path is irrelevant to it.
  1047. * Answered per runtime rather than per chunk on purpose — a module's generated source
  1048. * and the runtime module of every chunk holding it have to agree on the shape, and
  1049. * they ask from opposite ends; one loader serves a whole runtime, so that is the
  1050. * finest scope on which they can. Without a runtime, or where the runtimes cannot be
  1051. * told apart, the answer covers the compilation.
  1052. * @param {RuntimeSpec=} runtime the runtime being asked about
  1053. * @returns {boolean} true when a chunk of that runtime fetches its binaries
  1054. */
  1055. _anyWasmChunkFetches(runtime) {
  1056. const fetching = this._wasmFetchingGroups();
  1057. if (fetching === undefined) return false;
  1058. // Without a runtime to place it in there is nothing to narrow by, so any chunk
  1059. // answers for all of them.
  1060. if (runtime === undefined) return true;
  1061. const groups = this._wasmRuntimeGroups();
  1062. if (typeof runtime === "string") {
  1063. return fetching.has(this._wasmGroupOf(groups, runtime));
  1064. }
  1065. for (const key of runtime) {
  1066. if (fetching.has(this._wasmGroupOf(groups, key))) return true;
  1067. }
  1068. return false;
  1069. }
  1070. /**
  1071. * Whether every entry of a wasm runtime group reads its binaries with `fetch`. Only
  1072. * an entry names a loader, so the scan is of entries, as `_wasmFetchingGroups` is.
  1073. * @returns {Map<string, boolean>} whether each group fetches and nothing else
  1074. */
  1075. _wasmGroupOnlyFetches() {
  1076. if (this._wasmGroupOnlyFetchesMap === undefined) {
  1077. const groups = this._wasmRuntimeGroups();
  1078. /** @type {Map<string, boolean>} */
  1079. const only = new Map();
  1080. for (const chunk of this.compilation.chunks) {
  1081. if (!chunk.getEntryOptions()) continue;
  1082. const fetches = this._chunkWasmLoading(chunk) === "fetch";
  1083. forEachRuntime(chunk.runtime, (key) => {
  1084. const group = this._wasmGroupOf(groups, /** @type {string} */ (key));
  1085. only.set(group, only.get(group) !== false && fetches);
  1086. });
  1087. }
  1088. this._wasmGroupOnlyFetchesMap = only;
  1089. }
  1090. return this._wasmGroupOnlyFetchesMap;
  1091. }
  1092. /**
  1093. * Whether a public path needing a base can be spelled from the chunk every binary of
  1094. * a runtime sits in — `fetch` reads it against the document, so a literal climbs back
  1095. * there first. Per group, as `_anyWasmChunkFetches` is, since the two ends must agree.
  1096. * @param {RuntimeSpec=} runtime the runtime being asked about
  1097. * @returns {boolean} true when every binary of that group can be spelled
  1098. */
  1099. _wasmFetchAnchorIsKnown(runtime) {
  1100. if (this._wasmAnchorKnownByGroup === undefined) {
  1101. const { chunkGraph, modules } = this.compilation;
  1102. const publicPath = /** @type {PublicPath} */ (
  1103. this.outputOptions.publicPath
  1104. );
  1105. const groups = this._wasmRuntimeGroups();
  1106. /** @type {Map<string, boolean>} */
  1107. const known = new Map();
  1108. for (const module of modules) {
  1109. if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
  1110. const spellable =
  1111. this._modulePlacement(module, chunkGraph).loaded !== null &&
  1112. this._resolvePublicPathPrefix(publicPath, module) !== null;
  1113. for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
  1114. forEachRuntime(moduleRuntime, (key) => {
  1115. const group = this._wasmGroupOf(
  1116. groups,
  1117. /** @type {string} */ (key)
  1118. );
  1119. known.set(group, known.get(group) !== false && spellable);
  1120. });
  1121. }
  1122. }
  1123. // A group one entry reads with `readFile` cannot take a prefix meant for the
  1124. // document, and only an entry names its loader.
  1125. for (const [group, only] of this._wasmGroupOnlyFetches()) {
  1126. if (!only) known.set(group, false);
  1127. }
  1128. this._wasmAnchorKnownByGroup = known;
  1129. }
  1130. const known = this._wasmAnchorKnownByGroup;
  1131. // No runtime to place it in leaves every group answering, so one that cannot be
  1132. // spelled speaks for all of them.
  1133. if (runtime === undefined) {
  1134. for (const value of known.values()) if (!value) return false;
  1135. return known.size > 0;
  1136. }
  1137. const groups = this._wasmRuntimeGroups();
  1138. if (typeof runtime === "string") {
  1139. return known.get(this._wasmGroupOf(groups, runtime)) === true;
  1140. }
  1141. for (const key of runtime) {
  1142. if (known.get(this._wasmGroupOf(groups, key)) !== true) return false;
  1143. }
  1144. return true;
  1145. }
  1146. /**
  1147. * The runtime groups an entry of which asked for the `fetch` loader, or `undefined`
  1148. * where none did — the cheap answer for a compilation with no fetching entry at all,
  1149. * which is every non-web target. Only an entry names a loader; every other chunk of
  1150. * the runtime is served by the one its entry asked for.
  1151. * @returns {Set<string> | undefined} the groups that fetch
  1152. */
  1153. _wasmFetchingGroups() {
  1154. if (this._wasmFetchingGroupSet === undefined) {
  1155. /** @type {Set<string>} */
  1156. const fetching = new Set();
  1157. /** @type {Map<string, string> | undefined} */
  1158. let groups;
  1159. for (const chunk of this.compilation.chunks) {
  1160. // Only an entry names a loader; every other chunk of the runtime is served
  1161. // by the one its entry asked for, so it says nothing on its own.
  1162. if (!chunk.getEntryOptions()) continue;
  1163. if (this._chunkWasmLoading(chunk) !== "fetch") continue;
  1164. // Built only once something fetches, so nothing pays for the grouping.
  1165. if (groups === undefined) groups = this._wasmRuntimeGroups();
  1166. const named = /** @type {Map<string, string>} */ (groups);
  1167. forEachRuntime(chunk.runtime, (key) => {
  1168. fetching.add(this._wasmGroupOf(named, /** @type {string} */ (key)));
  1169. });
  1170. }
  1171. this._wasmFetchingGroupSet = fetching.size === 0 ? false : fetching;
  1172. }
  1173. return this._wasmFetchingGroupSet === false
  1174. ? undefined
  1175. : this._wasmFetchingGroupSet;
  1176. }
  1177. /**
  1178. * Runtime keys mapped to the group they answer with, named by one key of it. Code
  1179. * generation runs once for runtimes a module hashes alike in, and nothing in a
  1180. * binary's hash knows which loader will read it — so a binary two runtimes reach
  1181. * carries one shape into both, and a third runtime sharing another binary with
  1182. * either is pulled in after them. A key in no group answers as itself. Asked of the
  1183. * same modules the loaders are created for, and only once per compilation.
  1184. * @returns {Map<string, string>} runtime key to the group it answers with
  1185. */
  1186. _wasmRuntimeGroups() {
  1187. if (this._wasmRuntimeGroupsByKey === undefined) {
  1188. const { chunkGraph } = this.compilation;
  1189. /** @type {Map<string, string>} */
  1190. const parent = new Map();
  1191. /**
  1192. * @param {string} key runtime key
  1193. * @returns {string} the key naming its group
  1194. */
  1195. const find = (key) => {
  1196. let root = key;
  1197. let seen = parent.get(root);
  1198. while (seen !== undefined && seen !== root) {
  1199. root = seen;
  1200. seen = parent.get(root);
  1201. }
  1202. // Path compression keeps a long share chain from costing more than once.
  1203. let walk = key;
  1204. let next = parent.get(walk);
  1205. while (next !== undefined && next !== root) {
  1206. parent.set(walk, root);
  1207. walk = next;
  1208. next = parent.get(walk);
  1209. }
  1210. return root;
  1211. };
  1212. /** @type {string[]} */
  1213. const keys = [];
  1214. /**
  1215. * @param {RuntimeSpec} runtime a runtime the module is generated for
  1216. * @returns {void}
  1217. */
  1218. const collectKeys = (runtime) => {
  1219. forEachRuntime(runtime, (key) => {
  1220. keys.push(/** @type {string} */ (key));
  1221. });
  1222. };
  1223. for (const module of this.compilation.modules) {
  1224. if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
  1225. keys.length = 0;
  1226. for (const runtime of chunkGraph.getModuleRuntimes(module)) {
  1227. collectKeys(runtime);
  1228. }
  1229. for (const key of keys) {
  1230. if (!parent.has(key)) parent.set(key, key);
  1231. }
  1232. // Every runtime this binary reaches answers with the first one.
  1233. for (let i = 1; i < keys.length; i++) {
  1234. parent.set(find(keys[i]), find(keys[0]));
  1235. }
  1236. }
  1237. // Flattened once, so a lookup is a single `get` rather than a chain walk.
  1238. for (const key of parent.keys()) parent.set(key, find(key));
  1239. this._wasmRuntimeGroupsByKey = parent;
  1240. }
  1241. return this._wasmRuntimeGroupsByKey;
  1242. }
  1243. /**
  1244. * @param {Map<string, string>} groups runtime key to the group it answers with
  1245. * @param {string} key a runtime key
  1246. * @returns {string} the group it answers with, or itself when it shares nothing
  1247. */
  1248. _wasmGroupOf(groups, key) {
  1249. const group = groups.get(key);
  1250. // An entry named "" makes "" a runtime key, so test absence, not a falsy value.
  1251. return group === undefined ? key : group;
  1252. }
  1253. supportTemplateLiteral() {
  1254. return this.outputOptions.environment.templateLiteral;
  1255. }
  1256. supportNodePrefixForCoreModules() {
  1257. return this.outputOptions.environment.nodePrefixForCoreModules;
  1258. }
  1259. /**
  1260. * Renders node prefix for core module.
  1261. * @param {string} mod a module
  1262. * @returns {string} a module with `node:` prefix when supported, otherwise an original name
  1263. */
  1264. renderNodePrefixForCoreModule(mod) {
  1265. return this.outputOptions.environment.nodePrefixForCoreModules
  1266. ? `"node:${mod}"`
  1267. : `"${mod}"`;
  1268. }
  1269. /**
  1270. * Renders return const when it is supported, otherwise let when supported, otherwise var.
  1271. * @returns {"const" | "let" | "var"} return `const` when it is supported, otherwise `let` when supported, otherwise `var`
  1272. */
  1273. renderConst() {
  1274. return this.supportsConst() ? "const" : this.supportsLet() ? "let" : "var";
  1275. }
  1276. /**
  1277. * Renders return let when it is supported, otherwise var.
  1278. * @returns {"let" | "var"} return `let` when it is supported, otherwise `var`
  1279. */
  1280. renderLet() {
  1281. return this.supportsLet() ? "let" : "var";
  1282. }
  1283. /**
  1284. * Returning function.
  1285. * @param {string} returnValue return value
  1286. * @param {string} args arguments
  1287. * @returns {string} returning function
  1288. */
  1289. returningFunction(returnValue, args = "") {
  1290. return this.supportsArrowFunction()
  1291. ? `(${args}) => (${returnValue})`
  1292. : `function(${args}) { return ${returnValue}; }`;
  1293. }
  1294. /**
  1295. * Returns basic function.
  1296. * @param {string} args arguments
  1297. * @param {string | string[]} body body
  1298. * @returns {string} basic function
  1299. */
  1300. basicFunction(args, body) {
  1301. return this.supportsArrowFunction()
  1302. ? `(${args}) => {\n${Template.indent(body)}\n}`
  1303. : `function(${args}) {\n${Template.indent(body)}\n}`;
  1304. }
  1305. /**
  1306. * Returns result expression.
  1307. * @param {(string | { expr: string })[]} args args
  1308. * @returns {string} result expression
  1309. */
  1310. concatenation(...args) {
  1311. const len = args.length;
  1312. if (len === 2) return this._es5Concatenation(args);
  1313. if (len === 0) return '""';
  1314. if (len === 1) {
  1315. return typeof args[0] === "string"
  1316. ? JSON.stringify(args[0])
  1317. : `"" + ${args[0].expr}`;
  1318. }
  1319. if (!this.supportTemplateLiteral()) return this._es5Concatenation(args);
  1320. // cost comparison between template literal and concatenation:
  1321. // both need equal surroundings: `xxx` vs "xxx"
  1322. // template literal has constant cost of 3 chars for each expression
  1323. // es5 concatenation has cost of 3 + n chars for n expressions in row
  1324. // when a es5 concatenation ends with an expression it reduces cost by 3
  1325. // when a es5 concatenation starts with an single expression it reduces cost by 3
  1326. // e. g. `${a}${b}${c}` (3*3 = 9) is longer than ""+a+b+c ((3+3)-3 = 3)
  1327. // e. g. `x${a}x${b}x${c}x` (3*3 = 9) is shorter than "x"+a+"x"+b+"x"+c+"x" (4+4+4 = 12)
  1328. let templateCost = 0;
  1329. let concatenationCost = 0;
  1330. let lastWasExpr = false;
  1331. for (const arg of args) {
  1332. const isExpr = typeof arg !== "string";
  1333. if (isExpr) {
  1334. templateCost += 3;
  1335. concatenationCost += lastWasExpr ? 1 : 4;
  1336. }
  1337. lastWasExpr = isExpr;
  1338. }
  1339. if (lastWasExpr) concatenationCost -= 3;
  1340. if (typeof args[0] !== "string" && typeof args[1] === "string") {
  1341. concatenationCost -= 3;
  1342. }
  1343. if (concatenationCost <= templateCost) return this._es5Concatenation(args);
  1344. return `\`${args
  1345. .map((arg) => (typeof arg === "string" ? arg : `\${${arg.expr}}`))
  1346. .join("")}\``;
  1347. }
  1348. /**
  1349. * Returns result expression.
  1350. * @param {(string | { expr: string })[]} args args (len >= 2)
  1351. * @returns {string} result expression
  1352. * @private
  1353. */
  1354. _es5Concatenation(args) {
  1355. const str = args
  1356. .map((arg) => (typeof arg === "string" ? JSON.stringify(arg) : arg.expr))
  1357. .join(" + ");
  1358. // when the first two args are expression, we need to prepend "" + to force string
  1359. // concatenation instead of number addition.
  1360. return typeof args[0] !== "string" && typeof args[1] !== "string"
  1361. ? `"" + ${str}`
  1362. : str;
  1363. }
  1364. /**
  1365. * Expression function.
  1366. * @param {string} expression expression
  1367. * @param {string} args arguments
  1368. * @returns {string} expression function code
  1369. */
  1370. expressionFunction(expression, args = "") {
  1371. return this.supportsArrowFunction()
  1372. ? `(${args}) => (${expression})`
  1373. : `function(${args}) { ${expression}; }`;
  1374. }
  1375. /**
  1376. * Returns empty function code.
  1377. * @returns {string} empty function code
  1378. */
  1379. emptyFunction() {
  1380. // `x => {}` over `() => {}`: a minifier keeps the parameter, so the named
  1381. // one is a byte shorter.
  1382. return this.supportsArrowFunction() ? "x => {}" : "function() {}";
  1383. }
  1384. /**
  1385. * Guards an access/call on `object` with optional chaining when supported,
  1386. * otherwise an equivalent `&&` short-circuit. `object` is evaluated twice in
  1387. * the fallback, so it must be side-effect free.
  1388. * @param {string} object base expression (side-effect free)
  1389. * @param {string} access continuation after the optional point, e.g. `()`, `prop`, `method(arg)` or `[key]`
  1390. * @returns {string} guarded access expression
  1391. */
  1392. optionalChaining(object, access) {
  1393. if (this.supportsOptionalChaining()) {
  1394. return `${object}?.${access}`;
  1395. }
  1396. const sep = access[0] === "(" || access[0] === "[" ? "" : ".";
  1397. return `${object} && ${object}${sep}${access}`;
  1398. }
  1399. /**
  1400. * Reads a node builtin via `process.getBuiltinModule()`, guarded to stay falsy off node so universal `["node", "web"]` bundles don't crash (also falsy on node <22.3).
  1401. * @param {string} request builtin module request as a JS string expression, e.g. from `renderNodePrefixForCoreModule`
  1402. * @param {string=} access member/call chain appended to the module, e.g. `.Worker` or `.createRequire(url)`
  1403. * @returns {string} guarded expression
  1404. */
  1405. getBuiltinModule(request, access = "") {
  1406. const getter = `process.getBuiltinModule(${request})${access}`;
  1407. if (this.outputOptions.environment.nodeBuiltinModuleGetter) {
  1408. return `typeof process !== "undefined" && ${getter}`;
  1409. }
  1410. return `typeof process !== "undefined" && typeof process.getBuiltinModule === "function" && ${getter}`;
  1411. }
  1412. /**
  1413. * Renders a `then` callback calling `fn` with `args`. An arrow keeps the `this`
  1414. * a method call gives; the bound form is shorter without arrows.
  1415. * @param {string} fn callee, a member of `__webpack_require__` or itself
  1416. * @param {string} args arguments
  1417. * @returns {string} callback expression
  1418. */
  1419. deferredCall(fn, args) {
  1420. return this.supportsArrowFunction()
  1421. ? this.returningFunction(`${fn}(${args})`)
  1422. : `${fn}.bind(${RuntimeGlobals.require}, ${args})`;
  1423. }
  1424. /**
  1425. * Renders an object-literal method, using method shorthand when supported
  1426. * and falling back to a `prop: function/arrow` property otherwise.
  1427. * @param {string} prop property name (or computed key like `[x]`)
  1428. * @param {string} args arguments
  1429. * @param {string | string[]} body body
  1430. * @returns {string} method code
  1431. */
  1432. method(prop, args, body) {
  1433. return this.supportsMethodShorthand()
  1434. ? `${prop}(${args}) {\n${Template.indent(body)}\n}`
  1435. : `${prop}: ${this.basicFunction(args, body)}`;
  1436. }
  1437. /**
  1438. * Returns an own-property check, using `Object.hasOwn` when supported and
  1439. * falling back to `Object.prototype.hasOwnProperty.call` otherwise.
  1440. * @param {string} object object expression
  1441. * @param {string} property property expression
  1442. * @returns {string} own-property check expression
  1443. */
  1444. objectHasOwn(object, property) {
  1445. return this.supportsObjectHasOwn()
  1446. ? `Object.hasOwn(${object}, ${property})`
  1447. : `Object.prototype.hasOwnProperty.call(${object}, ${property})`;
  1448. }
  1449. /**
  1450. * Returns a self-defaulting assignment, using the `||=` logical assignment
  1451. * operator when supported and falling back to `target = target || value`
  1452. * otherwise. `target` is evaluated twice in the fallback, so it must be
  1453. * side-effect free. The expression evaluates to the resulting value.
  1454. * Models `||` only, so `target` must never hold a legitimate falsy value
  1455. * (`0`, `""`, `false`) — it would be overwritten; use it for object/array defaults.
  1456. * @param {string} target assignment target (side-effect free)
  1457. * @param {string} value default value expression
  1458. * @returns {string} assignment expression
  1459. */
  1460. assignOr(target, value) {
  1461. return this.supportsLogicalAssignment()
  1462. ? `${target} ||= ${value}`
  1463. : `${target} = ${target} || ${value}`;
  1464. }
  1465. /**
  1466. * Returns destructure array code.
  1467. * @param {string[]} items items
  1468. * @param {string} value value
  1469. * @returns {string} destructure array code
  1470. */
  1471. destructureArray(items, value) {
  1472. const decl = this.renderLet();
  1473. return this.supportsDestructuring()
  1474. ? `${decl} [${items.join(", ")}] = ${value};`
  1475. : Template.asString(
  1476. items.map((item, i) => `${decl} ${item} = ${value}[${i}];`)
  1477. );
  1478. }
  1479. /**
  1480. * Destructure object.
  1481. * @param {string[]} items items
  1482. * @param {string} value value
  1483. * @returns {string} destructure object code
  1484. */
  1485. destructureObject(items, value) {
  1486. const decl = this.renderLet();
  1487. return this.supportsDestructuring()
  1488. ? `${decl} {${items.join(", ")}} = ${value};`
  1489. : Template.asString(
  1490. items.map(
  1491. (item) => `${decl} ${item} = ${value}${propertyAccess([item])};`
  1492. )
  1493. );
  1494. }
  1495. /**
  1496. * Returns iIFE code.
  1497. * @param {string} args arguments
  1498. * @param {string} body body
  1499. * @returns {string} IIFE code
  1500. */
  1501. iife(args, body) {
  1502. return `(${this.basicFunction(args, body)})()`;
  1503. }
  1504. /**
  1505. * Returns for each code.
  1506. * @param {string} variable variable
  1507. * @param {string} array array
  1508. * @param {string | string[]} body body
  1509. * @returns {string} for each code
  1510. */
  1511. forEach(variable, array, body) {
  1512. return this.supportsForOf()
  1513. ? `for(const ${variable} of ${array}) {\n${Template.indent(body)}\n}`
  1514. : `${array}.forEach(function(${variable}) {\n${Template.indent(
  1515. body
  1516. )}\n});`;
  1517. }
  1518. /**
  1519. * Returns comment.
  1520. * @param {object} options Information content of the comment
  1521. * @param {string=} options.request request string used originally
  1522. * @param {(string | null)=} options.chunkName name of the chunk referenced
  1523. * @param {string=} options.chunkReason reason information of the chunk
  1524. * @param {string=} options.message additional message
  1525. * @param {string=} options.exportName name of the export
  1526. * @returns {string} comment
  1527. */
  1528. comment({ request, chunkName, chunkReason, message, exportName }) {
  1529. /** @type {string} */
  1530. let content;
  1531. if (this.outputOptions.pathinfo) {
  1532. content = [message, request, chunkName, chunkReason]
  1533. .filter(Boolean)
  1534. .map((item) => this.requestShortener.shorten(item))
  1535. .join(" | ");
  1536. } else {
  1537. content = [message, chunkName, chunkReason]
  1538. .filter(Boolean)
  1539. .map((item) => this.requestShortener.shorten(item))
  1540. .join(" | ");
  1541. }
  1542. if (!content) return "";
  1543. if (this.outputOptions.pathinfo) {
  1544. return `${Template.toComment(content)} `;
  1545. }
  1546. return `${Template.toNormalComment(content)} `;
  1547. }
  1548. /**
  1549. * Throw missing module error block.
  1550. * @param {object} options generation options
  1551. * @param {string=} options.request request string used originally
  1552. * @returns {string} generated error block
  1553. */
  1554. throwMissingModuleErrorBlock({ request }) {
  1555. const err = `Cannot find module '${request}'`;
  1556. return `${this.renderConst()} e = new Error(${JSON.stringify(
  1557. err
  1558. )}); e.code = 'MODULE_NOT_FOUND'; throw e;`;
  1559. }
  1560. /**
  1561. * Throw missing module error function.
  1562. * @param {object} options generation options
  1563. * @param {string=} options.request request string used originally
  1564. * @returns {string} generated error function
  1565. */
  1566. throwMissingModuleErrorFunction({ request }) {
  1567. return `function webpackMissingModule() { ${this.throwMissingModuleErrorBlock(
  1568. { request }
  1569. )} }`;
  1570. }
  1571. /**
  1572. * Returns generated error IIFE.
  1573. * @param {object} options generation options
  1574. * @param {string=} options.request request string used originally
  1575. * @returns {string} generated error IIFE
  1576. */
  1577. missingModule({ request }) {
  1578. return `Object(${this.throwMissingModuleErrorFunction({ request })}())`;
  1579. }
  1580. /**
  1581. * Missing module statement.
  1582. * @param {object} options generation options
  1583. * @param {string=} options.request request string used originally
  1584. * @returns {string} generated error statement
  1585. */
  1586. missingModuleStatement({ request }) {
  1587. return `${this.missingModule({ request })};\n`;
  1588. }
  1589. /**
  1590. * Missing module promise.
  1591. * @param {object} options generation options
  1592. * @param {string=} options.request request string used originally
  1593. * @returns {string} generated error code
  1594. */
  1595. missingModulePromise({ request }) {
  1596. return `Promise.resolve().then(${this.throwMissingModuleErrorFunction({
  1597. request
  1598. })})`;
  1599. }
  1600. /**
  1601. * Returns the code.
  1602. * @param {object} options options object
  1603. * @param {ChunkGraph} options.chunkGraph the chunk graph
  1604. * @param {Module} options.module the module
  1605. * @param {string=} options.request the request that should be printed as comment
  1606. * @param {string=} options.idExpr expression to use as id expression
  1607. * @param {"expression" | "promise" | "statements"} options.type which kind of code should be returned
  1608. * @returns {string} the code
  1609. */
  1610. weakError({ module, chunkGraph, request, idExpr, type }) {
  1611. const moduleId = chunkGraph.getModuleId(module);
  1612. const errorMessage =
  1613. moduleId === null
  1614. ? JSON.stringify("Module is not available (weak dependency)")
  1615. : idExpr
  1616. ? `"Module '" + ${idExpr} + "' is not available (weak dependency)"`
  1617. : JSON.stringify(
  1618. `Module '${moduleId}' is not available (weak dependency)`
  1619. );
  1620. const comment = request ? `${Template.toNormalComment(request)} ` : "";
  1621. const errorStatements = `${this.renderConst()} e = new Error(${errorMessage}); ${comment}e.code = 'MODULE_NOT_FOUND'; throw e;`;
  1622. switch (type) {
  1623. case "statements":
  1624. return errorStatements;
  1625. case "promise":
  1626. return `Promise.resolve().then(${this.basicFunction(
  1627. "",
  1628. errorStatements
  1629. )})`;
  1630. case "expression":
  1631. return this.iife("", errorStatements);
  1632. }
  1633. }
  1634. /**
  1635. * Returns the expression.
  1636. * @param {object} options options object
  1637. * @param {Module} options.module the module
  1638. * @param {ChunkGraph} options.chunkGraph the chunk graph
  1639. * @param {string=} options.request the request that should be printed as comment
  1640. * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
  1641. * @returns {string} the expression
  1642. */
  1643. moduleId({ module, chunkGraph, request, weak }) {
  1644. if (!module) {
  1645. return this.missingModule({
  1646. request
  1647. });
  1648. }
  1649. const moduleId = chunkGraph.getModuleId(module);
  1650. if (moduleId === null) {
  1651. if (weak) {
  1652. return "null /* weak dependency, without id */";
  1653. }
  1654. throw new Error(
  1655. `RuntimeTemplate.moduleId(): ${noModuleIdErrorMessage(
  1656. module,
  1657. chunkGraph
  1658. )}`
  1659. );
  1660. }
  1661. return `${this.comment({ request })}${JSON.stringify(moduleId)}`;
  1662. }
  1663. /**
  1664. * Returns the expression.
  1665. * @param {object} options options object
  1666. * @param {Module | null} options.module the module
  1667. * @param {ChunkGraph} options.chunkGraph the chunk graph
  1668. * @param {string=} options.request the request that should be printed as comment
  1669. * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
  1670. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  1671. * @returns {string} the expression
  1672. */
  1673. moduleRaw({ module, chunkGraph, request, weak, runtimeRequirements }) {
  1674. if (!module) {
  1675. return this.missingModule({
  1676. request
  1677. });
  1678. }
  1679. const moduleId = chunkGraph.getModuleId(module);
  1680. if (moduleId === null) {
  1681. if (weak) {
  1682. // only weak referenced modules don't get an id
  1683. // we can always emit an error emitting code here
  1684. return this.weakError({
  1685. module,
  1686. chunkGraph,
  1687. request,
  1688. type: "expression"
  1689. });
  1690. }
  1691. throw new Error(
  1692. `RuntimeTemplate.moduleId(): ${noModuleIdErrorMessage(
  1693. module,
  1694. chunkGraph
  1695. )}`
  1696. );
  1697. }
  1698. runtimeRequirements.add(RuntimeGlobals.require);
  1699. return `${RuntimeGlobals.require}(${this.moduleId({
  1700. module,
  1701. chunkGraph,
  1702. request,
  1703. weak
  1704. })})`;
  1705. }
  1706. /**
  1707. * Returns the expression.
  1708. * @param {object} options options object
  1709. * @param {Module | null} options.module the module
  1710. * @param {ChunkGraph} options.chunkGraph the chunk graph
  1711. * @param {string} options.request the request that should be printed as comment
  1712. * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
  1713. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  1714. * @returns {string} the expression
  1715. */
  1716. moduleExports({ module, chunkGraph, request, weak, runtimeRequirements }) {
  1717. return this.moduleRaw({
  1718. module,
  1719. chunkGraph,
  1720. request,
  1721. weak,
  1722. runtimeRequirements
  1723. });
  1724. }
  1725. /**
  1726. * Returns the expression.
  1727. * @param {object} options options object
  1728. * @param {Module} options.module the module
  1729. * @param {ChunkGraph} options.chunkGraph the chunk graph
  1730. * @param {string} options.request the request that should be printed as comment
  1731. * @param {boolean=} options.strict if the current module is in strict esm mode
  1732. * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
  1733. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  1734. * @returns {string} the expression
  1735. */
  1736. moduleNamespace({
  1737. module,
  1738. chunkGraph,
  1739. request,
  1740. strict,
  1741. weak,
  1742. runtimeRequirements
  1743. }) {
  1744. if (!module) {
  1745. return this.missingModule({
  1746. request
  1747. });
  1748. }
  1749. if (chunkGraph.getModuleId(module) === null) {
  1750. if (weak) {
  1751. // only weak referenced modules don't get an id
  1752. // we can always emit an error emitting code here
  1753. return this.weakError({
  1754. module,
  1755. chunkGraph,
  1756. request,
  1757. type: "expression"
  1758. });
  1759. }
  1760. throw new Error(
  1761. `RuntimeTemplate.moduleNamespace(): ${noModuleIdErrorMessage(
  1762. module,
  1763. chunkGraph
  1764. )}`
  1765. );
  1766. }
  1767. const moduleId = this.moduleId({
  1768. module,
  1769. chunkGraph,
  1770. request,
  1771. weak
  1772. });
  1773. const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
  1774. switch (exportsType) {
  1775. case "namespace":
  1776. return this.moduleRaw({
  1777. module,
  1778. chunkGraph,
  1779. request,
  1780. weak,
  1781. runtimeRequirements
  1782. });
  1783. case "default-with-named":
  1784. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  1785. return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`;
  1786. case "default-only":
  1787. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  1788. return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 1)`;
  1789. case "dynamic":
  1790. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  1791. return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 7)`;
  1792. }
  1793. }
  1794. /**
  1795. * Module namespace promise.
  1796. * @param {object} options options object
  1797. * @param {ChunkGraph} options.chunkGraph the chunk graph
  1798. * @param {AsyncDependenciesBlock=} options.block the current dependencies block
  1799. * @param {Module} options.module the module
  1800. * @param {string} options.request the request that should be printed as comment
  1801. * @param {string} options.message a message for the comment
  1802. * @param {boolean=} options.strict if the current module is in strict esm mode
  1803. * @param {boolean=} options.weak if the dependency is weak (will create a nice error message)
  1804. * @param {Dependency} options.dependency dependency
  1805. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  1806. * @param {Module=} options.originModule the module the `import()` is emitted into
  1807. * @returns {string} the promise expression
  1808. */
  1809. moduleNamespacePromise({
  1810. chunkGraph,
  1811. block,
  1812. module,
  1813. request,
  1814. message,
  1815. strict,
  1816. weak,
  1817. dependency,
  1818. runtimeRequirements,
  1819. originModule
  1820. }) {
  1821. if (!module) {
  1822. return this.missingModulePromise({
  1823. request
  1824. });
  1825. }
  1826. const moduleId = chunkGraph.getModuleId(module);
  1827. if (moduleId === null) {
  1828. if (weak) {
  1829. // only weak referenced modules don't get an id
  1830. // we can always emit an error emitting code here
  1831. return this.weakError({
  1832. module,
  1833. chunkGraph,
  1834. request,
  1835. type: "promise"
  1836. });
  1837. }
  1838. throw new Error(
  1839. `RuntimeTemplate.moduleNamespacePromise(): ${noModuleIdErrorMessage(
  1840. module,
  1841. chunkGraph
  1842. )}`
  1843. );
  1844. }
  1845. const promise = this.blockPromise({
  1846. chunkGraph,
  1847. block,
  1848. message,
  1849. runtimeRequirements,
  1850. originModule
  1851. });
  1852. /** @type {string} */
  1853. let appending;
  1854. let idExpr = JSON.stringify(chunkGraph.getModuleId(module));
  1855. const comment = this.comment({
  1856. request
  1857. });
  1858. let header = "";
  1859. if (weak) {
  1860. if (idExpr.length > 8) {
  1861. // 'var x="nnnnnn";x,"+x+",x' vs '"nnnnnn",nnnnnn,"nnnnnn"'
  1862. header += `${this.renderConst()} id = ${idExpr}; `;
  1863. idExpr = "id";
  1864. }
  1865. runtimeRequirements.add(RuntimeGlobals.moduleFactories);
  1866. header += `if(!${
  1867. RuntimeGlobals.moduleFactories
  1868. }[${idExpr}]) { ${this.weakError({
  1869. module,
  1870. chunkGraph,
  1871. request,
  1872. idExpr,
  1873. type: "statements"
  1874. })} } `;
  1875. }
  1876. const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
  1877. const isModuleDeferred =
  1878. (dependency instanceof HarmonyImportDependency ||
  1879. dependency instanceof ImportDependency) &&
  1880. ImportPhaseUtils.isDefer(dependency.phase) &&
  1881. !(/** @type {BuildMeta} */ (module.buildMeta).async);
  1882. if (isModuleDeferred) {
  1883. runtimeRequirements.add(RuntimeGlobals.makeDeferredNamespaceObject);
  1884. let mode = getMakeDeferredNamespaceModeFromExportsType(exportsType);
  1885. if (mode) mode = `${mode} | 16`;
  1886. const asyncDeps = Array.from(
  1887. getOutgoingAsyncModules(chunkGraph.moduleGraph, module),
  1888. (m) => chunkGraph.getModuleId(m)
  1889. ).filter((id) => id !== null);
  1890. if (asyncDeps.length) {
  1891. if (header) {
  1892. appending = `.then(${this.basicFunction(
  1893. "",
  1894. `${header}return ${
  1895. RuntimeGlobals.deferredModuleAsyncTransitiveDependencies
  1896. }(${JSON.stringify(asyncDeps)});`
  1897. )})`;
  1898. } else {
  1899. runtimeRequirements.add(RuntimeGlobals.require);
  1900. appending = `.then(${this.returningFunction(
  1901. `${
  1902. RuntimeGlobals.deferredModuleAsyncTransitiveDependencies
  1903. }(${JSON.stringify(asyncDeps)})`
  1904. )})`;
  1905. }
  1906. appending += `.then(${this.deferredCall(
  1907. RuntimeGlobals.makeDeferredNamespaceObject,
  1908. `${comment}${idExpr}, ${mode}`
  1909. )})`;
  1910. } else if (header) {
  1911. appending = `.then(${this.basicFunction(
  1912. "",
  1913. `${header}return ${RuntimeGlobals.makeDeferredNamespaceObject}(${comment}${idExpr}, ${mode});`
  1914. )})`;
  1915. } else {
  1916. runtimeRequirements.add(RuntimeGlobals.require);
  1917. appending = `.then(${this.deferredCall(
  1918. RuntimeGlobals.makeDeferredNamespaceObject,
  1919. `${comment}${idExpr}, ${mode}`
  1920. )})`;
  1921. }
  1922. } else {
  1923. let fakeType = 16;
  1924. switch (exportsType) {
  1925. case "namespace":
  1926. if (header) {
  1927. const rawModule = this.moduleRaw({
  1928. module,
  1929. chunkGraph,
  1930. request,
  1931. weak,
  1932. runtimeRequirements
  1933. });
  1934. appending = `.then(${this.basicFunction(
  1935. "",
  1936. `${header}return ${rawModule};`
  1937. )})`;
  1938. } else {
  1939. runtimeRequirements.add(RuntimeGlobals.require);
  1940. appending = `.then(${this.deferredCall(
  1941. RuntimeGlobals.require,
  1942. `${comment}${idExpr}`
  1943. )})`;
  1944. }
  1945. break;
  1946. case "dynamic":
  1947. fakeType |= 4;
  1948. /* fall through */
  1949. case "default-with-named":
  1950. fakeType |= 2;
  1951. /* fall through */
  1952. case "default-only":
  1953. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  1954. if (chunkGraph.moduleGraph.isAsync(module)) {
  1955. if (header) {
  1956. const rawModule = this.moduleRaw({
  1957. module,
  1958. chunkGraph,
  1959. request,
  1960. weak,
  1961. runtimeRequirements
  1962. });
  1963. appending = `.then(${this.basicFunction(
  1964. "",
  1965. `${header}return ${rawModule};`
  1966. )})`;
  1967. } else {
  1968. runtimeRequirements.add(RuntimeGlobals.require);
  1969. appending = `.then(${this.deferredCall(
  1970. RuntimeGlobals.require,
  1971. `${comment}${idExpr}`
  1972. )})`;
  1973. }
  1974. appending += `.then(${this.returningFunction(
  1975. `${RuntimeGlobals.createFakeNamespaceObject}(m, ${fakeType})`,
  1976. "m"
  1977. )})`;
  1978. } else {
  1979. fakeType |= 1;
  1980. if (header) {
  1981. const moduleIdExpr = this.moduleId({
  1982. module,
  1983. chunkGraph,
  1984. request,
  1985. weak
  1986. });
  1987. const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, ${fakeType})`;
  1988. appending = `.then(${this.basicFunction(
  1989. "",
  1990. `${header}return ${returnExpression};`
  1991. )})`;
  1992. } else {
  1993. appending = `.then(${this.deferredCall(
  1994. RuntimeGlobals.createFakeNamespaceObject,
  1995. `${comment}${idExpr}, ${fakeType}`
  1996. )})`;
  1997. }
  1998. }
  1999. break;
  2000. }
  2001. }
  2002. return `${promise || "Promise.resolve()"}${appending}`;
  2003. }
  2004. /**
  2005. * Runtime condition expression.
  2006. * @param {object} options options object
  2007. * @param {ChunkGraph} options.chunkGraph the chunk graph
  2008. * @param {RuntimeSpec=} options.runtime runtime for which this code will be generated
  2009. * @param {RuntimeSpec | boolean=} options.runtimeCondition only execute the statement in some runtimes
  2010. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  2011. * @returns {string} expression
  2012. */
  2013. runtimeConditionExpression({
  2014. chunkGraph,
  2015. runtimeCondition,
  2016. runtime,
  2017. runtimeRequirements
  2018. }) {
  2019. if (runtimeCondition === undefined) return "true";
  2020. if (typeof runtimeCondition === "boolean") return `${runtimeCondition}`;
  2021. /** @type {Set<string>} */
  2022. const positiveRuntimeIds = new Set();
  2023. forEachRuntime(runtimeCondition, (runtime) =>
  2024. positiveRuntimeIds.add(
  2025. `${chunkGraph.getRuntimeId(/** @type {string} */ (runtime))}`
  2026. )
  2027. );
  2028. /** @type {Set<string>} */
  2029. const negativeRuntimeIds = new Set();
  2030. forEachRuntime(subtractRuntime(runtime, runtimeCondition), (runtime) =>
  2031. negativeRuntimeIds.add(
  2032. `${chunkGraph.getRuntimeId(/** @type {string} */ (runtime))}`
  2033. )
  2034. );
  2035. runtimeRequirements.add(RuntimeGlobals.runtimeId);
  2036. return compileBooleanMatcher.fromLists(
  2037. [...positiveRuntimeIds],
  2038. [...negativeRuntimeIds]
  2039. )(RuntimeGlobals.runtimeId);
  2040. }
  2041. /**
  2042. * Returns the import statement and the compat statement.
  2043. * @param {object} options options object
  2044. * @param {boolean=} options.update whether a new variable should be created or the existing one updated
  2045. * @param {Module} options.module the module
  2046. * @param {Module} options.originModule module in which the statement is emitted
  2047. * @param {ModuleGraph} options.moduleGraph the module graph
  2048. * @param {ChunkGraph} options.chunkGraph the chunk graph
  2049. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  2050. * @param {string} options.importVar name of the import variable
  2051. * @param {string=} options.request the request that should be printed as comment
  2052. * @param {boolean=} options.weak true, if this is a weak dependency
  2053. * @param {ModuleDependency=} options.dependency module dependency
  2054. * @returns {[string, string]} the import statement and the compat statement
  2055. */
  2056. importStatement({
  2057. update,
  2058. module,
  2059. moduleGraph,
  2060. chunkGraph,
  2061. request,
  2062. importVar,
  2063. originModule,
  2064. weak,
  2065. dependency,
  2066. runtimeRequirements
  2067. }) {
  2068. if (!module) {
  2069. return [
  2070. this.missingModuleStatement({
  2071. request
  2072. }),
  2073. ""
  2074. ];
  2075. }
  2076. if (chunkGraph.getModuleId(module) === null) {
  2077. if (weak) {
  2078. // only weak referenced modules don't get an id
  2079. // we can always emit an error emitting code here
  2080. return [
  2081. this.weakError({
  2082. module,
  2083. chunkGraph,
  2084. request,
  2085. type: "statements"
  2086. }),
  2087. ""
  2088. ];
  2089. }
  2090. throw new Error(
  2091. `RuntimeTemplate.importStatement(): ${noModuleIdErrorMessage(
  2092. module,
  2093. chunkGraph
  2094. )}`
  2095. );
  2096. }
  2097. const moduleId = this.moduleId({
  2098. module,
  2099. chunkGraph,
  2100. request,
  2101. weak
  2102. });
  2103. // Harmony imports may be wrapped in runtime-condition `if` blocks
  2104. // but referenced outside those blocks (e.g. by harmony reexport),
  2105. // so they must remain function-scoped (`var`) rather than
  2106. // block-scoped (`let`/`const`).
  2107. const optDeclaration = update ? "" : "var ";
  2108. const exportsType = module.getExportsType(
  2109. chunkGraph.moduleGraph,
  2110. /** @type {BuildMeta} */
  2111. (originModule.buildMeta).strictHarmonyModule
  2112. );
  2113. runtimeRequirements.add(RuntimeGlobals.require);
  2114. /** @type {string} */
  2115. let importContent;
  2116. const isModuleDeferred =
  2117. (dependency instanceof HarmonyImportDependency ||
  2118. dependency instanceof ImportDependency) &&
  2119. ImportPhaseUtils.isDefer(dependency.phase) &&
  2120. !(/** @type {BuildMeta} */ (module.buildMeta).async);
  2121. if (isModuleDeferred) {
  2122. /** @type {Set<Module>} */
  2123. const outgoingAsyncModules = getOutgoingAsyncModules(moduleGraph, module);
  2124. importContent = `/* deferred harmony import */ ${optDeclaration}${importVar} = ${getOptimizedDeferredModule(
  2125. moduleId,
  2126. exportsType,
  2127. Array.from(outgoingAsyncModules, (mod) => chunkGraph.getModuleId(mod)),
  2128. getDeferredCycleModuleIds(
  2129. getDeferredCycleModules(moduleGraph, module),
  2130. (mod) => chunkGraph.getModuleId(mod)
  2131. ),
  2132. runtimeRequirements
  2133. )};\n`;
  2134. return [importContent, ""];
  2135. }
  2136. importContent = `/* harmony import */ ${optDeclaration}${importVar} = ${RuntimeGlobals.require}(${moduleId});\n`;
  2137. if (exportsType === "dynamic") {
  2138. runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
  2139. return [
  2140. importContent,
  2141. `/* harmony import */ ${optDeclaration}${importVar}_default = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${importVar});\n`
  2142. ];
  2143. }
  2144. return [importContent, ""];
  2145. }
  2146. /**
  2147. * Export from import.
  2148. * @template GenerateContext
  2149. * @param {object} options options
  2150. * @param {ModuleGraph} options.moduleGraph the module graph
  2151. * @param {ChunkGraph} options.chunkGraph the chunk graph
  2152. * @param {Module} options.module the module
  2153. * @param {string} options.request the request
  2154. * @param {string | string[]} options.exportName the export name
  2155. * @param {Module} options.originModule the origin module
  2156. * @param {boolean | undefined} options.asiSafe true, if location is safe for ASI, a bracket can be emitted
  2157. * @param {boolean | undefined} options.isCall true, if expression will be called
  2158. * @param {boolean | null} options.callContext when false, call context will not be preserved
  2159. * @param {boolean} options.defaultInterop when true and accessing the default exports, interop code will be generated
  2160. * @param {string} options.importVar the identifier name of the import variable
  2161. * @param {InitFragment<GenerateContext>[]} options.initFragments init fragments will be added here
  2162. * @param {RuntimeSpec} options.runtime runtime for which this code will be generated
  2163. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  2164. * @param {ModuleDependency} options.dependency module dependency
  2165. * @param {boolean=} options.mangleableNamespace true, when a whole-namespace value may use a decoupled namespace object that keeps the original export names
  2166. * @returns {string} expression
  2167. */
  2168. exportFromImport({
  2169. moduleGraph,
  2170. chunkGraph,
  2171. module,
  2172. request,
  2173. exportName,
  2174. originModule,
  2175. asiSafe,
  2176. isCall,
  2177. callContext,
  2178. defaultInterop,
  2179. importVar,
  2180. initFragments,
  2181. runtime,
  2182. runtimeRequirements,
  2183. dependency,
  2184. mangleableNamespace = false
  2185. }) {
  2186. if (!module) {
  2187. return this.missingModule({
  2188. request
  2189. });
  2190. }
  2191. if (!Array.isArray(exportName)) {
  2192. exportName = exportName ? [exportName] : [];
  2193. }
  2194. const exportsType = module.getExportsType(
  2195. moduleGraph,
  2196. /** @type {BuildMeta} */
  2197. (originModule.buildMeta).strictHarmonyModule
  2198. );
  2199. const isModuleDeferred =
  2200. (dependency instanceof HarmonyImportDependency ||
  2201. dependency instanceof ImportDependency) &&
  2202. ImportPhaseUtils.isDefer(dependency.phase) &&
  2203. !(/** @type {BuildMeta} */ (module.buildMeta).async);
  2204. if (defaultInterop) {
  2205. // when the defaultInterop is used (when a ESM imports a CJS module),
  2206. if (exportName.length > 0 && exportName[0] === "default") {
  2207. if (isModuleDeferred && exportsType !== "namespace") {
  2208. const exportsInfo = moduleGraph.getExportsInfo(module);
  2209. const name = exportName.slice(1);
  2210. const used = exportsInfo.getUsedName(name, runtime);
  2211. if (!used) {
  2212. const comment = Template.toNormalComment(
  2213. `unused export ${propertyAccess(exportName)}`
  2214. );
  2215. return `${comment} undefined`;
  2216. }
  2217. if (used instanceof InlinedUsedName) {
  2218. throw new Error(
  2219. "Can't inline the exports of defer imported module"
  2220. );
  2221. }
  2222. const access = `${importVar}.a${propertyAccess(
  2223. Array.isArray(used) ? used : [used]
  2224. )}`;
  2225. if (isCall || asiSafe === undefined) {
  2226. return access;
  2227. }
  2228. return asiSafe ? `(${access})` : `;(${access})`;
  2229. }
  2230. // accessing the .default property is same thing as `require()` the module.
  2231. // For example:
  2232. // import mod from "cjs"; mod.default.x;
  2233. // is translated to
  2234. // var mod = require("cjs"); mod.x;
  2235. switch (exportsType) {
  2236. case "dynamic":
  2237. if (isCall) {
  2238. return `${importVar}_default()${propertyAccess(exportName, 1)}`;
  2239. }
  2240. return asiSafe
  2241. ? `(${importVar}_default()${propertyAccess(exportName, 1)})`
  2242. : asiSafe === false
  2243. ? `;(${importVar}_default()${propertyAccess(exportName, 1)})`
  2244. : `${importVar}_default.a${propertyAccess(exportName, 1)}`;
  2245. case "default-only":
  2246. case "default-with-named":
  2247. exportName = exportName.slice(1);
  2248. break;
  2249. }
  2250. } else if (exportName.length > 0) {
  2251. // the property used is not .default.
  2252. // For example:
  2253. // import * as ns from "cjs"; cjs.prop;
  2254. if (exportsType === "default-only") {
  2255. // in the strictest case, it is a runtime error (e.g. NodeJS behavior of CJS-ESM interop).
  2256. return `/* non-default import from non-esm module */undefined${propertyAccess(
  2257. exportName,
  2258. 1
  2259. )}`;
  2260. } else if (
  2261. exportsType !== "namespace" &&
  2262. exportName[0] === "__esModule"
  2263. ) {
  2264. return "/* __esModule */true";
  2265. }
  2266. } else if (isModuleDeferred) {
  2267. // now exportName.length is 0
  2268. // fall through to the end of this function, create the namespace there.
  2269. } else if (
  2270. exportsType === "default-only" ||
  2271. exportsType === "default-with-named"
  2272. ) {
  2273. // now exportName.length is 0, which means the namespace object is used in an unknown way
  2274. // for example:
  2275. // import * as ns from "cjs"; console.log(ns);
  2276. // we will need to createFakeNamespaceObject that simulates ES Module namespace object
  2277. runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
  2278. initFragments.push(
  2279. new InitFragment(
  2280. `${this.renderLet()} ${importVar}_namespace_cache;\n`,
  2281. InitFragment.STAGE_CONSTANTS,
  2282. -1,
  2283. `${importVar}_namespace_cache`
  2284. )
  2285. );
  2286. return `/*#__PURE__*/ ${
  2287. asiSafe ? "" : asiSafe === false ? ";" : "Object"
  2288. }(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${
  2289. RuntimeGlobals.createFakeNamespaceObject
  2290. }(${importVar}${exportsType === "default-only" ? "" : ", 2"})))`;
  2291. }
  2292. }
  2293. if (exportName.length > 0) {
  2294. const exportsInfo = moduleGraph.getExportsInfo(module);
  2295. // in some case the exported item is renamed (get this by getUsedName). for example,
  2296. // x.default might be emitted as x.Z (default is renamed to Z)
  2297. const used = exportsInfo.getUsedName(exportName, runtime);
  2298. if (!used) {
  2299. const comment = Template.toNormalComment(
  2300. `unused export ${propertyAccess(exportName)}`
  2301. );
  2302. return `${comment} undefined`;
  2303. }
  2304. if (used instanceof InlinedUsedName) {
  2305. return used.render(
  2306. Template.toNormalComment(
  2307. `inlined export ${propertyAccess(exportName)}`
  2308. )
  2309. );
  2310. }
  2311. const comment = equals(used, exportName)
  2312. ? ""
  2313. : `${Template.toNormalComment(propertyAccess(exportName))} `;
  2314. const access = `${importVar}${
  2315. isModuleDeferred ? ".a" : ""
  2316. }${comment}${propertyAccess(Array.isArray(used) ? used : [used])}`;
  2317. if (isCall && callContext === false) {
  2318. return asiSafe
  2319. ? `(0,${access})`
  2320. : asiSafe === false
  2321. ? `;(0,${access})`
  2322. : `/*#__PURE__*/Object(${access})`;
  2323. }
  2324. return access;
  2325. }
  2326. if (isModuleDeferred) {
  2327. initFragments.push(
  2328. new InitFragment(
  2329. `${this.renderLet()} ${importVar}_deferred_namespace_cache;\n`,
  2330. InitFragment.STAGE_CONSTANTS,
  2331. -1,
  2332. `${importVar}_deferred_namespace_cache`
  2333. )
  2334. );
  2335. runtimeRequirements.add(RuntimeGlobals.makeDeferredNamespaceObject);
  2336. const id = chunkGraph.getModuleId(module);
  2337. const type = getMakeDeferredNamespaceModeFromExportsType(exportsType);
  2338. const init = `${
  2339. RuntimeGlobals.makeDeferredNamespaceObject
  2340. }(${JSON.stringify(id)}, ${type})`;
  2341. return `/*#__PURE__*/ ${
  2342. asiSafe ? "" : asiSafe === false ? ";" : "Object"
  2343. }(${importVar}_deferred_namespace_cache || (${importVar}_deferred_namespace_cache = ${init}))`;
  2344. }
  2345. // The whole namespace object is used as a value. If the module's exports
  2346. // were mangled, importVar's keys are the mangled names, so we materialize
  2347. // a decoupled namespace object that exposes the original names.
  2348. if (
  2349. exportsType === "namespace" &&
  2350. mangleableNamespace &&
  2351. this.compilation.options.optimization.mangleExports
  2352. ) {
  2353. const materialized = this._materializedNamespaceObject({
  2354. moduleGraph,
  2355. module,
  2356. importVar,
  2357. initFragments,
  2358. runtime,
  2359. runtimeRequirements
  2360. });
  2361. if (materialized !== undefined) return materialized;
  2362. }
  2363. // if we hit here, the importVar is either
  2364. // - already a ES module namespace object
  2365. // - or imported by a way that does not need interop.
  2366. return importVar;
  2367. }
  2368. /**
  2369. * Materializes a namespace object that keeps the original export names while
  2370. * the module's own exports are mangled. Returns undefined when no export was
  2371. * mangled (then the raw namespace object can be used as-is).
  2372. * @template GenerateContext
  2373. * @param {object} options options
  2374. * @param {ModuleGraph} options.moduleGraph the module graph
  2375. * @param {Module} options.module the imported module
  2376. * @param {string} options.importVar the import variable referencing the module
  2377. * @param {InitFragment<GenerateContext>[]} options.initFragments target array for init fragments
  2378. * @param {RuntimeSpec} options.runtime the runtime
  2379. * @param {RuntimeRequirements} options.runtimeRequirements runtime requirements
  2380. * @returns {string | undefined} expression of the materialized namespace object, or undefined
  2381. */
  2382. _materializedNamespaceObject({
  2383. moduleGraph,
  2384. module,
  2385. importVar,
  2386. initFragments,
  2387. runtime,
  2388. runtimeRequirements
  2389. }) {
  2390. const exportsInfo = moduleGraph.getExportsInfo(module);
  2391. /** @type {string[]} */
  2392. const definitions = [];
  2393. let mangled = false;
  2394. for (const exportInfo of exportsInfo.orderedExports) {
  2395. if (exportInfo.provided === false) continue;
  2396. const used = exportsInfo.getUsedName([exportInfo.name], runtime);
  2397. if (!used) continue;
  2398. if (used instanceof InlinedUsedName) {
  2399. // An inlined export isn't reachable by name on the raw exports object,
  2400. // so the decoupled object must expose the inlined value directly.
  2401. mangled = true;
  2402. definitions.push(
  2403. `${propertyName(exportInfo.name)}: ${this.returningFunction(
  2404. used.render(
  2405. Template.toNormalComment(
  2406. `inlined export ${propertyAccess([exportInfo.name])}`
  2407. )
  2408. )
  2409. )}`
  2410. );
  2411. continue;
  2412. }
  2413. if (used[used.length - 1] !== exportInfo.name) mangled = true;
  2414. definitions.push(
  2415. `${propertyName(exportInfo.name)}: ${this.returningFunction(
  2416. `${importVar}${propertyAccess(/** @type {string[]} */ (used))}`
  2417. )}`
  2418. );
  2419. }
  2420. if (!mangled) return;
  2421. const name = `${importVar}_namespace_object`;
  2422. runtimeRequirements.add(RuntimeGlobals.exports);
  2423. runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
  2424. runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
  2425. initFragments.push(
  2426. new InitFragment(
  2427. `var ${name} = {};\n${RuntimeGlobals.makeNamespaceObject}(${name});\n${
  2428. RuntimeGlobals.definePropertyGetters
  2429. }(${name}, {\n\t${definitions.join(",\n\t")}\n});\n`,
  2430. InitFragment.STAGE_PROVIDES,
  2431. 0,
  2432. name
  2433. )
  2434. );
  2435. return name;
  2436. }
  2437. /**
  2438. * Returns expression.
  2439. * @param {object} options options
  2440. * @param {AsyncDependenciesBlock | undefined} options.block the async block
  2441. * @param {string} options.message the message
  2442. * @param {ChunkGraph} options.chunkGraph the chunk graph
  2443. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  2444. * @param {Module=} options.originModule the module the `import()` is emitted into
  2445. * @returns {string} expression
  2446. */
  2447. blockPromise({
  2448. block,
  2449. message,
  2450. chunkGraph,
  2451. runtimeRequirements,
  2452. originModule
  2453. }) {
  2454. if (!block) {
  2455. const comment = this.comment({
  2456. message
  2457. });
  2458. return `Promise.resolve(${comment.trim()})`;
  2459. }
  2460. const chunkGroup = chunkGraph.getBlockChunkGroup(block);
  2461. if (!chunkGroup || chunkGroup.chunks.length === 0) {
  2462. const comment = this.comment({
  2463. message
  2464. });
  2465. return `Promise.resolve(${comment.trim()})`;
  2466. }
  2467. const chunks = chunkGroup.chunks.filter(
  2468. (chunk) => !chunk.hasRuntime() && chunk.id !== null
  2469. );
  2470. const comment = this.comment({
  2471. message,
  2472. chunkName: block.chunkName
  2473. });
  2474. // `fetchPriority` is unsupported for ESM output (a native `import()` can't carry it,
  2475. // and the ESM chunk loader ignores the argument), so it never blocks the analyzable form.
  2476. // TODO recheck: browsers honor `fetchpriority` on `modulepreload` only when the
  2477. // preload scanner sees it, so a runtime-injected hint is inert; support it here if
  2478. // that changes.
  2479. const fetchPriority = chunkGroup.options.fetchPriority;
  2480. if (chunks.length === 1) {
  2481. const analyzable = this.analyzableChunkImport(
  2482. chunks[0],
  2483. comment,
  2484. runtimeRequirements,
  2485. originModule,
  2486. chunkGraph
  2487. );
  2488. if (analyzable !== null) {
  2489. return analyzable;
  2490. }
  2491. const chunkId = JSON.stringify(chunks[0].id);
  2492. runtimeRequirements.add(RuntimeGlobals.ensureChunk);
  2493. if (fetchPriority) {
  2494. runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
  2495. }
  2496. return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${
  2497. fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
  2498. })`;
  2499. } else if (chunks.length > 0) {
  2500. let needEnsureChunk = false;
  2501. /**
  2502. * Analyzable `import()` for a solely-owned JS chunk, else runtime ensureChunk.
  2503. * @param {Chunk} chunk chunk
  2504. * @returns {string} require chunk id code
  2505. */
  2506. const requireChunkId = (chunk) => {
  2507. const analyzable = this.analyzableChunkImport(
  2508. chunk,
  2509. "",
  2510. runtimeRequirements,
  2511. originModule,
  2512. chunkGraph
  2513. );
  2514. if (analyzable !== null) return analyzable;
  2515. needEnsureChunk = true;
  2516. return `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${
  2517. fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
  2518. })`;
  2519. };
  2520. const items = chunks.map(requireChunkId);
  2521. if (needEnsureChunk) {
  2522. runtimeRequirements.add(RuntimeGlobals.ensureChunk);
  2523. // Only needed when an `ensureChunk(id, priority)` call is actually emitted.
  2524. if (fetchPriority) {
  2525. runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
  2526. }
  2527. }
  2528. return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
  2529. }
  2530. return `Promise.resolve(${comment.trim()})`;
  2531. }
  2532. /**
  2533. * For ESM module output, load a single statically-named chunk through the
  2534. * `analyzableChunkImport` helper — a literal `import("./chunk.js")` other bundlers
  2535. * and webpack itself can follow, wrapped to keep `ensureChunk` timing and deduplication.
  2536. * Returns `null` to fall back to the runtime `ensureChunk` form.
  2537. * @param {Chunk} chunk the chunk to load
  2538. * @param {string} comment leading comment (chunk name / message)
  2539. * @param {RuntimeRequirements} runtimeRequirements runtime requirements
  2540. * @param {Module | undefined} originModule the module the `import()` is emitted into
  2541. * @param {ChunkGraph} chunkGraph the chunk graph
  2542. * @returns {string | null} the import expression, or `null`
  2543. */
  2544. analyzableChunkImport(
  2545. chunk,
  2546. comment,
  2547. runtimeRequirements,
  2548. originModule,
  2549. chunkGraph
  2550. ) {
  2551. // `blockPromise` has already dropped any chunk without an id. Without an origin
  2552. // there is nothing the specifier could be relative to.
  2553. if (
  2554. !originModule ||
  2555. !this.supportsAnalyzable("import", chunkGraph, originModule)
  2556. ) {
  2557. return null;
  2558. }
  2559. // Prefetch/preload children are injected by the runtime `.f` handlers, which `.ei`
  2560. // runs too — but they attach to `.f`, so it has to exist.
  2561. const needsHintHandlers =
  2562. chunk.hasChildByOrder(chunkGraph, "prefetch", true) ||
  2563. chunk.hasChildByOrder(chunkGraph, "preload", true) ||
  2564. chunk.hasChildByOrder(chunkGraph, "cssPreload", true);
  2565. // `.ei` always performs the import, where `.e` only reaches the javascript
  2566. // loader when there is javascript to load. A module federation remote is the
  2567. // case that matters: its chunk is emitted by the container's build, not this one.
  2568. if (!JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) {
  2569. this._analyzableBailout(
  2570. originModule,
  2571. "this compilation emits no javascript for the chunk, so there is nothing to import"
  2572. );
  2573. return null;
  2574. }
  2575. let hasNonJsTypes = false;
  2576. for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
  2577. for (const type of chunkGraph.getModuleSourceTypes(module)) {
  2578. if (!TYPES_WITHOUT_CHUNK_HANDLER.has(type)) {
  2579. // Loaded by that type's own `.f` handler, which `.ei` still dispatches.
  2580. hasNonJsTypes = true;
  2581. }
  2582. }
  2583. }
  2584. // Relative to the consuming chunk (`import.meta.url`) for `auto`, else an
  2585. // absolute publicPath prefix.
  2586. const specifier = this._getAnalyzableChunkSpecifier(
  2587. undefined,
  2588. chunk,
  2589. originModule,
  2590. chunkGraph
  2591. );
  2592. if (specifier === null) {
  2593. return null;
  2594. }
  2595. // `import()` needs a resolvable specifier — relative (`./`, `../`), absolute (`/`)
  2596. // or a URL scheme. A bare one is a package name, so make it explicitly relative
  2597. // the way the chunk loader does. (`new URL(...)` callers accept bare vs their base.)
  2598. const resolvableSpecifier = /^"(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(
  2599. specifier
  2600. )
  2601. ? specifier
  2602. : `"./${specifier.slice(1)}`;
  2603. runtimeRequirements.add(RuntimeGlobals.analyzableChunkImport);
  2604. if (needsHintHandlers || hasNonJsTypes) {
  2605. // Those handlers attach to the `.f` map, which has to exist — but the runtime
  2606. // `ensureChunk` around it does not, since `.ei` dispatches them itself.
  2607. runtimeRequirements.add(RuntimeGlobals.ensureChunkHandlers);
  2608. }
  2609. // Drop-in for `ensureChunk(id)`: the literal `import()` can be statically
  2610. // followed, the helper keeps webpack's install timing and deduplication.
  2611. return `${RuntimeGlobals.analyzableChunkImport}(${JSON.stringify(
  2612. chunk.id
  2613. )}, ${this.returningFunction(`import(${comment}${resolvableSpecifier})`)})`;
  2614. }
  2615. /**
  2616. * Whether this chunk's hash settles before every chunk a stand-in would land in.
  2617. * That is what makes a baked name readable from the consuming chunk's own hash, and
  2618. * it is the tie-break that lets one direction of a cycle bake — `createHash` fixes a
  2619. * total order, so the answer is the same in every build.
  2620. * @param {Chunk} chunk the referenced chunk
  2621. * @param {Iterable<Chunk>} targets the chunks the stand-in is written into
  2622. * @returns {boolean} true when this one may bake and the others may not
  2623. */
  2624. _namesBeforeAll(chunk, targets) {
  2625. if (chunk.id === null) return false;
  2626. for (const target of targets) {
  2627. if (!this._hashesBefore(chunk, target)) return false;
  2628. }
  2629. return true;
  2630. }
  2631. /**
  2632. * Whether `createHash` settles `chunk`'s hash before `target`'s: rounds first, then
  2633. * id inside a round. The runtime round is ordered by references between its chunks
  2634. * rather than by id, which the guard below sidesteps by reading no hash from one.
  2635. * @param {Chunk} chunk the chunk whose hash would be read
  2636. * @param {Chunk} target the chunk reading it
  2637. * @returns {boolean} true when the hash exists by the time the target is hashed
  2638. */
  2639. _hashesBefore(chunk, target) {
  2640. if (chunk === target || target.id === null) return false;
  2641. // One settling after the compilation hash is read only by one settling later.
  2642. // Before the marks exist, the answer is the one the marking will bring about.
  2643. if (this._chunksBakingFullHash !== undefined) {
  2644. const late = this._settlesLate(chunk);
  2645. if (late !== this._settlesLate(target)) return !late;
  2646. }
  2647. const chunkGraph = /** @type {ChunkGraph} */ (this.compilation.chunkGraph);
  2648. const round = hashRound(chunk, chunkGraph);
  2649. const targetRound = hashRound(target, chunkGraph);
  2650. if (round !== targetRound) return round < targetRound;
  2651. // The runtime round is ordered by references between its chunks rather than by
  2652. // id: an async entrypoint the target reaches is settled before it, which is the
  2653. // only order that round fixes — a worker's chunk against the one spawning it.
  2654. if (round === RUNTIME_HASH_ROUND) {
  2655. for (const entrypoint of target.getAllReferencedAsyncEntrypoints()) {
  2656. const { chunks } = entrypoint;
  2657. if (chunks[chunks.length - 1] === chunk) return true;
  2658. }
  2659. return false;
  2660. }
  2661. return (
  2662. compareIds(
  2663. /** @type {ChunkId} */ (chunk.id),
  2664. /** @type {ChunkId} */ (target.id)
  2665. ) < 0
  2666. );
  2667. }
  2668. /**
  2669. * Whether `createHash` settles this chunk's hash in the round that runs after the
  2670. * compilation hash rather than in one of the four before it. Asked of the chunk
  2671. * graph, which by then says so exactly: a chunk reaches that round by carrying a
  2672. * full-hash runtime module, or by being put there by `_markChunksSettlingLate`.
  2673. * @param {Chunk} chunk the chunk
  2674. * @returns {boolean} true when its hash is taken last
  2675. */
  2676. _settlesLate(chunk) {
  2677. return (
  2678. /** @type {ChunkGraph} */
  2679. (this.compilation.chunkGraph).getChunkFullHashModulesIterable(chunk) !==
  2680. undefined
  2681. );
  2682. }
  2683. /**
  2684. * Whether this chunk's name is settled only once the compilation hash exists, because
  2685. * the deferred pass writes that hash into its bytes. Marking it puts it in
  2686. * `createHash`'s full-hash round, where the name is taken again afterwards — which is
  2687. * what a chunk needing `__webpack_require__.p` gets for free, and what one that bakes
  2688. * the same text instead has to be given.
  2689. * @param {Chunk} chunk the chunk
  2690. * @returns {boolean} true when it was marked
  2691. */
  2692. _bakesFullHash(chunk) {
  2693. return (
  2694. this._chunksBakingFullHash !== undefined &&
  2695. this._chunksBakingFullHash.has(chunk)
  2696. );
  2697. }
  2698. /**
  2699. * Finds the chunks whose bytes will carry the compilation hash and puts each in
  2700. * `createHash`'s full-hash round, so its name is taken after that hash exists rather
  2701. * than before. Read off what was generated rather than off what asked for it: a
  2702. * module restored from the persistent cache carries a stand-in without being
  2703. * generated again, and the token it carries is the whole question.
  2704. * @returns {void}
  2705. */
  2706. _markChunksSettlingLate() {
  2707. this._chunksBakingFullHash = new Set();
  2708. const { compilation } = this;
  2709. const chunkGraph = /** @type {ChunkGraph} */ (compilation.chunkGraph);
  2710. const results = compilation.codeGenerationResults;
  2711. if (results === undefined) return;
  2712. /** @type {Map<Chunk, Set<string>>} */
  2713. const namesBaked = new Map();
  2714. this._namesBakedInto = namesBaked;
  2715. /** @type {Map<string, Chunk>} */
  2716. const chunksById = new Map();
  2717. this._chunksByIdForFold = chunksById;
  2718. for (const chunk of compilation.chunks) {
  2719. if (chunk.id !== null) chunksById.set(String(chunk.id), chunk);
  2720. }
  2721. for (const chunk of compilation.chunks) {
  2722. // One whose name does not move with its content has nothing to settle late.
  2723. if (this._chunkNameIndependentOfContent(chunk)) continue;
  2724. const demand = this._analyzableDemandOf(chunk, results, chunkGraph);
  2725. if (demand === null) continue;
  2726. if (demand.carriesFullHash) {
  2727. this._chunksBakingFullHash.add(chunk);
  2728. chunkGraph.attachFullHashModules(chunk, []);
  2729. }
  2730. if (demand.names.size > 0) namesBaked.set(chunk, demand.names);
  2731. }
  2732. // A late name makes the name it is baked into late too, and that one may be
  2733. // baked further up — so this runs to a fixed point.
  2734. let changed = true;
  2735. while (changed) {
  2736. changed = false;
  2737. for (const [chunk, names] of namesBaked) {
  2738. if (this._settlesLate(chunk)) continue;
  2739. for (const id of names) {
  2740. const other = chunksById.get(id);
  2741. if (other === undefined || !this._settlesLate(other)) continue;
  2742. chunkGraph.attachFullHashModules(chunk, []);
  2743. changed = true;
  2744. break;
  2745. }
  2746. }
  2747. }
  2748. }
  2749. /**
  2750. * What the deferred pass will write into this chunk: whether any of it is built from
  2751. * the compilation hash, and which chunks it names. Read off what was generated rather
  2752. * than off what asked for it — a module restored from the persistent cache carries a
  2753. * stand-in without being generated again, and the stand-in spells its own recipe.
  2754. * @param {Chunk} chunk the chunk
  2755. * @param {CodeGenerationResults} results this compilation's generated code
  2756. * @param {ChunkGraph} chunkGraph the chunk graph
  2757. * @returns {{ carriesFullHash: boolean, names: Set<string> } | null} what it writes,
  2758. * or `null` where nothing is written
  2759. */
  2760. _analyzableDemandOf(chunk, results, chunkGraph) {
  2761. const modules = chunkGraph.getChunkModulesIterableBySourceType(
  2762. chunk,
  2763. JAVASCRIPT_TYPE
  2764. );
  2765. if (modules === undefined) return null;
  2766. let carriesFullHash = false;
  2767. /** @type {Set<string>} */
  2768. const names = new Set();
  2769. let found = false;
  2770. for (const module of modules) {
  2771. if (!results.has(module, chunk.runtime)) continue;
  2772. const source = results.getSource(module, chunk.runtime, JAVASCRIPT_TYPE);
  2773. const content = source && source.source();
  2774. if (typeof content !== "string") continue;
  2775. if (this._hasReservedFullHash(content)) {
  2776. carriesFullHash = true;
  2777. found = true;
  2778. }
  2779. const regexp = new RegExp(
  2780. ANALYZABLE_TOKEN_REGEXP.source,
  2781. ANALYZABLE_TOKEN_REGEXP.flags
  2782. );
  2783. /** @type {RegExpExecArray | null} */
  2784. let match;
  2785. while ((match = regexp.exec(content)) !== null) {
  2786. const parts = RuntimeTemplate._readAnalyzableSpecifier(match[1]);
  2787. if (parts === null) continue;
  2788. found = true;
  2789. for (const [kind, value] of parts) {
  2790. if (
  2791. kind === "publicPath" ||
  2792. kind === "template" ||
  2793. kind === "unserved"
  2794. ) {
  2795. carriesFullHash = true;
  2796. } else if (CHUNK_SPECIFIER_PART_KINDS.has(kind)) {
  2797. names.add(String(value));
  2798. }
  2799. }
  2800. }
  2801. }
  2802. return found ? { carriesFullHash, names } : null;
  2803. }
  2804. /**
  2805. * Whether everything in front of a chunk's filename is text the fold can account for.
  2806. * `literal` is already in the chunk's modules, and `undo` is the `../` depth of the
  2807. * asset it lands in, which `_chunkPlacement` reads off the filename template with the
  2808. * hashes neutralized — so both are known while that chunk is hashed. A public path or
  2809. * a template is not: it resolves against the compilation hash, which by then is still
  2810. * being built out of this very hash.
  2811. * @param {SpecifierPart[]} prefix what goes in front of the filename
  2812. * @param {Iterable<Chunk>} chunks the chunks the stand-in is written into
  2813. * @returns {boolean} true when the filename is all that is left to account for
  2814. */
  2815. _foldsWholeName(prefix, chunks) {
  2816. for (const [kind] of prefix) {
  2817. if (kind === "literal") continue;
  2818. if (kind !== "undo") return false;
  2819. // An `undo` resolves to each asset's own depth, so every chunk it may land in
  2820. // has to have one this can be sure of.
  2821. for (const chunk of chunks) {
  2822. if (this._chunkPlacement(chunk).undo === null) return false;
  2823. }
  2824. }
  2825. return true;
  2826. }
  2827. /**
  2828. * Folds the names this chunk will have filled in by the deferred pass into its own
  2829. * hash, so a name taken from that hash already stands for the bytes the fill leaves
  2830. * behind — what lets a chunk named by `[chunkhash]`, or by `[contenthash]` with
  2831. * nothing to repair it afterwards, hold a baked reference at all. The same thing
  2832. * `RuntimeModule.dependentHash` does for the runtime form of the reference.
  2833. *
  2834. * Asked of every chunk whose name could move, and answered from the chunk graph
  2835. * rather than from what was generated: a module restored from the persistent cache
  2836. * carries a stand-in without being generated again. That over-counts a chunk whose
  2837. * reference kept the runtime form, which costs a hash that changes when it needn't —
  2838. * never a name that stays put while the bytes move.
  2839. * Memoized because `createHash` asks twice — once for `chunk.hash` and once for
  2840. * `chunk.contentHash` — and nothing an earlier chunk contributes moves between the
  2841. * two, while the walk behind the answer is over everything the chunk reaches.
  2842. * @param {Chunk} chunk the chunk being hashed
  2843. * @param {Hash} hash its hash
  2844. * @returns {void}
  2845. */
  2846. _foldAnalyzableNames(chunk, hash) {
  2847. // Nothing to bring back in line where the name does not move with the content,
  2848. // and folding there would move hashes that are settled correctly today.
  2849. if (this._chunkNameIndependentOfContent(chunk)) return;
  2850. // A chunk baking the compilation hash is asked twice with different answers —
  2851. // once before that hash exists and once in the round that follows it — so the
  2852. // memo would hand back the first one.
  2853. const bakesFullHash = this._bakesFullHash(chunk);
  2854. // A chunk settling late is asked once in its normal round and again in that one,
  2855. // where what it reads has moved on, so the memo would hand back the first answer.
  2856. const late = bakesFullHash || this._settlesLate(chunk);
  2857. let folded = late ? undefined : this._foldedAnalyzableNames.get(chunk);
  2858. if (folded === undefined) {
  2859. const { compilation } = this;
  2860. const { outputOptions } = compilation;
  2861. // Read back off what was generated: walking the graph would fold in whatever
  2862. // the group reaches, moving a split chunk that references nothing.
  2863. const named = this._namesBakedInto && this._namesBakedInto.get(chunk);
  2864. /** @type {Set<Chunk>} */
  2865. const reachable = new Set();
  2866. for (const id of named || []) {
  2867. const referenced =
  2868. this._chunksByIdForFold && this._chunksByIdForFold.get(id);
  2869. if (referenced !== undefined) reachable.add(referenced);
  2870. }
  2871. // Its own `../` depth, which an `undo` stand-in in it resolves to. Constant per
  2872. // chunk, but the bytes still move with it, so the name has to as well.
  2873. const { undo } = this._chunkPlacement(chunk);
  2874. const names = [undo === null ? "" : undo];
  2875. // What the fill will write in place of every compilation-hash stand-in. Read
  2876. // here rather than folded in as text elsewhere, because this is the one round
  2877. // where it exists before the name is taken.
  2878. if (bakesFullHash && compilation.hash !== undefined) {
  2879. names.push(compilation.hash);
  2880. }
  2881. for (const referenced of reachable) {
  2882. if (!this._hashesBefore(referenced, chunk)) continue;
  2883. let byType = this._analyzableAssetNames.get(referenced);
  2884. if (byType === undefined) {
  2885. byType = new Map();
  2886. this._analyzableAssetNames.set(referenced, byType);
  2887. }
  2888. for (const [contentHashType, naming] of CHUNK_ASSET_NAMING) {
  2889. // No hash of that type is no asset of that type, so nothing names one.
  2890. if (referenced.contentHash[contentHashType] === undefined) continue;
  2891. let name = byType.get(contentHashType);
  2892. if (name === undefined) {
  2893. // The very call the fill makes, so what is folded in is what lands
  2894. // there — a filename function included, which resolves to a name here
  2895. // either way. Settled once: the hash it reads is, by `_hashesBefore`.
  2896. name = compilation.getPath(
  2897. naming.template(referenced, outputOptions),
  2898. {
  2899. chunk: referenced,
  2900. runtime: referenced.runtime,
  2901. contentHashType
  2902. }
  2903. );
  2904. byType.set(contentHashType, name);
  2905. }
  2906. names.push(name);
  2907. }
  2908. }
  2909. folded = names.join("\n");
  2910. if (!late) this._foldedAnalyzableNames.set(chunk, folded);
  2911. }
  2912. if (folded !== "") hash.update(folded);
  2913. }
  2914. /**
  2915. * Drops what the fold cached, once `createHash` is done and nothing reads it again.
  2916. * Replaced rather than emptied: a `WeakMap` has no `clear`.
  2917. * @returns {void}
  2918. */
  2919. _releaseAnalyzableNameCaches() {
  2920. this._foldedAnalyzableNames = new WeakMap();
  2921. this._analyzableAssetNames = new WeakMap();
  2922. this._namesBakedInto = undefined;
  2923. this._chunksByIdForFold = undefined;
  2924. }
  2925. /**
  2926. * Whether `chunk` can reach any of `targets` by following chunk groups, which is
  2927. * what turns a baked hashed name into a hash that depends on itself.
  2928. * @param {Chunk} chunk the referenced chunk
  2929. * @param {Iterable<Chunk>} targets the chunks the reference is written into
  2930. * @returns {boolean} true when one of them is reachable from `chunk`
  2931. */
  2932. _reachesAny(chunk, targets) {
  2933. const wanted = new Set(targets);
  2934. if (wanted.size === 0) return false;
  2935. if (wanted.has(chunk)) return true;
  2936. /** @type {Set<ChunkGroup>} */
  2937. const seen = new Set();
  2938. /** @type {ChunkGroup[]} */
  2939. const queue = [...chunk.groupsIterable];
  2940. for (const group of queue) seen.add(group);
  2941. for (let i = 0; i < queue.length; i++) {
  2942. for (const child of queue[i].childrenIterable) {
  2943. if (seen.has(child)) continue;
  2944. seen.add(child);
  2945. for (const candidate of child.chunks) {
  2946. if (wanted.has(candidate)) return true;
  2947. }
  2948. queue.push(child);
  2949. }
  2950. }
  2951. return false;
  2952. }
  2953. /**
  2954. * The chunks a reference emitted into `module` is written into — the assets a
  2955. * stand-in of ours would land in, and so the only ones a deferred fill could go
  2956. * stale in. Resolved through concatenation first: it may have absorbed the module
  2957. * that wrote the reference, and an absorbed one is in no chunk at all.
  2958. * @param {Module} module the module a reference is emitted into
  2959. * @param {ChunkGraph} chunkGraph the chunk graph
  2960. * @returns {Iterable<Chunk>} the chunks holding it
  2961. */
  2962. _moduleChunks(module, chunkGraph) {
  2963. return chunkGraph.getModuleChunksIterable(
  2964. getConcatenatedModule().getChunkGraphModule(this.compilation, module)
  2965. );
  2966. }
  2967. /**
  2968. * The `../` path back out of a public path that needs a base, which is where the
  2969. * chunk loader puts what it fetches. Reads nothing but `output`, so it is answered
  2970. * once: `""` where the path adds no depth, `null` where its shape is unknown.
  2971. * @returns {string | null} the path back out of it
  2972. */
  2973. _publicPathClimb() {
  2974. if (this._publicPathClimbText === undefined) {
  2975. const shape = this._publicPathShape();
  2976. const undo =
  2977. shape === undefined
  2978. ? null
  2979. : getUndoPath(
  2980. `${shape}x`,
  2981. /** @type {string} */ (this.outputOptions.path),
  2982. true
  2983. );
  2984. this._publicPathClimbText = undo === "./" ? "" : undo;
  2985. }
  2986. return this._publicPathClimbText;
  2987. }
  2988. /**
  2989. * Where a literal emitted into a chunk is read from: the `../` path back to the
  2990. * output root, and whether the chunk loader fetched the chunk through
  2991. * `output.publicPath` — such a chunk sits one public path below the root the runtime
  2992. * resolves against, where an initial chunk the host fetched does not. Reads only the
  2993. * chunk, so it is memoized on it and shared by every module in it.
  2994. * @param {Chunk} chunk a chunk a reference is written into
  2995. * @returns {Placement} where a literal in it is read from
  2996. */
  2997. _chunkPlacement(chunk) {
  2998. const cached = this._placementByChunk.get(chunk);
  2999. if (cached !== undefined) return cached;
  3000. const { compilation } = this;
  3001. const { outputOptions } = compilation;
  3002. const shape = this._chunkNameShape(chunk);
  3003. const chunkName =
  3004. shape === null
  3005. ? null
  3006. : compilation.getPath(shape, {
  3007. chunk,
  3008. runtime: chunk.runtime,
  3009. contentHashType: JAVASCRIPT_TYPE
  3010. });
  3011. const placement = {
  3012. // A name whose shape is unknown has an unknown depth, and the deferred pass
  3013. // reads the real one off the asset it lands in.
  3014. undo:
  3015. chunkName === null
  3016. ? null
  3017. : getUndoPath(
  3018. chunkName,
  3019. /** @type {string} */ (outputOptions.path),
  3020. true
  3021. ),
  3022. // A chunk in an initial group and an async one both is served at two urls,
  3023. // one public path apart, so no one literal in it is right for both.
  3024. loaded: chunk.isOnlyInitial() ? false : chunk.canBeInitial() ? null : true
  3025. };
  3026. this._placementByChunk.set(chunk, placement);
  3027. return placement;
  3028. }
  3029. /**
  3030. * The chunk's filename with every hash neutralized, which is all the `../` depth
  3031. * needs — hashes are not settled when this is asked and sit in the basename anyway.
  3032. * A function is asked for the template it returns rather than handed to `getPath`,
  3033. * which would have to resolve a placeholder in it against a hash that does not exist
  3034. * yet; one that builds the name out of a hash itself gets a stand-in to build from.
  3035. * @param {Chunk} chunk the chunk
  3036. * @returns {string | null} the shape, or `null` where it cannot be known
  3037. */
  3038. _chunkNameShape(chunk) {
  3039. const template = JavascriptModulesPlugin.getChunkFilenameTemplate(
  3040. chunk,
  3041. this.outputOptions
  3042. );
  3043. if (typeof template === "string") {
  3044. return template.replace(HASH_IN_FILENAME_GLOBAL, "x");
  3045. }
  3046. try {
  3047. return template({
  3048. chunk: createHashProbeChunk(chunk, HASH_PROBE, true),
  3049. runtime: chunk.runtime,
  3050. contentHashType: JAVASCRIPT_TYPE,
  3051. hash: HASH_PROBE,
  3052. contentHash: HASH_PROBE
  3053. }).replace(HASH_IN_FILENAME_GLOBAL, "x");
  3054. } catch (_error) {
  3055. // Nothing to report: the naming call is given strictly less than this probe, so
  3056. // one that throws here fails the build where the name is actually needed.
  3057. return null;
  3058. }
  3059. }
  3060. /**
  3061. * The `../` path from a chunk's own asset back to the output root. Hashes are
  3062. * neutralized first: a runtime module is generated once to be hashed, before any
  3063. * hash exists, so resolving one there throws — and `RuntimeModule.updateHash`
  3064. * swallows that, pinning the module's hash to the message.
  3065. * @param {Chunk} chunk the chunk whose asset holds the reference
  3066. * @param {boolean} enforceRelative whether the answer keeps a leading `./`
  3067. * @returns {string} the path back to the output root
  3068. */
  3069. chunkRootOutputDir(chunk, enforceRelative) {
  3070. const shape = this._chunkNameShape(chunk);
  3071. const name = this.compilation.getPath(
  3072. shape === null
  3073. ? JavascriptModulesPlugin.getChunkFilenameTemplate(
  3074. chunk,
  3075. this.outputOptions
  3076. )
  3077. : shape,
  3078. { chunk, contentHashType: JAVASCRIPT_TYPE }
  3079. );
  3080. return getUndoPath(
  3081. name,
  3082. /** @type {string} */ (this.outputOptions.path),
  3083. enforceRelative
  3084. );
  3085. }
  3086. /**
  3087. * The one answer every chunk holding a reference agrees on, with either half `null`
  3088. * where they do not — then no one literal is right for all of them.
  3089. * @param {Module} module the module the reference is emitted into
  3090. * @param {ChunkGraph} chunkGraph the chunk graph
  3091. * @returns {Placement} where a literal in it is read from
  3092. */
  3093. _modulePlacement(module, chunkGraph) {
  3094. return this._placementOf(this._moduleChunks(module, chunkGraph));
  3095. }
  3096. /**
  3097. * Whether each of these chunks is served one way — either the host fetched it or the
  3098. * loader did, not both. One that is both is at two urls a public path apart with no
  3099. * answer of its own, which no per-asset stand-in can supply.
  3100. * @param {Iterable<Chunk>} chunks the chunks a literal is written into
  3101. * @returns {boolean} true when each has an answer to give
  3102. */
  3103. _eachChunkServedOneWay(chunks) {
  3104. for (const chunk of chunks) {
  3105. if (this._chunkPlacement(chunk).loaded === null) return false;
  3106. }
  3107. return true;
  3108. }
  3109. /**
  3110. * The one answer every chunk in `chunks` agrees on, with either half `null` where
  3111. * they do not.
  3112. * @param {Iterable<Chunk>} chunks the chunks a literal is written into
  3113. * @returns {Placement} where a literal in them is read from
  3114. */
  3115. _placementOf(chunks) {
  3116. /** @type {Placement | undefined} */
  3117. let first;
  3118. /** @type {string | null} */
  3119. let undo = null;
  3120. /** @type {boolean | null} */
  3121. let loaded = null;
  3122. for (const chunk of chunks) {
  3123. const own = this._chunkPlacement(chunk);
  3124. if (first === undefined) {
  3125. first = own;
  3126. undo = own.undo;
  3127. loaded = own.loaded;
  3128. continue;
  3129. }
  3130. if (undo !== own.undo) undo = null;
  3131. if (loaded !== own.loaded) loaded = null;
  3132. }
  3133. if (first === undefined) return NO_PLACEMENT;
  3134. // A module in one chunk — nearly all of them — hands back what that chunk said,
  3135. // so the common answer costs no object of its own.
  3136. return undo === first.undo && loaded === first.loaded
  3137. ? first
  3138. : { undo, loaded };
  3139. }
  3140. /**
  3141. * Static literal specifier (already quoted) for a `new URL(<here>, import.meta.url)`
  3142. * or `import(<here>)` pointing at `chunk`'s JS file, or `null` when it can't be known
  3143. * statically — a content hash in the filename, or a dynamic/templated publicPath.
  3144. * @param {string | undefined} overridePublicPath per-dependency public path (wins over `output.publicPath`)
  3145. * @param {Chunk} chunk the chunk to reference
  3146. * @param {Module | undefined} consumingModule the module the reference is emitted
  3147. * into, or `undefined` when `consumingChunks` names where it goes instead
  3148. * @param {ChunkGraph} chunkGraph the chunk graph
  3149. * @param {RuntimeRequirements=} runtimeRequirements set when the caller wraps the result in
  3150. * `new URL(...)` and so accepts a runtime public path prefix around the literal filename
  3151. * @param {Chunk[]=} consumingChunks the chunks the reference is written into, where
  3152. * they are known without a module to read them from
  3153. * @param {string=} sourceType which half of the chunk is named — its javascript by
  3154. * default, or its stylesheet
  3155. * @returns {string | null} a JS string literal or expression, or `null` to fall back to the runtime form
  3156. */
  3157. _getAnalyzableChunkSpecifier(
  3158. overridePublicPath,
  3159. chunk,
  3160. consumingModule,
  3161. chunkGraph,
  3162. runtimeRequirements,
  3163. consumingChunks,
  3164. sourceType = JAVASCRIPT_TYPE
  3165. ) {
  3166. const { compilation } = this;
  3167. const { outputOptions } = compilation;
  3168. const naming = CHUNK_ASSET_NAMING.get(sourceType);
  3169. // Nothing here names this type's asset, so nothing can spell where it will be.
  3170. if (naming === undefined) return null;
  3171. const template = this._resolveChunkFilenameTemplate(
  3172. naming.template(chunk, outputOptions),
  3173. chunk,
  3174. sourceType
  3175. );
  3176. if (template === null) return null;
  3177. // A hashed name is settled long after this code is generated, so a stand-in is
  3178. // emitted and filled in once the hash exists.
  3179. const deferred = template === undefined || HASH_IN_FILENAME.test(template);
  3180. // An id names the chunk in the stand-in, and one nothing could resolve would
  3181. // reach the bundle verbatim. The whole name is re-resolved later rather than
  3182. // carrying a stand-in of its own, so any hash spelling is fine here.
  3183. // One of the two always names where the reference goes.
  3184. const chunks =
  3185. consumingChunks ||
  3186. this._moduleChunks(/** @type {Module} */ (consumingModule), chunkGraph);
  3187. // Baking makes the consuming chunk's content depend on this one's hash. A pair that
  3188. // reaches back has no fixed point if both bake, so only the lower id's name does.
  3189. const cycles =
  3190. deferred &&
  3191. this._reachesAny(chunk, chunks) &&
  3192. !this._namesBeforeAll(chunk, chunks);
  3193. // An id names the chunk in the stand-in. No reference reaches here without one —
  3194. // `blockPromise` drops an id-less chunk before asking, and one the whole build
  3195. // keeps has no name to be emitted under — so the guard carries no reason of its
  3196. // own; it only keeps `null` out of a name.
  3197. const canReserve =
  3198. chunk.id !== null && !cycles && this._canDeferAnalyzableName(chunks);
  3199. // A content-named consumer bakes anyway when this chunk settles first: the fold
  3200. // puts the name into its hash. Only what `_foldsWholeName` covers, though.
  3201. const canFold = !canReserve && this._namesBeforeAll(chunk, chunks);
  3202. /**
  3203. * @returns {null} always, having recorded why no stand-in may be reserved
  3204. */
  3205. const cannotReserve = () => {
  3206. this._analyzableBailout(
  3207. consumingModule,
  3208. cycles
  3209. ? "this chunk and the one it references name each other, so neither hash could settle"
  3210. : DEFER_BAILOUT
  3211. );
  3212. return null;
  3213. };
  3214. if (deferred && !canReserve && !canFold) return cannotReserve();
  3215. const filename = deferred
  3216. ? ""
  3217. : compilation.getPath(/** @type {string} */ (template), {
  3218. chunk,
  3219. // Matches what names the asset, or a placeholder resolved here would
  3220. // not be the one on disk.
  3221. runtime: chunk.runtime,
  3222. contentHashType: sourceType
  3223. });
  3224. /**
  3225. * @param {SpecifierPart[]} prefix what goes in front of the chunk's filename
  3226. * @returns {string | null} the specifier already quoted, or `null` when the
  3227. * recipe needs a stand-in that cannot be reserved
  3228. */
  3229. const specifier = (prefix) => {
  3230. if (!deferred) {
  3231. const text = literalText(prefix);
  3232. if (text !== null) return toJsStringLiteral(text + filename);
  3233. }
  3234. if (!canReserve && !(canFold && this._foldsWholeName(prefix, chunks))) {
  3235. return cannotReserve();
  3236. }
  3237. return toJsStringLiteral(
  3238. this._reserveAnalyzableSpecifier([
  3239. ...prefix,
  3240. [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
  3241. ])
  3242. );
  3243. };
  3244. if (overridePublicPath) {
  3245. const resolved = this._resolvePublicPathPrefix(
  3246. overridePublicPath,
  3247. consumingModule,
  3248. chunks
  3249. );
  3250. return resolved === null ? null : specifier(resolved);
  3251. }
  3252. const { publicPath } = outputOptions;
  3253. if (publicPath === "auto") {
  3254. const { undo } = this._placementOf(chunks);
  3255. if (undo !== null) return specifier([["literal", undo]]);
  3256. // Different depths — no one `../` path is right for every asset the reference
  3257. // lands in, so the deferred pass builds each asset's own.
  3258. const perAsset = specifier([["undo", ""]]);
  3259. if (perAsset !== null) return perAsset;
  3260. // Only a stand-in that could not be reserved reaches here, and `specifier`
  3261. // has already recorded why.
  3262. if (deferred || !runtimeRequirements) return null;
  3263. // No bundler follows a concatenation, but a `new URL(...)` caller still sheds
  3264. // the `.u(id)` lookup this way; `import()` needs a static specifier.
  3265. runtimeRequirements.add(RuntimeGlobals.publicPath);
  3266. return `${RuntimeGlobals.publicPath} + ${toJsStringLiteral(filename)}`;
  3267. }
  3268. const prefix = this._analyzablePathPrefix(
  3269. consumingModule,
  3270. chunkGraph,
  3271. chunks
  3272. );
  3273. return prefix === null ? null : specifier(prefix);
  3274. }
  3275. /**
  3276. * The parts that go in front of a name so a literal read from the chunk holding it
  3277. * reaches what the runtime would. A public path needing no base is the whole answer.
  3278. * One that needs a base is read from the output root, so the `../` path back there
  3279. * comes first — and is the whole answer again where the chunk loader fetched this
  3280. * chunk through that same path, since climbing out of it only to spell it again
  3281. * names the place it started from. An entry `baseUri` sits between the two, so
  3282. * there both are written. Never asked of an `auto` public path, which is no path
  3283. * to walk back over.
  3284. * @param {Module | undefined} module the module the reference is emitted into
  3285. * @param {ChunkGraph} chunkGraph the chunk graph
  3286. * @param {Iterable<Chunk>} chunks the chunks a stand-in would be written into
  3287. * @param {string=} relativeBase an entry `baseUri` read against the output root
  3288. * @returns {SpecifierPart[] | null} the parts, or `null` having recorded why not
  3289. */
  3290. _analyzablePathPrefix(module, chunkGraph, chunks, relativeBase) {
  3291. const publicPath = /** @type {PublicPath} */ (
  3292. this.outputOptions.publicPath
  3293. );
  3294. const shape = this._publicPathShape();
  3295. if (shape === undefined) return null;
  3296. const resolve = () =>
  3297. this._resolvePublicPathPrefix(publicPath, module, chunks);
  3298. if (isBaseIndependent(shape)) return resolve();
  3299. const { undo, loaded } = this._placementOf(chunks);
  3300. // What a chunk the loader fetched climbs back out of. One of no depth leaves
  3301. // nothing to climb, and then both answers put the same text in front.
  3302. const served = this._publicPathClimb();
  3303. const climb =
  3304. loaded === null ? (served === "" ? "" : null) : loaded ? served : "";
  3305. /** @type {SpecifierPart[]} */
  3306. const head = [undo === null ? ["undo", ""] : ["literal", undo]];
  3307. if (climb === null) {
  3308. // Each knows its own answer, so the fill asks per asset — where each has one,
  3309. // and where nothing else goes between the two shapes.
  3310. if (relativeBase !== undefined || !this._eachChunkServedOneWay(chunks)) {
  3311. this._analyzableBailout(module, SERVED_BAILOUT);
  3312. return null;
  3313. }
  3314. return [...head, ["unserved", ""]];
  3315. }
  3316. if (climb !== "" && relativeBase === undefined) return head;
  3317. const resolved = resolve();
  3318. if (resolved === null) return null;
  3319. return [
  3320. ...head,
  3321. .../** @type {SpecifierPart[]} */ (
  3322. climb === "" ? [] : [["literal", climb]]
  3323. ),
  3324. .../** @type {SpecifierPart[]} */ (
  3325. relativeBase === undefined ? [] : [["literal", relativeBase]]
  3326. ),
  3327. ...rootedParts(resolved)
  3328. ];
  3329. }
  3330. /**
  3331. * What a public path puts in front of a filename, as the parts it is built from.
  3332. * A plain one is literal text. A templated one is resolved as far as code
  3333. * generation can, leaving the compilation hash it may carry as a stand-in exactly
  3334. * as `PublicPathRuntimeModule` resolves the same string once that hash exists — and
  3335. * a hash re-encoded to another digest, which no stand-in can carry, is handed to
  3336. * the deferred pass whole instead. A function is called for its value rather than
  3337. * read as a template, so one whose answer moves with the hash is called again there.
  3338. * @param {PublicPath} publicPath the configured public path
  3339. * @param {Module=} module the module the reference is emitted into, to record why
  3340. * a name no stand-in may be reserved for kept the runtime form
  3341. * @param {Iterable<Chunk>=} chunks the chunks a stand-in would be written into
  3342. * @returns {SpecifierPart[] | null} the parts, or `null` when it cannot be known
  3343. */
  3344. _resolvePublicPathPrefix(publicPath, module, chunks) {
  3345. if (typeof publicPath === "function") {
  3346. // One that answers nothing to a probe cannot be placed, absolute or not.
  3347. if (this._publicPathShape() === undefined) return null;
  3348. const resolved = this._resolveHashIndependent(
  3349. publicPath,
  3350. this._publicPathShape()
  3351. );
  3352. if (resolved !== null) return [["literal", resolved]];
  3353. // Called again by the fill against the compilation hash, so what it answers
  3354. // there is that hash by another name.
  3355. return this._canDeferOrBakeFullHash(true, chunks, module)
  3356. ? [["publicPath", ""]]
  3357. : null;
  3358. }
  3359. if (!publicPath.includes("[")) return [["literal", publicPath]];
  3360. // A re-encoded digest cannot be spelled by a stand-in, so it stays a template.
  3361. if (getTemplatedPathPlugin().usesFullHashDigest(publicPath)) {
  3362. return this._canDeferOrBakeFullHash(true, chunks, module)
  3363. ? [["template", publicPath]]
  3364. : null;
  3365. }
  3366. const literal = this.compilation.getPath(
  3367. publicPath,
  3368. this._deferredFullHashPathData()
  3369. );
  3370. return this._canDeferOrBakeFullHash(
  3371. this._hasReservedFullHash(literal),
  3372. chunks,
  3373. module
  3374. )
  3375. ? [["literal", literal]]
  3376. : null;
  3377. }
  3378. /**
  3379. * `output.publicPath` as the text it will have the shape of — a function's answer to
  3380. * a stand-in hash, which says whether it is absolute even when its value is not
  3381. * settled yet. `"auto"` reads as the empty string, which needs a base and so takes
  3382. * the path that needs no answer; a function that answers nothing says nothing about
  3383. * its shape either, and nothing may be built on it.
  3384. * @returns {string | undefined} the shape of the public path
  3385. */
  3386. _publicPathShape() {
  3387. if (this._publicPathShapeText === undefined) {
  3388. const { publicPath } = this.outputOptions;
  3389. if (typeof publicPath !== "function") {
  3390. this._publicPathShapeText = publicPath === "auto" ? "" : publicPath;
  3391. } else {
  3392. try {
  3393. this._publicPathShapeText = this.compilation.getPath(publicPath, {
  3394. hash: HASH_PROBE
  3395. });
  3396. } catch (_error) {
  3397. this._publicPathShapeText = false;
  3398. }
  3399. }
  3400. }
  3401. return this._publicPathShapeText === false
  3402. ? undefined
  3403. : this._publicPathShapeText;
  3404. }
  3405. /**
  3406. * A path built by a function, resolved to the value it will have — or `null` when
  3407. * it moves with the compilation hash, which code generation does not know.
  3408. * @param {import("./TemplatedPathPlugin").TemplatePathFn<EXPECTED_ANY>} fn the function
  3409. * @param {string | undefined} value its answer to the first probe, or `undefined`
  3410. * when it answered nothing
  3411. * @returns {string | null} the settled value, or `null` when it is hash-dependent
  3412. */
  3413. _resolveHashIndependent(fn, value) {
  3414. // The shape is this function's answer to the first probe, already taken and
  3415. // memoized, so only the second one is new here.
  3416. if (value === undefined) return null;
  3417. try {
  3418. return this.compilation.getPath(fn, { hash: HASH_PROBE_ALTERNATE }) ===
  3419. value
  3420. ? value
  3421. : null;
  3422. } catch (_error) {
  3423. // One that needs more than a hash can't be resolved here.
  3424. return null;
  3425. }
  3426. }
  3427. /**
  3428. * Static literal specifier (already quoted) for a `new URL(<here>, import.meta.url)`
  3429. * pointing at an emitted file — an asset, or a wasm binary. The base is the asset the
  3430. * reference sits in; the runtime form resolves against the output root instead, so a
  3431. * public path that needs a base is put behind the `../` path back to that root rather
  3432. * than baked as the whole prefix.
  3433. * @param {Module} module the module the reference is emitted into
  3434. * @param {ChunkGraph} chunkGraph the chunk graph
  3435. * @param {SpecifierPart[]} file the emitted file's name, relative to the output root
  3436. * @param {boolean} bakePublicPath whether the public path belongs in the literal
  3437. * @param {string=} relativeBase an entry `baseUri` the runtime reads against the
  3438. * chunk, so it belongs between the path back to the output root and the public path
  3439. * @returns {string | null} a quoted literal, or `null` to fall back
  3440. */
  3441. _getAnalyzableFileSpecifier(
  3442. module,
  3443. chunkGraph,
  3444. file,
  3445. bakePublicPath,
  3446. relativeBase
  3447. ) {
  3448. const { publicPath } = this.outputOptions;
  3449. const chunks = this._moduleChunks(module, chunkGraph);
  3450. /**
  3451. * @param {SpecifierPart[]} parts the whole specifier
  3452. * @returns {string | null} it already quoted, or `null` when no stand-in may be reserved
  3453. */
  3454. const specifier = (parts) => this._specifierOf(parts, chunks, module);
  3455. if (bakePublicPath && publicPath !== "auto") {
  3456. const prefix = this._analyzablePathPrefix(
  3457. module,
  3458. chunkGraph,
  3459. chunks,
  3460. relativeBase
  3461. );
  3462. return prefix === null ? null : specifier([...prefix, ...file]);
  3463. }
  3464. // No public path to place it against, so the `../` path back to the output root
  3465. // is the whole prefix. Different depths — no one is right for every asset the
  3466. // reference is emitted into, so the deferred pass builds each asset's own.
  3467. const { undo } = this._modulePlacement(module, chunkGraph);
  3468. return specifier([
  3469. undo === null ? ["undo", ""] : ["literal", undo],
  3470. ...(relativeBase === undefined
  3471. ? []
  3472. : /** @type {SpecifierPart[]} */ ([["literal", relativeBase]])),
  3473. ...file
  3474. ]);
  3475. }
  3476. /**
  3477. * Static `new URL(<file>, import.meta.url)` for every stylesheet a runtime can load,
  3478. * keyed by chunk id, or `null` when any of them has to keep the runtime
  3479. * `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
  3480. * and the plugin declaring what it needs ask this, so the two always agree. The
  3481. * runtime hands an absolute url string to `link.href`, and so does this — the browser
  3482. * resolves the element against the document, which is not where the chunk sits, and
  3483. * the loader reads the url as text either way. Nothing is written out for a runtime
  3484. * that also carries the hot handler; see below.
  3485. * @param {Chunk} runtimeChunk the chunk holding the stylesheet loader
  3486. * @param {ChunkGraph} chunkGraph the chunk graph
  3487. * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
  3488. * @param {Module=} consumingModule the runtime module, where one exists to report against
  3489. * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
  3490. */
  3491. analyzableCssChunkUrls(
  3492. runtimeChunk,
  3493. chunkGraph,
  3494. runtimeRequirements,
  3495. consumingModule
  3496. ) {
  3497. const { chunkHasCss } = getCssModulesPlugin();
  3498. // An initial stylesheet is already in the document, but the hot path re-loads it
  3499. // by id like any other, so it needs a url here too.
  3500. const reachable = new Set([
  3501. ...runtimeChunk.getAllReferencedChunks(),
  3502. ...runtimeChunk.getAllInitialChunks()
  3503. ]);
  3504. const chunks = [];
  3505. for (const chunk of reachable) {
  3506. if (chunkHasCss(chunk, chunkGraph)) chunks.push(chunk);
  3507. }
  3508. return this._analyzableChunkUrls(
  3509. chunks,
  3510. chunkGraph,
  3511. consumingModule,
  3512. [runtimeChunk],
  3513. CSS_TYPE,
  3514. runtimeRequirements
  3515. );
  3516. }
  3517. /**
  3518. * Static `new URL(<file>, import.meta.url).href` for every javascript chunk a
  3519. * runtime can hint at with `<link rel="prefetch"/"modulepreload">`, keyed by chunk
  3520. * id, or `null` when any of them has to keep the runtime
  3521. * `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
  3522. * them and the plugin declaring what it needs ask this, so the two always agree.
  3523. * @param {Chunk} runtimeChunk the chunk holding the hint handlers
  3524. * @param {ChunkGraph} chunkGraph the chunk graph
  3525. * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
  3526. * @param {Module=} consumingModule the runtime module, where one exists to report against
  3527. * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
  3528. */
  3529. analyzableChunkScriptUrls(
  3530. runtimeChunk,
  3531. chunkGraph,
  3532. runtimeRequirements,
  3533. consumingModule
  3534. ) {
  3535. // Only a child some order names reaches a handler. Every order counts, not the
  3536. // two that reach javascript today: an unknown one costs bytes, not a missing url.
  3537. const orders = runtimeChunk.getChildIdsByOrdersMap(
  3538. chunkGraph,
  3539. true,
  3540. JavascriptModulesPlugin.chunkHasJs
  3541. );
  3542. /** @type {Set<ChunkId>} */
  3543. const hinted = new Set();
  3544. for (const order of Object.keys(orders)) {
  3545. for (const from of Object.keys(orders[order])) {
  3546. for (const id of orders[order][/** @type {ChunkId} */ (from)]) {
  3547. hinted.add(id);
  3548. }
  3549. }
  3550. }
  3551. /** @type {Chunk[]} */
  3552. const chunks = [];
  3553. for (const chunk of runtimeChunk.getAllReferencedChunks()) {
  3554. if (hinted.has(/** @type {ChunkId} */ (chunk.id))) chunks.push(chunk);
  3555. }
  3556. return this._analyzableChunkUrls(
  3557. chunks,
  3558. chunkGraph,
  3559. consumingModule,
  3560. [runtimeChunk],
  3561. JAVASCRIPT_TYPE,
  3562. runtimeRequirements
  3563. );
  3564. }
  3565. /**
  3566. * The urls of one asset of each of `chunks`, written out so they can be read by
  3567. * chunk id, or `null` as soon as one of them cannot be named here.
  3568. * @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
  3569. * @param {ChunkGraph} chunkGraph the chunk graph
  3570. * @param {Module | undefined} consumingModule the runtime module, where one exists to report against
  3571. * @param {Chunk[]} consumingChunks the chunks the urls are written into
  3572. * @param {string} sourceType which asset of each chunk to name
  3573. * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
  3574. * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
  3575. */
  3576. _analyzableChunkUrls(
  3577. chunks,
  3578. chunkGraph,
  3579. consumingModule,
  3580. consumingChunks,
  3581. sourceType,
  3582. runtimeRequirements
  3583. ) {
  3584. // A map written now cannot answer for whatever id an update names, so it yields
  3585. // to HMR — analyzable output is what ships.
  3586. if (
  3587. runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers) ||
  3588. !this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)
  3589. ) {
  3590. return null;
  3591. }
  3592. /** @type {Map<ChunkId, string>} */
  3593. const urls = new Map();
  3594. for (const chunk of chunks) {
  3595. if (chunk.id === null) continue;
  3596. const specifier = this._getAnalyzableChunkSpecifier(
  3597. undefined,
  3598. chunk,
  3599. consumingModule,
  3600. chunkGraph,
  3601. undefined,
  3602. consumingChunks,
  3603. sourceType
  3604. );
  3605. if (specifier === null) return null;
  3606. urls.set(chunk.id, `${this.importMetaUrl(specifier)}.href`);
  3607. }
  3608. return urls.size > 0 ? urls : null;
  3609. }
  3610. /**
  3611. * Static `new URL(<file>, import.meta.url)` for the binary emitted for an async wasm
  3612. * module. Only called when `supportsAnalyzable("wasm")` holds.
  3613. * @param {Module} module the async wasm module
  3614. * @param {ChunkGraph} chunkGraph the chunk graph
  3615. * @param {RuntimeSpec} runtime the runtime
  3616. * @param {RuntimeRequirements} runtimeRequirements runtime requirements
  3617. * @returns {string} expression evaluating to the binary's URL
  3618. */
  3619. getAnalyzableWasmUrl(module, chunkGraph, runtime, runtimeRequirements) {
  3620. const { compilation } = this;
  3621. const template = /** @type {string} */ (
  3622. this.outputOptions.webassemblyModuleFilename
  3623. );
  3624. // The module's own hash and id are settled here, the compilation's is not — and
  3625. // a placeholder nothing answers is left in the name, so what comes back is either
  3626. // the final name or a template carrying only `[fullhash]`.
  3627. const filename = compilation.getPath(template, {
  3628. module,
  3629. runtime,
  3630. chunkGraph
  3631. });
  3632. // Only a fetched binary carries the public path: `readFile` addresses it relative
  3633. // to the chunk anyway. One needing a base is spelled as an asset url is.
  3634. const specifier = this._getAnalyzableFileSpecifier(
  3635. module,
  3636. chunkGraph,
  3637. [[filename.includes("[") ? "template" : "literal", filename]],
  3638. this._wasmModuleFetches(module, chunkGraph)
  3639. );
  3640. if (specifier !== null) return this.importMetaUrl(specifier);
  3641. // No bundler follows a concatenation, but this still sheds the module id and
  3642. // hash the runtime form would need.
  3643. runtimeRequirements.add(RuntimeGlobals.publicPath);
  3644. return this.importMetaUrl(
  3645. `${RuntimeGlobals.publicPath} + ${toJsStringLiteral(
  3646. compilation.getPath(template, {
  3647. module,
  3648. runtime,
  3649. chunkGraph,
  3650. ...this._deferredFullHashPathData()
  3651. })
  3652. )}`
  3653. );
  3654. }
  3655. /**
  3656. * The chunk filename template as a plain string. A function is called twice, with
  3657. * a different stand-in hash each time; disagreeing answers mean the name depends on
  3658. * a hash, which is not knowable during code generation, so it is left to the
  3659. * deferred pass to ask again once the hashes are settled.
  3660. * @param {ChunkFilenameTemplate} filenameTemplate the configured template
  3661. * @param {Chunk} chunk the chunk being referenced
  3662. * @param {string} contentHashType which of the chunk's hashes the name reads
  3663. * @returns {string | undefined | null} the template, `undefined` to defer, or
  3664. * `null` to fall back
  3665. */
  3666. _resolveChunkFilenameTemplate(filenameTemplate, chunk, contentHashType) {
  3667. if (typeof filenameTemplate === "string") return filenameTemplate;
  3668. try {
  3669. // Everything the naming call is given except the hashes, so only a hash can
  3670. // make the two answers differ.
  3671. const template = filenameTemplate({
  3672. chunk: createHashProbeChunk(chunk, HASH_PROBE, true),
  3673. runtime: chunk.runtime,
  3674. contentHashType,
  3675. hash: HASH_PROBE,
  3676. contentHash: HASH_PROBE
  3677. });
  3678. const probe = filenameTemplate({
  3679. chunk: createHashProbeChunk(chunk, HASH_PROBE_ALTERNATE, false),
  3680. runtime: chunk.runtime,
  3681. contentHashType,
  3682. hash: HASH_PROBE_ALTERNATE,
  3683. contentHash: HASH_PROBE_ALTERNATE
  3684. });
  3685. return template === probe ? template : undefined;
  3686. } catch (_error) {
  3687. // Nothing to report: the probe is given strictly more than the naming call,
  3688. // so one that throws here throws there too and fails the build regardless.
  3689. return null;
  3690. }
  3691. }
  3692. /**
  3693. * Whether `module`'s binary is read through `fetch`, the one loader the public path
  3694. * reaches. Asked of its runtimes, not its chunks: only an entry names a loader.
  3695. * @param {Module} module the async wasm module
  3696. * @param {ChunkGraph} chunkGraph the chunk graph
  3697. * @returns {boolean} true when every runtime reaching it fetches
  3698. */
  3699. _wasmModuleFetches(module, chunkGraph) {
  3700. /** @type {string[]} */
  3701. const keys = [];
  3702. for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
  3703. forEachRuntime(moduleRuntime, (key) => {
  3704. keys.push(/** @type {string} */ (key));
  3705. });
  3706. }
  3707. // In no runtime at all nothing named a loader, so `output` answers.
  3708. if (keys.length === 0) return this.outputOptions.wasmLoading === "fetch";
  3709. const only = this._wasmGroupOnlyFetches();
  3710. const groups = this._wasmRuntimeGroups();
  3711. for (const key of keys) {
  3712. if (!only.get(this._wasmGroupOf(groups, key))) return false;
  3713. }
  3714. return true;
  3715. }
  3716. /**
  3717. * The loader a chunk's WebAssembly is read with. An entry names one, and every
  3718. * other chunk of the runtime is served by the one its entry asked for — so one
  3719. * that is no entry answers with what `output` says.
  3720. * @param {Chunk} chunk the chunk
  3721. * @returns {WasmLoading} the loader it is served by
  3722. */
  3723. _chunkWasmLoading(chunk) {
  3724. const entryOptions = chunk.getEntryOptions();
  3725. return entryOptions && entryOptions.wasmLoading !== undefined
  3726. ? entryOptions.wasmLoading
  3727. : this.outputOptions.wasmLoading;
  3728. }
  3729. /**
  3730. * Async module factory.
  3731. * @param {object} options options
  3732. * @param {AsyncDependenciesBlock} options.block the async block
  3733. * @param {ChunkGraph} options.chunkGraph the chunk graph
  3734. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  3735. * @param {string=} options.request request string used originally
  3736. * @param {Module=} options.originModule the module the factory is emitted into
  3737. * @returns {string} expression
  3738. */
  3739. asyncModuleFactory({
  3740. block,
  3741. chunkGraph,
  3742. runtimeRequirements,
  3743. request,
  3744. originModule
  3745. }) {
  3746. const dep = block.dependencies[0];
  3747. const module = chunkGraph.moduleGraph.getModule(dep);
  3748. const ensureChunk = this.blockPromise({
  3749. block,
  3750. message: "",
  3751. chunkGraph,
  3752. runtimeRequirements,
  3753. originModule
  3754. });
  3755. const factory = this.returningFunction(
  3756. this.moduleRaw({
  3757. module,
  3758. chunkGraph,
  3759. request,
  3760. runtimeRequirements
  3761. })
  3762. );
  3763. return this.returningFunction(
  3764. ensureChunk.startsWith("Promise.resolve(")
  3765. ? `${factory}`
  3766. : `${ensureChunk}.then(${this.returningFunction(factory)})`
  3767. );
  3768. }
  3769. /**
  3770. * Sync module factory.
  3771. * @param {object} options options
  3772. * @param {Dependency} options.dependency the dependency
  3773. * @param {ChunkGraph} options.chunkGraph the chunk graph
  3774. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  3775. * @param {string=} options.request request string used originally
  3776. * @returns {string} expression
  3777. */
  3778. syncModuleFactory({ dependency, chunkGraph, runtimeRequirements, request }) {
  3779. const module = chunkGraph.moduleGraph.getModule(dependency);
  3780. const factory = this.returningFunction(
  3781. this.moduleRaw({
  3782. module,
  3783. chunkGraph,
  3784. request,
  3785. runtimeRequirements
  3786. })
  3787. );
  3788. return this.returningFunction(factory);
  3789. }
  3790. /**
  3791. * Define es module flag statement.
  3792. * @param {object} options options
  3793. * @param {string} options.exportsArgument the name of the exports object
  3794. * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
  3795. * @returns {string} statement
  3796. */
  3797. defineEsModuleFlagStatement({ exportsArgument, runtimeRequirements }) {
  3798. runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
  3799. runtimeRequirements.add(RuntimeGlobals.exports);
  3800. return `${RuntimeGlobals.makeNamespaceObject}(${exportsArgument});\n`;
  3801. }
  3802. /**
  3803. * Reserves a name only the deferred pass can spell, as a stand-in that looks like a
  3804. * relative specifier so the code around it needs no special case. It carries what it
  3805. * resolves to rather than an index into per-build state — a module restored from the
  3806. * persistent cache is never generated again.
  3807. * @param {SpecifierPart[]} parts what the stand-in resolves to, in order
  3808. * @returns {string} the stand-in to emit
  3809. */
  3810. _reserveAnalyzableSpecifier(parts) {
  3811. return `./@@webpackAnalyzableChunk:${Buffer.from(JSON.stringify(parts))
  3812. .toString("base64")
  3813. .replace(/\+/g, "-")
  3814. .replace(/\//g, "_")
  3815. .replace(/[=]/g, "")}@@`;
  3816. }
  3817. /**
  3818. * Whether text still carries a compilation-hash stand-in, so nothing may be resolved
  3819. * against it here — the fill would land inside an already-resolved result.
  3820. * @param {string} value text that may carry one
  3821. * @returns {boolean} true when one is present
  3822. */
  3823. _hasReservedFullHash(value) {
  3824. return value.includes(FULL_HASH_TOKEN_PREFIX);
  3825. }
  3826. /**
  3827. * `getPath` data that leaves every compilation-hash placeholder as a stand-in while
  3828. * the rest of the name resolves.
  3829. * @returns {typeof DEFERRED_FULL_HASH_PATH_DATA} the path data
  3830. */
  3831. _deferredFullHashPathData() {
  3832. return DEFERRED_FULL_HASH_PATH_DATA;
  3833. }
  3834. /**
  3835. * Fills in the names reserved during code generation, once the hashes they are built
  3836. * from exist: a chunk's own filename, and the compilation hash inside any other
  3837. * emitted asset's. Replaces in place so the asset keeps its mappings, and runs before
  3838. * anything reads it — `RealContentHashPlugin` still repairs each rewritten chunk's own
  3839. * name later. Registered wherever `output.module` is read, since nothing reserves a
  3840. * stand-in without it — a reservation cannot arrange this itself, as a module restored
  3841. * from the cache carries one without being generated again.
  3842. * @param {Compiler} compiler the compiler
  3843. * @returns {void}
  3844. */
  3845. static fillReservedNames(compiler) {
  3846. compiler.hooks.compilation.tap(PASS_NAME, (compilation) => {
  3847. const cache = compilation.getCache(PASS_NAME);
  3848. // Code generation is over, so what carries the compilation hash is settled and
  3849. // each such chunk can be moved into the round that follows that hash.
  3850. compilation.hooks.beforeHash.tap(PASS_NAME, () => {
  3851. compilation.runtimeTemplate._markChunksSettlingLate();
  3852. });
  3853. // Reaches both `chunk.hash` and `chunk.contentHash.javascript`, the two a
  3854. // filled-in name can leave behind.
  3855. JavascriptModulesPlugin.getCompilationHooks(compilation).chunkHash.tap(
  3856. PASS_NAME,
  3857. (chunk, hash) => {
  3858. compilation.runtimeTemplate._foldAnalyzableNames(chunk, hash);
  3859. }
  3860. );
  3861. // Nothing past hashing reads what the fold cached, and it holds a name per
  3862. // edge between chunks, so it is dropped rather than kept until seal.
  3863. compilation.hooks.afterHash.tap(PASS_NAME, () => {
  3864. compilation.runtimeTemplate._releaseAnalyzableNameCaches();
  3865. });
  3866. compilation.hooks.processAssets.tapPromise(
  3867. {
  3868. name: PASS_NAME,
  3869. // Before source maps are written and before a minifier runs: both read
  3870. // the asset, and a stand-in is a different length than what replaces it.
  3871. // Every hash it reads is already settled — `createHash` runs ahead of
  3872. // every `processAssets` stage — and `RealContentHashPlugin` still repairs
  3873. // the names afterwards.
  3874. stage: getCompilation().PROCESS_ASSETS_STAGE_DERIVED
  3875. },
  3876. async () => {
  3877. const { outputOptions } = compilation;
  3878. const fullHash = compilation.hash;
  3879. /** @type {Map<string, Chunk> | undefined} */
  3880. let chunksById;
  3881. /** @type {Map<string, Chunk> | undefined} */
  3882. let chunkByAsset;
  3883. /**
  3884. * @param {string} name an emitted asset's name
  3885. * @returns {Chunk | undefined} the chunk it was emitted for
  3886. */
  3887. const chunkOf = (name) => {
  3888. if (chunkByAsset === undefined) {
  3889. chunkByAsset = new Map();
  3890. for (const chunk of compilation.chunks) {
  3891. for (const file of chunk.files) chunkByAsset.set(file, chunk);
  3892. }
  3893. }
  3894. return chunkByAsset.get(name);
  3895. };
  3896. /**
  3897. * @param {string} value text that may carry compilation-hash stand-ins
  3898. * @returns {string} the text with each of them filled in
  3899. */
  3900. const fillFullHash = (value) => {
  3901. if (fullHash === undefined) return value;
  3902. FULL_HASH_TOKEN_REGEXP.lastIndex = 0;
  3903. return value.replace(FULL_HASH_TOKEN_REGEXP, (_match, length) =>
  3904. length === undefined
  3905. ? fullHash
  3906. : fullHash.slice(0, Number(length))
  3907. );
  3908. };
  3909. /**
  3910. * @param {string} payload the encoded half of a stand-in
  3911. * @param {string} assetName name of the asset the stand-in sits in
  3912. * @returns {string | null} the specifier, or `null` if unresolvable
  3913. */
  3914. const resolve = (payload, assetName) => {
  3915. const parts = RuntimeTemplate._readAnalyzableSpecifier(payload);
  3916. if (parts === null) return null;
  3917. /** @type {string | undefined} */
  3918. let base;
  3919. let specifier = "";
  3920. for (const [kind, value] of parts) {
  3921. if (kind === "base") {
  3922. base = /** @type {string} */ (value);
  3923. } else if (kind === "literal") {
  3924. specifier += value;
  3925. } else if (kind === "undo") {
  3926. specifier += getUndoPath(
  3927. assetName,
  3928. /** @type {string} */ (outputOptions.path),
  3929. true
  3930. );
  3931. } else if (kind === "template") {
  3932. specifier += compilation.getPath(
  3933. /** @type {string} */ (value),
  3934. {}
  3935. );
  3936. } else if (kind === "publicPath") {
  3937. specifier += compilation.getPath(
  3938. outputOptions.publicPath || "",
  3939. {}
  3940. );
  3941. } else if (kind === "unserved") {
  3942. const holder = chunkOf(assetName);
  3943. if (holder === undefined) return null;
  3944. // Only an asset the host fetched needs the public path put in
  3945. // front. One the loader fetched already sits under it, and the
  3946. // `../` ahead of this walked back to exactly there.
  3947. if (
  3948. compilation.runtimeTemplate._chunkPlacement(holder).loaded ===
  3949. false
  3950. ) {
  3951. const path = compilation.getPath(
  3952. outputOptions.publicPath || "",
  3953. {}
  3954. );
  3955. // The `../` already reached the root this is read from.
  3956. specifier += path.startsWith("./") ? path.slice(2) : path;
  3957. }
  3958. } else {
  3959. const naming = CHUNK_ASSET_NAMING_BY_STAND_IN.get(kind);
  3960. // Nothing reserves a kind this pass cannot spell, so one arriving
  3961. // here was written by something else and names no asset of ours.
  3962. if (naming === undefined) return null;
  3963. if (chunksById === undefined) {
  3964. chunksById = new Map();
  3965. for (const chunk of compilation.chunks) {
  3966. if (chunk.id !== null) {
  3967. chunksById.set(String(chunk.id), chunk);
  3968. }
  3969. }
  3970. }
  3971. const chunk = chunksById.get(String(value));
  3972. if (chunk === undefined) return null;
  3973. specifier += compilation.getPath(
  3974. naming.template(chunk, outputOptions),
  3975. // Matches what names the asset, or a placeholder resolved here would
  3976. // not be the one on disk.
  3977. {
  3978. chunk,
  3979. runtime: chunk.runtime,
  3980. contentHashType: naming.contentHashType
  3981. }
  3982. );
  3983. }
  3984. }
  3985. if (base !== undefined) {
  3986. // An entry base replaces the output root, so the rest is read against it
  3987. // here exactly as the runtime would have read it against `.b`.
  3988. try {
  3989. return new URL(fillFullHash(specifier), base).href;
  3990. } catch (_error) {
  3991. return null;
  3992. }
  3993. }
  3994. // A bare specifier is a package name, so make it explicitly relative the way
  3995. // the chunk loader does. A literal part may still carry a stand-in of its own,
  3996. // so finish those here rather than scanning again.
  3997. return fillFullHash(
  3998. /^(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(specifier)
  3999. ? specifier
  4000. : `./${specifier}`
  4001. );
  4002. };
  4003. /** @type {{ name: string, source: Source, replacements: Replacement[] }[]} */
  4004. const tasks = [];
  4005. for (const name of Object.keys(compilation.assets)) {
  4006. const source = compilation.assets[name];
  4007. const content = source.source();
  4008. if (typeof content !== "string") continue;
  4009. ANALYZABLE_TOKEN_REGEXP.lastIndex = 0;
  4010. FULL_HASH_TOKEN_REGEXP.lastIndex = 0;
  4011. const hasChunkToken = ANALYZABLE_TOKEN_REGEXP.test(content);
  4012. const hasFullHashToken =
  4013. fullHash !== undefined && FULL_HASH_TOKEN_REGEXP.test(content);
  4014. if (!hasChunkToken && !hasFullHashToken) continue;
  4015. /** @type {Replacement[]} */
  4016. const replacements = [];
  4017. /**
  4018. * @param {RegExp} pattern what to look for
  4019. * @param {(match: string, group: string) => string | null} fill what to put there
  4020. * @returns {void}
  4021. */
  4022. const collect = (pattern, fill) => {
  4023. // Its own instance: `fill` may run the shared one over what it
  4024. // returns, and a `replace` there would rewind this scan.
  4025. const regexp = new RegExp(pattern.source, pattern.flags);
  4026. /** @type {RegExpExecArray | null} */
  4027. let match;
  4028. while ((match = regexp.exec(content)) !== null) {
  4029. const value = fill(match[0], match[1]);
  4030. if (value === null) continue;
  4031. replacements.push([
  4032. match.index,
  4033. match.index + match[0].length - 1,
  4034. value
  4035. ]);
  4036. }
  4037. };
  4038. if (hasChunkToken) {
  4039. collect(ANALYZABLE_TOKEN_REGEXP, (_match, payload) =>
  4040. resolve(payload, name)
  4041. );
  4042. }
  4043. if (hasFullHashToken) {
  4044. collect(FULL_HASH_TOKEN_REGEXP, (match) => fillFullHash(match));
  4045. }
  4046. if (replacements.length === 0) continue;
  4047. tasks.push({ name, source, replacements });
  4048. }
  4049. if (tasks.length === 0) return;
  4050. await Promise.all(
  4051. tasks.map(async ({ name, source, replacements }) => {
  4052. const replaced = await cache.providePromise(
  4053. name,
  4054. cache.mergeEtags(
  4055. cache.getLazyHashedEtag(source),
  4056. JSON.stringify(replacements)
  4057. ),
  4058. () => {
  4059. const replacedSource = new ReplaceSource(source);
  4060. for (const [start, end, value] of replacements) {
  4061. replacedSource.replace(start, end, value);
  4062. }
  4063. return new CachedSource(replacedSource);
  4064. }
  4065. );
  4066. compilation.updateAsset(name, replaced);
  4067. })
  4068. );
  4069. }
  4070. );
  4071. });
  4072. }
  4073. /**
  4074. * Reads back what `_reserveAnalyzableSpecifier` wrote. Source of our own can spell the
  4075. * token too, so nothing about a payload is given and every shape it does not produce
  4076. * is refused rather than reached for.
  4077. * @param {string} payload the encoded half of a stand-in
  4078. * @returns {SpecifierPart[] | null} what it resolves to, or `null` if unreadable
  4079. */
  4080. static _readAnalyzableSpecifier(payload) {
  4081. /** @type {EXPECTED_ANY} */
  4082. let decoded;
  4083. try {
  4084. decoded = JSON.parse(
  4085. Buffer.from(
  4086. payload.replace(/-/g, "+").replace(/_/g, "/"),
  4087. "base64"
  4088. ).toString()
  4089. );
  4090. } catch (_error) {
  4091. return null;
  4092. }
  4093. if (!Array.isArray(decoded)) return null;
  4094. for (const part of decoded) {
  4095. if (!Array.isArray(part) || part.length !== 2) return null;
  4096. if (!SPECIFIER_PART_KINDS.has(part[0])) return null;
  4097. // Only a chunk id may be a number; the rest are read as text.
  4098. if (
  4099. typeof part[1] !== "string" &&
  4100. (!CHUNK_SPECIFIER_PART_KINDS.has(part[0]) ||
  4101. typeof part[1] !== "number")
  4102. ) {
  4103. return null;
  4104. }
  4105. }
  4106. return decoded;
  4107. }
  4108. }
  4109. module.exports = RuntimeTemplate;