ExternalModule.js 27 KB

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