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