UNPKG

7.61 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7const RuntimeGlobals = require("../RuntimeGlobals");
8const RuntimeModule = require("../RuntimeModule");
9const Template = require("../Template");
10const {
11 getChunkFilenameTemplate,
12 chunkHasJs
13} = require("../javascript/JavascriptModulesPlugin");
14const { getInitialChunkIds } = require("../javascript/StartupHelpers");
15const compileBooleanMatcher = require("../util/compileBooleanMatcher");
16const { getUndoPath } = require("../util/identifier");
17
18class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
19 constructor(runtimeRequirements, withCreateScriptUrl) {
20 super("importScripts chunk loading", RuntimeModule.STAGE_ATTACH);
21 this.runtimeRequirements = runtimeRequirements;
22 this._withCreateScriptUrl = withCreateScriptUrl;
23 }
24
25 /**
26 * @returns {string} runtime code
27 */
28 generate() {
29 const {
30 chunk,
31 chunkGraph,
32 compilation: {
33 runtimeTemplate,
34 outputOptions: { globalObject, chunkLoadingGlobal, hotUpdateGlobal }
35 },
36 _withCreateScriptUrl: withCreateScriptUrl
37 } = this;
38 const fn = RuntimeGlobals.ensureChunkHandlers;
39 const withBaseURI = this.runtimeRequirements.has(RuntimeGlobals.baseURI);
40 const withLoading = this.runtimeRequirements.has(
41 RuntimeGlobals.ensureChunkHandlers
42 );
43 const withHmr = this.runtimeRequirements.has(
44 RuntimeGlobals.hmrDownloadUpdateHandlers
45 );
46 const withHmrManifest = this.runtimeRequirements.has(
47 RuntimeGlobals.hmrDownloadManifest
48 );
49 const chunkLoadingGlobalExpr = `${globalObject}[${JSON.stringify(
50 chunkLoadingGlobal
51 )}]`;
52 const hasJsMatcher = compileBooleanMatcher(
53 chunkGraph.getChunkConditionMap(chunk, chunkHasJs)
54 );
55 const initialChunkIds = getInitialChunkIds(chunk, chunkGraph);
56
57 const outputName = this.compilation.getPath(
58 getChunkFilenameTemplate(chunk, this.compilation.outputOptions),
59 {
60 chunk,
61 contentHashType: "javascript"
62 }
63 );
64 const rootOutputDir = getUndoPath(
65 outputName,
66 this.compilation.outputOptions.path,
67 false
68 );
69
70 const stateExpression = withHmr
71 ? `${RuntimeGlobals.hmrRuntimeStatePrefix}_importScripts`
72 : undefined;
73
74 return Template.asString([
75 withBaseURI
76 ? Template.asString([
77 `${RuntimeGlobals.baseURI} = self.location + ${JSON.stringify(
78 rootOutputDir ? "/../" + rootOutputDir : ""
79 )};`
80 ])
81 : "// no baseURI",
82 "",
83 "// object to store loaded chunks",
84 '// "1" means "already loaded"',
85 `var installedChunks = ${
86 stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""
87 }{`,
88 Template.indent(
89 Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 1`).join(
90 ",\n"
91 )
92 ),
93 "};",
94 "",
95 withLoading
96 ? Template.asString([
97 "// importScripts chunk loading",
98 `var installChunk = ${runtimeTemplate.basicFunction("data", [
99 runtimeTemplate.destructureArray(
100 ["chunkIds", "moreModules", "runtime"],
101 "data"
102 ),
103 "for(var moduleId in moreModules) {",
104 Template.indent([
105 `if(${RuntimeGlobals.hasOwnProperty}(moreModules, moduleId)) {`,
106 Template.indent(
107 `${RuntimeGlobals.moduleFactories}[moduleId] = moreModules[moduleId];`
108 ),
109 "}"
110 ]),
111 "}",
112 "if(runtime) runtime(__webpack_require__);",
113 "while(chunkIds.length)",
114 Template.indent("installedChunks[chunkIds.pop()] = 1;"),
115 "parentChunkLoadingFunction(data);"
116 ])};`
117 ])
118 : "// no chunk install function needed",
119 withLoading
120 ? Template.asString([
121 `${fn}.i = ${runtimeTemplate.basicFunction(
122 "chunkId, promises",
123 hasJsMatcher !== false
124 ? [
125 '// "1" is the signal for "already loaded"',
126 "if(!installedChunks[chunkId]) {",
127 Template.indent([
128 hasJsMatcher === true
129 ? "if(true) { // all chunks have JS"
130 : `if(${hasJsMatcher("chunkId")}) {`,
131 Template.indent(
132 `importScripts(${
133 withCreateScriptUrl
134 ? `${RuntimeGlobals.createScriptUrl}(${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId))`
135 : `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId)`
136 });`
137 ),
138 "}"
139 ]),
140 "}"
141 ]
142 : "installedChunks[chunkId] = 1;"
143 )};`,
144 "",
145 `var chunkLoadingGlobal = ${chunkLoadingGlobalExpr} = ${chunkLoadingGlobalExpr} || [];`,
146 "var parentChunkLoadingFunction = chunkLoadingGlobal.push.bind(chunkLoadingGlobal);",
147 "chunkLoadingGlobal.push = installChunk;"
148 ])
149 : "// no chunk loading",
150 "",
151 withHmr
152 ? Template.asString([
153 "function loadUpdateChunk(chunkId, updatedModulesList) {",
154 Template.indent([
155 "var success = false;",
156 `${globalObject}[${JSON.stringify(
157 hotUpdateGlobal
158 )}] = ${runtimeTemplate.basicFunction("_, moreModules, runtime", [
159 "for(var moduleId in moreModules) {",
160 Template.indent([
161 `if(${RuntimeGlobals.hasOwnProperty}(moreModules, moduleId)) {`,
162 Template.indent([
163 "currentUpdate[moduleId] = moreModules[moduleId];",
164 "if(updatedModulesList) updatedModulesList.push(moduleId);"
165 ]),
166 "}"
167 ]),
168 "}",
169 "if(runtime) currentUpdateRuntime.push(runtime);",
170 "success = true;"
171 ])};`,
172 "// start update chunk loading",
173 `importScripts(${
174 withCreateScriptUrl
175 ? `${RuntimeGlobals.createScriptUrl}(${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId))`
176 : `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId)`
177 });`,
178 'if(!success) throw new Error("Loading update chunk failed for unknown reason");'
179 ]),
180 "}",
181 "",
182 Template.getFunctionContent(
183 require("../hmr/JavascriptHotModuleReplacement.runtime.js")
184 )
185 .replace(/\$key\$/g, "importScrips")
186 .replace(/\$installedChunks\$/g, "installedChunks")
187 .replace(/\$loadUpdateChunk\$/g, "loadUpdateChunk")
188 .replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
189 .replace(/\$moduleFactories\$/g, RuntimeGlobals.moduleFactories)
190 .replace(
191 /\$ensureChunkHandlers\$/g,
192 RuntimeGlobals.ensureChunkHandlers
193 )
194 .replace(/\$hasOwnProperty\$/g, RuntimeGlobals.hasOwnProperty)
195 .replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
196 .replace(
197 /\$hmrDownloadUpdateHandlers\$/g,
198 RuntimeGlobals.hmrDownloadUpdateHandlers
199 )
200 .replace(
201 /\$hmrInvalidateModuleHandlers\$/g,
202 RuntimeGlobals.hmrInvalidateModuleHandlers
203 )
204 ])
205 : "// no HMR",
206 "",
207 withHmrManifest
208 ? Template.asString([
209 `${
210 RuntimeGlobals.hmrDownloadManifest
211 } = ${runtimeTemplate.basicFunction("", [
212 'if (typeof fetch === "undefined") throw new Error("No browser support: need fetch API");',
213 `return fetch(${RuntimeGlobals.publicPath} + ${
214 RuntimeGlobals.getUpdateManifestFilename
215 }()).then(${runtimeTemplate.basicFunction("response", [
216 "if(response.status === 404) return; // no update available",
217 'if(!response.ok) throw new Error("Failed to fetch update manifest " + response.statusText);',
218 "return response.json();"
219 ])});`
220 ])};`
221 ])
222 : "// no HMR manifest"
223 ]);
224 }
225}
226
227module.exports = ImportScriptsChunkLoadingRuntimeModule;