UNPKG

7.42 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 return Template.asString([
71 withBaseURI
72 ? Template.asString([
73 `${RuntimeGlobals.baseURI} = self.location + ${JSON.stringify(
74 rootOutputDir ? "/../" + rootOutputDir : ""
75 )};`
76 ])
77 : "// no baseURI",
78 "",
79 "// object to store loaded chunks",
80 '// "1" means "already loaded"',
81 "var installedChunks = {",
82 Template.indent(
83 Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 1`).join(
84 ",\n"
85 )
86 ),
87 "};",
88 "",
89 withLoading
90 ? Template.asString([
91 "// importScripts chunk loading",
92 `var installChunk = ${runtimeTemplate.basicFunction("data", [
93 runtimeTemplate.destructureArray(
94 ["chunkIds", "moreModules", "runtime"],
95 "data"
96 ),
97 "for(var moduleId in moreModules) {",
98 Template.indent([
99 `if(${RuntimeGlobals.hasOwnProperty}(moreModules, moduleId)) {`,
100 Template.indent(
101 `${RuntimeGlobals.moduleFactories}[moduleId] = moreModules[moduleId];`
102 ),
103 "}"
104 ]),
105 "}",
106 "if(runtime) runtime(__webpack_require__);",
107 "while(chunkIds.length)",
108 Template.indent("installedChunks[chunkIds.pop()] = 1;"),
109 "parentChunkLoadingFunction(data);"
110 ])};`
111 ])
112 : "// no chunk install function needed",
113 withLoading
114 ? Template.asString([
115 `${fn}.i = ${runtimeTemplate.basicFunction(
116 "chunkId, promises",
117 hasJsMatcher !== false
118 ? [
119 '// "1" is the signal for "already loaded"',
120 "if(!installedChunks[chunkId]) {",
121 Template.indent([
122 hasJsMatcher === true
123 ? "if(true) { // all chunks have JS"
124 : `if(${hasJsMatcher("chunkId")}) {`,
125 Template.indent(
126 `importScripts(${
127 withCreateScriptUrl
128 ? `${RuntimeGlobals.createScriptUrl}(${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId))`
129 : `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkScriptFilename}(chunkId)`
130 });`
131 ),
132 "}"
133 ]),
134 "}"
135 ]
136 : "installedChunks[chunkId] = 1;"
137 )};`,
138 "",
139 `var chunkLoadingGlobal = ${chunkLoadingGlobalExpr} = ${chunkLoadingGlobalExpr} || [];`,
140 "var parentChunkLoadingFunction = chunkLoadingGlobal.push.bind(chunkLoadingGlobal);",
141 "chunkLoadingGlobal.push = installChunk;"
142 ])
143 : "// no chunk loading",
144 "",
145 withHmr
146 ? Template.asString([
147 "function loadUpdateChunk(chunkId, updatedModulesList) {",
148 Template.indent([
149 "var success = false;",
150 `${globalObject}[${JSON.stringify(
151 hotUpdateGlobal
152 )}] = ${runtimeTemplate.basicFunction("_, moreModules, runtime", [
153 "for(var moduleId in moreModules) {",
154 Template.indent([
155 `if(${RuntimeGlobals.hasOwnProperty}(moreModules, moduleId)) {`,
156 Template.indent([
157 "currentUpdate[moduleId] = moreModules[moduleId];",
158 "if(updatedModulesList) updatedModulesList.push(moduleId);"
159 ]),
160 "}"
161 ]),
162 "}",
163 "if(runtime) currentUpdateRuntime.push(runtime);",
164 "success = true;"
165 ])};`,
166 "// start update chunk loading",
167 `importScripts(${
168 withCreateScriptUrl
169 ? `${RuntimeGlobals.createScriptUrl}(${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId))`
170 : `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkUpdateScriptFilename}(chunkId)`
171 });`,
172 'if(!success) throw new Error("Loading update chunk failed for unknown reason");'
173 ]),
174 "}",
175 "",
176 Template.getFunctionContent(
177 require("../hmr/JavascriptHotModuleReplacement.runtime.js")
178 )
179 .replace(/\$key\$/g, "importScrips")
180 .replace(/\$installedChunks\$/g, "installedChunks")
181 .replace(/\$loadUpdateChunk\$/g, "loadUpdateChunk")
182 .replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
183 .replace(/\$moduleFactories\$/g, RuntimeGlobals.moduleFactories)
184 .replace(
185 /\$ensureChunkHandlers\$/g,
186 RuntimeGlobals.ensureChunkHandlers
187 )
188 .replace(/\$hasOwnProperty\$/g, RuntimeGlobals.hasOwnProperty)
189 .replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
190 .replace(
191 /\$hmrDownloadUpdateHandlers\$/g,
192 RuntimeGlobals.hmrDownloadUpdateHandlers
193 )
194 .replace(
195 /\$hmrInvalidateModuleHandlers\$/g,
196 RuntimeGlobals.hmrInvalidateModuleHandlers
197 )
198 ])
199 : "// no HMR",
200 "",
201 withHmrManifest
202 ? Template.asString([
203 `${
204 RuntimeGlobals.hmrDownloadManifest
205 } = ${runtimeTemplate.basicFunction("", [
206 'if (typeof fetch === "undefined") throw new Error("No browser support: need fetch API");',
207 `return fetch(${RuntimeGlobals.publicPath} + ${
208 RuntimeGlobals.getUpdateManifestFilename
209 }()).then(${runtimeTemplate.basicFunction("response", [
210 "if(response.status === 404) return; // no update available",
211 'if(!response.ok) throw new Error("Failed to fetch update manifest " + response.statusText);',
212 "return response.json();"
213 ])});`
214 ])};`
215 ])
216 : "// no HMR manifest"
217 ]);
218 }
219}
220
221module.exports = ImportScriptsChunkLoadingRuntimeModule;