10
0

ExternalModule.js 29 KB

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