1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | const RuntimeGlobals = require("../RuntimeGlobals");
|
8 | const RuntimeModule = require("../RuntimeModule");
|
9 | const Template = require("../Template");
|
10 | const {
|
11 | chunkHasJs,
|
12 | getChunkFilenameTemplate
|
13 | } = require("../javascript/JavascriptModulesPlugin");
|
14 | const { getInitialChunkIds } = require("../javascript/StartupHelpers");
|
15 | const compileBooleanMatcher = require("../util/compileBooleanMatcher");
|
16 | const { getUndoPath } = require("../util/identifier");
|
17 |
|
18 |
|
19 |
|
20 | class RequireChunkLoadingRuntimeModule extends RuntimeModule {
|
21 | constructor(runtimeRequirements) {
|
22 | super("require chunk loading", RuntimeModule.STAGE_ATTACH);
|
23 | this.runtimeRequirements = runtimeRequirements;
|
24 | }
|
25 |
|
26 | |
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | _generateBaseUri(chunk, rootOutputDir) {
|
33 | const options = chunk.getEntryOptions();
|
34 | if (options && options.baseUri) {
|
35 | return `${RuntimeGlobals.baseURI} = ${JSON.stringify(options.baseUri)};`;
|
36 | }
|
37 |
|
38 | return `${RuntimeGlobals.baseURI} = require("url").pathToFileURL(${
|
39 | rootOutputDir !== "./"
|
40 | ? `__dirname + ${JSON.stringify("/" + rootOutputDir)}`
|
41 | : "__filename"
|
42 | });`;
|
43 | }
|
44 |
|
45 | |
46 |
|
47 |
|
48 | generate() {
|
49 | const { chunkGraph, chunk } = this;
|
50 | const { runtimeTemplate } = this.compilation;
|
51 | const fn = RuntimeGlobals.ensureChunkHandlers;
|
52 | const withBaseURI = this.runtimeRequirements.has(RuntimeGlobals.baseURI);
|
53 | const withExternalInstallChunk = this.runtimeRequirements.has(
|
54 | RuntimeGlobals.externalInstallChunk
|
55 | );
|
56 | const withOnChunkLoad = this.runtimeRequirements.has(
|
57 | RuntimeGlobals.onChunksLoaded
|
58 | );
|
59 | const withLoading = this.runtimeRequirements.has(
|
60 | RuntimeGlobals.ensureChunkHandlers
|
61 | );
|
62 | const withHmr = this.runtimeRequirements.has(
|
63 | RuntimeGlobals.hmrDownloadUpdateHandlers
|
64 | );
|
65 | const withHmrManifest = this.runtimeRequirements.has(
|
66 | RuntimeGlobals.hmrDownloadManifest
|
67 | );
|
68 | const conditionMap = chunkGraph.getChunkConditionMap(chunk, chunkHasJs);
|
69 | const hasJsMatcher = compileBooleanMatcher(conditionMap);
|
70 | const initialChunkIds = getInitialChunkIds(chunk, chunkGraph, chunkHasJs);
|
71 |
|
72 | const outputName = this.compilation.getPath(
|
73 | getChunkFilenameTemplate(chunk, this.compilation.outputOptions),
|
74 | {
|
75 | chunk,
|
76 | contentHashType: "javascript"
|
77 | }
|
78 | );
|
79 | const rootOutputDir = getUndoPath(
|
80 | outputName,
|
81 | this.compilation.outputOptions.path,
|
82 | true
|
83 | );
|
84 |
|
85 | const stateExpression = withHmr
|
86 | ? `${RuntimeGlobals.hmrRuntimeStatePrefix}_require`
|
87 | : undefined;
|
88 |
|
89 | return Template.asString([
|
90 | withBaseURI
|
91 | ? this._generateBaseUri(chunk, rootOutputDir)
|
92 | : "// no baseURI",
|
93 | "",
|
94 | "// object to store loaded chunks",
|
95 | '// "1" means "loaded", otherwise not loaded yet',
|
96 | `var installedChunks = ${
|
97 | stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""
|
98 | }{`,
|
99 | Template.indent(
|
100 | Array.from(initialChunkIds, id => `${JSON.stringify(id)}: 1`).join(
|
101 | ",\n"
|
102 | )
|
103 | ),
|
104 | "};",
|
105 | "",
|
106 | withOnChunkLoad
|
107 | ? `${
|
108 | RuntimeGlobals.onChunksLoaded
|
109 | }.require = ${runtimeTemplate.returningFunction(
|
110 | "installedChunks[chunkId]",
|
111 | "chunkId"
|
112 | )};`
|
113 | : "// no on chunks loaded",
|
114 | "",
|
115 | withLoading || withExternalInstallChunk
|
116 | ? `var installChunk = ${runtimeTemplate.basicFunction("chunk", [
|
117 | "var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;",
|
118 | "for(var moduleId in moreModules) {",
|
119 | Template.indent([
|
120 | `if(${RuntimeGlobals.hasOwnProperty}(moreModules, moduleId)) {`,
|
121 | Template.indent([
|
122 | `${RuntimeGlobals.moduleFactories}[moduleId] = moreModules[moduleId];`
|
123 | ]),
|
124 | "}"
|
125 | ]),
|
126 | "}",
|
127 | `if(runtime) runtime(__webpack_require__);`,
|
128 | "for(var i = 0; i < chunkIds.length; i++)",
|
129 | Template.indent("installedChunks[chunkIds[i]] = 1;"),
|
130 | withOnChunkLoad ? `${RuntimeGlobals.onChunksLoaded}();` : ""
|
131 | ])};`
|
132 | : "// no chunk install function needed",
|
133 | "",
|
134 | withLoading
|
135 | ? Template.asString([
|
136 | "// require() chunk loading for javascript",
|
137 | `${fn}.require = ${runtimeTemplate.basicFunction(
|
138 | "chunkId, promises",
|
139 | hasJsMatcher !== false
|
140 | ? [
|
141 | '// "1" is the signal for "already loaded"',
|
142 | "if(!installedChunks[chunkId]) {",
|
143 | Template.indent([
|
144 | hasJsMatcher === true
|
145 | ? "if(true) { // all chunks have JS"
|
146 | : `if(${hasJsMatcher("chunkId")}) {`,
|
147 | Template.indent([
|
148 | `installChunk(require(${JSON.stringify(
|
149 | rootOutputDir
|
150 | )} + ${
|
151 | RuntimeGlobals.getChunkScriptFilename
|
152 | }(chunkId)));`
|
153 | ]),
|
154 | "} else installedChunks[chunkId] = 1;",
|
155 | ""
|
156 | ]),
|
157 | "}"
|
158 | ]
|
159 | : "installedChunks[chunkId] = 1;"
|
160 | )};`
|
161 | ])
|
162 | : "// no chunk loading",
|
163 | "",
|
164 | withExternalInstallChunk
|
165 | ? Template.asString([
|
166 | "module.exports = __webpack_require__;",
|
167 | `${RuntimeGlobals.externalInstallChunk} = installChunk;`
|
168 | ])
|
169 | : "// no external install chunk",
|
170 | "",
|
171 | withHmr
|
172 | ? Template.asString([
|
173 | "function loadUpdateChunk(chunkId, updatedModulesList) {",
|
174 | Template.indent([
|
175 | `var update = require(${JSON.stringify(rootOutputDir)} + ${
|
176 | RuntimeGlobals.getChunkUpdateScriptFilename
|
177 | }(chunkId));`,
|
178 | "var updatedModules = update.modules;",
|
179 | "var runtime = update.runtime;",
|
180 | "for(var moduleId in updatedModules) {",
|
181 | Template.indent([
|
182 | `if(${RuntimeGlobals.hasOwnProperty}(updatedModules, moduleId)) {`,
|
183 | Template.indent([
|
184 | `currentUpdate[moduleId] = updatedModules[moduleId];`,
|
185 | "if(updatedModulesList) updatedModulesList.push(moduleId);"
|
186 | ]),
|
187 | "}"
|
188 | ]),
|
189 | "}",
|
190 | "if(runtime) currentUpdateRuntime.push(runtime);"
|
191 | ]),
|
192 | "}",
|
193 | "",
|
194 | Template.getFunctionContent(
|
195 | require("../hmr/JavascriptHotModuleReplacement.runtime.js")
|
196 | )
|
197 | .replace(/\$key\$/g, "require")
|
198 | .replace(/\$installedChunks\$/g, "installedChunks")
|
199 | .replace(/\$loadUpdateChunk\$/g, "loadUpdateChunk")
|
200 | .replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
|
201 | .replace(/\$moduleFactories\$/g, RuntimeGlobals.moduleFactories)
|
202 | .replace(
|
203 | /\$ensureChunkHandlers\$/g,
|
204 | RuntimeGlobals.ensureChunkHandlers
|
205 | )
|
206 | .replace(/\$hasOwnProperty\$/g, RuntimeGlobals.hasOwnProperty)
|
207 | .replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
|
208 | .replace(
|
209 | /\$hmrDownloadUpdateHandlers\$/g,
|
210 | RuntimeGlobals.hmrDownloadUpdateHandlers
|
211 | )
|
212 | .replace(
|
213 | /\$hmrInvalidateModuleHandlers\$/g,
|
214 | RuntimeGlobals.hmrInvalidateModuleHandlers
|
215 | )
|
216 | ])
|
217 | : "// no HMR",
|
218 | "",
|
219 | withHmrManifest
|
220 | ? Template.asString([
|
221 | `${RuntimeGlobals.hmrDownloadManifest} = function() {`,
|
222 | Template.indent([
|
223 | "return Promise.resolve().then(function() {",
|
224 | Template.indent([
|
225 | `return require(${JSON.stringify(rootOutputDir)} + ${
|
226 | RuntimeGlobals.getUpdateManifestFilename
|
227 | }());`
|
228 | ]),
|
229 | "})['catch'](function(err) { if(err.code !== 'MODULE_NOT_FOUND') throw err; });"
|
230 | ]),
|
231 | "}"
|
232 | ])
|
233 | : "// no HMR manifest"
|
234 | ]);
|
235 | }
|
236 | }
|
237 |
|
238 | module.exports = RequireChunkLoadingRuntimeModule;
|