UNPKG

12.3 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 "key, version, requiredVersion",
107 [
108 `return "Unsatisfied version " + version + " of shared singleton module " + key + " (required " + rangeToString(requiredVersion) + ")"`
109 ]
110 )};`,
111 `var getSingletonVersion = ${runtimeTemplate.basicFunction(
112 "scope, scopeName, key, requiredVersion",
113 [
114 "var version = findSingletonVersionKey(scope, key);",
115 "if (!satisfy(requiredVersion, version)) " +
116 'typeof console !== "undefined" && console.warn && console.warn(getInvalidSingletonVersionMessage(key, version, requiredVersion));',
117 "return get(scope[key][version]);"
118 ]
119 )};`,
120 `var getStrictSingletonVersion = ${runtimeTemplate.basicFunction(
121 "scope, scopeName, key, requiredVersion",
122 [
123 "var version = findSingletonVersionKey(scope, key);",
124 "if (!satisfy(requiredVersion, version)) " +
125 "throw new Error(getInvalidSingletonVersionMessage(key, version, requiredVersion));",
126 "return get(scope[key][version]);"
127 ]
128 )};`,
129 `var findValidVersion = ${runtimeTemplate.basicFunction(
130 "scope, key, requiredVersion",
131 [
132 "var versions = scope[key];",
133 `var key = Object.keys(versions).reduce(${runtimeTemplate.basicFunction(
134 "a, b",
135 [
136 "if (!satisfy(requiredVersion, b)) return a;",
137 "return !a || versionLt(a, b) ? b : a;"
138 ]
139 )}, 0);`,
140 "return key && versions[key]"
141 ]
142 )};`,
143 `var getInvalidVersionMessage = ${runtimeTemplate.basicFunction(
144 "scope, scopeName, key, requiredVersion",
145 [
146 "var versions = scope[key];",
147 'return "No satisfying version (" + rangeToString(requiredVersion) + ") of shared module " + key + " found in shared scope " + scopeName + ".\\n" +',
148 `\t"Available versions: " + Object.keys(versions).map(${runtimeTemplate.basicFunction(
149 "key",
150 ['return key + " from " + versions[key].from;']
151 )}).join(", ");`
152 ]
153 )};`,
154 `var getValidVersion = ${runtimeTemplate.basicFunction(
155 "scope, scopeName, key, requiredVersion",
156 [
157 "var entry = findValidVersion(scope, key, requiredVersion);",
158 "if(entry) return get(entry);",
159 "throw new Error(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));"
160 ]
161 )};`,
162 `var warnInvalidVersion = ${runtimeTemplate.basicFunction(
163 "scope, scopeName, key, requiredVersion",
164 [
165 'typeof console !== "undefined" && console.warn && console.warn(getInvalidVersionMessage(scope, scopeName, key, requiredVersion));'
166 ]
167 )};`,
168 `var get = ${runtimeTemplate.basicFunction("entry", [
169 "entry.loaded = 1;",
170 "return entry.get()"
171 ])};`,
172 `var init = ${runtimeTemplate.returningFunction(
173 Template.asString([
174 "function(scopeName, a, b, c) {",
175 Template.indent([
176 `var promise = ${RuntimeGlobals.initializeSharing}(scopeName);`,
177 `if (promise && promise.then) return promise.then(fn.bind(fn, scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c));`,
178 `return fn(scopeName, ${RuntimeGlobals.shareScopeMap}[scopeName], a, b, c);`
179 ]),
180 "}"
181 ]),
182 "fn"
183 )};`,
184 "",
185 `var load = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
186 "scopeName, scope, key",
187 [
188 "ensureExistence(scopeName, key);",
189 "return get(findVersion(scope, key));"
190 ]
191 )});`,
192 `var loadFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
193 "scopeName, scope, key, fallback",
194 [
195 `return scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) ? get(findVersion(scope, key)) : fallback();`
196 ]
197 )});`,
198 `var loadVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
199 "scopeName, scope, key, version",
200 [
201 "ensureExistence(scopeName, key);",
202 "return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
203 ]
204 )});`,
205 `var loadSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
206 "scopeName, scope, key, version",
207 [
208 "ensureExistence(scopeName, key);",
209 "return getSingletonVersion(scope, scopeName, key, version);"
210 ]
211 )});`,
212 `var loadStrictVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
213 "scopeName, scope, key, version",
214 [
215 "ensureExistence(scopeName, key);",
216 "return getValidVersion(scope, scopeName, key, version);"
217 ]
218 )});`,
219 `var loadStrictSingletonVersionCheck = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
220 "scopeName, scope, key, version",
221 [
222 "ensureExistence(scopeName, key);",
223 "return getStrictSingletonVersion(scope, scopeName, key, version);"
224 ]
225 )});`,
226 `var loadVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
227 "scopeName, scope, key, version, fallback",
228 [
229 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
230 "return get(findValidVersion(scope, key, version) || warnInvalidVersion(scope, scopeName, key, version) || findVersion(scope, key));"
231 ]
232 )});`,
233 `var loadSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
234 "scopeName, scope, key, version, fallback",
235 [
236 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
237 "return getSingletonVersion(scope, scopeName, key, version);"
238 ]
239 )});`,
240 `var loadStrictVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
241 "scopeName, scope, key, version, fallback",
242 [
243 `var entry = scope && ${RuntimeGlobals.hasOwnProperty}(scope, key) && findValidVersion(scope, key, version);`,
244 `return entry ? get(entry) : fallback();`
245 ]
246 )});`,
247 `var loadStrictSingletonVersionCheckFallback = /*#__PURE__*/ init(${runtimeTemplate.basicFunction(
248 "scopeName, scope, key, version, fallback",
249 [
250 `if(!scope || !${RuntimeGlobals.hasOwnProperty}(scope, key)) return fallback();`,
251 "return getStrictSingletonVersion(scope, scopeName, key, version);"
252 ]
253 )});`,
254 "var installedModules = {};",
255 "var moduleToHandlerMapping = {",
256 Template.indent(
257 Array.from(
258 moduleIdToSourceMapping,
259 ([key, source]) => `${JSON.stringify(key)}: ${source.source()}`
260 ).join(",\n")
261 ),
262 "};",
263
264 initialConsumes.length > 0
265 ? Template.asString([
266 `var initialConsumes = ${JSON.stringify(initialConsumes)};`,
267 `initialConsumes.forEach(${runtimeTemplate.basicFunction("id", [
268 `${
269 RuntimeGlobals.moduleFactories
270 }[id] = ${runtimeTemplate.basicFunction("module", [
271 "// Handle case when module is used sync",
272 "installedModules[id] = 0;",
273 `delete ${RuntimeGlobals.moduleCache}[id];`,
274 "var factory = moduleToHandlerMapping[id]();",
275 'if(typeof factory !== "function") throw new Error("Shared module is not available for eager consumption: " + id);',
276 `module.exports = factory();`
277 ])}`
278 ])});`
279 ])
280 : "// no consumes in initial chunks",
281 this._runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)
282 ? Template.asString([
283 `var chunkMapping = ${JSON.stringify(
284 chunkToModuleMapping,
285 null,
286 "\t"
287 )};`,
288 `${
289 RuntimeGlobals.ensureChunkHandlers
290 }.consumes = ${runtimeTemplate.basicFunction("chunkId, promises", [
291 `if(${RuntimeGlobals.hasOwnProperty}(chunkMapping, chunkId)) {`,
292 Template.indent([
293 `chunkMapping[chunkId].forEach(${runtimeTemplate.basicFunction(
294 "id",
295 [
296 `if(${RuntimeGlobals.hasOwnProperty}(installedModules, id)) return promises.push(installedModules[id]);`,
297 `var onFactory = ${runtimeTemplate.basicFunction(
298 "factory",
299 [
300 "installedModules[id] = 0;",
301 `${
302 RuntimeGlobals.moduleFactories
303 }[id] = ${runtimeTemplate.basicFunction("module", [
304 `delete ${RuntimeGlobals.moduleCache}[id];`,
305 "module.exports = factory();"
306 ])}`
307 ]
308 )};`,
309 `var onError = ${runtimeTemplate.basicFunction("error", [
310 "delete installedModules[id];",
311 `${
312 RuntimeGlobals.moduleFactories
313 }[id] = ${runtimeTemplate.basicFunction("module", [
314 `delete ${RuntimeGlobals.moduleCache}[id];`,
315 "throw error;"
316 ])}`
317 ])};`,
318 "try {",
319 Template.indent([
320 "var promise = moduleToHandlerMapping[id]();",
321 "if(promise.then) {",
322 Template.indent(
323 `promises.push(installedModules[id] = promise.then(onFactory).catch(onError));`
324 ),
325 "} else onFactory(promise);"
326 ]),
327 "} catch(e) { onError(e); }"
328 ]
329 )});`
330 ]),
331 "}"
332 ])}`
333 ])
334 : "// no chunk loading of consumes"
335 ]);
336 }
337}
338
339module.exports = ConsumeSharedRuntimeModule;