ExternalModule.js 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { OriginalSource, RawSource } = require("webpack-sources");
  7. const ConcatenationScope = require("./ConcatenationScope");
  8. const EnvironmentNotSupportAsyncWarning = require("./EnvironmentNotSupportAsyncWarning");
  9. const { UsageState } = require("./ExportsInfo");
  10. const InitFragment = require("./InitFragment");
  11. const Module = require("./Module");
  12. const {
  13. CSS_IMPORT_TYPES,
  14. CSS_URL_TYPES,
  15. JAVASCRIPT_TYPE,
  16. JAVASCRIPT_TYPES
  17. } = require("./ModuleSourceTypeConstants");
  18. const { JAVASCRIPT_MODULE_TYPE_DYNAMIC } = require("./ModuleTypeConstants");
  19. const RuntimeGlobals = require("./RuntimeGlobals");
  20. const Template = require("./Template");
  21. const { DEFAULTS } = require("./config/defaults");
  22. const StaticExportsDependency = require("./dependencies/StaticExportsDependency");
  23. const createHash = require("./util/createHash");
  24. const extractUrlAndGlobal = require("./util/extractUrlAndGlobal");
  25. const makeSerializable = require("./util/makeSerializable");
  26. const propertyAccess = require("./util/propertyAccess");
  27. const { register } = require("./util/serialization");
  28. /** @typedef {import("webpack-sources").Source} Source */
  29. /** @typedef {import("../declarations/WebpackOptions").ExternalsType} ExternalsType */
  30. /** @typedef {import("../declarations/WebpackOptions").HashFunction} HashFunction */
  31. /** @typedef {import("./config/defaults").WebpackOptionsNormalizedWithDefaults} WebpackOptions */
  32. /** @typedef {import("./Chunk")} Chunk */
  33. /** @typedef {import("./ChunkGraph")} ChunkGraph */
  34. /** @typedef {import("./Compilation")} Compilation */
  35. /** @typedef {import("./Compilation").UnsafeCacheData} UnsafeCacheData */
  36. /** @typedef {import("./Dependency").UpdateHashContext} UpdateHashContext */
  37. /** @typedef {import("./ExportsInfo")} ExportsInfo */
  38. /** @typedef {import("./Generator").GenerateContext} GenerateContext */
  39. /** @typedef {import("./Generator").SourceTypes} SourceTypes */
  40. /** @typedef {import("./Module").ModuleId} ModuleId */
  41. /** @typedef {import("./Module").BuildCallback} BuildCallback */
  42. /** @typedef {import("./Module").BuildInfo} BuildInfo */
  43. /** @typedef {import("./Module").CodeGenerationContext} CodeGenerationContext */
  44. /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
  45. /** @typedef {import("./Module").CodeGenerationResultData} CodeGenerationResultData */
  46. /** @typedef {import("./Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
  47. /** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */
  48. /** @typedef {import("./Module").LibIdent} LibIdent */
  49. /** @typedef {import("./Module").NeedBuildCallback} NeedBuildCallback */
  50. /** @typedef {import("./Module").NeedBuildContext} NeedBuildContext */
  51. /** @typedef {import("./Module").RuntimeRequirements} RuntimeRequirements */
  52. /** @typedef {import("./Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
  53. /** @typedef {import("./Module").Sources} Sources */
  54. /** @typedef {import("./ModuleGraph")} ModuleGraph */
  55. /** @typedef {import("./NormalModuleFactory")} NormalModuleFactory */
  56. /** @typedef {import("./RequestShortener")} RequestShortener */
  57. /** @typedef {import("./ResolverFactory").ResolverWithOptions} ResolverWithOptions */
  58. /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
  59. /** @typedef {import("./javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
  60. /** @typedef {import("./javascript/JavascriptParser").ImportAttributes} ImportAttributes */
  61. /** @typedef {import("./serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
  62. /** @typedef {import("./serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
  63. /** @typedef {import("./util/Hash")} Hash */
  64. /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
  65. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  66. /** @typedef {{ attributes?: ImportAttributes, externalType: "import" | "module" | undefined }} ImportDependencyMeta */
  67. /** @typedef {{ layer?: string, supports?: string, media?: string }} CssImportDependencyMeta */
  68. /** @typedef {{ sourceType: "css-url" }} AssetDependencyMeta */
  69. /** @typedef {ImportDependencyMeta | CssImportDependencyMeta | AssetDependencyMeta} DependencyMeta */
  70. /**
  71. * @typedef {object} SourceData
  72. * @property {boolean=} iife
  73. * @property {string=} init
  74. * @property {string} expression
  75. * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
  76. * @property {ReadOnlyRuntimeRequirements=} runtimeRequirements
  77. * @property {[string, string][]=} specifiers
  78. */
  79. /** @typedef {true | [string, string][]} Imported */
  80. /** @type {RuntimeRequirements} */
  81. const RUNTIME_REQUIREMENTS = new Set([RuntimeGlobals.module]);
  82. /** @type {RuntimeRequirements} */
  83. const RUNTIME_REQUIREMENTS_FOR_SCRIPT = new Set([RuntimeGlobals.loadScript]);
  84. /** @type {RuntimeRequirements} */
  85. const RUNTIME_REQUIREMENTS_FOR_MODULE = new Set([
  86. RuntimeGlobals.definePropertyGetters
  87. ]);
  88. /** @type {RuntimeRequirements} */
  89. const EMPTY_RUNTIME_REQUIREMENTS = new Set();
  90. /**
  91. * @param {string | string[]} variableName the variable name or path
  92. * @param {string} type the module system
  93. * @returns {SourceData} the generated source
  94. */
  95. const getSourceForGlobalVariableExternal = (variableName, type) => {
  96. if (!Array.isArray(variableName)) {
  97. // make it an array as the look up works the same basically
  98. variableName = [variableName];
  99. }
  100. // needed for e.g. window["some"]["thing"]
  101. const objectLookup = variableName
  102. .map((r) => `[${JSON.stringify(r)}]`)
  103. .join("");
  104. return {
  105. iife: type === "this",
  106. expression: `${type}${objectLookup}`
  107. };
  108. };
  109. /** @typedef {string | string[]} ModuleAndSpecifiers */
  110. /**
  111. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  112. * @returns {SourceData} the generated source
  113. */
  114. const getSourceForCommonJsExternal = (moduleAndSpecifiers) => {
  115. if (!Array.isArray(moduleAndSpecifiers)) {
  116. return {
  117. expression: `require(${JSON.stringify(moduleAndSpecifiers)})`
  118. };
  119. }
  120. const moduleName = moduleAndSpecifiers[0];
  121. return {
  122. expression: `require(${JSON.stringify(moduleName)})${propertyAccess(
  123. moduleAndSpecifiers,
  124. 1
  125. )}`
  126. };
  127. };
  128. /**
  129. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  130. * @returns {InitFragment<ChunkRenderContext>} code
  131. */
  132. const getExternalModuleNodeCommonjsInitFragment = (runtimeTemplate) => {
  133. const importMetaName = runtimeTemplate.outputOptions.importMetaName;
  134. return new InitFragment(
  135. `import { createRequire as __WEBPACK_EXTERNAL_createRequire } from ${runtimeTemplate.renderNodePrefixForCoreModule(
  136. "module"
  137. )};\n${runtimeTemplate.renderConst()} __WEBPACK_EXTERNAL_createRequire_require = __WEBPACK_EXTERNAL_createRequire(${importMetaName}.url);\n`,
  138. InitFragment.STAGE_HARMONY_IMPORTS,
  139. 0,
  140. "external module node-commonjs"
  141. );
  142. };
  143. /**
  144. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  145. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  146. * @returns {SourceData} the generated source
  147. */
  148. const getSourceForCommonJsExternalInNodeModule = (
  149. moduleAndSpecifiers,
  150. runtimeTemplate
  151. ) => {
  152. const chunkInitFragments = [
  153. getExternalModuleNodeCommonjsInitFragment(runtimeTemplate)
  154. ];
  155. if (!Array.isArray(moduleAndSpecifiers)) {
  156. return {
  157. chunkInitFragments,
  158. expression: `__WEBPACK_EXTERNAL_createRequire_require(${JSON.stringify(
  159. moduleAndSpecifiers
  160. )})`
  161. };
  162. }
  163. const moduleName = moduleAndSpecifiers[0];
  164. return {
  165. chunkInitFragments,
  166. expression: `__WEBPACK_EXTERNAL_createRequire_require(${JSON.stringify(
  167. moduleName
  168. )})${propertyAccess(moduleAndSpecifiers, 1)}`
  169. };
  170. };
  171. /**
  172. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  173. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  174. * @param {ImportDependencyMeta=} dependencyMeta the dependency meta
  175. * @returns {SourceData} the generated source
  176. */
  177. const getSourceForImportExternal = (
  178. moduleAndSpecifiers,
  179. runtimeTemplate,
  180. dependencyMeta
  181. ) => {
  182. const importName = runtimeTemplate.outputOptions.importFunctionName;
  183. if (
  184. !runtimeTemplate.supportsDynamicImport() &&
  185. (importName === "import" || importName === "module-import")
  186. ) {
  187. throw new Error(
  188. "The target environment doesn't support 'import()' so it's not possible to use external type 'import'"
  189. );
  190. }
  191. const attributes =
  192. dependencyMeta && dependencyMeta.attributes
  193. ? dependencyMeta.attributes._isLegacyAssert
  194. ? `, { assert: ${JSON.stringify(
  195. dependencyMeta.attributes,
  196. importAssertionReplacer
  197. )} }`
  198. : `, { with: ${JSON.stringify(dependencyMeta.attributes)} }`
  199. : "";
  200. if (!Array.isArray(moduleAndSpecifiers)) {
  201. return {
  202. expression: `${importName}(${JSON.stringify(
  203. moduleAndSpecifiers
  204. )}${attributes});`
  205. };
  206. }
  207. if (moduleAndSpecifiers.length === 1) {
  208. return {
  209. expression: `${importName}(${JSON.stringify(
  210. moduleAndSpecifiers[0]
  211. )}${attributes});`
  212. };
  213. }
  214. const moduleName = moduleAndSpecifiers[0];
  215. return {
  216. expression: `${importName}(${JSON.stringify(
  217. moduleName
  218. )}${attributes}).then(${runtimeTemplate.returningFunction(
  219. `module${propertyAccess(moduleAndSpecifiers, 1)}`,
  220. "module"
  221. )});`
  222. };
  223. };
  224. /**
  225. * @param {string} key key
  226. * @param {ImportAttributes | string | boolean | undefined} value value
  227. * @returns {ImportAttributes | string | boolean | undefined} replaced value
  228. */
  229. const importAssertionReplacer = (key, value) => {
  230. if (key === "_isLegacyAssert") {
  231. return;
  232. }
  233. return value;
  234. };
  235. /**
  236. * @extends {InitFragment<GenerateContext>}
  237. */
  238. class ModuleExternalInitFragment extends InitFragment {
  239. /**
  240. * @param {string} request import source
  241. * @param {Imported} imported the imported specifiers
  242. * @param {string=} ident recomputed ident
  243. * @param {ImportDependencyMeta=} dependencyMeta the dependency meta
  244. * @param {HashFunction=} hashFunction the hash function to use
  245. */
  246. constructor(
  247. request,
  248. imported,
  249. ident,
  250. dependencyMeta,
  251. hashFunction = DEFAULTS.HASH_FUNCTION
  252. ) {
  253. if (ident === undefined) {
  254. ident = Template.toIdentifier(request);
  255. if (ident !== request) {
  256. ident += `_${createHash(hashFunction)
  257. .update(request)
  258. .digest("hex")
  259. .slice(0, 8)}`;
  260. }
  261. }
  262. super(
  263. "",
  264. InitFragment.STAGE_HARMONY_IMPORTS,
  265. 0,
  266. `external module import ${ident} ${imported === true ? imported : imported.join(" ")}`
  267. );
  268. this._ident = ident;
  269. this._request = request;
  270. this._dependencyMeta = dependencyMeta;
  271. this._identifier = this.buildIdentifier(ident);
  272. this._imported = this.buildImported(imported);
  273. }
  274. /**
  275. * @returns {Imported} imported
  276. */
  277. getImported() {
  278. return this._imported;
  279. }
  280. /**
  281. * @param {Imported} imported imported
  282. */
  283. setImported(imported) {
  284. this._imported = imported;
  285. }
  286. /**
  287. * @param {GenerateContext} context context
  288. * @returns {string | Source | undefined} the source code that will be included as initialization code
  289. */
  290. getContent(context) {
  291. const {
  292. _dependencyMeta: dependencyMeta,
  293. _imported: imported,
  294. _request: request,
  295. _identifier: identifier
  296. } = this;
  297. const attributes =
  298. dependencyMeta && dependencyMeta.attributes
  299. ? dependencyMeta.attributes._isLegacyAssert &&
  300. dependencyMeta.attributes._isLegacyAssert
  301. ? ` assert ${JSON.stringify(
  302. dependencyMeta.attributes,
  303. importAssertionReplacer
  304. )}`
  305. : ` with ${JSON.stringify(dependencyMeta.attributes)}`
  306. : "";
  307. let content = "";
  308. if (imported === true) {
  309. // namespace
  310. content = `import * as ${identifier} from ${JSON.stringify(request)}${
  311. attributes
  312. };\n`;
  313. } else if (imported.length === 0) {
  314. // just import, no use
  315. content = `import ${JSON.stringify(request)}${attributes};\n`;
  316. } else {
  317. content = `import { ${imported
  318. .map(([name, finalName]) => {
  319. if (name !== finalName) {
  320. return `${name} as ${finalName}`;
  321. }
  322. return name;
  323. })
  324. .join(", ")} } from ${JSON.stringify(request)}${attributes};\n`;
  325. }
  326. return content;
  327. }
  328. getNamespaceIdentifier() {
  329. return this._identifier;
  330. }
  331. /**
  332. * @param {string} ident ident
  333. * @returns {string} identifier
  334. */
  335. buildIdentifier(ident) {
  336. return `__WEBPACK_EXTERNAL_MODULE_${ident}__`;
  337. }
  338. /**
  339. * @param {Imported} imported imported
  340. * @returns {Imported} normalized imported
  341. */
  342. buildImported(imported) {
  343. if (Array.isArray(imported)) {
  344. return imported.map(([name]) => {
  345. const ident = `${this._ident}_${name}`;
  346. return [name, this.buildIdentifier(ident)];
  347. });
  348. }
  349. return imported;
  350. }
  351. }
  352. register(
  353. ModuleExternalInitFragment,
  354. "webpack/lib/ExternalModule",
  355. "ModuleExternalInitFragment",
  356. {
  357. serialize(obj, { write }) {
  358. write(obj._request);
  359. write(obj._imported);
  360. write(obj._ident);
  361. write(obj._dependencyMeta);
  362. },
  363. deserialize({ read }) {
  364. return new ModuleExternalInitFragment(read(), read(), read(), read());
  365. }
  366. }
  367. );
  368. /**
  369. * @param {string} input input
  370. * @param {ExportsInfo} exportsInfo the exports info
  371. * @param {RuntimeSpec=} runtime the runtime
  372. * @param {RuntimeTemplate=} runtimeTemplate the runtime template
  373. * @returns {string | undefined} the module remapping
  374. */
  375. const generateModuleRemapping = (
  376. input,
  377. exportsInfo,
  378. runtime,
  379. runtimeTemplate
  380. ) => {
  381. if (exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused) {
  382. /** @type {string[]} */
  383. const properties = [];
  384. for (const exportInfo of exportsInfo.orderedExports) {
  385. const used = exportInfo.getUsedName(exportInfo.name, runtime);
  386. if (!used) continue;
  387. const nestedInfo = exportInfo.getNestedExportsInfo();
  388. if (nestedInfo) {
  389. const nestedExpr = generateModuleRemapping(
  390. `${input}${propertyAccess([exportInfo.name])}`,
  391. nestedInfo
  392. );
  393. if (nestedExpr) {
  394. properties.push(`[${JSON.stringify(used)}]: y(${nestedExpr})`);
  395. continue;
  396. }
  397. }
  398. properties.push(
  399. `[${JSON.stringify(used)}]: ${
  400. /** @type {RuntimeTemplate} */ (runtimeTemplate).returningFunction(
  401. `${input}${propertyAccess([exportInfo.name])}`
  402. )
  403. }`
  404. );
  405. }
  406. return `x({ ${properties.join(", ")} })`;
  407. }
  408. };
  409. /**
  410. * @param {ModuleAndSpecifiers} moduleAndSpecifiers the module request
  411. * @param {ExportsInfo} exportsInfo exports info of this module
  412. * @param {RuntimeSpec} runtime the runtime
  413. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  414. * @param {ImportDependencyMeta} dependencyMeta the dependency meta
  415. * @param {ConcatenationScope=} concatenationScope concatenationScope
  416. * @returns {SourceData} the generated source
  417. */
  418. const getSourceForModuleExternal = (
  419. moduleAndSpecifiers,
  420. exportsInfo,
  421. runtime,
  422. runtimeTemplate,
  423. dependencyMeta,
  424. concatenationScope
  425. ) => {
  426. /** @type {Imported} */
  427. let imported = true;
  428. if (concatenationScope) {
  429. const usedExports = exportsInfo.getUsedExports(runtime);
  430. switch (usedExports) {
  431. case true:
  432. case null:
  433. // unknown exports
  434. imported = true;
  435. break;
  436. case false:
  437. // no used exports
  438. imported = [];
  439. break;
  440. default:
  441. imported = [...usedExports.entries()];
  442. }
  443. }
  444. if (!Array.isArray(moduleAndSpecifiers)) {
  445. moduleAndSpecifiers = [moduleAndSpecifiers];
  446. }
  447. // Return to `namespace` when the external request includes a specific export
  448. if (moduleAndSpecifiers.length > 1) {
  449. imported = true;
  450. }
  451. const initFragment = new ModuleExternalInitFragment(
  452. moduleAndSpecifiers[0],
  453. imported,
  454. undefined,
  455. dependencyMeta,
  456. runtimeTemplate.outputOptions.hashFunction
  457. );
  458. const normalizedImported = initFragment.getImported();
  459. const baseAccess = `${initFragment.getNamespaceIdentifier()}${propertyAccess(
  460. moduleAndSpecifiers,
  461. 1
  462. )}`;
  463. let expression = baseAccess;
  464. const useNamespace = imported === true;
  465. /** @type {undefined | string} */
  466. let moduleRemapping;
  467. if (useNamespace) {
  468. moduleRemapping = generateModuleRemapping(
  469. baseAccess,
  470. exportsInfo,
  471. runtime,
  472. runtimeTemplate
  473. );
  474. expression = moduleRemapping || baseAccess;
  475. }
  476. return {
  477. expression,
  478. init: moduleRemapping
  479. ? `var x = ${runtimeTemplate.basicFunction(
  480. "y",
  481. `var x = {}; ${RuntimeGlobals.definePropertyGetters}(x, y); return x`
  482. )} \nvar y = ${runtimeTemplate.returningFunction(
  483. runtimeTemplate.returningFunction("x"),
  484. "x"
  485. )}`
  486. : undefined,
  487. specifiers: normalizedImported === true ? undefined : normalizedImported,
  488. runtimeRequirements: moduleRemapping
  489. ? RUNTIME_REQUIREMENTS_FOR_MODULE
  490. : undefined,
  491. chunkInitFragments: [
  492. /** @type {InitFragment<EXPECTED_ANY>} */ (initFragment)
  493. ]
  494. };
  495. };
  496. /**
  497. * @param {string | string[]} urlAndGlobal the script request
  498. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  499. * @returns {SourceData} the generated source
  500. */
  501. const getSourceForScriptExternal = (urlAndGlobal, runtimeTemplate) => {
  502. if (typeof urlAndGlobal === "string") {
  503. urlAndGlobal = extractUrlAndGlobal(urlAndGlobal);
  504. }
  505. const url = urlAndGlobal[0];
  506. const globalName = urlAndGlobal[1];
  507. return {
  508. init: "var __webpack_error__ = new Error();",
  509. expression: `new Promise(${runtimeTemplate.basicFunction(
  510. "resolve, reject",
  511. [
  512. `if(typeof ${globalName} !== "undefined") return resolve();`,
  513. `${RuntimeGlobals.loadScript}(${JSON.stringify(
  514. url
  515. )}, ${runtimeTemplate.basicFunction("event", [
  516. `if(typeof ${globalName} !== "undefined") return resolve();`,
  517. "var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
  518. "var realSrc = event && event.target && event.target.src;",
  519. "__webpack_error__.message = 'Loading script failed.\\n(' + errorType + ': ' + realSrc + ')';",
  520. "__webpack_error__.name = 'ScriptExternalLoadError';",
  521. "__webpack_error__.type = errorType;",
  522. "__webpack_error__.request = realSrc;",
  523. "reject(__webpack_error__);"
  524. ])}, ${JSON.stringify(globalName)});`
  525. ]
  526. )}).then(${runtimeTemplate.returningFunction(
  527. `${globalName}${propertyAccess(urlAndGlobal, 2)}`
  528. )})`,
  529. runtimeRequirements: RUNTIME_REQUIREMENTS_FOR_SCRIPT
  530. };
  531. };
  532. /**
  533. * @param {string} variableName the variable name to check
  534. * @param {string} request the request path
  535. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  536. * @returns {string} the generated source
  537. */
  538. const checkExternalVariable = (variableName, request, runtimeTemplate) =>
  539. `if(typeof ${variableName} === 'undefined') { ${runtimeTemplate.throwMissingModuleErrorBlock(
  540. { request }
  541. )} }\n`;
  542. /**
  543. * @param {ModuleId | string} id the module id
  544. * @param {boolean} optional true, if the module is optional
  545. * @param {string | string[]} request the request path
  546. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  547. * @returns {SourceData} the generated source
  548. */
  549. const getSourceForAmdOrUmdExternal = (
  550. id,
  551. optional,
  552. request,
  553. runtimeTemplate
  554. ) => {
  555. const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
  556. `${id}`
  557. )}__`;
  558. return {
  559. init: optional
  560. ? checkExternalVariable(
  561. externalVariable,
  562. Array.isArray(request) ? request.join(".") : request,
  563. runtimeTemplate
  564. )
  565. : undefined,
  566. expression: externalVariable
  567. };
  568. };
  569. /**
  570. * @param {boolean} optional true, if the module is optional
  571. * @param {string | string[]} request the request path
  572. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  573. * @returns {SourceData} the generated source
  574. */
  575. const getSourceForDefaultCase = (optional, request, runtimeTemplate) => {
  576. if (!Array.isArray(request)) {
  577. // make it an array as the look up works the same basically
  578. request = [request];
  579. }
  580. const variableName = request[0];
  581. const objectLookup = propertyAccess(request, 1);
  582. return {
  583. init: optional
  584. ? checkExternalVariable(variableName, request.join("."), runtimeTemplate)
  585. : undefined,
  586. expression: `${variableName}${objectLookup}`
  587. };
  588. };
  589. /** @typedef {Record<string, string | string[]>} RequestRecord */
  590. /** @typedef {string | string[] | RequestRecord} ExternalModuleRequest */
  591. class ExternalModule extends Module {
  592. /**
  593. * @param {ExternalModuleRequest} request request
  594. * @param {ExternalsType} type type
  595. * @param {string} userRequest user request
  596. * @param {DependencyMeta=} dependencyMeta dependency meta
  597. */
  598. constructor(request, type, userRequest, dependencyMeta) {
  599. super(JAVASCRIPT_MODULE_TYPE_DYNAMIC, null);
  600. // Info from Factory
  601. /** @type {ExternalModuleRequest} */
  602. this.request = request;
  603. /** @type {ExternalsType} */
  604. this.externalType = type;
  605. /** @type {string} */
  606. this.userRequest = userRequest;
  607. /** @type {DependencyMeta=} */
  608. this.dependencyMeta = dependencyMeta;
  609. }
  610. /**
  611. * @returns {SourceTypes} types available (do not mutate)
  612. */
  613. getSourceTypes() {
  614. if (
  615. this.externalType === "asset" &&
  616. this.dependencyMeta &&
  617. /** @type {AssetDependencyMeta} */
  618. (this.dependencyMeta).sourceType === "css-url"
  619. ) {
  620. return CSS_URL_TYPES;
  621. } else if (this.externalType === "css-import") {
  622. return CSS_IMPORT_TYPES;
  623. }
  624. return JAVASCRIPT_TYPES;
  625. }
  626. /**
  627. * @param {LibIdentOptions} options options
  628. * @returns {LibIdent | null} an identifier for library inclusion
  629. */
  630. libIdent(options) {
  631. return this.userRequest;
  632. }
  633. /**
  634. * @param {Chunk} chunk the chunk which condition should be checked
  635. * @param {Compilation} compilation the compilation
  636. * @returns {boolean} true, if the chunk is ok for the module
  637. */
  638. chunkCondition(chunk, { chunkGraph }) {
  639. return this.externalType === "css-import"
  640. ? true
  641. : chunkGraph.getNumberOfEntryModules(chunk) > 0;
  642. }
  643. /**
  644. * @returns {string} a unique identifier of the module
  645. */
  646. identifier() {
  647. return `external ${this._resolveExternalType(this.externalType)} ${JSON.stringify(this.request)}`;
  648. }
  649. /**
  650. * @param {RequestShortener} requestShortener the request shortener
  651. * @returns {string} a user readable identifier of the module
  652. */
  653. readableIdentifier(requestShortener) {
  654. return `external ${JSON.stringify(this.request)}`;
  655. }
  656. /**
  657. * @param {NeedBuildContext} context context info
  658. * @param {NeedBuildCallback} callback callback function, returns true, if the module needs a rebuild
  659. * @returns {void}
  660. */
  661. needBuild(context, callback) {
  662. return callback(null, !this.buildMeta);
  663. }
  664. /**
  665. * @param {WebpackOptions} options webpack options
  666. * @param {Compilation} compilation the compilation
  667. * @param {ResolverWithOptions} resolver the resolver
  668. * @param {InputFileSystem} fs the file system
  669. * @param {BuildCallback} callback callback function
  670. * @returns {void}
  671. */
  672. build(options, compilation, resolver, fs, callback) {
  673. this.buildMeta = {
  674. async: false,
  675. exportsType: undefined
  676. };
  677. this.buildInfo = {
  678. strict: true,
  679. topLevelDeclarations: new Set(),
  680. javascriptModule: compilation.outputOptions.module
  681. };
  682. const { request, externalType } = this._getRequestAndExternalType();
  683. this.buildMeta.exportsType = "dynamic";
  684. let canMangle = false;
  685. this.clearDependenciesAndBlocks();
  686. switch (externalType) {
  687. case "this":
  688. this.buildInfo.strict = false;
  689. break;
  690. case "system":
  691. if (!Array.isArray(request) || request.length === 1) {
  692. this.buildMeta.exportsType = "namespace";
  693. canMangle = true;
  694. }
  695. break;
  696. case "module":
  697. if (this.buildInfo.javascriptModule) {
  698. if (!Array.isArray(request) || request.length === 1) {
  699. this.buildMeta.exportsType = "namespace";
  700. canMangle = true;
  701. }
  702. } else {
  703. this.buildMeta.async = true;
  704. EnvironmentNotSupportAsyncWarning.check(
  705. this,
  706. compilation.runtimeTemplate,
  707. "external module"
  708. );
  709. if (!Array.isArray(request) || request.length === 1) {
  710. this.buildMeta.exportsType = "namespace";
  711. canMangle = false;
  712. }
  713. }
  714. break;
  715. case "script":
  716. this.buildMeta.async = true;
  717. EnvironmentNotSupportAsyncWarning.check(
  718. this,
  719. compilation.runtimeTemplate,
  720. "external script"
  721. );
  722. break;
  723. case "promise":
  724. this.buildMeta.async = true;
  725. EnvironmentNotSupportAsyncWarning.check(
  726. this,
  727. compilation.runtimeTemplate,
  728. "external promise"
  729. );
  730. break;
  731. case "import":
  732. this.buildMeta.async = true;
  733. EnvironmentNotSupportAsyncWarning.check(
  734. this,
  735. compilation.runtimeTemplate,
  736. "external import"
  737. );
  738. if (!Array.isArray(request) || request.length === 1) {
  739. this.buildMeta.exportsType = "namespace";
  740. canMangle = false;
  741. }
  742. break;
  743. }
  744. this.addDependency(new StaticExportsDependency(true, canMangle));
  745. callback();
  746. }
  747. /**
  748. * restore unsafe cache data
  749. * @param {UnsafeCacheData} unsafeCacheData data from getUnsafeCacheData
  750. * @param {NormalModuleFactory} normalModuleFactory the normal module factory handling the unsafe caching
  751. */
  752. restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory) {
  753. this._restoreFromUnsafeCache(unsafeCacheData, normalModuleFactory);
  754. }
  755. /**
  756. * @param {ConcatenationBailoutReasonContext} context context
  757. * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
  758. */
  759. getConcatenationBailoutReason(context) {
  760. switch (this.externalType) {
  761. case "amd":
  762. case "amd-require":
  763. case "umd":
  764. case "umd2":
  765. case "system":
  766. case "jsonp":
  767. return `${this.externalType} externals can't be concatenated`;
  768. }
  769. return undefined;
  770. }
  771. /**
  772. * @private
  773. * @returns {{ request: string | string[], externalType: ExternalsType }} the request and external type
  774. */
  775. _getRequestAndExternalType() {
  776. let { request, externalType } = this;
  777. if (typeof request === "object" && !Array.isArray(request)) {
  778. request = request[externalType];
  779. }
  780. externalType = this._resolveExternalType(externalType);
  781. return { request, externalType };
  782. }
  783. /**
  784. * Resolve the detailed external type from the raw external type.
  785. * e.g. resolve "module" or "import" from "module-import" type
  786. * @param {ExternalsType} externalType raw external type
  787. * @returns {ExternalsType} resolved external type
  788. */
  789. _resolveExternalType(externalType) {
  790. if (externalType === "module-import") {
  791. if (
  792. this.dependencyMeta &&
  793. /** @type {ImportDependencyMeta} */
  794. (this.dependencyMeta).externalType
  795. ) {
  796. return /** @type {ImportDependencyMeta} */ (this.dependencyMeta)
  797. .externalType;
  798. }
  799. return "module";
  800. } else if (externalType === "asset") {
  801. if (
  802. this.dependencyMeta &&
  803. /** @type {AssetDependencyMeta} */
  804. (this.dependencyMeta).sourceType
  805. ) {
  806. return /** @type {AssetDependencyMeta} */ (this.dependencyMeta)
  807. .sourceType;
  808. }
  809. return "asset";
  810. }
  811. return externalType;
  812. }
  813. /**
  814. * @private
  815. * @param {string | string[]} request request
  816. * @param {ExternalsType} externalType the external type
  817. * @param {RuntimeTemplate} runtimeTemplate the runtime template
  818. * @param {ModuleGraph} moduleGraph the module graph
  819. * @param {ChunkGraph} chunkGraph the chunk graph
  820. * @param {RuntimeSpec} runtime the runtime
  821. * @param {DependencyMeta | undefined} dependencyMeta the dependency meta
  822. * @param {ConcatenationScope=} concatenationScope concatenationScope
  823. * @returns {SourceData} the source data
  824. */
  825. _getSourceData(
  826. request,
  827. externalType,
  828. runtimeTemplate,
  829. moduleGraph,
  830. chunkGraph,
  831. runtime,
  832. dependencyMeta,
  833. concatenationScope
  834. ) {
  835. switch (externalType) {
  836. case "this":
  837. case "window":
  838. case "self":
  839. return getSourceForGlobalVariableExternal(request, this.externalType);
  840. case "global":
  841. return getSourceForGlobalVariableExternal(
  842. request,
  843. runtimeTemplate.globalObject
  844. );
  845. case "commonjs":
  846. case "commonjs2":
  847. case "commonjs-module":
  848. case "commonjs-static":
  849. return getSourceForCommonJsExternal(request);
  850. case "node-commonjs":
  851. return /** @type {BuildInfo} */ (this.buildInfo).javascriptModule
  852. ? getSourceForCommonJsExternalInNodeModule(request, runtimeTemplate)
  853. : getSourceForCommonJsExternal(request);
  854. case "amd":
  855. case "amd-require":
  856. case "umd":
  857. case "umd2":
  858. case "system":
  859. case "jsonp": {
  860. const id = chunkGraph.getModuleId(this);
  861. return getSourceForAmdOrUmdExternal(
  862. id !== null ? id : this.identifier(),
  863. this.isOptional(moduleGraph),
  864. request,
  865. runtimeTemplate
  866. );
  867. }
  868. case "import":
  869. return getSourceForImportExternal(
  870. request,
  871. runtimeTemplate,
  872. /** @type {ImportDependencyMeta} */ (dependencyMeta)
  873. );
  874. case "script":
  875. return getSourceForScriptExternal(request, runtimeTemplate);
  876. case "module": {
  877. if (!(/** @type {BuildInfo} */ (this.buildInfo).javascriptModule)) {
  878. if (!runtimeTemplate.supportsDynamicImport()) {
  879. throw new Error(
  880. `The target environment doesn't support dynamic import() syntax so it's not possible to use external type 'module' within a script${
  881. runtimeTemplate.supportsEcmaScriptModuleSyntax()
  882. ? "\nDid you mean to build a EcmaScript Module ('output.module: true')?"
  883. : ""
  884. }`
  885. );
  886. }
  887. return getSourceForImportExternal(
  888. request,
  889. runtimeTemplate,
  890. /** @type {ImportDependencyMeta} */ (dependencyMeta)
  891. );
  892. }
  893. if (!runtimeTemplate.supportsEcmaScriptModuleSyntax()) {
  894. throw new Error(
  895. "The target environment doesn't support EcmaScriptModule syntax so it's not possible to use external type 'module'"
  896. );
  897. }
  898. return getSourceForModuleExternal(
  899. request,
  900. moduleGraph.getExportsInfo(this),
  901. runtime,
  902. runtimeTemplate,
  903. /** @type {ImportDependencyMeta} */ (dependencyMeta),
  904. concatenationScope
  905. );
  906. }
  907. case "var":
  908. case "promise":
  909. case "assign":
  910. default:
  911. return getSourceForDefaultCase(
  912. this.isOptional(moduleGraph),
  913. request,
  914. runtimeTemplate
  915. );
  916. }
  917. }
  918. /**
  919. * @param {CodeGenerationContext} context context for code generation
  920. * @returns {CodeGenerationResult} result
  921. */
  922. codeGeneration({
  923. runtimeTemplate,
  924. moduleGraph,
  925. chunkGraph,
  926. runtime,
  927. concatenationScope
  928. }) {
  929. const { request, externalType } = this._getRequestAndExternalType();
  930. switch (externalType) {
  931. case "asset": {
  932. /** @type {Sources} */
  933. const sources = new Map();
  934. sources.set(
  935. JAVASCRIPT_TYPE,
  936. new RawSource(`module.exports = ${JSON.stringify(request)};`)
  937. );
  938. /** @type {CodeGenerationResultData} */
  939. const data = new Map();
  940. data.set("url", { javascript: /** @type {string} */ (request) });
  941. return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
  942. }
  943. case "css-url": {
  944. /** @type {Sources} */
  945. const sources = new Map();
  946. /** @type {CodeGenerationResultData} */
  947. const data = new Map();
  948. data.set("url", { "css-url": /** @type {string} */ (request) });
  949. return { sources, runtimeRequirements: RUNTIME_REQUIREMENTS, data };
  950. }
  951. case "css-import": {
  952. /** @type {Sources} */
  953. const sources = new Map();
  954. const dependencyMeta = /** @type {CssImportDependencyMeta} */ (
  955. this.dependencyMeta
  956. );
  957. const layer =
  958. dependencyMeta.layer !== undefined
  959. ? ` layer(${dependencyMeta.layer})`
  960. : "";
  961. const supports = dependencyMeta.supports
  962. ? ` supports(${dependencyMeta.supports})`
  963. : "";
  964. const media = dependencyMeta.media ? ` ${dependencyMeta.media}` : "";
  965. sources.set(
  966. "css-import",
  967. new RawSource(
  968. `@import url(${JSON.stringify(
  969. request
  970. )})${layer}${supports}${media};`
  971. )
  972. );
  973. return {
  974. sources,
  975. runtimeRequirements: EMPTY_RUNTIME_REQUIREMENTS
  976. };
  977. }
  978. default: {
  979. const sourceData = this._getSourceData(
  980. request,
  981. externalType,
  982. runtimeTemplate,
  983. moduleGraph,
  984. chunkGraph,
  985. runtime,
  986. this.dependencyMeta,
  987. concatenationScope
  988. );
  989. // sourceString can be empty str only when there is concatenationScope
  990. let sourceString = sourceData.expression;
  991. if (sourceData.iife) {
  992. sourceString = `(function() { return ${sourceString}; }())`;
  993. }
  994. const specifiers = sourceData.specifiers;
  995. if (specifiers) {
  996. sourceString = "";
  997. const scope = /** @type {ConcatenationScope} */ (concatenationScope);
  998. for (const [specifier, finalName] of specifiers) {
  999. scope.registerRawExport(specifier, finalName);
  1000. }
  1001. } else if (concatenationScope) {
  1002. sourceString = `${runtimeTemplate.renderConst()} ${ConcatenationScope.NAMESPACE_OBJECT_EXPORT} = ${sourceString};`;
  1003. concatenationScope.registerNamespaceExport(
  1004. ConcatenationScope.NAMESPACE_OBJECT_EXPORT
  1005. );
  1006. } else {
  1007. sourceString = `module.exports = ${sourceString};`;
  1008. }
  1009. if (sourceData.init) {
  1010. sourceString = `${sourceData.init}\n${sourceString}`;
  1011. }
  1012. /** @type {undefined | CodeGenerationResultData} */
  1013. let data;
  1014. if (sourceData.chunkInitFragments) {
  1015. data = new Map();
  1016. data.set("chunkInitFragments", sourceData.chunkInitFragments);
  1017. }
  1018. /** @type {Sources} */
  1019. const sources = new Map();
  1020. if (this.useSourceMap || this.useSimpleSourceMap) {
  1021. sources.set(
  1022. JAVASCRIPT_TYPE,
  1023. new OriginalSource(sourceString, this.identifier())
  1024. );
  1025. } else {
  1026. sources.set(JAVASCRIPT_TYPE, new RawSource(sourceString));
  1027. }
  1028. let runtimeRequirements = sourceData.runtimeRequirements;
  1029. if (!concatenationScope) {
  1030. if (!runtimeRequirements) {
  1031. runtimeRequirements = RUNTIME_REQUIREMENTS;
  1032. } else {
  1033. const set = new Set(runtimeRequirements);
  1034. set.add(RuntimeGlobals.module);
  1035. runtimeRequirements = set;
  1036. }
  1037. }
  1038. return {
  1039. sources,
  1040. runtimeRequirements:
  1041. runtimeRequirements || EMPTY_RUNTIME_REQUIREMENTS,
  1042. data
  1043. };
  1044. }
  1045. }
  1046. }
  1047. /**
  1048. * @param {string=} type the source type for which the size should be estimated
  1049. * @returns {number} the estimated size of the module (must be non-zero)
  1050. */
  1051. size(type) {
  1052. return 42;
  1053. }
  1054. /**
  1055. * @param {Hash} hash the hash used to track dependencies
  1056. * @param {UpdateHashContext} context context
  1057. * @returns {void}
  1058. */
  1059. updateHash(hash, context) {
  1060. const { chunkGraph } = context;
  1061. hash.update(
  1062. `${this._resolveExternalType(this.externalType)}${JSON.stringify(this.request)}${this.isOptional(
  1063. chunkGraph.moduleGraph
  1064. )}`
  1065. );
  1066. super.updateHash(hash, context);
  1067. }
  1068. /**
  1069. * @param {ObjectSerializerContext} context context
  1070. */
  1071. serialize(context) {
  1072. const { write } = context;
  1073. write(this.request);
  1074. write(this.externalType);
  1075. write(this.userRequest);
  1076. write(this.dependencyMeta);
  1077. super.serialize(context);
  1078. }
  1079. /**
  1080. * @param {ObjectDeserializerContext} context context
  1081. */
  1082. deserialize(context) {
  1083. const { read } = context;
  1084. this.request = read();
  1085. this.externalType = read();
  1086. this.userRequest = read();
  1087. this.dependencyMeta = read();
  1088. super.deserialize(context);
  1089. }
  1090. }
  1091. makeSerializable(ExternalModule, "webpack/lib/ExternalModule");
  1092. module.exports = ExternalModule;
  1093. module.exports.ModuleExternalInitFragment = ModuleExternalInitFragment;
  1094. module.exports.getExternalModuleNodeCommonjsInitFragment =
  1095. getExternalModuleNodeCommonjsInitFragment;