source: frontend/node_modules/webpack/lib/Compiler.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 44.1 KB
RevLine 
[9af201e]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const asyncLib = require("neo-async");
9const {
10 AsyncParallelHook,
11 AsyncSeriesHook,
12 SyncBailHook,
13 SyncHook
14} = require("tapable");
15const { SizeOnlySource } = require("webpack-sources");
16const Cache = require("./Cache");
17const CacheFacade = require("./CacheFacade");
18const ChunkGraph = require("./ChunkGraph");
19const Compilation = require("./Compilation");
20const ContextModuleFactory = require("./ContextModuleFactory");
21const ModuleGraph = require("./ModuleGraph");
22const NormalModuleFactory = require("./NormalModuleFactory");
23const RequestShortener = require("./RequestShortener");
24const ResolverFactory = require("./ResolverFactory");
25const Stats = require("./Stats");
26const Watching = require("./Watching");
27const ConcurrentCompilationError = require("./errors/ConcurrentCompilationError");
28const WebpackError = require("./errors/WebpackError");
29const { Logger } = require("./logging/Logger");
30const { dirname, join, mkdirp } = require("./util/fs");
31const { makePathsRelative } = require("./util/identifier");
32const memoize = require("./util/memoize");
33const parseJson = require("./util/parseJson");
34const { isSourceEqual } = require("./util/source");
35const webpack = require(".");
36
37/** @typedef {import("webpack-sources").Source} Source */
38/** @typedef {import("../declarations/WebpackOptions").EntryNormalized} Entry */
39/** @typedef {import("../declarations/WebpackOptions").OutputNormalized} OutputOptions */
40/** @typedef {import("../declarations/WebpackOptions").WatchOptions} WatchOptions */
41/** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
42/** @typedef {import("../declarations/WebpackOptions").Plugins} Plugins */
43/** @typedef {import("./webpack").WebpackPluginFunction} WebpackPluginFunction */
44/** @typedef {import("./Chunk")} Chunk */
45/** @typedef {import("./Dependency")} Dependency */
46/** @typedef {import("./HotModuleReplacementPlugin").ChunkHashes} ChunkHashes */
47/** @typedef {import("./HotModuleReplacementPlugin").ChunkModuleHashes} ChunkModuleHashes */
48/** @typedef {import("./HotModuleReplacementPlugin").ChunkModuleIds} ChunkModuleIds */
49/** @typedef {import("./HotModuleReplacementPlugin").ChunkRuntime} ChunkRuntime */
50/** @typedef {import("./HotModuleReplacementPlugin").FullHashChunkModuleHashes} FullHashChunkModuleHashes */
51/** @typedef {import("./HotModuleReplacementPlugin").HotIndex} HotIndex */
52/** @typedef {import("./Module")} Module */
53/** @typedef {import("./Module").BuildInfo} BuildInfo */
54/** @typedef {import("./RecordIdsPlugin").RecordsChunks} RecordsChunks */
55/** @typedef {import("./RecordIdsPlugin").RecordsModules} RecordsModules */
56/** @typedef {import("./config/target").PlatformTargetProperties} PlatformTargetProperties */
57/** @typedef {import("./logging/createConsoleLogger").LoggingFunction} LoggingFunction */
58/** @typedef {import("./optimize/AggressiveSplittingPlugin").SplitData} SplitData */
59/** @typedef {import("./util/fs").IStats} IStats */
60/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
61/** @typedef {import("./util/fs").IntermediateFileSystem} IntermediateFileSystem */
62/** @typedef {import("./util/fs").OutputFileSystem} OutputFileSystem */
63/** @typedef {import("./util/fs").TimeInfoEntries} TimeInfoEntries */
64/** @typedef {import("./util/fs").WatchFileSystem} WatchFileSystem */
65/** @typedef {import("schema-utils").validate} Validate */
66/** @typedef {import("schema-utils").Schema} Schema */
67/** @typedef {import("schema-utils").ValidationErrorConfiguration} ValidationErrorConfiguration */
68
69/**
70 * Defines the compilation params type used by this module.
71 * @typedef {object} CompilationParams
72 * @property {NormalModuleFactory} normalModuleFactory
73 * @property {ContextModuleFactory} contextModuleFactory
74 */
75
76/**
77 * Defines the callback type used by this module.
78 * @template T
79 * @template [R=void]
80 * @typedef {import("./webpack").Callback<T, R>} Callback
81 */
82
83/** @typedef {import("./webpack").ErrorCallback} ErrorCallback */
84
85/**
86 * Defines the run as child callback callback.
87 * @callback RunAsChildCallback
88 * @param {Error | null} err
89 * @param {Chunk[]=} entries
90 * @param {Compilation=} compilation
91 * @returns {void}
92 */
93
94/**
95 * Defines the known records type used by this module.
96 * @typedef {object} KnownRecords
97 * @property {SplitData[]=} aggressiveSplits
98 * @property {RecordsChunks=} chunks
99 * @property {RecordsModules=} modules
100 * @property {string=} hash
101 * @property {HotIndex=} hotIndex
102 * @property {FullHashChunkModuleHashes=} fullHashChunkModuleHashes
103 * @property {ChunkModuleHashes=} chunkModuleHashes
104 * @property {ChunkHashes=} chunkHashes
105 * @property {ChunkRuntime=} chunkRuntime
106 * @property {ChunkModuleIds=} chunkModuleIds
107 */
108
109/** @typedef {KnownRecords & Record<string, KnownRecords[]> & Record<string, EXPECTED_ANY>} Records */
110
111/**
112 * Defines the asset emitted info type used by this module.
113 * @typedef {object} AssetEmittedInfo
114 * @property {Buffer} content
115 * @property {Source} source
116 * @property {Compilation} compilation
117 * @property {string} outputPath
118 * @property {string} targetPath
119 */
120
121/** @typedef {{ sizeOnlySource: SizeOnlySource | undefined, writtenTo: Map<string, number> }} CacheEntry */
122/** @typedef {{ path: string, source: Source, size: number | undefined, waiting: ({ cacheEntry: CacheEntry, file: string }[] | undefined) }} SimilarEntry */
123
124/** @typedef {WeakMap<Dependency, Module>} WeakReferences */
125/** @typedef {import("./util/WeakTupleMap")<EXPECTED_ANY[], EXPECTED_ANY>} MemCache */
126/** @typedef {{ buildInfo: BuildInfo, references: WeakReferences | undefined, memCache: MemCache }} ModuleMemCachesItem */
127
128/**
129 * Checks whether this object is sorted.
130 * @template T
131 * @param {T[]} array an array
132 * @returns {boolean} true, if the array is sorted
133 */
134const isSorted = (array) => {
135 for (let i = 1; i < array.length; i++) {
136 if (array[i - 1] > array[i]) return false;
137 }
138 return true;
139};
140
141/**
142 * Returns the object with properties sorted by property name.
143 * @template {object} T
144 * @param {T} obj an object
145 * @param {(keyof T)[]} keys the keys of the object
146 * @returns {T} the object with properties sorted by property name
147 */
148const sortObject = (obj, keys) => {
149 const o = /** @type {T} */ ({});
150 for (const k of keys.sort()) {
151 o[k] = obj[k];
152 }
153 return o;
154};
155
156/**
157 * Returns true, if the filename contains any hash.
158 * @param {string} filename filename
159 * @param {string | string[] | undefined} hashes list of hashes
160 * @returns {boolean} true, if the filename contains any hash
161 */
162const includesHash = (filename, hashes) => {
163 if (!hashes) return false;
164 if (Array.isArray(hashes)) {
165 return hashes.some((hash) => filename.includes(hash));
166 }
167 return filename.includes(hashes);
168};
169
170const getValidate = memoize(() => require("schema-utils").validate);
171
172class Compiler {
173 /**
174 * Creates an instance of Compiler.
175 * @param {string} context the compilation path
176 * @param {WebpackOptions} options options
177 */
178 constructor(context, options = /** @type {WebpackOptions} */ ({})) {
179 this.hooks = Object.freeze({
180 /** @type {SyncHook<[]>} */
181 initialize: new SyncHook([]),
182
183 /** @type {SyncBailHook<[Compilation], boolean | void>} */
184 shouldEmit: new SyncBailHook(["compilation"]),
185 /** @type {AsyncSeriesHook<[Stats]>} */
186 done: new AsyncSeriesHook(["stats"]),
187 /** @type {SyncHook<[Stats]>} */
188 afterDone: new SyncHook(["stats"]),
189 /** @type {AsyncSeriesHook<[]>} */
190 additionalPass: new AsyncSeriesHook([]),
191 /** @type {AsyncSeriesHook<[Compiler]>} */
192 beforeRun: new AsyncSeriesHook(["compiler"]),
193 /** @type {AsyncSeriesHook<[Compiler]>} */
194 run: new AsyncSeriesHook(["compiler"]),
195 /** @type {AsyncSeriesHook<[Compilation]>} */
196 emit: new AsyncSeriesHook(["compilation"]),
197 /** @type {AsyncSeriesHook<[string, AssetEmittedInfo]>} */
198 assetEmitted: new AsyncSeriesHook(["file", "info"]),
199 /** @type {AsyncSeriesHook<[Compilation]>} */
200 afterEmit: new AsyncSeriesHook(["compilation"]),
201
202 /** @type {SyncHook<[Compilation, CompilationParams]>} */
203 thisCompilation: new SyncHook(["compilation", "params"]),
204 /** @type {SyncHook<[Compilation, CompilationParams]>} */
205 compilation: new SyncHook(["compilation", "params"]),
206 /** @type {SyncHook<[NormalModuleFactory]>} */
207 normalModuleFactory: new SyncHook(["normalModuleFactory"]),
208 /** @type {SyncHook<[ContextModuleFactory]>} */
209 contextModuleFactory: new SyncHook(["contextModuleFactory"]),
210
211 /** @type {AsyncSeriesHook<[CompilationParams]>} */
212 beforeCompile: new AsyncSeriesHook(["params"]),
213 /** @type {SyncHook<[CompilationParams]>} */
214 compile: new SyncHook(["params"]),
215 /** @type {AsyncParallelHook<[Compilation]>} */
216 make: new AsyncParallelHook(["compilation"]),
217 /** @type {AsyncParallelHook<[Compilation]>} */
218 finishMake: new AsyncSeriesHook(["compilation"]),
219 /** @type {AsyncSeriesHook<[Compilation]>} */
220 afterCompile: new AsyncSeriesHook(["compilation"]),
221
222 /** @type {AsyncSeriesHook<[]>} */
223 readRecords: new AsyncSeriesHook([]),
224 /** @type {AsyncSeriesHook<[]>} */
225 emitRecords: new AsyncSeriesHook([]),
226
227 /** @type {AsyncSeriesHook<[Compiler]>} */
228 watchRun: new AsyncSeriesHook(["compiler"]),
229 /** @type {SyncHook<[Error]>} */
230 failed: new SyncHook(["error"]),
231 /** @type {SyncHook<[string | null, number]>} */
232 invalid: new SyncHook(["filename", "changeTime"]),
233 /** @type {SyncHook<[]>} */
234 watchClose: new SyncHook([]),
235 /** @type {AsyncSeriesHook<[]>} */
236 shutdown: new AsyncSeriesHook([]),
237
238 /** @type {SyncBailHook<[string, string, EXPECTED_ANY[] | undefined], true | void>} */
239 infrastructureLog: new SyncBailHook(["origin", "type", "args"]),
240
241 // TODO the following hooks are weirdly located here
242 // TODO move them for webpack 5
243 /** @type {SyncHook<[]>} */
244 validate: new SyncHook([]),
245 /** @type {SyncHook<[]>} */
246 environment: new SyncHook([]),
247 /** @type {SyncHook<[]>} */
248 afterEnvironment: new SyncHook([]),
249 /** @type {SyncHook<[Compiler]>} */
250 afterPlugins: new SyncHook(["compiler"]),
251 /** @type {SyncHook<[Compiler]>} */
252 afterResolvers: new SyncHook(["compiler"]),
253 /** @type {SyncBailHook<[string, Entry], boolean | void>} */
254 entryOption: new SyncBailHook(["context", "entry"])
255 });
256
257 this.webpack = webpack;
258
259 /** @type {string | undefined} */
260 this.name = undefined;
261 /** @type {Compilation | undefined} */
262 this.parentCompilation = undefined;
263 /** @type {Compiler} */
264 this.root = this;
265 /** @type {string} */
266 this.outputPath = "";
267 /** @type {Watching | undefined} */
268 this.watching = undefined;
269
270 /** @type {OutputFileSystem | null} */
271 this.outputFileSystem = null;
272 /** @type {IntermediateFileSystem | null} */
273 this.intermediateFileSystem = null;
274 /** @type {InputFileSystem | null} */
275 this.inputFileSystem = null;
276 /** @type {WatchFileSystem | null} */
277 this.watchFileSystem = null;
278
279 /** @type {string | null} */
280 this.recordsInputPath = null;
281 /** @type {string | null} */
282 this.recordsOutputPath = null;
283 /** @type {Records} */
284 this.records = {};
285 /** @type {Set<string | RegExp>} */
286 this.managedPaths = new Set();
287 /** @type {Set<string | RegExp>} */
288 this.unmanagedPaths = new Set();
289 /** @type {Set<string | RegExp>} */
290 this.immutablePaths = new Set();
291
292 /** @type {ReadonlySet<string> | undefined} */
293 this.modifiedFiles = undefined;
294 /** @type {ReadonlySet<string> | undefined} */
295 this.removedFiles = undefined;
296 /** @type {TimeInfoEntries | undefined} */
297 this.fileTimestamps = undefined;
298 /** @type {TimeInfoEntries | undefined} */
299 this.contextTimestamps = undefined;
300 /** @type {number | undefined} */
301 this.fsStartTime = undefined;
302
303 /** @type {ResolverFactory} */
304 this.resolverFactory = new ResolverFactory();
305
306 /** @type {LoggingFunction | undefined} */
307 this.infrastructureLogger = undefined;
308
309 /** @type {Readonly<PlatformTargetProperties>} */
310 this.platform = {
311 web: null,
312 browser: null,
313 webworker: null,
314 node: null,
315 nwjs: null,
316 electron: null
317 };
318
319 this.options = options;
320
321 this.context = context;
322
323 this.requestShortener = new RequestShortener(context, this.root);
324
325 this.cache = new Cache();
326
327 /** @type {Map<Module, ModuleMemCachesItem> | undefined} */
328 this.moduleMemCaches = undefined;
329
330 this.compilerPath = "";
331
332 /** @type {boolean} */
333 this.running = false;
334
335 /** @type {boolean} */
336 this.idle = false;
337
338 /** @type {boolean} */
339 this.watchMode = false;
340
341 this._backCompat = this.options.experiments.backCompat !== false;
342
343 /** @type {Compilation | undefined} */
344 this._lastCompilation = undefined;
345 /** @type {NormalModuleFactory | undefined} */
346 this._lastNormalModuleFactory = undefined;
347
348 /**
349 * @private
350 * @type {WeakMap<Source, CacheEntry>}
351 */
352 this._assetEmittingSourceCache = new WeakMap();
353 /**
354 * @private
355 * @type {Map<string, number>}
356 */
357 this._assetEmittingWrittenFiles = new Map();
358 /**
359 * @private
360 * @type {Set<string>}
361 */
362 this._assetEmittingPreviousFiles = new Set();
363 }
364
365 /**
366 * Returns the cache facade instance.
367 * @param {string} name cache name
368 * @returns {CacheFacade} the cache facade instance
369 */
370 getCache(name) {
371 return new CacheFacade(
372 this.cache,
373 `${this.compilerPath}${name}`,
374 this.options.output.hashFunction
375 );
376 }
377
378 /**
379 * Gets infrastructure logger.
380 * @param {string | (() => string)} name name of the logger, or function called once to get the logger name
381 * @returns {Logger} a logger with that name
382 */
383 getInfrastructureLogger(name) {
384 if (!name) {
385 throw new TypeError(
386 "Compiler.getInfrastructureLogger(name) called without a name"
387 );
388 }
389 return new Logger(
390 (type, args) => {
391 if (typeof name === "function") {
392 name = name();
393 if (!name) {
394 throw new TypeError(
395 "Compiler.getInfrastructureLogger(name) called with a function not returning a name"
396 );
397 }
398 }
399 if (
400 this.hooks.infrastructureLog.call(name, type, args) === undefined &&
401 this.infrastructureLogger !== undefined
402 ) {
403 this.infrastructureLogger(name, type, args);
404 }
405 },
406 (childName) => {
407 if (typeof name === "function") {
408 if (typeof childName === "function") {
409 return this.getInfrastructureLogger(() => {
410 if (typeof name === "function") {
411 name = name();
412 if (!name) {
413 throw new TypeError(
414 "Compiler.getInfrastructureLogger(name) called with a function not returning a name"
415 );
416 }
417 }
418 if (typeof childName === "function") {
419 childName = childName();
420 if (!childName) {
421 throw new TypeError(
422 "Logger.getChildLogger(name) called with a function not returning a name"
423 );
424 }
425 }
426 return `${name}/${childName}`;
427 });
428 }
429 return this.getInfrastructureLogger(() => {
430 if (typeof name === "function") {
431 name = name();
432 if (!name) {
433 throw new TypeError(
434 "Compiler.getInfrastructureLogger(name) called with a function not returning a name"
435 );
436 }
437 }
438 return `${name}/${childName}`;
439 });
440 }
441 if (typeof childName === "function") {
442 return this.getInfrastructureLogger(() => {
443 if (typeof childName === "function") {
444 childName = childName();
445 if (!childName) {
446 throw new TypeError(
447 "Logger.getChildLogger(name) called with a function not returning a name"
448 );
449 }
450 }
451 return `${name}/${childName}`;
452 });
453 }
454 return this.getInfrastructureLogger(`${name}/${childName}`);
455 }
456 );
457 }
458
459 // TODO webpack 6: solve this in a better way
460 // e.g. move compilation specific info from Modules into ModuleGraph
461 _cleanupLastCompilation() {
462 if (this._lastCompilation !== undefined) {
463 for (const childCompilation of this._lastCompilation.children) {
464 for (const module of childCompilation.modules) {
465 ChunkGraph.clearChunkGraphForModule(module);
466 ModuleGraph.clearModuleGraphForModule(module);
467 module.cleanupForCache();
468 }
469 for (const chunk of childCompilation.chunks) {
470 ChunkGraph.clearChunkGraphForChunk(chunk);
471 }
472 }
473
474 for (const module of this._lastCompilation.modules) {
475 ChunkGraph.clearChunkGraphForModule(module);
476 ModuleGraph.clearModuleGraphForModule(module);
477 module.cleanupForCache();
478 }
479 for (const chunk of this._lastCompilation.chunks) {
480 ChunkGraph.clearChunkGraphForChunk(chunk);
481 }
482 this._lastCompilation = undefined;
483 }
484 }
485
486 // TODO webpack 6: solve this in a better way
487 _cleanupLastNormalModuleFactory() {
488 if (this._lastNormalModuleFactory !== undefined) {
489 this._lastNormalModuleFactory.cleanupForCache();
490 this._lastNormalModuleFactory = undefined;
491 }
492 }
493
494 /**
495 * Returns a compiler watcher.
496 * @param {WatchOptions} watchOptions the watcher's options
497 * @param {Callback<Stats>} handler signals when the call finishes
498 * @returns {Watching | undefined} a compiler watcher
499 */
500 watch(watchOptions, handler) {
501 if (this.running) {
502 handler(new ConcurrentCompilationError());
503 return;
504 }
505
506 this.running = true;
507 this.watchMode = true;
508 this.watching = new Watching(this, watchOptions, handler);
509 return this.watching;
510 }
511
512 /**
513 * Processes the provided stat.
514 * @param {Callback<Stats>} callback signals when the call finishes
515 * @returns {void}
516 */
517 run(callback) {
518 if (this.running) {
519 callback(new ConcurrentCompilationError());
520 return;
521 }
522
523 /** @type {Logger | undefined} */
524 let logger;
525
526 /**
527 * Processes the provided err.
528 * @param {Error | null} err error
529 * @param {Stats=} stats stats
530 */
531 const finalCallback = (err, stats) => {
532 if (logger) logger.time("beginIdle");
533 this.idle = true;
534 this.cache.beginIdle();
535 if (logger) logger.timeEnd("beginIdle");
536 this.running = false;
537 if (err) {
538 this.hooks.failed.call(err);
539 }
540 if (callback !== undefined) callback(err, stats);
541 this.hooks.afterDone.call(/** @type {Stats} */ (stats));
542 };
543
544 const startTime = Date.now();
545
546 this.running = true;
547
548 /**
549 * Processes the provided err.
550 * @param {Error | null} err error
551 * @param {Compilation=} _compilation compilation
552 * @returns {void}
553 */
554 const onCompiled = (err, _compilation) => {
555 if (err) return finalCallback(err);
556
557 const compilation = /** @type {Compilation} */ (_compilation);
558
559 if (this.hooks.shouldEmit.call(compilation) === false) {
560 compilation.startTime = startTime;
561 compilation.endTime = Date.now();
562 const stats = new Stats(compilation);
563 this.hooks.done.callAsync(stats, (err) => {
564 if (err) return finalCallback(err);
565 return finalCallback(null, stats);
566 });
567 return;
568 }
569
570 process.nextTick(() => {
571 logger = compilation.getLogger("webpack.Compiler");
572 logger.time("emitAssets");
573 this.emitAssets(compilation, (err) => {
574 /** @type {Logger} */
575 (logger).timeEnd("emitAssets");
576 if (err) return finalCallback(err);
577
578 if (compilation.hooks.needAdditionalPass.call()) {
579 compilation.needAdditionalPass = true;
580
581 compilation.startTime = startTime;
582 compilation.endTime = Date.now();
583 /** @type {Logger} */
584 (logger).time("done hook");
585 const stats = new Stats(compilation);
586 this.hooks.done.callAsync(stats, (err) => {
587 /** @type {Logger} */
588 (logger).timeEnd("done hook");
589 if (err) return finalCallback(err);
590
591 this.hooks.additionalPass.callAsync((err) => {
592 if (err) return finalCallback(err);
593 this.compile(onCompiled);
594 });
595 });
596 return;
597 }
598
599 /** @type {Logger} */
600 (logger).time("emitRecords");
601 this.emitRecords((err) => {
602 /** @type {Logger} */
603 (logger).timeEnd("emitRecords");
604 if (err) return finalCallback(err);
605
606 compilation.startTime = startTime;
607 compilation.endTime = Date.now();
608 /** @type {Logger} */
609 (logger).time("done hook");
610 const stats = new Stats(compilation);
611 this.hooks.done.callAsync(stats, (err) => {
612 /** @type {Logger} */
613 (logger).timeEnd("done hook");
614 if (err) return finalCallback(err);
615 this.cache.storeBuildDependencies(
616 compilation.buildDependencies,
617 (err) => {
618 if (err) return finalCallback(err);
619 return finalCallback(null, stats);
620 }
621 );
622 });
623 });
624 });
625 });
626 };
627
628 const run = () => {
629 this.hooks.beforeRun.callAsync(this, (err) => {
630 if (err) return finalCallback(err);
631
632 this.hooks.run.callAsync(this, (err) => {
633 if (err) return finalCallback(err);
634
635 this.readRecords((err) => {
636 if (err) return finalCallback(err);
637
638 this.compile(onCompiled);
639 });
640 });
641 });
642 };
643
644 if (this.idle) {
645 this.cache.endIdle((err) => {
646 if (err) return finalCallback(err);
647
648 this.idle = false;
649 run();
650 });
651 } else {
652 run();
653 }
654 }
655
656 /**
657 * Processes the provided run as child callback.
658 * @param {RunAsChildCallback} callback signals when the call finishes
659 * @returns {void}
660 */
661 runAsChild(callback) {
662 const startTime = Date.now();
663
664 /**
665 * Processes the provided err.
666 * @param {Error | null} err error
667 * @param {Chunk[]=} entries entries
668 * @param {Compilation=} compilation compilation
669 */
670 const finalCallback = (err, entries, compilation) => {
671 try {
672 callback(err, entries, compilation);
673 } catch (runAsChildErr) {
674 const err = new WebpackError(
675 `compiler.runAsChild callback error: ${runAsChildErr}`,
676 { cause: runAsChildErr }
677 );
678 err.details = /** @type {Error} */ (runAsChildErr).stack;
679 /** @type {Compilation} */
680 (this.parentCompilation).errors.push(err);
681 }
682 };
683
684 this.compile((err, _compilation) => {
685 if (err) return finalCallback(err);
686
687 const compilation = /** @type {Compilation} */ (_compilation);
688 const parentCompilation = /** @type {Compilation} */ (
689 this.parentCompilation
690 );
691
692 parentCompilation.children.push(compilation);
693
694 for (const { name, source, info } of compilation.getAssets()) {
695 parentCompilation.emitAsset(name, source, info);
696 }
697
698 /** @type {Chunk[]} */
699 const entries = [];
700
701 for (const ep of compilation.entrypoints.values()) {
702 entries.push(...ep.chunks);
703 }
704
705 compilation.startTime = startTime;
706 compilation.endTime = Date.now();
707
708 return finalCallback(null, entries, compilation);
709 });
710 }
711
712 purgeInputFileSystem() {
713 if (this.inputFileSystem && this.inputFileSystem.purge) {
714 this.inputFileSystem.purge();
715 }
716 }
717
718 /**
719 * Processes the provided compilation.
720 * @param {Compilation} compilation the compilation
721 * @param {ErrorCallback} callback signals when the assets are emitted
722 * @returns {void}
723 */
724 emitAssets(compilation, callback) {
725 /** @type {string} */
726 let outputPath;
727
728 /**
729 * Processes the provided err.
730 * @param {Error=} err error
731 * @returns {void}
732 */
733 const emitFiles = (err) => {
734 if (err) return callback(err);
735
736 const assets = compilation.getAssets();
737 compilation.assets = { ...compilation.assets };
738 /** @type {Map<string, SimilarEntry>} */
739 const caseInsensitiveMap = new Map();
740 /** @type {Set<string>} */
741 const allTargetPaths = new Set();
742 asyncLib.forEachLimit(
743 assets,
744 15,
745 ({ name: file, source, info }, callback) => {
746 let targetFile = file;
747 let immutable = info.immutable;
748 const queryOrHashStringIdx = targetFile.search(/[?#]/);
749 if (queryOrHashStringIdx >= 0) {
750 targetFile = targetFile.slice(0, queryOrHashStringIdx);
751 // We may remove the hash, which is in the query string
752 // So we recheck if the file is immutable
753 // This doesn't cover all cases, but immutable is only a performance optimization anyway
754 immutable =
755 immutable &&
756 (includesHash(targetFile, info.contenthash) ||
757 includesHash(targetFile, info.chunkhash) ||
758 includesHash(targetFile, info.modulehash) ||
759 includesHash(targetFile, info.fullhash));
760 }
761
762 /**
763 * Processes the provided err.
764 * @param {Error=} err error
765 * @returns {void}
766 */
767 const writeOut = (err) => {
768 if (err) return callback(err);
769 const targetPath = join(
770 /** @type {OutputFileSystem} */
771 (this.outputFileSystem),
772 outputPath,
773 targetFile
774 );
775 allTargetPaths.add(targetPath);
776
777 // check if the target file has already been written by this Compiler
778 const targetFileGeneration =
779 this._assetEmittingWrittenFiles.get(targetPath);
780
781 // create an cache entry for this Source if not already existing
782 let cacheEntry = this._assetEmittingSourceCache.get(source);
783 if (cacheEntry === undefined) {
784 cacheEntry = {
785 sizeOnlySource: undefined,
786 /** @type {CacheEntry["writtenTo"]} */
787 writtenTo: new Map()
788 };
789 this._assetEmittingSourceCache.set(source, cacheEntry);
790 }
791
792 /** @type {SimilarEntry | undefined} */
793 let similarEntry;
794
795 const checkSimilarFile = () => {
796 const caseInsensitiveTargetPath = targetPath.toLowerCase();
797 similarEntry = caseInsensitiveMap.get(caseInsensitiveTargetPath);
798 if (similarEntry !== undefined) {
799 const { path: other, source: otherSource } = similarEntry;
800 if (isSourceEqual(otherSource, source)) {
801 // Size may or may not be available at this point.
802 // If it's not available add to "waiting" list and it will be updated once available
803 if (similarEntry.size !== undefined) {
804 updateWithReplacementSource(similarEntry.size);
805 } else {
806 if (!similarEntry.waiting) similarEntry.waiting = [];
807 similarEntry.waiting.push({ file, cacheEntry });
808 }
809 alreadyWritten();
810 } else {
811 const err =
812 new WebpackError(`Prevent writing to file that only differs in casing or query string from already written file.
813This will lead to a race-condition and corrupted files on case-insensitive file systems.
814${targetPath}
815${other}`);
816 err.file = file;
817 callback(err);
818 }
819 return true;
820 }
821 caseInsensitiveMap.set(
822 caseInsensitiveTargetPath,
823 (similarEntry = /** @type {SimilarEntry} */ ({
824 path: targetPath,
825 source,
826 size: undefined,
827 waiting: undefined
828 }))
829 );
830 return false;
831 };
832
833 /**
834 * get the binary (Buffer) content from the Source
835 * @returns {Buffer} content for the source
836 */
837 const getContent = () => {
838 if (typeof source.buffer === "function") {
839 return source.buffer();
840 }
841 const bufferOrString = source.source();
842 if (Buffer.isBuffer(bufferOrString)) {
843 return bufferOrString;
844 }
845 return Buffer.from(bufferOrString, "utf8");
846 };
847
848 const alreadyWritten = () => {
849 // cache the information that the Source has been already been written to that location
850 if (targetFileGeneration === undefined) {
851 const newGeneration = 1;
852 this._assetEmittingWrittenFiles.set(targetPath, newGeneration);
853 /** @type {CacheEntry} */
854 (cacheEntry).writtenTo.set(targetPath, newGeneration);
855 } else {
856 /** @type {CacheEntry} */
857 (cacheEntry).writtenTo.set(targetPath, targetFileGeneration);
858 }
859 callback();
860 };
861
862 /**
863 * Write the file to output file system
864 * @param {Buffer} content content to be written
865 * @returns {void}
866 */
867 const doWrite = (content) => {
868 /** @type {OutputFileSystem} */
869 (this.outputFileSystem).writeFile(targetPath, content, (err) => {
870 if (err) return callback(err);
871
872 // information marker that the asset has been emitted
873 compilation.emittedAssets.add(file);
874
875 // cache the information that the Source has been written to that location
876 const newGeneration =
877 targetFileGeneration === undefined
878 ? 1
879 : targetFileGeneration + 1;
880 /** @type {CacheEntry} */
881 (cacheEntry).writtenTo.set(targetPath, newGeneration);
882 this._assetEmittingWrittenFiles.set(targetPath, newGeneration);
883 this.hooks.assetEmitted.callAsync(
884 file,
885 {
886 content,
887 source,
888 outputPath,
889 compilation,
890 targetPath
891 },
892 callback
893 );
894 });
895 };
896
897 /**
898 * Updates with replacement source.
899 * @param {number} size size
900 */
901 const updateWithReplacementSource = (size) => {
902 updateFileWithReplacementSource(
903 file,
904 /** @type {CacheEntry} */ (cacheEntry),
905 size
906 );
907 /** @type {SimilarEntry} */
908 (similarEntry).size = size;
909 if (
910 /** @type {SimilarEntry} */ (similarEntry).waiting !== undefined
911 ) {
912 for (const { file, cacheEntry } of /** @type {SimilarEntry} */ (
913 similarEntry
914 ).waiting) {
915 updateFileWithReplacementSource(file, cacheEntry, size);
916 }
917 }
918 };
919
920 /**
921 * Updates file with replacement source.
922 * @param {string} file file
923 * @param {CacheEntry} cacheEntry cache entry
924 * @param {number} size size
925 */
926 const updateFileWithReplacementSource = (
927 file,
928 cacheEntry,
929 size
930 ) => {
931 // Create a replacement resource which only allows to ask for size
932 // This allows to GC all memory allocated by the Source
933 // (expect when the Source is stored in any other cache)
934 if (!cacheEntry.sizeOnlySource) {
935 cacheEntry.sizeOnlySource = new SizeOnlySource(size);
936 }
937 compilation.updateAsset(file, cacheEntry.sizeOnlySource, {
938 size
939 });
940 };
941
942 /**
943 * Process existing file.
944 * @param {IStats} stats stats
945 * @returns {void}
946 */
947 const processExistingFile = (stats) => {
948 // skip emitting if it's already there and an immutable file
949 if (immutable) {
950 updateWithReplacementSource(/** @type {number} */ (stats.size));
951 return alreadyWritten();
952 }
953
954 const content = getContent();
955
956 updateWithReplacementSource(content.length);
957
958 // if it exists and content on disk matches content
959 // skip writing the same content again
960 // (to keep mtime and don't trigger watchers)
961 // for a fast negative match file size is compared first
962 if (content.length === stats.size) {
963 compilation.comparedForEmitAssets.add(file);
964 return /** @type {OutputFileSystem} */ (
965 this.outputFileSystem
966 ).readFile(targetPath, (err, existingContent) => {
967 if (
968 err ||
969 !content.equals(/** @type {Buffer} */ (existingContent))
970 ) {
971 return doWrite(content);
972 }
973 return alreadyWritten();
974 });
975 }
976
977 return doWrite(content);
978 };
979
980 const processMissingFile = () => {
981 const content = getContent();
982
983 updateWithReplacementSource(content.length);
984
985 return doWrite(content);
986 };
987
988 // if the target file has already been written
989 if (targetFileGeneration !== undefined) {
990 // check if the Source has been written to this target file
991 const writtenGeneration = /** @type {CacheEntry} */ (
992 cacheEntry
993 ).writtenTo.get(targetPath);
994 if (writtenGeneration === targetFileGeneration) {
995 // if yes, we may skip writing the file
996 // if it's already there
997 // (we assume one doesn't modify files while the Compiler is running, other then removing them)
998
999 if (this._assetEmittingPreviousFiles.has(targetPath)) {
1000 const sizeOnlySource = /** @type {SizeOnlySource} */ (
1001 /** @type {CacheEntry} */ (cacheEntry).sizeOnlySource
1002 );
1003
1004 // We assume that assets from the last compilation say intact on disk (they are not removed)
1005 compilation.updateAsset(file, sizeOnlySource, {
1006 size: sizeOnlySource.size()
1007 });
1008
1009 return callback();
1010 }
1011 // Settings immutable will make it accept file content without comparing when file exist
1012 immutable = true;
1013 } else if (!immutable) {
1014 if (checkSimilarFile()) return;
1015 // We wrote to this file before which has very likely a different content
1016 // skip comparing and assume content is different for performance
1017 // This case happens often during watch mode.
1018 return processMissingFile();
1019 }
1020 }
1021
1022 if (checkSimilarFile()) return;
1023 if (this.options.output.compareBeforeEmit) {
1024 /** @type {OutputFileSystem} */
1025 (this.outputFileSystem).stat(targetPath, (err, stats) => {
1026 const exists = !err && /** @type {IStats} */ (stats).isFile();
1027
1028 if (exists) {
1029 processExistingFile(/** @type {IStats} */ (stats));
1030 } else {
1031 processMissingFile();
1032 }
1033 });
1034 } else {
1035 processMissingFile();
1036 }
1037 };
1038
1039 if (/\/|\\/.test(targetFile)) {
1040 const fs = /** @type {OutputFileSystem} */ (this.outputFileSystem);
1041 const dir = dirname(fs, join(fs, outputPath, targetFile));
1042 mkdirp(fs, dir, writeOut);
1043 } else {
1044 writeOut();
1045 }
1046 },
1047 (err) => {
1048 // Clear map to free up memory
1049 caseInsensitiveMap.clear();
1050 if (err) {
1051 this._assetEmittingPreviousFiles.clear();
1052 return callback(err);
1053 }
1054
1055 this._assetEmittingPreviousFiles = allTargetPaths;
1056
1057 this.hooks.afterEmit.callAsync(compilation, (err) => {
1058 if (err) return callback(err);
1059
1060 return callback(null);
1061 });
1062 }
1063 );
1064 };
1065
1066 this.hooks.emit.callAsync(compilation, (err) => {
1067 if (err) return callback(err);
1068 outputPath = compilation.getPath(this.outputPath, {});
1069 mkdirp(
1070 /** @type {OutputFileSystem} */ (this.outputFileSystem),
1071 outputPath,
1072 emitFiles
1073 );
1074 });
1075 }
1076
1077 /**
1078 * Processes the provided error callback.
1079 * @param {ErrorCallback} callback signals when the call finishes
1080 * @returns {void}
1081 */
1082 emitRecords(callback) {
1083 if (this.hooks.emitRecords.isUsed()) {
1084 if (this.recordsOutputPath) {
1085 asyncLib.parallel(
1086 [
1087 (cb) => this.hooks.emitRecords.callAsync(cb),
1088 this._emitRecords.bind(this)
1089 ],
1090 (err) => callback(/** @type {Error | null} */ (err))
1091 );
1092 } else {
1093 this.hooks.emitRecords.callAsync(callback);
1094 }
1095 } else if (this.recordsOutputPath) {
1096 this._emitRecords(callback);
1097 } else {
1098 callback(null);
1099 }
1100 }
1101
1102 /**
1103 * Processes the provided error callback.
1104 * @param {ErrorCallback} callback signals when the call finishes
1105 * @returns {void}
1106 */
1107 _emitRecords(callback) {
1108 const writeFile = () => {
1109 /** @type {OutputFileSystem} */
1110 (this.outputFileSystem).writeFile(
1111 /** @type {string} */ (this.recordsOutputPath),
1112 JSON.stringify(
1113 this.records,
1114 (n, value) => {
1115 if (
1116 typeof value === "object" &&
1117 value !== null &&
1118 !Array.isArray(value)
1119 ) {
1120 const keys = Object.keys(value);
1121 if (!isSorted(keys)) {
1122 return sortObject(value, keys);
1123 }
1124 }
1125 return value;
1126 },
1127 2
1128 ),
1129 callback
1130 );
1131 };
1132
1133 const recordsOutputPathDirectory = dirname(
1134 /** @type {OutputFileSystem} */
1135 (this.outputFileSystem),
1136 /** @type {string} */
1137 (this.recordsOutputPath)
1138 );
1139 if (!recordsOutputPathDirectory) {
1140 return writeFile();
1141 }
1142 mkdirp(
1143 /** @type {OutputFileSystem} */ (this.outputFileSystem),
1144 recordsOutputPathDirectory,
1145 (err) => {
1146 if (err) return callback(err);
1147 writeFile();
1148 }
1149 );
1150 }
1151
1152 /**
1153 * Processes the provided error callback.
1154 * @param {ErrorCallback} callback signals when the call finishes
1155 * @returns {void}
1156 */
1157 readRecords(callback) {
1158 if (this.hooks.readRecords.isUsed()) {
1159 if (this.recordsInputPath) {
1160 asyncLib.parallel(
1161 [
1162 (cb) => this.hooks.readRecords.callAsync(cb),
1163 this._readRecords.bind(this)
1164 ],
1165 (err) => callback(/** @type {Error | null} */ (err))
1166 );
1167 } else {
1168 this.records = {};
1169 this.hooks.readRecords.callAsync(callback);
1170 }
1171 } else if (this.recordsInputPath) {
1172 this._readRecords(callback);
1173 } else {
1174 this.records = {};
1175 callback(null);
1176 }
1177 }
1178
1179 /**
1180 * Processes the provided error callback.
1181 * @param {ErrorCallback} callback signals when the call finishes
1182 * @returns {void}
1183 */
1184 _readRecords(callback) {
1185 if (!this.recordsInputPath) {
1186 this.records = {};
1187 return callback(null);
1188 }
1189 /** @type {InputFileSystem} */
1190 (this.inputFileSystem).stat(this.recordsInputPath, (err) => {
1191 // It doesn't exist
1192 // We can ignore this.
1193 if (err) return callback(null);
1194
1195 /** @type {InputFileSystem} */
1196 (this.inputFileSystem).readFile(
1197 /** @type {string} */
1198 (this.recordsInputPath),
1199 (err, content) => {
1200 if (err) return callback(err);
1201
1202 try {
1203 this.records =
1204 /** @type {Records} */
1205 (parseJson(/** @type {Buffer} */ (content).toString("utf8")));
1206 } catch (parseErr) {
1207 return callback(
1208 new Error(
1209 `Cannot parse records: ${/** @type {Error} */ (parseErr).message}`
1210 )
1211 );
1212 }
1213
1214 return callback(null);
1215 }
1216 );
1217 });
1218 }
1219
1220 /**
1221 * Creates a child compiler.
1222 * @param {Compilation} compilation the compilation
1223 * @param {string} compilerName the compiler's name
1224 * @param {number} compilerIndex the compiler's index
1225 * @param {Partial<OutputOptions>=} outputOptions the output options
1226 * @param {Plugins=} plugins the plugins to apply
1227 * @returns {Compiler} a child compiler
1228 */
1229 createChildCompiler(
1230 compilation,
1231 compilerName,
1232 compilerIndex,
1233 outputOptions,
1234 plugins
1235 ) {
1236 const childCompiler = new Compiler(this.context, {
1237 ...this.options,
1238 output: {
1239 ...this.options.output,
1240 ...outputOptions
1241 }
1242 });
1243 childCompiler.name = compilerName;
1244 childCompiler.outputPath = this.outputPath;
1245 childCompiler.inputFileSystem = this.inputFileSystem;
1246 childCompiler.outputFileSystem = null;
1247 childCompiler.resolverFactory = this.resolverFactory;
1248 childCompiler.modifiedFiles = this.modifiedFiles;
1249 childCompiler.removedFiles = this.removedFiles;
1250 childCompiler.fileTimestamps = this.fileTimestamps;
1251 childCompiler.contextTimestamps = this.contextTimestamps;
1252 childCompiler.fsStartTime = this.fsStartTime;
1253 childCompiler.cache = this.cache;
1254 childCompiler.compilerPath = `${this.compilerPath}${compilerName}|${compilerIndex}|`;
1255 childCompiler._backCompat = this._backCompat;
1256
1257 const relativeCompilerName = makePathsRelative(
1258 this.context,
1259 compilerName,
1260 this.root
1261 );
1262 if (!this.records[relativeCompilerName]) {
1263 this.records[relativeCompilerName] = [];
1264 }
1265 if (this.records[relativeCompilerName][compilerIndex]) {
1266 childCompiler.records =
1267 /** @type {Records} */
1268 (this.records[relativeCompilerName][compilerIndex]);
1269 } else {
1270 this.records[relativeCompilerName].push((childCompiler.records = {}));
1271 }
1272
1273 childCompiler.parentCompilation = compilation;
1274 childCompiler.root = this.root;
1275 if (Array.isArray(plugins)) {
1276 for (const plugin of plugins) {
1277 if (typeof plugin === "function") {
1278 /** @type {WebpackPluginFunction} */
1279 (plugin).call(childCompiler, childCompiler);
1280 } else if (plugin) {
1281 plugin.apply(childCompiler);
1282 }
1283 }
1284 }
1285 for (const name in this.hooks) {
1286 if (
1287 ![
1288 "make",
1289 "compile",
1290 "emit",
1291 "afterEmit",
1292 "invalid",
1293 "done",
1294 "thisCompilation"
1295 ].includes(name) &&
1296 childCompiler.hooks[/** @type {keyof Compiler["hooks"]} */ (name)]
1297 ) {
1298 childCompiler.hooks[
1299 /** @type {keyof Compiler["hooks"]} */
1300 (name)
1301 ].taps = [
1302 ...this.hooks[
1303 /** @type {keyof Compiler["hooks"]} */
1304 (name)
1305 ].taps
1306 ];
1307 }
1308 }
1309
1310 compilation.hooks.childCompiler.call(
1311 childCompiler,
1312 compilerName,
1313 compilerIndex
1314 );
1315
1316 return childCompiler;
1317 }
1318
1319 isChild() {
1320 return Boolean(this.parentCompilation);
1321 }
1322
1323 /**
1324 * Creates a compilation.
1325 * @param {CompilationParams} params the compilation parameters
1326 * @returns {Compilation} compilation
1327 */
1328 createCompilation(params) {
1329 this._cleanupLastCompilation();
1330 return (this._lastCompilation = new Compilation(this, params));
1331 }
1332
1333 /**
1334 * Returns the created compilation.
1335 * @param {CompilationParams} params the compilation parameters
1336 * @returns {Compilation} the created compilation
1337 */
1338 newCompilation(params) {
1339 const compilation = this.createCompilation(params);
1340 compilation.name = this.name;
1341 compilation.records = this.records;
1342 this.hooks.thisCompilation.call(compilation, params);
1343 this.hooks.compilation.call(compilation, params);
1344 return compilation;
1345 }
1346
1347 createNormalModuleFactory() {
1348 this._cleanupLastNormalModuleFactory();
1349 const normalModuleFactory = new NormalModuleFactory({
1350 context: this.options.context,
1351 fs: /** @type {InputFileSystem} */ (this.inputFileSystem),
1352 resolverFactory: this.resolverFactory,
1353 options: this.options.module,
1354 associatedObjectForCache: this.root
1355 });
1356 this._lastNormalModuleFactory = normalModuleFactory;
1357 this.hooks.normalModuleFactory.call(normalModuleFactory);
1358 return normalModuleFactory;
1359 }
1360
1361 createContextModuleFactory() {
1362 const contextModuleFactory = new ContextModuleFactory(this.resolverFactory);
1363 this.hooks.contextModuleFactory.call(contextModuleFactory);
1364 return contextModuleFactory;
1365 }
1366
1367 newCompilationParams() {
1368 const params = {
1369 normalModuleFactory: this.createNormalModuleFactory(),
1370 contextModuleFactory: this.createContextModuleFactory()
1371 };
1372 return params;
1373 }
1374
1375 /**
1376 * Processes the provided compilation.
1377 * @param {Callback<Compilation>} callback signals when the compilation finishes
1378 * @returns {void}
1379 */
1380 compile(callback) {
1381 const params = this.newCompilationParams();
1382 this.hooks.beforeCompile.callAsync(params, (err) => {
1383 if (err) return callback(err);
1384
1385 this.hooks.compile.call(params);
1386
1387 const compilation = this.newCompilation(params);
1388
1389 const logger = compilation.getLogger("webpack.Compiler");
1390
1391 logger.time("make hook");
1392 this.hooks.make.callAsync(compilation, (err) => {
1393 logger.timeEnd("make hook");
1394 if (err) return callback(err);
1395
1396 logger.time("finish make hook");
1397 this.hooks.finishMake.callAsync(compilation, (err) => {
1398 logger.timeEnd("finish make hook");
1399 if (err) return callback(err);
1400
1401 process.nextTick(() => {
1402 logger.time("finish compilation");
1403 compilation.finish((err) => {
1404 logger.timeEnd("finish compilation");
1405 if (err) return callback(err);
1406
1407 logger.time("seal compilation");
1408 compilation.seal((err) => {
1409 logger.timeEnd("seal compilation");
1410 if (err) return callback(err);
1411
1412 logger.time("afterCompile hook");
1413 this.hooks.afterCompile.callAsync(compilation, (err) => {
1414 logger.timeEnd("afterCompile hook");
1415 if (err) return callback(err);
1416
1417 return callback(null, compilation);
1418 });
1419 });
1420 });
1421 });
1422 });
1423 });
1424 });
1425 }
1426
1427 /**
1428 * Processes the provided error callback.
1429 * @param {ErrorCallback} callback signals when the compiler closes
1430 * @returns {void}
1431 */
1432 close(callback) {
1433 if (this.watching) {
1434 // When there is still an active watching, close this first
1435 this.watching.close((_err) => {
1436 this.close(callback);
1437 });
1438 return;
1439 }
1440 this.hooks.shutdown.callAsync((err) => {
1441 if (err) return callback(err);
1442 // Get rid of reference to last compilation to avoid leaking memory
1443 // We can't run this._cleanupLastCompilation() as the Stats to this compilation
1444 // might be still in use. We try to get rid of the reference to the cache instead.
1445 this._lastCompilation = undefined;
1446 this._lastNormalModuleFactory = undefined;
1447 this.cache.shutdown(callback);
1448 });
1449 }
1450
1451 /**
1452 * Schema validation function with optional pre-compiled check
1453 * @template {EXPECTED_OBJECT | EXPECTED_OBJECT[]} [T=EXPECTED_OBJECT]
1454 * @param {Schema | (() => Schema)} schema schema
1455 * @param {T} value value
1456 * @param {ValidationErrorConfiguration=} options options
1457 * @param {((value: T) => boolean)=} check options
1458 */
1459 validate(schema, value, options, check) {
1460 // Avoid validation at all when disabled
1461 if (this.options.validate === false) {
1462 return;
1463 }
1464
1465 /**
1466 * Returns schema.
1467 * @returns {Schema} schema
1468 */
1469 const getSchema = () => {
1470 if (typeof schema === "function") {
1471 return schema();
1472 }
1473
1474 return schema;
1475 };
1476
1477 // // If we have precompiled schema let's use it
1478 if (check) {
1479 if (!check(value)) {
1480 getValidate()(getSchema(), value, options);
1481 require("util").deprecate(
1482 () => {},
1483 "webpack bug: Pre-compiled schema reports error while real schema is happy. This has performance drawbacks.",
1484 "DEP_WEBPACK_PRE_COMPILED_SCHEMA_INVALID"
1485 )();
1486 }
1487 return;
1488 }
1489
1490 // Otherwise let's standard validation
1491 getValidate()(getSchema(), value, options);
1492 }
1493}
1494
1495module.exports = Compiler;
Note: See TracBrowser for help on using the repository browser.