UNPKG

4.63 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 compareModulesByIdentifier,
13 compareStrings
14} = require("../util/comparators");
15
16class ShareRuntimeModule extends RuntimeModule {
17 constructor() {
18 super("sharing");
19 }
20
21 /**
22 * @returns {string} runtime code
23 */
24 generate() {
25 const { compilation, chunkGraph } = this;
26 const {
27 runtimeTemplate,
28 codeGenerationResults,
29 outputOptions: { uniqueName }
30 } = compilation;
31 /** @type {Map<string, Map<number, Set<string>>>} */
32 const initCodePerScope = new Map();
33 for (const chunk of this.chunk.getAllReferencedChunks()) {
34 const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
35 chunk,
36 "share-init",
37 compareModulesByIdentifier
38 );
39 if (!modules) continue;
40 for (const m of modules) {
41 const data = codeGenerationResults.getData(
42 m,
43 chunk.runtime,
44 "share-init"
45 );
46 if (!data) continue;
47 for (const item of data) {
48 const { shareScope, initStage, init } = item;
49 let stages = initCodePerScope.get(shareScope);
50 if (stages === undefined) {
51 initCodePerScope.set(shareScope, (stages = new Map()));
52 }
53 let list = stages.get(initStage || 0);
54 if (list === undefined) {
55 stages.set(initStage || 0, (list = new Set()));
56 }
57 list.add(init);
58 }
59 }
60 }
61 return Template.asString([
62 `${RuntimeGlobals.shareScopeMap} = {};`,
63 "var initPromises = {};",
64 "var initTokens = {};",
65 `${RuntimeGlobals.initializeSharing} = ${runtimeTemplate.basicFunction(
66 "name, initScope",
67 [
68 "if(!initScope) initScope = [];",
69 "// handling circular init calls",
70 "var initToken = initTokens[name];",
71 "if(!initToken) initToken = initTokens[name] = {};",
72 "if(initScope.indexOf(initToken) >= 0) return;",
73 "initScope.push(initToken);",
74 "// only runs once",
75 "if(initPromises[name]) return initPromises[name];",
76 "// creates a new share scope if needed",
77 `if(!${RuntimeGlobals.hasOwnProperty}(${RuntimeGlobals.shareScopeMap}, name)) ${RuntimeGlobals.shareScopeMap}[name] = {};`,
78 "// runs all init snippets from all modules reachable",
79 `var scope = ${RuntimeGlobals.shareScopeMap}[name];`,
80 `var warn = ${runtimeTemplate.returningFunction(
81 'typeof console !== "undefined" && console.warn && console.warn(msg)',
82 "msg"
83 )};`,
84 `var uniqueName = ${JSON.stringify(uniqueName || undefined)};`,
85 `var register = ${runtimeTemplate.basicFunction(
86 "name, version, factory, eager",
87 [
88 "var versions = scope[name] = scope[name] || {};",
89 "var activeVersion = versions[version];",
90 "if(!activeVersion || (!activeVersion.loaded && (!eager != !activeVersion.eager ? eager : uniqueName > activeVersion.from))) versions[version] = { get: factory, from: uniqueName, eager: !!eager };"
91 ]
92 )};`,
93 `var initExternal = ${runtimeTemplate.basicFunction("id", [
94 `var handleError = ${runtimeTemplate.expressionFunction(
95 'warn("Initialization of sharing external failed: " + err)',
96 "err"
97 )};`,
98 "try {",
99 Template.indent([
100 "var module = __webpack_require__(id);",
101 "if(!module) return;",
102 `var initFn = ${runtimeTemplate.returningFunction(
103 `module && module.init && module.init(${RuntimeGlobals.shareScopeMap}[name], initScope)`,
104 "module"
105 )}`,
106 "if(module.then) return promises.push(module.then(initFn, handleError));",
107 "var initResult = initFn(module);",
108 "if(initResult && initResult.then) return promises.push(initResult.catch(handleError));"
109 ]),
110 "} catch(err) { handleError(err); }"
111 ])}`,
112 "var promises = [];",
113 "switch(name) {",
114 ...Array.from(initCodePerScope)
115 .sort(([a], [b]) => compareStrings(a, b))
116 .map(([name, stages]) =>
117 Template.indent([
118 `case ${JSON.stringify(name)}: {`,
119 Template.indent(
120 Array.from(stages)
121 .sort(([a], [b]) => a - b)
122 .map(([, initCode]) =>
123 Template.asString(Array.from(initCode))
124 )
125 ),
126 "}",
127 "break;"
128 ])
129 ),
130 "}",
131 "if(!promises.length) return initPromises[name] = 1;",
132 `return initPromises[name] = Promise.all(promises).then(${runtimeTemplate.returningFunction(
133 "initPromises[name] = 1"
134 )});`
135 ]
136 )};`
137 ]);
138 }
139}
140
141module.exports = ShareRuntimeModule;