report dependencies from resolver to the compilation
refactor NormalModuleFactory
This commit is contained in:
parent
b97bc4bc06
commit
ef9e25d8ea
|
@ -62,6 +62,7 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
|
|||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./DependencyTemplate")} DependencyTemplate */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleFactory")} ModuleFactory */
|
||||
/** @typedef {import("./RuntimeModule")} RuntimeModule */
|
||||
/** @typedef {import("./Template").RenderManifestEntry} RenderManifestEntry */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
|
@ -99,25 +100,6 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
|
|||
/** @typedef {new (...args: any[]) => Dependency} DepConstructor */
|
||||
/** @typedef {Record<string, Source>} CompilationAssets */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModuleFactoryCreateDataContextInfo
|
||||
* @property {string} issuer
|
||||
* @property {string} compiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModuleFactoryCreateData
|
||||
* @property {ModuleFactoryCreateDataContextInfo} contextInfo
|
||||
* @property {any=} resolveOptions
|
||||
* @property {string} context
|
||||
* @property {Dependency[]} dependencies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModuleFactory
|
||||
* @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AvailableModulesChunkGroupMapping
|
||||
* @property {ChunkGroup} chunkGroup
|
||||
|
@ -552,8 +534,6 @@ class Compilation {
|
|||
this.usedChunkIds = null;
|
||||
/** @type {Set<number>} */
|
||||
this.usedModuleIds = null;
|
||||
/** @type {Set<string>=} */
|
||||
this.compilationDependencies = undefined;
|
||||
/** @type {boolean} */
|
||||
this.needAdditionalPass = false;
|
||||
/** @type {WeakSet<Module>} */
|
||||
|
@ -562,6 +542,12 @@ class Compilation {
|
|||
this._rebuildingModules = new Map();
|
||||
/** @type {WeakSet<Source>} */
|
||||
this.emittedAssets = new WeakSet();
|
||||
/** @type {SortableSet<string>} */
|
||||
this.fileDependencies = new SortableSet();
|
||||
/** @type {SortableSet<string>} */
|
||||
this.contextDependencies = new SortableSet();
|
||||
/** @type {SortableSet<string>} */
|
||||
this.missingDependencies = new SortableSet();
|
||||
}
|
||||
|
||||
getStats() {
|
||||
|
@ -999,7 +985,23 @@ class Compilation {
|
|||
: this.compiler.context,
|
||||
dependencies: dependencies
|
||||
},
|
||||
(err, newModule) => {
|
||||
(err, result) => {
|
||||
if (result) {
|
||||
const {
|
||||
fileDependencies,
|
||||
contextDependencies,
|
||||
missingDependencies
|
||||
} = result;
|
||||
if (fileDependencies) {
|
||||
addAllToSet(this.fileDependencies, fileDependencies);
|
||||
}
|
||||
if (contextDependencies) {
|
||||
addAllToSet(this.contextDependencies, contextDependencies);
|
||||
}
|
||||
if (missingDependencies) {
|
||||
addAllToSet(this.missingDependencies, missingDependencies);
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
const notFoundError = new ModuleNotFoundError(
|
||||
originModule,
|
||||
|
@ -1008,6 +1010,10 @@ class Compilation {
|
|||
);
|
||||
return callback(notFoundError);
|
||||
}
|
||||
if (!result) {
|
||||
return callback();
|
||||
}
|
||||
const newModule = result.module;
|
||||
if (!newModule) {
|
||||
return callback();
|
||||
}
|
||||
|
@ -2190,10 +2196,6 @@ class Compilation {
|
|||
}
|
||||
|
||||
summarizeDependencies() {
|
||||
this.fileDependencies = new SortableSet(this.compilationDependencies);
|
||||
this.contextDependencies = new SortableSet();
|
||||
this.missingDependencies = new SortableSet();
|
||||
|
||||
for (
|
||||
let indexChildren = 0;
|
||||
indexChildren < this.children.length;
|
||||
|
@ -2207,16 +2209,16 @@ class Compilation {
|
|||
}
|
||||
|
||||
for (const module of this.modules) {
|
||||
if (module.buildInfo.fileDependencies) {
|
||||
addAllToSet(this.fileDependencies, module.buildInfo.fileDependencies);
|
||||
const fileDependencies = module.buildInfo.fileDependencies;
|
||||
const contextDependencies = module.buildInfo.contextDependencies;
|
||||
if (fileDependencies) {
|
||||
addAllToSet(this.fileDependencies, fileDependencies);
|
||||
}
|
||||
if (module.buildInfo.contextDependencies) {
|
||||
addAllToSet(
|
||||
this.contextDependencies,
|
||||
module.buildInfo.contextDependencies
|
||||
);
|
||||
if (contextDependencies) {
|
||||
addAllToSet(this.contextDependencies, contextDependencies);
|
||||
}
|
||||
}
|
||||
|
||||
for (const error of this.errors) {
|
||||
if (
|
||||
typeof error.missing === "object" &&
|
||||
|
@ -2226,6 +2228,7 @@ class Compilation {
|
|||
addAllToSet(this.missingDependencies, error.missing);
|
||||
}
|
||||
}
|
||||
|
||||
this.fileDependencies.sort();
|
||||
this.contextDependencies.sort();
|
||||
this.missingDependencies.sort();
|
||||
|
|
|
@ -40,7 +40,6 @@ const { makePathsRelative } = require("./util/identifier");
|
|||
* @typedef {Object} CompilationParams
|
||||
* @property {NormalModuleFactory} normalModuleFactory
|
||||
* @property {ContextModuleFactory} contextModuleFactory
|
||||
* @property {Set<string>} compilationDependencies
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -139,9 +138,9 @@ class Compiler {
|
|||
this.records = {};
|
||||
/** @type {Set<string>} */
|
||||
this.removedFiles = new Set();
|
||||
/** @type {Map<string, FileSystemInfoEntry>} */
|
||||
/** @type {Map<string, FileSystemInfoEntry | null>} */
|
||||
this.fileTimestamps = new Map();
|
||||
/** @type {Map<string, FileSystemInfoEntry>} */
|
||||
/** @type {Map<string, FileSystemInfoEntry | null>} */
|
||||
this.contextTimestamps = new Map();
|
||||
/** @type {ResolverFactory} */
|
||||
this.resolverFactory = new ResolverFactory();
|
||||
|
@ -522,7 +521,6 @@ class Compiler {
|
|||
const compilation = this.createCompilation();
|
||||
compilation.name = this.name;
|
||||
compilation.records = this.records;
|
||||
compilation.compilationDependencies = params.compilationDependencies;
|
||||
this.hooks.thisCompilation.call(compilation, params);
|
||||
this.hooks.compilation.call(compilation, params);
|
||||
return compilation;
|
||||
|
@ -547,8 +545,7 @@ class Compiler {
|
|||
newCompilationParams() {
|
||||
const params = {
|
||||
normalModuleFactory: this.createNormalModuleFactory(),
|
||||
contextModuleFactory: this.createContextModuleFactory(),
|
||||
compilationDependencies: new Set()
|
||||
contextModuleFactory: this.createContextModuleFactory()
|
||||
};
|
||||
return params;
|
||||
}
|
||||
|
|
|
@ -10,14 +10,19 @@ const path = require("path");
|
|||
|
||||
const { AsyncSeriesWaterfallHook, SyncWaterfallHook } = require("tapable");
|
||||
const ContextModule = require("./ContextModule");
|
||||
const ModuleFactory = require("./ModuleFactory");
|
||||
const ContextElementDependency = require("./dependencies/ContextElementDependency");
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
|
||||
/** @typedef {import("./dependencies/ContextDependency")} ContextDependency */
|
||||
|
||||
const EMPTY_RESOLVE_OPTIONS = {};
|
||||
|
||||
module.exports = class ContextModuleFactory {
|
||||
module.exports = class ContextModuleFactory extends ModuleFactory {
|
||||
constructor(resolverFactory) {
|
||||
super();
|
||||
this.hooks = Object.freeze({
|
||||
/** @type {AsyncSeriesWaterfallHook<TODO>} */
|
||||
beforeResolve: new AsyncSeriesWaterfallHook(["data"]),
|
||||
|
@ -31,17 +36,28 @@ module.exports = class ContextModuleFactory {
|
|||
this.resolverFactory = resolverFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleFactoryCreateData} data data object
|
||||
* @param {function(Error=, ModuleFactoryResult=): void} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
create(data, callback) {
|
||||
const context = data.context;
|
||||
const dependencies = data.dependencies;
|
||||
const resolveOptions = data.resolveOptions;
|
||||
const dependency = dependencies[0];
|
||||
const dependency = /** @type {ContextDependency} */ (dependencies[0]);
|
||||
const fileDependencies = new Set();
|
||||
const missingDependencies = new Set();
|
||||
const contextDependencies = new Set();
|
||||
this.hooks.beforeResolve.callAsync(
|
||||
Object.assign(
|
||||
{
|
||||
context: context,
|
||||
dependencies: dependencies,
|
||||
resolveOptions
|
||||
resolveOptions,
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
},
|
||||
dependency.options
|
||||
),
|
||||
|
@ -147,10 +163,12 @@ module.exports = class ContextModuleFactory {
|
|||
// Ignored
|
||||
if (!result) return callback();
|
||||
|
||||
return callback(
|
||||
null,
|
||||
new ContextModule(result.resolveDependencies, result)
|
||||
);
|
||||
return callback(null, {
|
||||
module: new ContextModule(result.resolveDependencies, result),
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ class DelegatedModuleFactoryPlugin {
|
|||
apply(normalModuleFactory) {
|
||||
const scope = this.options.scope;
|
||||
if (scope) {
|
||||
normalModuleFactory.hooks.factory.tap(
|
||||
normalModuleFactory.hooks.factorize.tapAsync(
|
||||
"DelegatedModuleFactoryPlugin",
|
||||
factory => (data, callback) => {
|
||||
(data, callback) => {
|
||||
const dependency = data.dependencies[0];
|
||||
const request = dependency.request;
|
||||
if (request && request.indexOf(scope + "/") === 0) {
|
||||
|
@ -67,7 +67,7 @@ class DelegatedModuleFactoryPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
return factory(data, callback);
|
||||
return callback();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -6,17 +6,31 @@
|
|||
"use strict";
|
||||
|
||||
const DllModule = require("./DllModule");
|
||||
const ModuleFactory = require("./ModuleFactory");
|
||||
|
||||
class DllModuleFactory {
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
|
||||
/** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
|
||||
|
||||
class DllModuleFactory extends ModuleFactory {
|
||||
constructor() {
|
||||
super();
|
||||
this.hooks = Object.freeze({});
|
||||
}
|
||||
/**
|
||||
* @param {ModuleFactoryCreateData} data data object
|
||||
* @param {function(Error=, ModuleFactoryResult=): void} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
create(data, callback) {
|
||||
const dependency = data.dependencies[0];
|
||||
callback(
|
||||
null,
|
||||
new DllModule(data.context, dependency.dependencies, dependency.name)
|
||||
);
|
||||
const dependency = /** @type {DllEntryDependency} */ (data.dependencies[0]);
|
||||
callback(null, {
|
||||
module: new DllModule(
|
||||
data.context,
|
||||
dependency.dependencies,
|
||||
dependency.name
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ class DllReferencePlugin {
|
|||
constructor(options) {
|
||||
validateOptions(schema, options, "Dll Reference Plugin");
|
||||
this.options = options;
|
||||
/** @type {WeakMap<Object, {path: string, data: DllReferencePluginOptionsManifest?, error: Error?}>} */
|
||||
this._compilationData = new WeakMap();
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
|
@ -50,15 +52,17 @@ class DllReferencePlugin {
|
|||
if ("manifest" in this.options) {
|
||||
const manifest = this.options.manifest;
|
||||
if (typeof manifest === "string") {
|
||||
params.compilationDependencies.add(manifest);
|
||||
compiler.inputFileSystem.readFile(manifest, (err, result) => {
|
||||
if (err) return callback(err);
|
||||
const data = {
|
||||
path: manifest,
|
||||
data: undefined,
|
||||
error: undefined
|
||||
};
|
||||
// Catch errors parsing the manifest so that blank
|
||||
// or malformed manifest files don't kill the process.
|
||||
try {
|
||||
params["dll reference " + manifest] = parseJson(
|
||||
result.toString("utf-8")
|
||||
);
|
||||
data.data = parseJson(result.toString("utf-8"));
|
||||
} catch (e) {
|
||||
// Store the error in the params so that it can
|
||||
// be added as a compilation error later on.
|
||||
|
@ -67,10 +71,9 @@ class DllReferencePlugin {
|
|||
manifest,
|
||||
compiler.root
|
||||
);
|
||||
params[
|
||||
"dll reference parse error " + manifest
|
||||
] = new DllManifestError(manifestPath, e.message);
|
||||
data.error = new DllManifestError(manifestPath, e.message);
|
||||
}
|
||||
this._compilationData.set(params, data);
|
||||
return callback();
|
||||
});
|
||||
return;
|
||||
|
@ -89,16 +92,14 @@ class DllReferencePlugin {
|
|||
let manifestParameter = this.options.manifest;
|
||||
let manifest;
|
||||
if (typeof manifestParameter === "string") {
|
||||
const data = this._compilationData.get(params);
|
||||
// If there was an error parsing the manifest
|
||||
// file, exit now because the error will be added
|
||||
// as a compilation error in the "compilation" hook.
|
||||
if (params["dll reference parse error " + manifestParameter]) {
|
||||
if (data.error) {
|
||||
return;
|
||||
}
|
||||
manifest =
|
||||
/** @type {DllReferencePluginOptionsManifest} */ (params[
|
||||
"dll reference " + manifestParameter
|
||||
]);
|
||||
manifest = data.data;
|
||||
} else {
|
||||
manifest = manifestParameter;
|
||||
}
|
||||
|
@ -131,12 +132,13 @@ class DllReferencePlugin {
|
|||
if ("manifest" in this.options) {
|
||||
let manifest = this.options.manifest;
|
||||
if (typeof manifest === "string") {
|
||||
const data = this._compilationData.get(params);
|
||||
// If there was an error parsing the manifest file, add the
|
||||
// error as a compilation error to make the compilation fail.
|
||||
let e = params["dll reference parse error " + manifest];
|
||||
if (e) {
|
||||
compilation.errors.push(e);
|
||||
if (data.error) {
|
||||
compilation.errors.push(data.error);
|
||||
}
|
||||
compilation.fileDependencies.add(manifest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ class ExternalModuleFactoryPlugin {
|
|||
|
||||
apply(normalModuleFactory) {
|
||||
const globalType = this.type;
|
||||
normalModuleFactory.hooks.factory.tap(
|
||||
normalModuleFactory.hooks.factorize.tapAsync(
|
||||
"ExternalModuleFactoryPlugin",
|
||||
factory => (data, callback) => {
|
||||
(data, callback) => {
|
||||
const context = data.context;
|
||||
const dependency = data.dependencies[0];
|
||||
|
||||
|
@ -30,7 +30,7 @@ class ExternalModuleFactoryPlugin {
|
|||
const handleExternal = (value, type, callback) => {
|
||||
if (value === false) {
|
||||
// Not externals, fallback to original factory
|
||||
return factory(data, callback);
|
||||
return callback();
|
||||
}
|
||||
/** @type {string} */
|
||||
let externalConfig;
|
||||
|
@ -126,11 +126,7 @@ class ExternalModuleFactoryPlugin {
|
|||
callback();
|
||||
};
|
||||
|
||||
handleExternals(this.externals, (err, module) => {
|
||||
if (err) return callback(err);
|
||||
if (!module) return handleExternal(false, undefined, callback);
|
||||
return callback(null, module);
|
||||
});
|
||||
handleExternals(this.externals, callback);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,9 @@ const applyMtime = mtime => {
|
|||
class FileSystemInfo {
|
||||
constructor(fs) {
|
||||
this.fs = fs;
|
||||
/** @type {Map<string, FileSystemInfoEntry | null>} */
|
||||
this._fileTimestamps = new Map();
|
||||
/** @type {Map<string, FileSystemInfoEntry | null>} */
|
||||
this._contextTimestamps = new Map();
|
||||
this.fileTimestampQueue = new AsyncQueue({
|
||||
name: "file timestamp",
|
||||
|
@ -41,7 +43,7 @@ class FileSystemInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Map<string, FileSystemInfoEntry>} map timestamps
|
||||
* @param {Map<string, FileSystemInfoEntry | null>} map timestamps
|
||||
* @returns {void}
|
||||
*/
|
||||
addFileTimestamps(map) {
|
||||
|
@ -51,7 +53,7 @@ class FileSystemInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Map<string, FileSystemInfoEntry>} map timestamps
|
||||
* @param {Map<string, FileSystemInfoEntry | null>} map timestamps
|
||||
* @returns {void}
|
||||
*/
|
||||
addContextTimestamps(map) {
|
||||
|
|
|
@ -10,6 +10,7 @@ const schema = require("../schemas/plugins/IgnorePlugin.json");
|
|||
|
||||
/** @typedef {import("../declarations/plugins/IgnorePlugin").IgnorePluginOptions} IgnorePluginOptions */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./NormalModuleFactory").ResolveData} ResolveData */
|
||||
|
||||
class IgnorePlugin {
|
||||
/**
|
||||
|
@ -27,44 +28,40 @@ class IgnorePlugin {
|
|||
* Note that if "contextRegExp" is given, both the "resourceRegExp"
|
||||
* and "contextRegExp" have to match.
|
||||
*
|
||||
* @param {TODO} result result
|
||||
* @returns {TODO|null} returns result or null if result should be ignored
|
||||
* @param {ResolveData} resolveData resolve data
|
||||
* @returns {false|undefined} returns false when the request should be ignored, otherwise undefined
|
||||
*/
|
||||
checkIgnore(result) {
|
||||
if (!result) return result;
|
||||
|
||||
checkIgnore(resolveData) {
|
||||
if (
|
||||
"checkResource" in this.options &&
|
||||
this.options.checkResource &&
|
||||
this.options.checkResource(result.request, result.context)
|
||||
this.options.checkResource(resolveData.request, resolveData.context)
|
||||
) {
|
||||
// TODO webpack 5 remove checkContext, as checkResource already gets context
|
||||
if ("checkContext" in this.options && this.options.checkContext) {
|
||||
if (this.options.checkContext(result.context)) {
|
||||
return null;
|
||||
if (this.options.checkContext(resolveData.context)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
"resourceRegExp" in this.options &&
|
||||
this.options.resourceRegExp &&
|
||||
this.options.resourceRegExp.test(result.request)
|
||||
this.options.resourceRegExp.test(resolveData.request)
|
||||
) {
|
||||
if ("contextRegExp" in this.options && this.options.contextRegExp) {
|
||||
// if "contextRegExp" is given,
|
||||
// both the "resourceRegExp" and "contextRegExp" have to match.
|
||||
if (this.options.contextRegExp.test(result.context)) {
|
||||
return null;
|
||||
if (this.options.contextRegExp.test(resolveData.context)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModuleFactoryResult
|
||||
* @property {Module=} module the created module or unset if no module was created
|
||||
* @property {Set<string>=} fileDependencies
|
||||
* @property {Set<string>=} contextDependencies
|
||||
* @property {Set<string>=} missingDependencies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModuleFactoryCreateDataContextInfo
|
||||
* @property {string} issuer
|
||||
* @property {string} compiler
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ModuleFactoryCreateData
|
||||
* @property {ModuleFactoryCreateDataContextInfo} contextInfo
|
||||
* @property {any=} resolveOptions
|
||||
* @property {string} context
|
||||
* @property {Dependency[]} dependencies
|
||||
*/
|
||||
|
||||
class ModuleFactory {
|
||||
/**
|
||||
* @param {ModuleFactoryCreateData} data data object
|
||||
* @param {function(Error=, ModuleFactoryResult=): void} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
create(data, callback) {
|
||||
throw new Error("ModuleFactory.create must be overridden");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ModuleFactory;
|
|
@ -8,17 +8,36 @@
|
|||
const asyncLib = require("neo-async");
|
||||
const path = require("path");
|
||||
const {
|
||||
AsyncSeriesWaterfallHook,
|
||||
AsyncSeriesBailHook,
|
||||
SyncWaterfallHook,
|
||||
SyncBailHook,
|
||||
SyncHook,
|
||||
HookMap
|
||||
} = require("tapable");
|
||||
const Module = require("./Module");
|
||||
const ModuleFactory = require("./ModuleFactory");
|
||||
const NormalModule = require("./NormalModule");
|
||||
const RawModule = require("./RawModule");
|
||||
const RuleSet = require("./RuleSet");
|
||||
const cachedMerge = require("./util/cachedMerge");
|
||||
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
|
||||
/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ResolveData
|
||||
* @property {ModuleFactoryCreateData["contextInfo"]} contextInfo
|
||||
* @property {ModuleFactoryCreateData["resolveOptions"]} resolveOptions
|
||||
* @property {string} context
|
||||
* @property {string} request
|
||||
* @property {ModuleDependency[]} dependencies
|
||||
* @property {Object} createData
|
||||
* @property {Set<string>} fileDependencies
|
||||
* @property {Set<string>} missingDependencies
|
||||
* @property {Set<string>} contextDependencies
|
||||
*/
|
||||
|
||||
const EMPTY_RESOLVE_OPTIONS = {};
|
||||
|
||||
const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
|
||||
|
@ -56,17 +75,30 @@ const identToLoaderRequest = resultString => {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO webpack 6 remove
|
||||
const deprecationChangedHookMessage = name =>
|
||||
`NormalModuleFactory.${name} is no longer a waterfall hook, but a bailing hook instead. ` +
|
||||
"Do not return the passed object, but modify it instead. " +
|
||||
"Returning false will ignore the request and results in no module created.";
|
||||
|
||||
const dependencyCache = new WeakMap();
|
||||
|
||||
class NormalModuleFactory {
|
||||
class NormalModuleFactory extends ModuleFactory {
|
||||
constructor(context, resolverFactory, options) {
|
||||
super();
|
||||
this.hooks = Object.freeze({
|
||||
resolver: new SyncWaterfallHook(["resolver"]),
|
||||
factory: new SyncWaterfallHook(["factory"]),
|
||||
beforeResolve: new AsyncSeriesWaterfallHook(["data"]),
|
||||
afterResolve: new AsyncSeriesWaterfallHook(["data"]),
|
||||
createModule: new SyncBailHook(["data"]),
|
||||
module: new SyncWaterfallHook(["module", "data"]),
|
||||
/** @type {AsyncSeriesBailHook<ResolveData>} */
|
||||
resolve: new AsyncSeriesBailHook(["resolveData"]),
|
||||
/** @type {AsyncSeriesBailHook<ResolveData>} */
|
||||
factorize: new AsyncSeriesBailHook(["resolveData"]),
|
||||
/** @type {AsyncSeriesBailHook<ResolveData>} */
|
||||
beforeResolve: new AsyncSeriesBailHook(["resolveData"]),
|
||||
/** @type {AsyncSeriesBailHook<ResolveData>} */
|
||||
afterResolve: new AsyncSeriesBailHook(["resolveData"]),
|
||||
/** @type {SyncBailHook<ResolveData>} */
|
||||
createModule: new SyncBailHook(["resolveData"]),
|
||||
/** @type {SyncWaterfallHook<Module, ResolveData["createData"], ResolveData>} */
|
||||
module: new SyncWaterfallHook(["module", "createData", "resolveData"]),
|
||||
createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
|
||||
parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
|
||||
createGenerator: new HookMap(
|
||||
|
@ -86,232 +118,282 @@ class NormalModuleFactory {
|
|||
this.context = context || "";
|
||||
this.parserCache = Object.create(null);
|
||||
this.generatorCache = Object.create(null);
|
||||
this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
|
||||
let resolver = this.hooks.resolver.call(null);
|
||||
|
||||
// Ignored
|
||||
if (!resolver) return callback();
|
||||
|
||||
resolver(result, (err, data) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
// Ignored
|
||||
if (!data) return callback();
|
||||
|
||||
// direct module
|
||||
if (typeof data.source === "function") return callback(null, data);
|
||||
|
||||
this.hooks.afterResolve.callAsync(data, (err, result) => {
|
||||
this.hooks.factorize.tapAsync(
|
||||
/** @type {TODO} */ ({
|
||||
name: "NormalModuleFactory",
|
||||
stage: 100
|
||||
}),
|
||||
(resolveData, callback) => {
|
||||
this.hooks.resolve.callAsync(resolveData, (err, result) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
// Ignored
|
||||
if (!result) return callback();
|
||||
if (result === false) return callback();
|
||||
|
||||
let createdModule = this.hooks.createModule.call(result);
|
||||
if (!createdModule) {
|
||||
if (!result.request) {
|
||||
return callback(new Error("Empty dependency (no request)"));
|
||||
// direct module
|
||||
if (result instanceof Module) return callback(null, result);
|
||||
|
||||
if (typeof result === "object")
|
||||
throw new Error(
|
||||
deprecationChangedHookMessage("resolve") +
|
||||
" Returning a Module object will result in this module used as result."
|
||||
);
|
||||
|
||||
this.hooks.afterResolve.callAsync(resolveData, (err, result) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (typeof result === "object")
|
||||
throw new Error(deprecationChangedHookMessage("afterResolve"));
|
||||
|
||||
// Ignored
|
||||
if (result === false) return callback();
|
||||
|
||||
const createData = resolveData.createData;
|
||||
|
||||
let createdModule = this.hooks.createModule.call(createData);
|
||||
if (!createdModule) {
|
||||
if (!resolveData.request) {
|
||||
return callback(new Error("Empty dependency (no request)"));
|
||||
}
|
||||
|
||||
createdModule = new NormalModule(createData);
|
||||
}
|
||||
|
||||
createdModule = new NormalModule(result);
|
||||
}
|
||||
createdModule = this.hooks.module.call(
|
||||
createdModule,
|
||||
createData,
|
||||
resolveData
|
||||
);
|
||||
|
||||
createdModule = this.hooks.module.call(createdModule, result);
|
||||
|
||||
return callback(null, createdModule);
|
||||
return callback(null, createdModule);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
this.hooks.resolver.tap("NormalModuleFactory", () => (data, callback) => {
|
||||
const contextInfo = data.contextInfo;
|
||||
const context = data.context;
|
||||
const request = data.request;
|
||||
|
||||
const loaderResolver = this.getResolver("loader");
|
||||
const normalResolver = this.getResolver("normal", data.resolveOptions);
|
||||
|
||||
let matchResource = undefined;
|
||||
let requestWithoutMatchResource = request;
|
||||
const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
|
||||
if (matchResourceMatch) {
|
||||
matchResource = matchResourceMatch[1];
|
||||
if (/^\.\.?\//.test(matchResource)) {
|
||||
matchResource = path.join(context, matchResource);
|
||||
}
|
||||
requestWithoutMatchResource = request.substr(
|
||||
matchResourceMatch[0].length
|
||||
);
|
||||
}
|
||||
);
|
||||
this.hooks.resolve.tapAsync(
|
||||
/** @type {TODO} */ ({
|
||||
name: "NormalModuleFactory",
|
||||
stage: 100
|
||||
}),
|
||||
(data, callback) => {
|
||||
const {
|
||||
contextInfo,
|
||||
context,
|
||||
request,
|
||||
resolveOptions,
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
} = data;
|
||||
|
||||
const noPreAutoLoaders = requestWithoutMatchResource.startsWith("-!");
|
||||
const noAutoLoaders =
|
||||
noPreAutoLoaders || requestWithoutMatchResource.startsWith("!");
|
||||
const noPrePostAutoLoaders = requestWithoutMatchResource.startsWith("!!");
|
||||
let elements = requestWithoutMatchResource
|
||||
.replace(/^-?!+/, "")
|
||||
.replace(/!!+/g, "!")
|
||||
.split("!");
|
||||
let resource = elements.pop();
|
||||
elements = elements.map(identToLoaderRequest);
|
||||
const loaderResolver = this.getResolver("loader");
|
||||
const normalResolver = this.getResolver("normal", resolveOptions);
|
||||
|
||||
asyncLib.parallel(
|
||||
[
|
||||
callback =>
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
context,
|
||||
elements,
|
||||
loaderResolver,
|
||||
callback
|
||||
),
|
||||
callback => {
|
||||
if (resource === "" || resource[0] === "?") {
|
||||
return callback(null, {
|
||||
resource
|
||||
});
|
||||
}
|
||||
/** @type {string} */
|
||||
let matchResource = undefined;
|
||||
/** @type {string} */
|
||||
let requestWithoutMatchResource = request;
|
||||
const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
|
||||
if (matchResourceMatch) {
|
||||
matchResource = matchResourceMatch[1];
|
||||
if (/^\.\.?\//.test(matchResource)) {
|
||||
matchResource = path.join(context, matchResource);
|
||||
}
|
||||
requestWithoutMatchResource = request.substr(
|
||||
matchResourceMatch[0].length
|
||||
);
|
||||
}
|
||||
|
||||
normalResolver.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
resource,
|
||||
{},
|
||||
(err, resource, resourceResolveData) => {
|
||||
if (err) return callback(err);
|
||||
callback(null, {
|
||||
resourceResolveData,
|
||||
const noPreAutoLoaders = requestWithoutMatchResource.startsWith("-!");
|
||||
const noAutoLoaders =
|
||||
noPreAutoLoaders || requestWithoutMatchResource.startsWith("!");
|
||||
const noPrePostAutoLoaders = requestWithoutMatchResource.startsWith(
|
||||
"!!"
|
||||
);
|
||||
const rawElements = requestWithoutMatchResource
|
||||
.replace(/^-?!+/, "")
|
||||
.replace(/!!+/g, "!")
|
||||
.split("!");
|
||||
const resource = rawElements.pop();
|
||||
const elements = rawElements.map(identToLoaderRequest);
|
||||
|
||||
const resolveContext = {
|
||||
fileDependencies,
|
||||
missing: missingDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
};
|
||||
|
||||
asyncLib.parallel(
|
||||
[
|
||||
callback =>
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
context,
|
||||
elements,
|
||||
loaderResolver,
|
||||
resolveContext,
|
||||
callback
|
||||
),
|
||||
callback => {
|
||||
if (resource === "" || resource[0] === "?") {
|
||||
return callback(null, {
|
||||
resource
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
],
|
||||
(err, results) => {
|
||||
if (err) return callback(err);
|
||||
let loaders = results[0];
|
||||
const resourceResolveData = results[1].resourceResolveData;
|
||||
resource = results[1].resource;
|
||||
|
||||
// translate option idents
|
||||
try {
|
||||
for (const item of loaders) {
|
||||
if (typeof item.options === "string" && item.options[0] === "?") {
|
||||
const ident = item.options.substr(1);
|
||||
item.options = this.ruleSet.findOptionsByIdent(ident);
|
||||
item.ident = ident;
|
||||
normalResolver.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
resource,
|
||||
resolveContext,
|
||||
(err, resource, resourceResolveData) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
// TODO remove this when enhanced-resolve supports fileDependencies
|
||||
if (resource) {
|
||||
fileDependencies.add(resource);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
resourceResolveData,
|
||||
resource
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
],
|
||||
(err, results) => {
|
||||
if (err) return callback(err);
|
||||
let loaders = results[0];
|
||||
const resourceResolveData = results[1].resourceResolveData;
|
||||
const resource = results[1].resource;
|
||||
|
||||
// translate option idents
|
||||
try {
|
||||
for (const item of loaders) {
|
||||
if (
|
||||
typeof item.options === "string" &&
|
||||
item.options[0] === "?"
|
||||
) {
|
||||
const ident = item.options.substr(1);
|
||||
item.options = this.ruleSet.findOptionsByIdent(ident);
|
||||
item.ident = ident;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
if (resource === false) {
|
||||
// ignored
|
||||
return callback(
|
||||
null,
|
||||
new RawModule(
|
||||
"/* (ignored) */",
|
||||
`ignored|${request}`,
|
||||
`${request} (ignored)`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const userRequest =
|
||||
(matchResource !== undefined ? `${matchResource}!=!` : "") +
|
||||
loaders
|
||||
.map(loaderToIdent)
|
||||
.concat([resource])
|
||||
.join("!");
|
||||
|
||||
let resourcePath =
|
||||
matchResource !== undefined ? matchResource : resource;
|
||||
let resourceQuery = "";
|
||||
const queryIndex = resourcePath.indexOf("?");
|
||||
if (queryIndex >= 0) {
|
||||
resourceQuery = resourcePath.substr(queryIndex);
|
||||
resourcePath = resourcePath.substr(0, queryIndex);
|
||||
}
|
||||
|
||||
const result = this.ruleSet.exec({
|
||||
resource: resourcePath,
|
||||
realResource:
|
||||
matchResource !== undefined
|
||||
? resource.replace(/\?.*/, "")
|
||||
: resourcePath,
|
||||
resourceQuery,
|
||||
issuer: contextInfo.issuer,
|
||||
compiler: contextInfo.compiler
|
||||
});
|
||||
const settings = {};
|
||||
const useLoadersPost = [];
|
||||
const useLoaders = [];
|
||||
const useLoadersPre = [];
|
||||
for (const r of result) {
|
||||
if (r.type === "use") {
|
||||
if (r.enforce === "post" && !noPrePostAutoLoaders) {
|
||||
useLoadersPost.push(r.value);
|
||||
} else if (
|
||||
r.enforce === "pre" &&
|
||||
!noPreAutoLoaders &&
|
||||
!noPrePostAutoLoaders
|
||||
) {
|
||||
useLoadersPre.push(r.value);
|
||||
} else if (
|
||||
!r.enforce &&
|
||||
!noAutoLoaders &&
|
||||
!noPrePostAutoLoaders
|
||||
) {
|
||||
useLoaders.push(r.value);
|
||||
}
|
||||
} else if (
|
||||
typeof r.value === "object" &&
|
||||
r.value !== null &&
|
||||
typeof settings[r.type] === "object" &&
|
||||
settings[r.type] !== null
|
||||
) {
|
||||
settings[r.type] = cachedMerge(settings[r.type], r.value);
|
||||
} else {
|
||||
settings[r.type] = r.value;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
if (resource === false) {
|
||||
// ignored
|
||||
return callback(
|
||||
null,
|
||||
new RawModule(
|
||||
"/* (ignored) */",
|
||||
`ignored|${request}`,
|
||||
`${request} (ignored)`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const userRequest =
|
||||
(matchResource !== undefined ? `${matchResource}!=!` : "") +
|
||||
loaders
|
||||
.map(loaderToIdent)
|
||||
.concat([resource])
|
||||
.join("!");
|
||||
|
||||
let resourcePath =
|
||||
matchResource !== undefined ? matchResource : resource;
|
||||
let resourceQuery = "";
|
||||
const queryIndex = resourcePath.indexOf("?");
|
||||
if (queryIndex >= 0) {
|
||||
resourceQuery = resourcePath.substr(queryIndex);
|
||||
resourcePath = resourcePath.substr(0, queryIndex);
|
||||
}
|
||||
|
||||
const result = this.ruleSet.exec({
|
||||
resource: resourcePath,
|
||||
realResource:
|
||||
matchResource !== undefined
|
||||
? resource.replace(/\?.*/, "")
|
||||
: resourcePath,
|
||||
resourceQuery,
|
||||
issuer: contextInfo.issuer,
|
||||
compiler: contextInfo.compiler
|
||||
});
|
||||
const settings = {};
|
||||
const useLoadersPost = [];
|
||||
const useLoaders = [];
|
||||
const useLoadersPre = [];
|
||||
for (const r of result) {
|
||||
if (r.type === "use") {
|
||||
if (r.enforce === "post" && !noPrePostAutoLoaders) {
|
||||
useLoadersPost.push(r.value);
|
||||
} else if (
|
||||
r.enforce === "pre" &&
|
||||
!noPreAutoLoaders &&
|
||||
!noPrePostAutoLoaders
|
||||
) {
|
||||
useLoadersPre.push(r.value);
|
||||
} else if (
|
||||
!r.enforce &&
|
||||
!noAutoLoaders &&
|
||||
!noPrePostAutoLoaders
|
||||
) {
|
||||
useLoaders.push(r.value);
|
||||
}
|
||||
} else if (
|
||||
typeof r.value === "object" &&
|
||||
r.value !== null &&
|
||||
typeof settings[r.type] === "object" &&
|
||||
settings[r.type] !== null
|
||||
) {
|
||||
settings[r.type] = cachedMerge(settings[r.type], r.value);
|
||||
} else {
|
||||
settings[r.type] = r.value;
|
||||
}
|
||||
}
|
||||
asyncLib.parallel(
|
||||
[
|
||||
this.resolveRequestArray.bind(
|
||||
this,
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoadersPost,
|
||||
loaderResolver
|
||||
),
|
||||
this.resolveRequestArray.bind(
|
||||
this,
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoaders,
|
||||
loaderResolver
|
||||
),
|
||||
this.resolveRequestArray.bind(
|
||||
this,
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoadersPre,
|
||||
loaderResolver
|
||||
)
|
||||
],
|
||||
(err, results) => {
|
||||
if (err) return callback(err);
|
||||
loaders = results[0].concat(loaders, results[1], results[2]);
|
||||
process.nextTick(() => {
|
||||
asyncLib.parallel(
|
||||
[
|
||||
this.resolveRequestArray.bind(
|
||||
this,
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoadersPost,
|
||||
loaderResolver,
|
||||
resolveContext
|
||||
),
|
||||
this.resolveRequestArray.bind(
|
||||
this,
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoaders,
|
||||
loaderResolver,
|
||||
resolveContext
|
||||
),
|
||||
this.resolveRequestArray.bind(
|
||||
this,
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoadersPre,
|
||||
loaderResolver,
|
||||
resolveContext
|
||||
)
|
||||
],
|
||||
(err, results) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
loaders = results[0].concat(loaders, results[1], results[2]);
|
||||
const type = settings.type;
|
||||
const resolveOptions = settings.resolve;
|
||||
callback(null, {
|
||||
context: context,
|
||||
Object.assign(data.createData, {
|
||||
request: loaders
|
||||
.map(loaderToIdent)
|
||||
.concat([resource])
|
||||
.join("!"),
|
||||
dependencies: data.dependencies,
|
||||
userRequest,
|
||||
rawRequest: request,
|
||||
loaders,
|
||||
|
@ -324,59 +406,84 @@ class NormalModuleFactory {
|
|||
generator: this.getGenerator(type, settings.generator),
|
||||
resolveOptions
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
callback();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleFactoryCreateData} data data object
|
||||
* @param {function(Error=, ModuleFactoryResult=): void} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
create(data, callback) {
|
||||
const dependencies = data.dependencies;
|
||||
const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies);
|
||||
if (this.unsafeCache) {
|
||||
const cacheEntry = dependencyCache.get(dependencies[0]);
|
||||
if (cacheEntry) return callback(null, cacheEntry);
|
||||
}
|
||||
const context = data.context || this.context;
|
||||
const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
|
||||
const request = dependencies[0].request;
|
||||
const contextInfo = data.contextInfo || {};
|
||||
this.hooks.beforeResolve.callAsync(
|
||||
{
|
||||
contextInfo,
|
||||
resolveOptions,
|
||||
context,
|
||||
request,
|
||||
dependencies
|
||||
},
|
||||
(err, result) => {
|
||||
const dependency = dependencies[0];
|
||||
const request = dependency.request;
|
||||
const contextInfo = data.contextInfo;
|
||||
const fileDependencies = new Set();
|
||||
const missingDependencies = new Set();
|
||||
const contextDependencies = new Set();
|
||||
/** @type {ResolveData} */
|
||||
const resolveData = {
|
||||
contextInfo,
|
||||
resolveOptions,
|
||||
context,
|
||||
request,
|
||||
dependencies,
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies,
|
||||
createData: {}
|
||||
};
|
||||
this.hooks.beforeResolve.callAsync(resolveData, (err, result) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
// Ignored
|
||||
if (result === false) return callback();
|
||||
|
||||
if (typeof result === "object")
|
||||
throw new Error(deprecationChangedHookMessage("beforeResolve"));
|
||||
|
||||
this.hooks.factorize.callAsync(resolveData, (err, module) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
// Ignored
|
||||
if (!result) return callback();
|
||||
const factoryResult = {
|
||||
module,
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
};
|
||||
|
||||
const factory = this.hooks.factory.call(null);
|
||||
|
||||
// Ignored
|
||||
if (!factory) return callback();
|
||||
|
||||
factory(result, (err, module) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (this.unsafeCache && module && this.cachePredicate(module)) {
|
||||
for (const d of dependencies) {
|
||||
dependencyCache.set(d, module);
|
||||
}
|
||||
if (this.unsafeCache && module && this.cachePredicate(module)) {
|
||||
for (const d of dependencies) {
|
||||
dependencyCache.set(d, factoryResult);
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, module);
|
||||
});
|
||||
}
|
||||
);
|
||||
callback(null, factoryResult);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
resolveRequestArray(contextInfo, context, array, resolver, callback) {
|
||||
resolveRequestArray(
|
||||
contextInfo,
|
||||
context,
|
||||
array,
|
||||
resolver,
|
||||
resolveContext,
|
||||
callback
|
||||
) {
|
||||
if (array.length === 0) return callback(null, []);
|
||||
asyncLib.map(
|
||||
array,
|
||||
|
@ -385,7 +492,7 @@ class NormalModuleFactory {
|
|||
contextInfo,
|
||||
context,
|
||||
item.loader,
|
||||
{},
|
||||
resolveContext,
|
||||
(err, result) => {
|
||||
if (
|
||||
err &&
|
||||
|
@ -419,10 +526,20 @@ class NormalModuleFactory {
|
|||
options: item.options
|
||||
}
|
||||
: undefined;
|
||||
return callback(
|
||||
null,
|
||||
Object.assign({}, item, identToLoaderRequest(result), optionsOnly)
|
||||
|
||||
const resolved = Object.assign(
|
||||
{},
|
||||
item,
|
||||
identToLoaderRequest(result),
|
||||
optionsOnly
|
||||
);
|
||||
|
||||
// TODO remove this when enhanced-resolve supports fileDependencies
|
||||
if (resolved.loader) {
|
||||
resolveContext.fileDependencies.add(resolved.loader);
|
||||
}
|
||||
|
||||
return callback(null, resolved);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
|
@ -33,7 +33,6 @@ class NormalModuleReplacementPlugin {
|
|||
"NormalModuleReplacementPlugin",
|
||||
nmf => {
|
||||
nmf.hooks.beforeResolve.tap("NormalModuleReplacementPlugin", result => {
|
||||
if (!result) return;
|
||||
if (resourceRegExp.test(result.request)) {
|
||||
if (typeof newResource === "function") {
|
||||
newResource(result);
|
||||
|
@ -44,13 +43,13 @@ class NormalModuleReplacementPlugin {
|
|||
return result;
|
||||
});
|
||||
nmf.hooks.afterResolve.tap("NormalModuleReplacementPlugin", result => {
|
||||
if (!result) return;
|
||||
if (resourceRegExp.test(result.resource)) {
|
||||
const createData = result.createData;
|
||||
if (resourceRegExp.test(createData.resource)) {
|
||||
if (typeof newResource === "function") {
|
||||
newResource(result);
|
||||
} else {
|
||||
result.resource = path.resolve(
|
||||
path.dirname(result.resource),
|
||||
createData.resource = path.resolve(
|
||||
path.dirname(createData.resource),
|
||||
newResource
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,17 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
class NullFactory {
|
||||
const ModuleFactory = require("./ModuleFactory");
|
||||
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */
|
||||
/** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */
|
||||
|
||||
class NullFactory extends ModuleFactory {
|
||||
/**
|
||||
* @param {ModuleFactoryCreateData} data data object
|
||||
* @param {function(Error=, ModuleFactoryResult=): void} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
create(data, callback) {
|
||||
return callback();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const Stats = require("./Stats");
|
|||
const toFileSystemInfoEntryMap = timestamps => {
|
||||
const map = new Map();
|
||||
for (const [key, ts] of timestamps) {
|
||||
map.set(key, { safeTime: ts });
|
||||
map.set(key, ts ? { safeTime: ts } : null);
|
||||
}
|
||||
return map;
|
||||
};
|
||||
|
|
|
@ -72,6 +72,7 @@ class ResolverCachePlugin {
|
|||
const contextDependencies = new Set(
|
||||
newResolveContext.contextDependencies
|
||||
);
|
||||
// TODO remove this when enhanced-resolve supports fileDependencies
|
||||
if (result && result.path) {
|
||||
fileDependencies.add(result.path);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ class SideEffectsFlagPlugin {
|
|||
} else if (data.settings.sideEffects === true) {
|
||||
module.factoryMeta.sideEffectFree = false;
|
||||
}
|
||||
return module;
|
||||
});
|
||||
});
|
||||
compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => {
|
||||
|
|
|
@ -88,7 +88,7 @@ describe("StatsTestCases", () => {
|
|||
if (/error$/.test(testName)) {
|
||||
expect(stats.hasErrors()).toBe(true);
|
||||
} else if (stats.hasErrors()) {
|
||||
return done(new Error(stats.toJson().errors.join("\n\n")));
|
||||
return done(new Error(stats.toString({ all: false, errors: true })));
|
||||
}
|
||||
let toStringOptions = {
|
||||
context: path.join(base, testName),
|
||||
|
|
Loading…
Reference in New Issue