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