UNPKG

13.1 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const RuntimeGlobals = require("../RuntimeGlobals");
9const RuntimeModule = require("../RuntimeModule");
10const Template = require("../Template");
11const {
12 parseVersionRuntimeCode,
13 versionLtRuntimeCode,
14 rangeToStringRuntimeCode,
15 satisfyRuntimeCode
16} = require("../util/semver");
17
18/** @typedef {import("webpack-sources").Source} Source */
19/** @typedef {import("../Chunk")} Chunk */
20/** @typedef {import("../Module")} Module */
21/** @typedef {import("./ConsumeSharedModule")} ConsumeSharedModule */
22
23class ConsumeSharedRuntimeModule extends RuntimeModule {
24 constructor(runtimeRequirements) {
25 super("consumes", RuntimeModule.STAGE_ATTACH);
26 this._runtimeRequirements = runtimeRequirements;
27 }
28
29 /**
30 * @returns {string} runtime code
31 */
32 generate() {
33 const { compilation, chunkGraph } = this;
34 const { runtimeTemplate, codeGenerationResults } = compilation;
35 const chunkToModuleMapping = {};
36 /** @type {Map<string | number, Source>} */
37 const moduleIdToSourceMapping = new Map();
38 const initialConsumes = [];
39 /**
40 *
41 * @param {Iterable<Module>} modules modules
42 * @param {Chunk} chunk the chunk
43 * @param {(string | number)[]} list list of ids
44 */
45 const addModules = (modules, chunk, list) => {
46 for (const m of modules) {
47 const module = /** @type {ConsumeSharedModule} */ (m);
48 const id = chunkGraph.getModuleId(module);
49 list.push(id);
50 moduleIdToSourceMapping.set(
51 id,
52 codeGenerationResults.getSource(
53 module,
54 chunk.runtime,
55 "consume-shared"
56 )
57 );
58 }
59 };
60 for (const chunk of this.chunk.getAllAsyncChunks()) {
61 const modules = chunkGraph.getChunkModulesIterableBySourceType(
62 chunk,
63 "consume-shared"
64 );
65 if (!modules) continue;
66 addModules(modules, chunk, (chunkToModuleMapping[chunk.id] = []));
67 }
68 for (const chunk of this.chunk.getAllInitialChunks()) {
69 const modules = chunkGraph.getChunkModulesIterableBySourceType(
70 chunk,
71 "consume-shared"
72 );
73 if (!modules) continue;
74 addModules(modules, chunk, initialConsumes);
75 }
76 if (moduleIdToSourceMapping.size === 0) return null;
77 return Template.asString([
78 parseVersionRuntimeCode(runtimeTemplate),
79 versionLtRuntimeCode(runtimeTemplate),
80 rangeToStringRuntimeCode(runtimeTemplate),
81 satisfyRuntimeCode(runtimeTemplate),
82 `var ensureExistence = ${runtimeTemplate.basicFunction("scopeName, key", [
83 `var scope = ${RuntimeGlobals.shareScopeMap}[scopeName];`,
84 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) throw new Error("Shared module " + key + " doesn't exist in shared scope " + scopeName);`,
85 "return scope;"
86 ])};`,
87 `var findVersion = ${runtimeTemplate.basicFunction("scope, key", [
88 "var versions = scope[key];",
89 `var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
90 "a, b",
91 ["return !a || versionLt(a, b) ? b : a;"]
92 )}, 0);`,
93 "return key && versions[key]"
94 ])};`,
95 `var findSingletonVersionKey = ${runtimeTemplate.basicFunction(
96 "scope, key",
97 [
98 "var versions = scope[key];",
99 `return Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
100 "a, b",
101 ["return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;"]
102 )}, 0);`
103 ]
104 )};`,
105 `var getInvalidSingletonVersionMessage = ${runtimeTemplate.basicFunction(
106 "scope, key, version, requiredVersion",
107 [
108 `return "Unsatisfied version " + version + " from " + (version && scope[key][version].from) + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"`
109 ]
110 )};`,
111 `var getSingleton = ${runtimeTemplate.basicFunction(
112 "scope, scopeName, key, requiredVersion",
113 [
114 "var version = findSingletonVersionKey(scope, key);",
115 "return get(scope[key][version]);"
116 ]
117 )};`,
118 `var getSingletonVersion = ${runtimeTemplate.basicFunction(
119 "scope, scopeName, key, requiredVersion",
120 [
121 "var version = findSingletonVersionKey(scope, key);",
122 "if (!satisfy(requiredVersion, version)) " +
123 'typeof console !== "undefined" && console.warn && console.warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));',
124 "return get(scope[key][version]);"
125 ]
126 )};`,
127 `var getStrictSingletonVersion = ${runtimeTemplate.basicFunction(
128 "scope, scopeName, key, requiredVersion",
129 [
130 "var version = findSingletonVersionKey(scope, key);",
131 "if (!satisfy(requiredVersion, version)) " +
132 "throw new Error(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));",
133 "return get(scope[key][version]);"
134 ]
135 )};`,
136 `var findValidVersion = ${runtimeTemplate.basicFunction(
137 "scope, key, requiredVersion",
138 [
139 "var versions = scope[key];",
140 `var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
141 "a, b",
142 [
143 "if (!satisfy(requiredVersion, b)) return a;",
144 "return !a || versionLt(a, b) ? b : a;"
145 ]
146 )}, 0);`,
147 "return key && versions[key]"
148 ]
149 )};`,
150 `var getInvalidVersionMessage = ${runtimeTemplate.basicFunction(
151 "scope, scopeName, key, requiredVersion",
152 [
153 "var versions = scope[key];",
154 'return "No satisfying version (" + rangeToString(requiredVersion) + ") of shared module " + key + " found in shared scope " + scopeName + ".\\n" +',
155 `\t"Available versions: " + Object.keys(versions).map(${runtimeTemplate.basicFunction(
156 "key",
157 ['return key + " from " + versions[key].from;']
158 )}).join(", ");`
159 ]
160 )};`,
161 `var getValidVersion = ${runtimeTemplate.basicFunction(
162 "scope, scopeName, key, requiredVersion",
163 [
164 "var entry = findValidVersion(scope, key, requiredVersion);",
165 "if(entry) return get(entry);",
166 "throw new Error(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));"
167 ]
168 )};`,
169 `var warnInvalidVersion = ${runtimeTemplate.basicFunction(
170 "scope, scopeName, key, requiredVersion",
171 [
172 'typeof console !== "undefined" && console.warn && console.warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));'
173 ]
174 )};`,
175 `var get = ${runtimeTemplate.basicFunction("entry", [
176 "entry.loaded = 1;",
177 "return entry.get()"
178 ])};`,
179 `var init = ${runtimeTemplate.returningFunction(
180 Template.asString([
181 "function(scopeName, a, b, c) {",
182 Template.indent([
183 `var promise = ${RuntimeGlobals.initializeSharing}(scopeName);`,
184 `if (promise && promise.then) return promise.then(fn.bind(fn, scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c));`,
185 `return fn(scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c);`
186 ]),
187 "}"
188 ]),
189 "fn"
190 )};`,
191 "",
192 `var load = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
193 "scopeName, scope, key",
194 [
195 "ensureExistence(scopeName, key);",
196 "return get(findVersion(scope, key));"
197 ]
198 )});`,
199 `var loadFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
200 "scopeName, scope, key, fallback",
201 [
202 `return scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) ? get(findVersion(scope, key)) : fallback();`
203 ]
204 )});`,
205 `var loadVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
206 "scopeName, scope, key, version",
207 [
208 "ensureExistence(scopeName, key);",
209 "return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
210 ]
211 )});`,
212 `var loadSingleton = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
213 "scopeName, scope, key",
214 [
215 "ensureExistence(scopeName, key);",
216 "return getSingleton(scope, scopeName, key);"
217 ]
218 )});`,
219 `var loadSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
220 "scopeName, scope, key, version",
221 [
222 "ensureExistence(scopeName, key);",
223 "return getSingletonVersion(scope, scopeName, key, version);"
224 ]
225 )});`,
226 `var loadStrictVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
227 "scopeName, scope, key, version",
228 [
229 "ensureExistence(scopeName, key);",
230 "return getValidVersion(scope, scopeName, key, version);"
231 ]
232 )});`,
233 `var loadStrictSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
234 "scopeName, scope, key, version",
235 [
236 "ensureExistence(scopeName, key);",
237 "return getStrictSingletonVersion(scope, scopeName, key, version);"
238 ]
239 )});`,
240 `var loadVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
241 "scopeName, scope, key, version, fallback",
242 [
243 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
244 "return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
245 ]
246 )});`,
247 `var loadSingletonFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
248 "scopeName, scope, key, fallback",
249 [
250 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
251 "return getSingleton(scope, scopeName, key);"
252 ]
253 )});`,
254 `var loadSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
255 "scopeName, scope, key, version, fallback",
256 [
257 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
258 "return getSingletonVersion(scope, scopeName, key, version);"
259 ]
260 )});`,
261 `var loadStrictVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
262 "scopeName, scope, key, version, fallback",
263 [
264 `var entry = scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) && findValidVersion(scope, key, version);`,
265 `return entry ? get(entry) : fallback();`
266 ]
267 )});`,
268 `var loadStrictSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
269 "scopeName, scope, key, version, fallback",
270 [
271 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
272 "return getStrictSingletonVersion(scope, scopeName, key, version);"
273 ]
274 )});`,
275 "var installedModules = {};",
276 "var moduleToHandlerMapping = {",
277 Template.indent(
278 Array.from(
279 moduleIdToSourceMapping,
280 ([key, source]) => `${JSON.stringify(key)}: ${source.source()}`
281 ).join(",\n")
282 ),
283 "};",
284
285 initialConsumes.length > 0
286 ? Template.asString([
287 `var initialConsumes = ${JSON.stringify(initialConsumes)};`,
288 `initialConsumes.forEach(${runtimeTemplate.basicFunction("id", [
289 `${
290 RuntimeGlobals.moduleFactories
291 }[id] = ${runtimeTemplate.basicFunction("module", [
292 "// Handle case when module is used sync",
293 "installedModules[id] = 0;",
294 `delete ${RuntimeGlobals.moduleCache}[id];`,
295 "var factory = moduleToHandlerMapping[id]();",
296 'if(typeof factory !== "function") throw new Error("Shared module is not available for eager consumption: " + id);',
297 `module.exports = factory();`
298 ])}`
299 ])});`
300 ])
301 : "// no consumes in initial chunks",
302 this._runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)
303 ? Template.asString([
304 `var chunkMapping = ${JSON.stringify(
305 chunkToModuleMapping,
306 null,
307 "\t"
308 )};`,
309 `${
310 RuntimeGlobals.ensureChunkHandlers
311 }.consumes = ${runtimeTemplate.basicFunction("chunkId, promises", [
312 `if(${RuntimeGlobals.hasOwnProperty}(chunkMapping, chunkId)) {`,
313 Template.indent([
314 `chunkMapping[chunkId].forEach(${runtimeTemplate.basicFunction(
315 "id",
316 [
317 `if(${RuntimeGlobals.hasOwnProperty}(installedModules, id)) return promises.push(installedModules[id]);`,
318 `var onFactory = ${runtimeTemplate.basicFunction(
319 "factory",
320 [
321 "installedModules[id] = 0;",
322 `${
323 RuntimeGlobals.moduleFactories
324 }[id] = ${runtimeTemplate.basicFunction("module", [
325 `delete ${RuntimeGlobals.moduleCache}[id];`,
326 "module.exports = factory();"
327 ])}`
328 ]
329 )};`,
330 `var onError = ${runtimeTemplate.basicFunction("error", [
331 "delete installedModules[id];",
332 `${
333 RuntimeGlobals.moduleFactories
334 }[id] = ${runtimeTemplate.basicFunction("module", [
335 `delete ${RuntimeGlobals.moduleCache}[id];`,
336 "throw error;"
337 ])}`
338 ])};`,
339 "try {",
340 Template.indent([
341 "var promise = moduleToHandlerMapping[id]();",
342 "if(promise.then) {",
343 Template.indent(
344 "promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));"
345 ),
346 "} else onFactory(promise);"
347 ]),
348 "} catch(e) { onError(e); }"
349 ]
350 )});`
351 ]),
352 "}"
353 ])}`
354 ])
355 : "// no chunk loading of consumes"
356 ]);
357 }
358}
359
360module.exports = ConsumeSharedRuntimeModule;