source: imaps-frontend/node_modules/webpack/lib/hmr/LazyCompilationPlugin.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 13.5 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { RawSource } = require("webpack-sources");
9const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
10const Dependency = require("../Dependency");
11const Module = require("../Module");
12const ModuleFactory = require("../ModuleFactory");
13const { JS_TYPES } = require("../ModuleSourceTypesConstants");
14const {
15 WEBPACK_MODULE_TYPE_LAZY_COMPILATION_PROXY
16} = require("../ModuleTypeConstants");
17const RuntimeGlobals = require("../RuntimeGlobals");
18const Template = require("../Template");
19const CommonJsRequireDependency = require("../dependencies/CommonJsRequireDependency");
20const { registerNotSerializable } = require("../util/serialization");
21
22/** @typedef {import("../../declarations/WebpackOptions")} WebpackOptions */
23/** @typedef {import("../Compilation")} Compilation */
24/** @typedef {import("../Compiler")} Compiler */
25/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
26/** @typedef {import("../Module").BuildMeta} BuildMeta */
27/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
28/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
29/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
30/** @typedef {import("../Module").NeedBuildContext} NeedBuildContext */
31/** @typedef {import("../Module").SourceTypes} SourceTypes */
32/** @typedef {import("../ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
33/** @typedef {import("../ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
34/** @typedef {import("../RequestShortener")} RequestShortener */
35/** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
36/** @typedef {import("../WebpackError")} WebpackError */
37/** @typedef {import("../dependencies/HarmonyImportDependency")} HarmonyImportDependency */
38/** @typedef {import("../util/Hash")} Hash */
39/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
40
41/** @typedef {{ client: string, data: string, active: boolean }} ModuleResult */
42
43/**
44 * @typedef {object} BackendApi
45 * @property {function(function((Error | null)=) : void): void} dispose
46 * @property {function(Module): ModuleResult} module
47 */
48
49const HMR_DEPENDENCY_TYPES = new Set([
50 "import.meta.webpackHot.accept",
51 "import.meta.webpackHot.decline",
52 "module.hot.accept",
53 "module.hot.decline"
54]);
55
56/**
57 * @param {undefined|string|RegExp|Function} test test option
58 * @param {Module} module the module
59 * @returns {boolean | null | string} true, if the module should be selected
60 */
61const checkTest = (test, module) => {
62 if (test === undefined) return true;
63 if (typeof test === "function") {
64 return test(module);
65 }
66 if (typeof test === "string") {
67 const name = module.nameForCondition();
68 return name && name.startsWith(test);
69 }
70 if (test instanceof RegExp) {
71 const name = module.nameForCondition();
72 return name && test.test(name);
73 }
74 return false;
75};
76
77class LazyCompilationDependency extends Dependency {
78 /**
79 * @param {LazyCompilationProxyModule} proxyModule proxy module
80 */
81 constructor(proxyModule) {
82 super();
83 this.proxyModule = proxyModule;
84 }
85
86 get category() {
87 return "esm";
88 }
89
90 get type() {
91 return "lazy import()";
92 }
93
94 /**
95 * @returns {string | null} an identifier to merge equal requests
96 */
97 getResourceIdentifier() {
98 return this.proxyModule.originalModule.identifier();
99 }
100}
101
102registerNotSerializable(LazyCompilationDependency);
103
104class LazyCompilationProxyModule extends Module {
105 /**
106 * @param {string} context context
107 * @param {Module} originalModule an original module
108 * @param {string} request request
109 * @param {ModuleResult["client"]} client client
110 * @param {ModuleResult["data"]} data data
111 * @param {ModuleResult["active"]} active true when active, otherwise false
112 */
113 constructor(context, originalModule, request, client, data, active) {
114 super(
115 WEBPACK_MODULE_TYPE_LAZY_COMPILATION_PROXY,
116 context,
117 originalModule.layer
118 );
119 this.originalModule = originalModule;
120 this.request = request;
121 this.client = client;
122 this.data = data;
123 this.active = active;
124 }
125
126 /**
127 * @returns {string} a unique identifier of the module
128 */
129 identifier() {
130 return `${WEBPACK_MODULE_TYPE_LAZY_COMPILATION_PROXY}|${this.originalModule.identifier()}`;
131 }
132
133 /**
134 * @param {RequestShortener} requestShortener the request shortener
135 * @returns {string} a user readable identifier of the module
136 */
137 readableIdentifier(requestShortener) {
138 return `${WEBPACK_MODULE_TYPE_LAZY_COMPILATION_PROXY} ${this.originalModule.readableIdentifier(
139 requestShortener
140 )}`;
141 }
142
143 /**
144 * Assuming this module is in the cache. Update the (cached) module with
145 * the fresh module from the factory. Usually updates internal references
146 * and properties.
147 * @param {Module} module fresh module
148 * @returns {void}
149 */
150 updateCacheModule(module) {
151 super.updateCacheModule(module);
152 const m = /** @type {LazyCompilationProxyModule} */ (module);
153 this.originalModule = m.originalModule;
154 this.request = m.request;
155 this.client = m.client;
156 this.data = m.data;
157 this.active = m.active;
158 }
159
160 /**
161 * @param {LibIdentOptions} options options
162 * @returns {string | null} an identifier for library inclusion
163 */
164 libIdent(options) {
165 return `${this.originalModule.libIdent(
166 options
167 )}!${WEBPACK_MODULE_TYPE_LAZY_COMPILATION_PROXY}`;
168 }
169
170 /**
171 * @param {NeedBuildContext} context context info
172 * @param {function((WebpackError | null)=, boolean=): void} callback callback function, returns true, if the module needs a rebuild
173 * @returns {void}
174 */
175 needBuild(context, callback) {
176 callback(null, !this.buildInfo || this.buildInfo.active !== this.active);
177 }
178
179 /**
180 * @param {WebpackOptions} options webpack options
181 * @param {Compilation} compilation the compilation
182 * @param {ResolverWithOptions} resolver the resolver
183 * @param {InputFileSystem} fs the file system
184 * @param {function(WebpackError=): void} callback callback function
185 * @returns {void}
186 */
187 build(options, compilation, resolver, fs, callback) {
188 this.buildInfo = {
189 active: this.active
190 };
191 /** @type {BuildMeta} */
192 this.buildMeta = {};
193 this.clearDependenciesAndBlocks();
194 const dep = new CommonJsRequireDependency(this.client);
195 this.addDependency(dep);
196 if (this.active) {
197 const dep = new LazyCompilationDependency(this);
198 const block = new AsyncDependenciesBlock({});
199 block.addDependency(dep);
200 this.addBlock(block);
201 }
202 callback();
203 }
204
205 /**
206 * @returns {SourceTypes} types available (do not mutate)
207 */
208 getSourceTypes() {
209 return JS_TYPES;
210 }
211
212 /**
213 * @param {string=} type the source type for which the size should be estimated
214 * @returns {number} the estimated size of the module (must be non-zero)
215 */
216 size(type) {
217 return 200;
218 }
219
220 /**
221 * @param {CodeGenerationContext} context context for code generation
222 * @returns {CodeGenerationResult} result
223 */
224 codeGeneration({ runtimeTemplate, chunkGraph, moduleGraph }) {
225 const sources = new Map();
226 const runtimeRequirements = new Set();
227 runtimeRequirements.add(RuntimeGlobals.module);
228 const clientDep = /** @type {CommonJsRequireDependency} */ (
229 this.dependencies[0]
230 );
231 const clientModule = moduleGraph.getModule(clientDep);
232 const block = this.blocks[0];
233 const client = Template.asString([
234 `var client = ${runtimeTemplate.moduleExports({
235 module: clientModule,
236 chunkGraph,
237 request: clientDep.userRequest,
238 runtimeRequirements
239 })}`,
240 `var data = ${JSON.stringify(this.data)};`
241 ]);
242 const keepActive = Template.asString([
243 `var dispose = client.keepAlive({ data: data, active: ${JSON.stringify(
244 Boolean(block)
245 )}, module: module, onError: onError });`
246 ]);
247 let source;
248 if (block) {
249 const dep = block.dependencies[0];
250 const module = /** @type {Module} */ (moduleGraph.getModule(dep));
251 source = Template.asString([
252 client,
253 `module.exports = ${runtimeTemplate.moduleNamespacePromise({
254 chunkGraph,
255 block,
256 module,
257 request: this.request,
258 strict: false, // TODO this should be inherited from the original module
259 message: "import()",
260 runtimeRequirements
261 })};`,
262 "if (module.hot) {",
263 Template.indent([
264 "module.hot.accept();",
265 `module.hot.accept(${JSON.stringify(
266 chunkGraph.getModuleId(module)
267 )}, function() { module.hot.invalidate(); });`,
268 "module.hot.dispose(function(data) { delete data.resolveSelf; dispose(data); });",
269 "if (module.hot.data && module.hot.data.resolveSelf) module.hot.data.resolveSelf(module.exports);"
270 ]),
271 "}",
272 "function onError() { /* ignore */ }",
273 keepActive
274 ]);
275 } else {
276 source = Template.asString([
277 client,
278 "var resolveSelf, onError;",
279 "module.exports = new Promise(function(resolve, reject) { resolveSelf = resolve; onError = reject; });",
280 "if (module.hot) {",
281 Template.indent([
282 "module.hot.accept();",
283 "if (module.hot.data && module.hot.data.resolveSelf) module.hot.data.resolveSelf(module.exports);",
284 "module.hot.dispose(function(data) { data.resolveSelf = resolveSelf; dispose(data); });"
285 ]),
286 "}",
287 keepActive
288 ]);
289 }
290 sources.set("javascript", new RawSource(source));
291 return {
292 sources,
293 runtimeRequirements
294 };
295 }
296
297 /**
298 * @param {Hash} hash the hash used to track dependencies
299 * @param {UpdateHashContext} context context
300 * @returns {void}
301 */
302 updateHash(hash, context) {
303 super.updateHash(hash, context);
304 hash.update(this.active ? "active" : "");
305 hash.update(JSON.stringify(this.data));
306 }
307}
308
309registerNotSerializable(LazyCompilationProxyModule);
310
311class LazyCompilationDependencyFactory extends ModuleFactory {
312 constructor() {
313 super();
314 }
315
316 /**
317 * @param {ModuleFactoryCreateData} data data object
318 * @param {function((Error | null)=, ModuleFactoryResult=): void} callback callback
319 * @returns {void}
320 */
321 create(data, callback) {
322 const dependency = /** @type {LazyCompilationDependency} */ (
323 data.dependencies[0]
324 );
325 callback(null, {
326 module: dependency.proxyModule.originalModule
327 });
328 }
329}
330
331/**
332 * @callback BackendHandler
333 * @param {Compiler} compiler compiler
334 * @param {function(Error | null, BackendApi=): void} callback callback
335 * @returns {void}
336 */
337
338/**
339 * @callback PromiseBackendHandler
340 * @param {Compiler} compiler compiler
341 * @returns {Promise<BackendApi>} backend
342 */
343
344class LazyCompilationPlugin {
345 /**
346 * @param {object} options options
347 * @param {BackendHandler | PromiseBackendHandler} options.backend the backend
348 * @param {boolean} options.entries true, when entries are lazy compiled
349 * @param {boolean} options.imports true, when import() modules are lazy compiled
350 * @param {RegExp | string | (function(Module): boolean) | undefined} options.test additional filter for lazy compiled entrypoint modules
351 */
352 constructor({ backend, entries, imports, test }) {
353 this.backend = backend;
354 this.entries = entries;
355 this.imports = imports;
356 this.test = test;
357 }
358
359 /**
360 * Apply the plugin
361 * @param {Compiler} compiler the compiler instance
362 * @returns {void}
363 */
364 apply(compiler) {
365 /** @type {BackendApi} */
366 let backend;
367 compiler.hooks.beforeCompile.tapAsync(
368 "LazyCompilationPlugin",
369 (params, callback) => {
370 if (backend !== undefined) return callback();
371 const promise = this.backend(compiler, (err, result) => {
372 if (err) return callback(err);
373 backend = /** @type {BackendApi} */ (result);
374 callback();
375 });
376 if (promise && promise.then) {
377 promise.then(b => {
378 backend = b;
379 callback();
380 }, callback);
381 }
382 }
383 );
384 compiler.hooks.thisCompilation.tap(
385 "LazyCompilationPlugin",
386 (compilation, { normalModuleFactory }) => {
387 normalModuleFactory.hooks.module.tap(
388 "LazyCompilationPlugin",
389 (originalModule, createData, resolveData) => {
390 if (
391 resolveData.dependencies.every(dep =>
392 HMR_DEPENDENCY_TYPES.has(dep.type)
393 )
394 ) {
395 // for HMR only resolving, try to determine if the HMR accept/decline refers to
396 // an import() or not
397 const hmrDep = resolveData.dependencies[0];
398 const originModule =
399 /** @type {Module} */
400 (compilation.moduleGraph.getParentModule(hmrDep));
401 const isReferringToDynamicImport = originModule.blocks.some(
402 block =>
403 block.dependencies.some(
404 dep =>
405 dep.type === "import()" &&
406 /** @type {HarmonyImportDependency} */ (dep).request ===
407 hmrDep.request
408 )
409 );
410 if (!isReferringToDynamicImport) return;
411 } else if (
412 !resolveData.dependencies.every(
413 dep =>
414 HMR_DEPENDENCY_TYPES.has(dep.type) ||
415 (this.imports &&
416 (dep.type === "import()" ||
417 dep.type === "import() context element")) ||
418 (this.entries && dep.type === "entry")
419 )
420 )
421 return;
422 if (
423 /webpack[/\\]hot[/\\]|webpack-dev-server[/\\]client|webpack-hot-middleware[/\\]client/.test(
424 resolveData.request
425 ) ||
426 !checkTest(this.test, originalModule)
427 )
428 return;
429 const moduleInfo = backend.module(originalModule);
430 if (!moduleInfo) return;
431 const { client, data, active } = moduleInfo;
432
433 return new LazyCompilationProxyModule(
434 compiler.context,
435 originalModule,
436 resolveData.request,
437 client,
438 data,
439 active
440 );
441 }
442 );
443 compilation.dependencyFactories.set(
444 LazyCompilationDependency,
445 new LazyCompilationDependencyFactory()
446 );
447 }
448 );
449 compiler.hooks.shutdown.tapAsync("LazyCompilationPlugin", callback => {
450 backend.dispose(callback);
451 });
452 }
453}
454
455module.exports = LazyCompilationPlugin;
Note: See TracBrowser for help on using the repository browser.