123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
- const RuntimeGlobals = require("../RuntimeGlobals");
- const RuntimeModule = require("../RuntimeModule");
- const Template = require("../Template");
- const {
- compareModulesByIdentifier,
- compareStrings
- } = require("../util/comparators");
- /** @typedef {import("../Chunk")} Chunk */
- /** @typedef {import("../ChunkGraph")} ChunkGraph */
- /** @typedef {import("../Compilation")} Compilation */
- class ShareRuntimeModule extends RuntimeModule {
- constructor() {
- super("sharing");
- }
- /**
- * @returns {string | null} runtime code
- */
- generate() {
- const compilation = /** @type {Compilation} */ (this.compilation);
- const {
- runtimeTemplate,
- codeGenerationResults,
- outputOptions: { uniqueName, ignoreBrowserWarnings }
- } = compilation;
- const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
- /** @type {Map<string, Map<number, Set<string>>>} */
- const initCodePerScope = new Map();
- for (const chunk of /** @type {Chunk} */ (
- this.chunk
- ).getAllReferencedChunks()) {
- const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
- chunk,
- "share-init",
- compareModulesByIdentifier
- );
- if (!modules) continue;
- for (const m of modules) {
- const data = codeGenerationResults.getData(
- m,
- chunk.runtime,
- "share-init"
- );
- if (!data) continue;
- for (const item of data) {
- const { shareScope, initStage, init } = item;
- let stages = initCodePerScope.get(shareScope);
- if (stages === undefined) {
- initCodePerScope.set(shareScope, (stages = new Map()));
- }
- let list = stages.get(initStage || 0);
- if (list === undefined) {
- stages.set(initStage || 0, (list = new Set()));
- }
- list.add(init);
- }
- }
- }
- return Template.asString([
- `${RuntimeGlobals.shareScopeMap} = {};`,
- "var initPromises = {};",
- "var initTokens = {};",
- `${RuntimeGlobals.initializeSharing} = ${runtimeTemplate.basicFunction(
- "name, initScope",
- [
- "if(!initScope) initScope = [];",
- "// handling circular init calls",
- "var initToken = initTokens[name];",
- "if(!initToken) initToken = initTokens[name] = {};",
- "if(initScope.indexOf(initToken) >= 0) return;",
- "initScope.push(initToken);",
- "// only runs once",
- "if(initPromises[name]) return initPromises[name];",
- "// creates a new share scope if needed",
- `if(!${RuntimeGlobals.hasOwnProperty}(${RuntimeGlobals.shareScopeMap}, name)) ${RuntimeGlobals.shareScopeMap}[name] = {};`,
- "// runs all init snippets from all modules reachable",
- `var scope = ${RuntimeGlobals.shareScopeMap}[name];`,
- `var warn = ${
- ignoreBrowserWarnings
- ? runtimeTemplate.basicFunction("", "")
- : runtimeTemplate.basicFunction("msg", [
- 'if (typeof console !== "undefined" && console.warn) console.warn(msg);'
- ])
- };`,
- `var uniqueName = ${JSON.stringify(uniqueName || undefined)};`,
- `var register = ${runtimeTemplate.basicFunction(
- "name, version, factory, eager",
- [
- "var versions = scope[name] = scope[name] || {};",
- "var activeVersion = versions[version];",
- "if(!activeVersion || (!activeVersion.loaded && (!eager != !activeVersion.eager ? eager : uniqueName > activeVersion.from))) versions[version] = { get: factory, from: uniqueName, eager: !!eager };"
- ]
- )};`,
- `var initExternal = ${runtimeTemplate.basicFunction("id", [
- `var handleError = ${runtimeTemplate.expressionFunction(
- 'warn("Initialization of sharing external failed: " + err)',
- "err"
- )};`,
- "try {",
- Template.indent([
- `var module = ${RuntimeGlobals.require}(id);`,
- "if(!module) return;",
- `var initFn = ${runtimeTemplate.returningFunction(
- `module && module.init && module.init(${RuntimeGlobals.shareScopeMap}[name], initScope)`,
- "module"
- )}`,
- "if(module.then) return promises.push(module.then(initFn, handleError));",
- "var initResult = initFn(module);",
- "if(initResult && initResult.then) return promises.push(initResult['catch'](handleError));"
- ]),
- "} catch(err) { handleError(err); }"
- ])}`,
- "var promises = [];",
- "switch(name) {",
- ...Array.from(initCodePerScope)
- .sort(([a], [b]) => compareStrings(a, b))
- .map(([name, stages]) =>
- Template.indent([
- `case ${JSON.stringify(name)}: {`,
- Template.indent(
- Array.from(stages)
- .sort(([a], [b]) => a - b)
- .map(([, initCode]) =>
- Template.asString(Array.from(initCode))
- )
- ),
- "}",
- "break;"
- ])
- ),
- "}",
- "if(!promises.length) return initPromises[name] = 1;",
- `return initPromises[name] = Promise.all(promises).then(${runtimeTemplate.returningFunction(
- "initPromises[name] = 1"
- )});`
- ]
- )};`
- ]);
- }
- }
- module.exports = ShareRuntimeModule;
|