mirror of https://github.com/webpack/webpack.git
Merge branch 'next' into feat_afterDone_hook
This commit is contained in:
commit
4f3e0d27b5
|
|
@ -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() {
|
||||
|
|
@ -822,37 +808,44 @@ class Compilation {
|
|||
}
|
||||
}
|
||||
|
||||
// This is nested so we need to allow one additional task
|
||||
this.processDependenciesQueue.increaseParallelism();
|
||||
if (sortedDependencies.length === 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
asyncLib.forEach(
|
||||
sortedDependencies,
|
||||
(item, callback) => {
|
||||
this.handleModuleCreation(
|
||||
{
|
||||
factory: item.factory,
|
||||
dependencies: item.dependencies,
|
||||
originModule: module
|
||||
},
|
||||
err => {
|
||||
// In V8, the Error objects keep a reference to the functions on the stack. These warnings &
|
||||
// errors are created inside closures that keep a reference to the Compilation, so errors are
|
||||
// leaking the Compilation object.
|
||||
if (err && this.bail) {
|
||||
// eslint-disable-next-line no-self-assign
|
||||
err.stack = err.stack;
|
||||
return callback(err);
|
||||
process.nextTick(() => {
|
||||
// This is nested so we need to allow one additional task
|
||||
this.processDependenciesQueue.increaseParallelism();
|
||||
|
||||
asyncLib.forEach(
|
||||
sortedDependencies,
|
||||
(item, callback) => {
|
||||
this.handleModuleCreation(
|
||||
{
|
||||
factory: item.factory,
|
||||
dependencies: item.dependencies,
|
||||
originModule: module
|
||||
},
|
||||
err => {
|
||||
// In V8, the Error objects keep a reference to the functions on the stack. These warnings &
|
||||
// errors are created inside closures that keep a reference to the Compilation, so errors are
|
||||
// leaking the Compilation object.
|
||||
if (err && this.bail) {
|
||||
// eslint-disable-next-line no-self-assign
|
||||
err.stack = err.stack;
|
||||
return callback(err);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
err => {
|
||||
this.processDependenciesQueue.decreaseParallelism();
|
||||
);
|
||||
},
|
||||
err => {
|
||||
this.processDependenciesQueue.decreaseParallelism();
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
);
|
||||
return callback(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -999,7 +992,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 +1017,10 @@ class Compilation {
|
|||
);
|
||||
return callback(notFoundError);
|
||||
}
|
||||
if (!result) {
|
||||
return callback();
|
||||
}
|
||||
const newModule = result.module;
|
||||
if (!newModule) {
|
||||
return callback();
|
||||
}
|
||||
|
|
@ -2190,10 +2203,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 +2216,20 @@ 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;
|
||||
const missingDependencies = module.buildInfo.missingDependencies;
|
||||
if (fileDependencies) {
|
||||
addAllToSet(this.fileDependencies, fileDependencies);
|
||||
}
|
||||
if (module.buildInfo.contextDependencies) {
|
||||
addAllToSet(
|
||||
this.contextDependencies,
|
||||
module.buildInfo.contextDependencies
|
||||
);
|
||||
if (contextDependencies) {
|
||||
addAllToSet(this.contextDependencies, contextDependencies);
|
||||
}
|
||||
if (missingDependencies) {
|
||||
addAllToSet(this.missingDependencies, missingDependencies);
|
||||
}
|
||||
}
|
||||
|
||||
for (const error of this.errors) {
|
||||
if (
|
||||
typeof error.missing === "object" &&
|
||||
|
|
@ -2226,6 +2239,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
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -141,9 +140,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();
|
||||
|
|
@ -193,7 +192,9 @@ class Compiler {
|
|||
const finalCallback = (err, stats) => {
|
||||
this.cache.beginIdle();
|
||||
this.running = false;
|
||||
|
||||
if (err) {
|
||||
this.hooks.failed.call(err);
|
||||
}
|
||||
if (callback !== undefined) callback(err, stats);
|
||||
this.hooks.afterDone.call(stats);
|
||||
};
|
||||
|
|
@ -216,35 +217,37 @@ class Compiler {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emitAssets(compilation, err => {
|
||||
if (err) return finalCallback(err);
|
||||
|
||||
if (compilation.hooks.needAdditionalPass.call()) {
|
||||
compilation.needAdditionalPass = true;
|
||||
|
||||
const stats = new Stats(compilation);
|
||||
stats.startTime = startTime;
|
||||
stats.endTime = Date.now();
|
||||
this.hooks.done.callAsync(stats, err => {
|
||||
if (err) return finalCallback(err);
|
||||
|
||||
this.hooks.additionalPass.callAsync(err => {
|
||||
if (err) return finalCallback(err);
|
||||
this.compile(onCompiled);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.emitRecords(err => {
|
||||
process.nextTick(() => {
|
||||
this.emitAssets(compilation, err => {
|
||||
if (err) return finalCallback(err);
|
||||
|
||||
const stats = new Stats(compilation);
|
||||
stats.startTime = startTime;
|
||||
stats.endTime = Date.now();
|
||||
this.hooks.done.callAsync(stats, err => {
|
||||
if (compilation.hooks.needAdditionalPass.call()) {
|
||||
compilation.needAdditionalPass = true;
|
||||
|
||||
const stats = new Stats(compilation);
|
||||
stats.startTime = startTime;
|
||||
stats.endTime = Date.now();
|
||||
this.hooks.done.callAsync(stats, err => {
|
||||
if (err) return finalCallback(err);
|
||||
|
||||
this.hooks.additionalPass.callAsync(err => {
|
||||
if (err) return finalCallback(err);
|
||||
this.compile(onCompiled);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.emitRecords(err => {
|
||||
if (err) return finalCallback(err);
|
||||
return finalCallback(null, stats);
|
||||
|
||||
const stats = new Stats(compilation);
|
||||
stats.startTime = startTime;
|
||||
stats.endTime = Date.now();
|
||||
this.hooks.done.callAsync(stats, err => {
|
||||
if (err) return finalCallback(err);
|
||||
return finalCallback(null, stats);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -525,7 +528,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;
|
||||
|
|
@ -550,8 +552,7 @@ class Compiler {
|
|||
newCompilationParams() {
|
||||
const params = {
|
||||
normalModuleFactory: this.createNormalModuleFactory(),
|
||||
contextModuleFactory: this.createContextModuleFactory(),
|
||||
compilationDependencies: new Set()
|
||||
contextModuleFactory: this.createContextModuleFactory()
|
||||
};
|
||||
return params;
|
||||
}
|
||||
|
|
@ -572,16 +573,18 @@ class Compiler {
|
|||
this.hooks.make.callAsync(compilation, err => {
|
||||
if (err) return callback(err);
|
||||
|
||||
compilation.finish(err => {
|
||||
if (err) return callback(err);
|
||||
|
||||
compilation.seal(err => {
|
||||
process.nextTick(() => {
|
||||
compilation.finish(err => {
|
||||
if (err) return callback(err);
|
||||
|
||||
this.hooks.afterCompile.callAsync(compilation, err => {
|
||||
compilation.seal(err => {
|
||||
if (err) return callback(err);
|
||||
|
||||
return callback(null, compilation);
|
||||
this.hooks.afterCompile.callAsync(compilation, err => {
|
||||
if (err) return callback(err);
|
||||
|
||||
return callback(null, compilation);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,14 @@ class RuntimeValue {
|
|||
}
|
||||
|
||||
exec(parser) {
|
||||
const buildInfo = parser.state.module.buildInfo;
|
||||
if (this.fileDependencies === true) {
|
||||
parser.state.module.buildInfo.cacheable = false;
|
||||
buildInfo.cacheable = false;
|
||||
} else {
|
||||
for (const fileDependency of this.fileDependencies) {
|
||||
parser.state.module.buildInfo.fileDependencies.add(fileDependency);
|
||||
buildInfo.fileDependencies.add(fileDependency);
|
||||
if (!buildInfo.snapshot.fileTimestamps.has(fileDependency))
|
||||
buildInfo.snapshot.fileTimestamps.set(fileDependency, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -82,6 +84,165 @@ class FileSystemInfo {
|
|||
this.contextTimestampQueue.add(path, callback);
|
||||
}
|
||||
|
||||
createSnapshot(startTime, files, directories, missing, options, callback) {
|
||||
const fileTimestamps = new Map();
|
||||
const contextTimestamps = new Map();
|
||||
const missingTimestamps = new Map();
|
||||
let jobs = 1;
|
||||
const jobDone = () => {
|
||||
if (--jobs === 0) {
|
||||
callback(null, {
|
||||
startTime,
|
||||
fileTimestamps,
|
||||
contextTimestamps,
|
||||
missingTimestamps
|
||||
});
|
||||
}
|
||||
};
|
||||
if (files) {
|
||||
for (const path of files) {
|
||||
const cache = this._fileTimestamps.get(path);
|
||||
if (cache !== undefined) {
|
||||
fileTimestamps.set(path, cache);
|
||||
} else {
|
||||
jobs++;
|
||||
this.fileTimestampQueue.add(path, (err, entry) => {
|
||||
if (err) {
|
||||
fileTimestamps.set(path, "error");
|
||||
} else {
|
||||
fileTimestamps.set(path, entry);
|
||||
}
|
||||
jobDone();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (directories) {
|
||||
for (const path of directories) {
|
||||
contextTimestamps.set(path, "error");
|
||||
// TODO: getContextTimestamp is not implemented yet
|
||||
}
|
||||
}
|
||||
if (missing) {
|
||||
for (const path of missing) {
|
||||
const cache = this._fileTimestamps.get(path);
|
||||
if (cache !== undefined) {
|
||||
missingTimestamps.set(path, cache);
|
||||
} else {
|
||||
jobs++;
|
||||
this.fileTimestampQueue.add(path, (err, entry) => {
|
||||
if (err) {
|
||||
missingTimestamps.set(path, "error");
|
||||
} else {
|
||||
missingTimestamps.set(path, entry);
|
||||
}
|
||||
jobDone();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
jobDone();
|
||||
}
|
||||
|
||||
checkSnapshotValid(snapshot, callback) {
|
||||
const {
|
||||
startTime,
|
||||
fileTimestamps,
|
||||
contextTimestamps,
|
||||
missingTimestamps
|
||||
} = snapshot;
|
||||
let jobs = 1;
|
||||
const jobDone = () => {
|
||||
if (--jobs === 0) {
|
||||
callback(null, true);
|
||||
}
|
||||
};
|
||||
const invalid = () => {
|
||||
if (jobs > 0) {
|
||||
jobs = NaN;
|
||||
callback(null, false);
|
||||
}
|
||||
};
|
||||
const checkExistance = (current, snap) => {
|
||||
if (snap === "error") {
|
||||
// If there was an error while snapshotting (i. e. EBUSY)
|
||||
// we can't compare further data and assume it's invalid
|
||||
return false;
|
||||
}
|
||||
return !current === !snap;
|
||||
};
|
||||
const checkFile = (current, snap) => {
|
||||
if (snap === "error") {
|
||||
// If there was an error while snapshotting (i. e. EBUSY)
|
||||
// we can't compare further data and assume it's invalid
|
||||
return false;
|
||||
}
|
||||
if (current && current.safeTime > startTime) {
|
||||
// If a change happened after starting reading the item
|
||||
// this may no longer be valid
|
||||
return false;
|
||||
}
|
||||
if (!current !== !snap) {
|
||||
// If existance of item differs
|
||||
// it's invalid
|
||||
return false;
|
||||
}
|
||||
if (current) {
|
||||
// For existing items only
|
||||
if (
|
||||
snap.timestamp !== undefined &&
|
||||
current.timestamp !== snap.timestamp
|
||||
) {
|
||||
// If we have a timestamp (it was a file or symlink) and it differs from current timestamp
|
||||
// it's invalid
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
for (const [path, ts] of fileTimestamps) {
|
||||
const cache = this._fileTimestamps.get(path);
|
||||
if (cache !== undefined) {
|
||||
if (!checkFile(cache, ts)) {
|
||||
invalid();
|
||||
}
|
||||
} else {
|
||||
jobs++;
|
||||
this.fileTimestampQueue.add(path, (err, entry) => {
|
||||
if (err) return invalid();
|
||||
if (!checkFile(entry, ts)) {
|
||||
invalid();
|
||||
} else {
|
||||
jobDone();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (contextTimestamps.size > 0) {
|
||||
// TODO: getContextTimestamp is not implemented yet
|
||||
invalid();
|
||||
}
|
||||
for (const [path, ts] of missingTimestamps) {
|
||||
const cache = this._fileTimestamps.get(path);
|
||||
if (cache !== undefined) {
|
||||
if (!checkExistance(cache, ts)) {
|
||||
invalid();
|
||||
}
|
||||
} else {
|
||||
jobs++;
|
||||
this.fileTimestampQueue.add(path, (err, entry) => {
|
||||
if (err) return invalid();
|
||||
if (!checkExistance(entry, ts)) {
|
||||
invalid();
|
||||
} else {
|
||||
jobDone();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
jobDone();
|
||||
}
|
||||
|
||||
// TODO getFileHash(path, callback)
|
||||
|
||||
_readFileTimestamp(path, callback) {
|
||||
|
|
@ -94,12 +255,13 @@ class FileSystemInfo {
|
|||
return callback(err);
|
||||
}
|
||||
|
||||
if (stat.mtime) applyMtime(+stat.mtime);
|
||||
const mtime = +stat.mtime;
|
||||
|
||||
if (mtime) applyMtime(mtime);
|
||||
|
||||
const mtime = +stat.mtime || Infinity;
|
||||
const ts = {
|
||||
safeTime: mtime + FS_ACCURACY,
|
||||
timestamp: mtime
|
||||
safeTime: mtime ? mtime + FS_ACCURACY : Infinity,
|
||||
timestamp: stat.isDirectory() ? undefined : mtime
|
||||
};
|
||||
|
||||
this._fileTimestamps.set(path, ts);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,22 @@ const Template = require("./Template");
|
|||
|
||||
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
|
||||
|
||||
const joinIterableWithComma = iterable => {
|
||||
// This is more performant than Array.from().join(", ")
|
||||
// as it doesn't create an array
|
||||
let str = "";
|
||||
let first = true;
|
||||
for (const item of iterable) {
|
||||
str += item;
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
str += ", ";
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
class FunctionModuleTemplatePlugin {
|
||||
constructor({ compilation }) {
|
||||
this.compilation = compilation;
|
||||
|
|
@ -62,9 +78,11 @@ class FunctionModuleTemplatePlugin {
|
|||
const req = module.readableIdentifier(
|
||||
moduleTemplate.runtimeTemplate.requestShortener
|
||||
);
|
||||
source.add("/*!****" + req.replace(/./g, "*") + "****!*\\\n");
|
||||
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n");
|
||||
source.add(" \\****" + req.replace(/./g, "*") + "****/\n");
|
||||
const reqStr = req.replace(/\*\//g, "*_/");
|
||||
const reqStrStar = "*".repeat(reqStr.length);
|
||||
source.add("/*!****" + reqStrStar + "****!*\\\n");
|
||||
source.add(" !*** " + reqStr + " ***!\n");
|
||||
source.add(" \\****" + reqStrStar + "****/\n");
|
||||
const providedExports = moduleGraph.getProvidedExports(module);
|
||||
if (Array.isArray(providedExports)) {
|
||||
if (providedExports.length === 0) {
|
||||
|
|
@ -81,9 +99,9 @@ class FunctionModuleTemplatePlugin {
|
|||
}
|
||||
source.add(
|
||||
Template.toComment(
|
||||
`runtime requirements: ${Array.from(
|
||||
`runtime requirements: ${joinIterableWithComma(
|
||||
chunkGraph.getModuleRuntimeRequirements(module)
|
||||
).join(", ")}`
|
||||
)}`
|
||||
) + "\n"
|
||||
);
|
||||
const usedExports = moduleGraph.getUsedExports(module);
|
||||
|
|
@ -97,7 +115,7 @@ class FunctionModuleTemplatePlugin {
|
|||
} else {
|
||||
source.add(
|
||||
Template.toComment(
|
||||
"exports used: " + Array.from(usedExports).join(", ")
|
||||
"exports used: " + joinIterableWithComma(usedExports)
|
||||
) + "\n"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -495,6 +495,20 @@ class JavascriptParser {
|
|||
res.setNumber(~argument.number);
|
||||
res.setRange(expr.range);
|
||||
return res;
|
||||
} else if (expr.operator === "+") {
|
||||
const argument = this.evaluateExpression(expr.argument);
|
||||
if (!argument) return;
|
||||
if (argument.isNumber()) {
|
||||
const res = new BasicEvaluatedExpression();
|
||||
res.setNumber(+argument.number);
|
||||
res.setRange(expr.range);
|
||||
return res;
|
||||
} else if (argument.isString()) {
|
||||
const res = new BasicEvaluatedExpression();
|
||||
res.setNumber(+argument.string);
|
||||
res.setRange(expr.range);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.hooks.evaluateTypeof.for("undefined").tap("JavascriptParser", expr => {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
"use strict";
|
||||
|
||||
const { getContext, runLoaders } = require("loader-runner");
|
||||
const asyncLib = require("neo-async");
|
||||
const { SyncHook } = require("tapable");
|
||||
const {
|
||||
CachedSource,
|
||||
|
|
@ -51,8 +50,6 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
* @property {TODO} options
|
||||
*/
|
||||
|
||||
const EARLY_RETURN_ERROR = new Error("flags early return is not an error");
|
||||
|
||||
/**
|
||||
* @param {string | Buffer} input the input
|
||||
* @returns {string} the converted string
|
||||
|
|
@ -163,8 +160,6 @@ class NormalModule extends Module {
|
|||
this.error = null;
|
||||
/** @private @type {Source=} */
|
||||
this._source = null;
|
||||
/** @type {number=} */
|
||||
this.buildTimestamp = undefined;
|
||||
/** @private @type {Map<string, GenerateSourceResult & CachedSourceEntry>} */
|
||||
this._cachedSources = new Map();
|
||||
|
||||
|
|
@ -337,11 +332,10 @@ class NormalModule extends Module {
|
|||
|
||||
/**
|
||||
* @param {string | Buffer} content the content
|
||||
* @param {string | Buffer} resourceBuffer TODO
|
||||
* @param {string | TODO} sourceMap an optional source map
|
||||
* @returns {Source} the created source
|
||||
*/
|
||||
createSource(content, resourceBuffer, sourceMap) {
|
||||
createSource(content, sourceMap) {
|
||||
if (Buffer.isBuffer(content)) {
|
||||
// @ts-ignore
|
||||
// TODO We need to fix @types/webpack-sources to allow RawSource to take a Buffer | string
|
||||
|
|
@ -371,6 +365,56 @@ class NormalModule extends Module {
|
|||
fs
|
||||
);
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
const processResult = (err, result) => {
|
||||
if (err) {
|
||||
if (!(err instanceof Error)) {
|
||||
err = new NonErrorEmittedError(err);
|
||||
}
|
||||
const currentLoader = this.getCurrentLoader(loaderContext);
|
||||
const error = new ModuleBuildError(err, {
|
||||
from:
|
||||
currentLoader &&
|
||||
compilation.runtimeTemplate.requestShortener.shorten(
|
||||
currentLoader.loader
|
||||
)
|
||||
});
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
const source = result[0];
|
||||
const sourceMap = result.length >= 1 ? result[1] : null;
|
||||
const extraInfo = result.length >= 2 ? result[2] : null;
|
||||
|
||||
if (!Buffer.isBuffer(source) && typeof source !== "string") {
|
||||
const currentLoader = this.getCurrentLoader(loaderContext, 0);
|
||||
const err = new Error(
|
||||
`Final loader (${
|
||||
currentLoader
|
||||
? compilation.runtimeTemplate.requestShortener.shorten(
|
||||
currentLoader.loader
|
||||
)
|
||||
: "unknown"
|
||||
}) didn't return a Buffer or String`
|
||||
);
|
||||
const error = new ModuleBuildError(err);
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
this._source = this.createSource(
|
||||
this.binary ? asBuffer(source) : asString(source),
|
||||
sourceMap
|
||||
);
|
||||
this._ast =
|
||||
typeof extraInfo === "object" &&
|
||||
extraInfo !== null &&
|
||||
extraInfo.webpackAST !== undefined
|
||||
? extraInfo.webpackAST
|
||||
: null;
|
||||
return callback();
|
||||
};
|
||||
|
||||
runLoaders(
|
||||
{
|
||||
resource: this.resource,
|
||||
|
|
@ -379,61 +423,36 @@ class NormalModule extends Module {
|
|||
readResource: fs.readFile.bind(fs)
|
||||
},
|
||||
(err, result) => {
|
||||
if (result) {
|
||||
this.buildInfo.cacheable = result.cacheable;
|
||||
this.buildInfo.fileDependencies = new Set(result.fileDependencies);
|
||||
this.buildInfo.contextDependencies = new Set(
|
||||
result.contextDependencies
|
||||
if (!result) {
|
||||
processResult(
|
||||
err || new Error("No result from loader-runner processing"),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (!(err instanceof Error)) {
|
||||
err = new NonErrorEmittedError(err);
|
||||
}
|
||||
const currentLoader = this.getCurrentLoader(loaderContext);
|
||||
const error = new ModuleBuildError(err, {
|
||||
from:
|
||||
currentLoader &&
|
||||
compilation.runtimeTemplate.requestShortener.shorten(
|
||||
currentLoader.loader
|
||||
)
|
||||
});
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
const resourceBuffer = result.resourceBuffer;
|
||||
const source = result.result[0];
|
||||
const sourceMap = result.result.length >= 1 ? result.result[1] : null;
|
||||
const extraInfo = result.result.length >= 2 ? result.result[2] : null;
|
||||
|
||||
if (!Buffer.isBuffer(source) && typeof source !== "string") {
|
||||
const currentLoader = this.getCurrentLoader(loaderContext, 0);
|
||||
const err = new Error(
|
||||
`Final loader (${
|
||||
currentLoader
|
||||
? compilation.runtimeTemplate.requestShortener.shorten(
|
||||
currentLoader.loader
|
||||
)
|
||||
: "unknown"
|
||||
}) didn't return a Buffer or String`
|
||||
);
|
||||
const error = new ModuleBuildError(err);
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
this._source = this.createSource(
|
||||
this.binary ? asBuffer(source) : asString(source),
|
||||
resourceBuffer,
|
||||
sourceMap
|
||||
this.buildInfo.fileDependencies = new Set(result.fileDependencies);
|
||||
this.buildInfo.contextDependencies = new Set(
|
||||
result.contextDependencies
|
||||
);
|
||||
this.buildInfo.missingDependencies = new Set(
|
||||
result.missingDependencies
|
||||
);
|
||||
if (!result.cacheable) {
|
||||
this.buildInfo.cacheable = false;
|
||||
processResult(err, result.result);
|
||||
return;
|
||||
}
|
||||
this.buildInfo.cacheable = true;
|
||||
compilation.fileSystemInfo.createSnapshot(
|
||||
startTime,
|
||||
result.fileDependencies,
|
||||
result.contextDependencies,
|
||||
result.missingDependencies,
|
||||
null,
|
||||
(err2, snapshot) => {
|
||||
this.buildInfo.snapshot = snapshot;
|
||||
processResult(err || err2, result.result);
|
||||
}
|
||||
);
|
||||
this._ast =
|
||||
typeof extraInfo === "object" &&
|
||||
extraInfo !== null &&
|
||||
extraInfo.webpackAST !== undefined
|
||||
? extraInfo.webpackAST
|
||||
: null;
|
||||
return callback();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -515,7 +534,6 @@ class NormalModule extends Module {
|
|||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
this.buildTimestamp = Date.now();
|
||||
this._forceBuild = false;
|
||||
this._source = null;
|
||||
this._ast = null;
|
||||
|
|
@ -530,6 +548,7 @@ class NormalModule extends Module {
|
|||
parsed: true,
|
||||
fileDependencies: undefined,
|
||||
contextDependencies: undefined,
|
||||
missingDependencies: undefined,
|
||||
hash: undefined,
|
||||
assets: undefined
|
||||
};
|
||||
|
|
@ -717,41 +736,10 @@ class NormalModule extends Module {
|
|||
// always build when module is not cacheable
|
||||
if (!this.buildInfo.cacheable) return callback(null, true);
|
||||
|
||||
// Check timestamps of all dependencies
|
||||
// Missing timestamp -> need build
|
||||
// Timestamp bigger than buildTimestamp -> need build
|
||||
asyncLib.parallel(
|
||||
[
|
||||
callback =>
|
||||
asyncLib.each(
|
||||
this.buildInfo.fileDependencies,
|
||||
(file, callback) => {
|
||||
fileSystemInfo.getFileTimestamp(file, (err, info) => {
|
||||
if (err) return callback(err);
|
||||
if (!info || info.safeTime >= this.buildTimestamp)
|
||||
return callback(EARLY_RETURN_ERROR);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
callback
|
||||
),
|
||||
callback =>
|
||||
asyncLib.each(
|
||||
this.buildInfo.contextDependencies,
|
||||
(context, callback) => {
|
||||
fileSystemInfo.getContextTimestamp(context, (err, info) => {
|
||||
if (err) return callback(err);
|
||||
if (!info || info.safeTime >= this.buildTimestamp)
|
||||
return callback(EARLY_RETURN_ERROR);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
callback
|
||||
)
|
||||
],
|
||||
err =>
|
||||
err === EARLY_RETURN_ERROR ? callback(null, true) : callback(err, false)
|
||||
);
|
||||
// check snapshot for validity
|
||||
fileSystemInfo.checkSnapshotValid(this.buildInfo.snapshot, (err, valid) => {
|
||||
callback(err, !valid);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -788,7 +776,6 @@ class NormalModule extends Module {
|
|||
write(this.resource);
|
||||
// deserialize
|
||||
write(this._source);
|
||||
write(this.buildTimestamp);
|
||||
write(this.error);
|
||||
write(this._cachedSources);
|
||||
write(this._lastSuccessfulBuildMeta);
|
||||
|
|
@ -818,7 +805,6 @@ class NormalModule extends Module {
|
|||
deserialize(context) {
|
||||
const { read } = context;
|
||||
this._source = read();
|
||||
this.buildTimestamp = read();
|
||||
this.error = read();
|
||||
this._cachedSources = read();
|
||||
this._lastSuccessfulBuildMeta = read();
|
||||
|
|
|
|||
|
|
@ -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 = /^([^!]+)!=!/;
|
||||
|
|
@ -39,6 +58,14 @@ const loaderToIdent = data => {
|
|||
return data.loader + "?" + JSON.stringify(data.options);
|
||||
};
|
||||
|
||||
const stringifyLoadersAndResource = (loaders, resource) => {
|
||||
let str = "";
|
||||
for (const loader of loaders) {
|
||||
str += loaderToIdent(loader) + "!";
|
||||
}
|
||||
return str + resource;
|
||||
};
|
||||
|
||||
const identToLoaderRequest = resultString => {
|
||||
const idx = resultString.indexOf("?");
|
||||
if (idx >= 0) {
|
||||
|
|
@ -56,17 +83,42 @@ const identToLoaderRequest = resultString => {
|
|||
}
|
||||
};
|
||||
|
||||
const needCalls = (times, callback) => {
|
||||
return err => {
|
||||
if (--times === 0) {
|
||||
return callback(err);
|
||||
}
|
||||
if (err && times > 0) {
|
||||
times = NaN;
|
||||
return callback(err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 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,111 +138,127 @@ 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);
|
||||
|
||||
createdModule = new NormalModule(result);
|
||||
}
|
||||
|
||||
createdModule = this.hooks.module.call(createdModule, result);
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
asyncLib.parallel(
|
||||
[
|
||||
callback =>
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
context,
|
||||
elements,
|
||||
loaderResolver,
|
||||
callback
|
||||
),
|
||||
callback => {
|
||||
if (resource === "" || resource[0] === "?") {
|
||||
return callback(null, {
|
||||
resource
|
||||
});
|
||||
}
|
||||
|
||||
normalResolver.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
resource,
|
||||
{},
|
||||
(err, resource, resourceResolveData) => {
|
||||
if (err) return callback(err);
|
||||
callback(null, {
|
||||
resourceResolveData,
|
||||
resource
|
||||
});
|
||||
}
|
||||
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 = this.hooks.module.call(
|
||||
createdModule,
|
||||
createData,
|
||||
resolveData
|
||||
);
|
||||
|
||||
return callback(null, createdModule);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
this.hooks.resolve.tapAsync(
|
||||
/** @type {TODO} */ ({
|
||||
name: "NormalModuleFactory",
|
||||
stage: 100
|
||||
}),
|
||||
(data, callback) => {
|
||||
const {
|
||||
contextInfo,
|
||||
context,
|
||||
request,
|
||||
resolveOptions,
|
||||
fileDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
} = data;
|
||||
|
||||
const loaderResolver = this.getResolver("loader");
|
||||
const normalResolver = this.getResolver("normal", resolveOptions);
|
||||
|
||||
/** @type {string} */
|
||||
let matchResource = undefined;
|
||||
/** @type {string} */
|
||||
let requestWithoutMatchResource = request;
|
||||
const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
|
||||
if (matchResourceMatch) {
|
||||
matchResource = matchResourceMatch[1];
|
||||
if (matchResource.charCodeAt(0) === 46) {
|
||||
// 46 === ".", 47 === "/"
|
||||
const secondChar = matchResource.charCodeAt(1);
|
||||
if (
|
||||
secondChar === 47 ||
|
||||
(secondChar === 46 && matchResource.charCodeAt(2) === 47)
|
||||
) {
|
||||
// if matchResources startsWith ../ or ./
|
||||
matchResource = path.join(context, matchResource);
|
||||
}
|
||||
}
|
||||
],
|
||||
(err, results) => {
|
||||
requestWithoutMatchResource = request.substr(
|
||||
matchResourceMatch[0].length
|
||||
);
|
||||
}
|
||||
|
||||
const firstChar = requestWithoutMatchResource.charCodeAt(0);
|
||||
const secondChar = requestWithoutMatchResource.charCodeAt(1);
|
||||
const noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
|
||||
const noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
|
||||
const noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
|
||||
const rawElements = requestWithoutMatchResource
|
||||
.slice(
|
||||
noPreAutoLoaders || noPrePostAutoLoaders ? 2 : noAutoLoaders ? 1 : 0
|
||||
)
|
||||
.split(/!+/);
|
||||
const unresolvedResource = rawElements.pop();
|
||||
const elements = rawElements.map(identToLoaderRequest);
|
||||
|
||||
const resolveContext = {
|
||||
fileDependencies,
|
||||
missing: missingDependencies,
|
||||
missingDependencies,
|
||||
contextDependencies
|
||||
};
|
||||
|
||||
/** @type {string | false} */
|
||||
let resource;
|
||||
let resourceResolveData;
|
||||
let loaders;
|
||||
|
||||
const continueCallback = needCalls(2, err => {
|
||||
if (err) return callback(err);
|
||||
let loaders = results[0];
|
||||
const resourceResolveData = results[1].resourceResolveData;
|
||||
resource = results[1].resource;
|
||||
|
||||
// translate option idents
|
||||
try {
|
||||
|
|
@ -219,10 +287,7 @@ class NormalModuleFactory {
|
|||
|
||||
const userRequest =
|
||||
(matchResource !== undefined ? `${matchResource}!=!` : "") +
|
||||
loaders
|
||||
.map(loaderToIdent)
|
||||
.concat([resource])
|
||||
.join("!");
|
||||
stringifyLoadersAndResource(loaders, resource);
|
||||
|
||||
let resourcePath =
|
||||
matchResource !== undefined ? matchResource : resource;
|
||||
|
|
@ -275,109 +340,184 @@ class NormalModuleFactory {
|
|||
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(() => {
|
||||
const type = settings.type;
|
||||
const resolveOptions = settings.resolve;
|
||||
callback(null, {
|
||||
context: context,
|
||||
request: loaders
|
||||
.map(loaderToIdent)
|
||||
.concat([resource])
|
||||
.join("!"),
|
||||
dependencies: data.dependencies,
|
||||
userRequest,
|
||||
rawRequest: request,
|
||||
loaders,
|
||||
resource,
|
||||
matchResource,
|
||||
resourceResolveData,
|
||||
settings,
|
||||
type,
|
||||
parser: this.getParser(type, settings.parser),
|
||||
generator: this.getGenerator(type, settings.generator),
|
||||
resolveOptions
|
||||
});
|
||||
});
|
||||
|
||||
let postLoaders, normalLoaders, preLoaders;
|
||||
|
||||
const continueCallback = needCalls(3, err => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const allLoaders = postLoaders;
|
||||
for (const loader of loaders) allLoaders.push(loader);
|
||||
for (const loader of normalLoaders) allLoaders.push(loader);
|
||||
for (const loader of preLoaders) allLoaders.push(loader);
|
||||
const type = settings.type;
|
||||
const resolveOptions = settings.resolve;
|
||||
Object.assign(data.createData, {
|
||||
request: stringifyLoadersAndResource(allLoaders, resource),
|
||||
userRequest,
|
||||
rawRequest: request,
|
||||
loaders: allLoaders,
|
||||
resource,
|
||||
matchResource,
|
||||
resourceResolveData,
|
||||
settings,
|
||||
type,
|
||||
parser: this.getParser(type, settings.parser),
|
||||
generator: this.getGenerator(type, settings.generator),
|
||||
resolveOptions
|
||||
});
|
||||
callback();
|
||||
});
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoadersPost,
|
||||
loaderResolver,
|
||||
resolveContext,
|
||||
(err, result) => {
|
||||
postLoaders = result;
|
||||
continueCallback(err);
|
||||
}
|
||||
);
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoaders,
|
||||
loaderResolver,
|
||||
resolveContext,
|
||||
(err, result) => {
|
||||
normalLoaders = result;
|
||||
continueCallback(err);
|
||||
}
|
||||
);
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
this.context,
|
||||
useLoadersPre,
|
||||
loaderResolver,
|
||||
resolveContext,
|
||||
(err, result) => {
|
||||
preLoaders = result;
|
||||
continueCallback(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
this.resolveRequestArray(
|
||||
contextInfo,
|
||||
context,
|
||||
elements,
|
||||
loaderResolver,
|
||||
resolveContext,
|
||||
(err, result) => {
|
||||
if (err) return continueCallback(err);
|
||||
loaders = result;
|
||||
continueCallback();
|
||||
}
|
||||
);
|
||||
|
||||
if (
|
||||
unresolvedResource === "" ||
|
||||
unresolvedResource.charCodeAt(0) === 63
|
||||
) {
|
||||
// 63 === "?"
|
||||
resource = unresolvedResource;
|
||||
return continueCallback();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
normalResolver.resolve(
|
||||
contextInfo,
|
||||
context,
|
||||
unresolvedResource,
|
||||
resolveContext,
|
||||
(err, resolvedResource, resolvedResourceResolveData) => {
|
||||
if (err) return continueCallback(err);
|
||||
|
||||
// TODO remove this when enhanced-resolve supports fileDependencies
|
||||
if (resolvedResource) {
|
||||
fileDependencies.add(resolvedResource);
|
||||
}
|
||||
|
||||
resource = resolvedResource;
|
||||
resourceResolveData = resolvedResourceResolveData;
|
||||
continueCallback();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
if (array.length === 0) return callback(null, []);
|
||||
resolveRequestArray(
|
||||
contextInfo,
|
||||
context,
|
||||
array,
|
||||
resolver,
|
||||
resolveContext,
|
||||
callback
|
||||
) {
|
||||
if (array.length === 0) return callback(null, array);
|
||||
asyncLib.map(
|
||||
array,
|
||||
(item, callback) => {
|
||||
|
|
@ -385,7 +525,7 @@ class NormalModuleFactory {
|
|||
contextInfo,
|
||||
context,
|
||||
item.loader,
|
||||
{},
|
||||
resolveContext,
|
||||
(err, result) => {
|
||||
if (
|
||||
err &&
|
||||
|
|
@ -396,7 +536,7 @@ class NormalModuleFactory {
|
|||
contextInfo,
|
||||
context,
|
||||
item.loader + "-loader",
|
||||
{},
|
||||
resolveContext,
|
||||
err2 => {
|
||||
if (!err2) {
|
||||
err.message =
|
||||
|
|
@ -414,15 +554,22 @@ class NormalModuleFactory {
|
|||
}
|
||||
if (err) return callback(err);
|
||||
|
||||
const optionsOnly = item.options
|
||||
? {
|
||||
options: item.options
|
||||
}
|
||||
: undefined;
|
||||
return callback(
|
||||
null,
|
||||
Object.assign({}, item, identToLoaderRequest(result), optionsOnly)
|
||||
);
|
||||
const parsedResult = identToLoaderRequest(result);
|
||||
const resolved = {
|
||||
loader: parsedResult.loader,
|
||||
options:
|
||||
item.options === undefined
|
||||
? parsedResult.options
|
||||
: item.options,
|
||||
ident: item.options === undefined ? undefined : item.ident
|
||||
};
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,15 +34,7 @@ class IgnoringWatchFileSystem {
|
|||
missing,
|
||||
startTime,
|
||||
options,
|
||||
(
|
||||
err,
|
||||
filesModified,
|
||||
dirsModified,
|
||||
missingModified,
|
||||
fileTimestamps,
|
||||
dirTimestamps,
|
||||
removedFiles
|
||||
) => {
|
||||
(err, fileTimestamps, dirTimestamps, removedFiles) => {
|
||||
if (err) return callback(err);
|
||||
for (const path of ignoredFiles) {
|
||||
fileTimestamps.set(path, 1);
|
||||
|
|
@ -52,15 +44,7 @@ class IgnoringWatchFileSystem {
|
|||
dirTimestamps.set(path, 1);
|
||||
}
|
||||
|
||||
callback(
|
||||
err,
|
||||
filesModified,
|
||||
dirsModified,
|
||||
missingModified,
|
||||
fileTimestamps,
|
||||
dirTimestamps,
|
||||
removedFiles
|
||||
);
|
||||
callback(err, fileTimestamps, dirTimestamps, removedFiles);
|
||||
},
|
||||
callbackUndelayed
|
||||
);
|
||||
|
|
@ -68,15 +52,15 @@ class IgnoringWatchFileSystem {
|
|||
return {
|
||||
close: () => watcher.close(),
|
||||
pause: () => watcher.pause(),
|
||||
getContextTimestamps: () => {
|
||||
const dirTimestamps = watcher.getContextTimestamps();
|
||||
getContextInfoEntries: () => {
|
||||
const dirTimestamps = watcher.getContextInfoEntries();
|
||||
for (const path of ignoredDirs) {
|
||||
dirTimestamps.set(path, 1);
|
||||
}
|
||||
return dirTimestamps;
|
||||
},
|
||||
getFileTimestamps: () => {
|
||||
const fileTimestamps = watcher.getFileTimestamps();
|
||||
getFileTimeInfoEntries: () => {
|
||||
const fileTimestamps = watcher.getFileTimeInfoEntries();
|
||||
for (const path of ignoredFiles) {
|
||||
fileTimestamps.set(path, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,6 @@ const Stats = require("./Stats");
|
|||
* @param {T=} result
|
||||
*/
|
||||
|
||||
// TODO refactor watchpack to report timestamps in the correct format
|
||||
const toFileSystemInfoEntryMap = timestamps => {
|
||||
const map = new Map();
|
||||
for (const [key, ts] of timestamps) {
|
||||
map.set(key, { safeTime: ts });
|
||||
}
|
||||
return map;
|
||||
};
|
||||
|
||||
class Watching {
|
||||
/**
|
||||
* @param {Compiler} compiler the compiler
|
||||
|
|
@ -77,30 +68,32 @@ class Watching {
|
|||
return this._done(null, compilation);
|
||||
}
|
||||
|
||||
this.compiler.emitAssets(compilation, err => {
|
||||
if (err) return this._done(err);
|
||||
if (this.invalid) return this._done();
|
||||
|
||||
this.compiler.emitRecords(err => {
|
||||
process.nextTick(() => {
|
||||
this.compiler.emitAssets(compilation, err => {
|
||||
if (err) return this._done(err);
|
||||
if (this.invalid) return this._done();
|
||||
|
||||
if (compilation.hooks.needAdditionalPass.call()) {
|
||||
compilation.needAdditionalPass = true;
|
||||
this.compiler.emitRecords(err => {
|
||||
if (err) return this._done(err);
|
||||
|
||||
const stats = new Stats(compilation);
|
||||
stats.startTime = this.startTime;
|
||||
stats.endTime = Date.now();
|
||||
this.compiler.hooks.done.callAsync(stats, err => {
|
||||
if (err) return this._done(err);
|
||||
if (compilation.hooks.needAdditionalPass.call()) {
|
||||
compilation.needAdditionalPass = true;
|
||||
|
||||
this.compiler.hooks.additionalPass.callAsync(err => {
|
||||
const stats = new Stats(compilation);
|
||||
stats.startTime = this.startTime;
|
||||
stats.endTime = Date.now();
|
||||
this.compiler.hooks.done.callAsync(stats, err => {
|
||||
if (err) return this._done(err);
|
||||
this.compiler.compile(onCompiled);
|
||||
|
||||
this.compiler.hooks.additionalPass.callAsync(err => {
|
||||
if (err) return this._done(err);
|
||||
this.compiler.compile(onCompiled);
|
||||
});
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
return this._done(null, compilation);
|
||||
return;
|
||||
}
|
||||
return this._done(null, compilation);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
@ -140,13 +133,15 @@ class Watching {
|
|||
this.compiler.hooks.done.callAsync(stats, () => {
|
||||
this.compiler.cache.beginIdle();
|
||||
this.handler(null, stats);
|
||||
if (!this.closed) {
|
||||
this.watch(
|
||||
Array.from(compilation.fileDependencies),
|
||||
Array.from(compilation.contextDependencies),
|
||||
Array.from(compilation.missingDependencies)
|
||||
);
|
||||
}
|
||||
process.nextTick(() => {
|
||||
if (!this.closed) {
|
||||
this.watch(
|
||||
Array.from(compilation.fileDependencies),
|
||||
Array.from(compilation.contextDependencies),
|
||||
Array.from(compilation.missingDependencies)
|
||||
);
|
||||
}
|
||||
});
|
||||
for (const cb of this.callbacks) cb();
|
||||
this.callbacks.length = 0;
|
||||
this.compiler.hooks.afterDone.call(stats);
|
||||
|
|
@ -161,24 +156,14 @@ class Watching {
|
|||
missing,
|
||||
this.startTime,
|
||||
this.watchOptions,
|
||||
(
|
||||
err,
|
||||
filesModified,
|
||||
contextModified,
|
||||
missingModified,
|
||||
fileTimestamps,
|
||||
contextTimestamps,
|
||||
removedFiles
|
||||
) => {
|
||||
(err, fileTimeInfoEntries, contextTimeInfoEntries, removedFiles) => {
|
||||
this.pausedWatcher = this.watcher;
|
||||
this.watcher = null;
|
||||
if (err) {
|
||||
return this.handler(err);
|
||||
}
|
||||
this.compiler.fileTimestamps = toFileSystemInfoEntryMap(fileTimestamps);
|
||||
this.compiler.contextTimestamps = toFileSystemInfoEntryMap(
|
||||
contextTimestamps
|
||||
);
|
||||
this.compiler.fileTimestamps = fileTimeInfoEntries;
|
||||
this.compiler.contextTimestamps = contextTimeInfoEntries;
|
||||
this.compiler.removedFiles = removedFiles;
|
||||
this._invalidate();
|
||||
},
|
||||
|
|
@ -197,12 +182,8 @@ class Watching {
|
|||
this.callbacks.push(callback);
|
||||
}
|
||||
if (this.watcher) {
|
||||
this.compiler.fileTimestamps = toFileSystemInfoEntryMap(
|
||||
this.watcher.getFileTimestamps()
|
||||
);
|
||||
this.compiler.contextTimestamps = toFileSystemInfoEntryMap(
|
||||
this.watcher.getContextTimestamps()
|
||||
);
|
||||
this.compiler.fileTimestamps = this.watcher.getFileTimeInfoEntries();
|
||||
this.compiler.contextTimestamps = this.watcher.getContextTimeInfoEntries();
|
||||
}
|
||||
this._invalidate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
if (options.optimization.minimize) {
|
||||
for (const minimizer of options.optimization.minimizer) {
|
||||
if (typeof minimizer === "function") {
|
||||
minimizer.apply(compiler);
|
||||
minimizer.call(compiler, compiler);
|
||||
} else {
|
||||
minimizer.apply(compiler);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
|
|||
return Object.assign({}, value);
|
||||
}
|
||||
});
|
||||
this.set("node.global", false);
|
||||
this.set("node.global", true);
|
||||
this.set("node.__filename", "mock");
|
||||
this.set("node.__dirname", "mock");
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ const WebpackError = require("./WebpackError");
|
|||
|
||||
const getSchemaPart = (path, parents, additionalPath) => {
|
||||
parents = parents || 0;
|
||||
path = path.split("/");
|
||||
path = path.slice(0, path.length - parents);
|
||||
path = path.split("/", path.length - parents);
|
||||
if (additionalPath) {
|
||||
additionalPath = additionalPath.split("/");
|
||||
path = path.concat(additionalPath);
|
||||
|
|
|
|||
|
|
@ -5,13 +5,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const asyncLib = require("neo-async");
|
||||
|
||||
/** @typedef {import("enhanced-resolve/lib/Resolver")} Resolver */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../FileSystemInfo")} FileSystemInfo */
|
||||
|
||||
const INVALID = {};
|
||||
const requestToString = request => {
|
||||
let str = "";
|
||||
for (const key in request) {
|
||||
const value = request[key];
|
||||
if (typeof value === "object" && value !== null) {
|
||||
str += `/${key}={${requestToString(value)}}`;
|
||||
} else {
|
||||
str += `/${key}=${value}`;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
class ResolverCachePlugin {
|
||||
/**
|
||||
|
|
@ -63,68 +72,37 @@ class ResolverCachePlugin {
|
|||
propagate("fileDependencies");
|
||||
propagate("contextDependencies");
|
||||
if (err) return callback(err);
|
||||
const fileDependencies = new Set(newResolveContext.fileDependencies);
|
||||
if (newResolveContext.missing) {
|
||||
for (const missing of newResolveContext.missing) {
|
||||
fileDependencies.add(missing);
|
||||
}
|
||||
}
|
||||
const contextDependencies = new Set(
|
||||
newResolveContext.contextDependencies
|
||||
);
|
||||
const fileDependencies = newResolveContext.fileDependencies;
|
||||
const contextDependencies = newResolveContext.contextDependencies;
|
||||
const missingDependencies = newResolveContext.missing;
|
||||
// TODO remove this when enhanced-resolve supports fileDependencies
|
||||
if (result && result.path) {
|
||||
fileDependencies.add(result.path);
|
||||
}
|
||||
const fileTimestamps = new Map();
|
||||
const contextTimestamps = new Map();
|
||||
const store = () => {
|
||||
cache.store(
|
||||
identifier,
|
||||
null,
|
||||
{
|
||||
result,
|
||||
resolveTime,
|
||||
fileTimestamps,
|
||||
contextTimestamps
|
||||
},
|
||||
restoreErr => {
|
||||
if (restoreErr) return callback(restoreErr);
|
||||
if (result) return callback(null, result);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
};
|
||||
asyncLib.parallel(
|
||||
[
|
||||
asyncLib.each.bind(
|
||||
asyncLib,
|
||||
fileDependencies,
|
||||
(dep, callback) => {
|
||||
fileSystemInfo.getFileTimestamp(dep, (err, entry) => {
|
||||
if (err) {
|
||||
fileTimestamps.set(dep, "error");
|
||||
} else {
|
||||
fileTimestamps.set(dep, entry && entry.timestamp);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
),
|
||||
asyncLib.each.bind(
|
||||
asyncLib,
|
||||
contextDependencies,
|
||||
(dep, callback) => {
|
||||
fileSystemInfo.getContextTimestamp(dep, (err, entry) => {
|
||||
contextTimestamps.set(dep, "error");
|
||||
// TODO: getContextTimestamp is not implemented yet
|
||||
callback();
|
||||
});
|
||||
}
|
||||
)
|
||||
],
|
||||
err => {
|
||||
fileSystemInfo.createSnapshot(
|
||||
resolveTime,
|
||||
fileDependencies,
|
||||
contextDependencies,
|
||||
missingDependencies,
|
||||
null,
|
||||
(err, snapshot) => {
|
||||
if (err) return callback(err);
|
||||
store();
|
||||
cache.store(
|
||||
identifier,
|
||||
null,
|
||||
{
|
||||
result,
|
||||
missing: newResolveContext.missing,
|
||||
fileDependencies: newResolveContext.fileDependencies,
|
||||
contextDependencies: newResolveContext.contextDependencies,
|
||||
snapshot
|
||||
},
|
||||
storeErr => {
|
||||
if (storeErr) return callback(storeErr);
|
||||
if (result) return callback(null, result);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -150,76 +128,17 @@ class ResolverCachePlugin {
|
|||
if (request._ResolverCachePluginCacheMiss || !fileSystemInfo) {
|
||||
return callback();
|
||||
}
|
||||
const identifier = `/resolve/${type}/${JSON.stringify(
|
||||
const identifier = `/resolve/${type}${requestToString(
|
||||
request
|
||||
)}`;
|
||||
cache.get(identifier, null, (err, cacheEntry) => {
|
||||
const processCacheResult = (err, cacheEntry) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (cacheEntry) {
|
||||
const {
|
||||
result,
|
||||
resolveTime,
|
||||
fileTimestamps,
|
||||
contextTimestamps
|
||||
} = cacheEntry;
|
||||
asyncLib.parallel(
|
||||
[
|
||||
asyncLib.each.bind(
|
||||
asyncLib,
|
||||
fileTimestamps,
|
||||
([dep, ts], callback) => {
|
||||
fileSystemInfo.getFileTimestamp(
|
||||
dep,
|
||||
(err, entry) => {
|
||||
if (err) return callback(err);
|
||||
if (ts === "error") {
|
||||
return callback(
|
||||
!entry || entry.safeTime > resolveTime
|
||||
? INVALID
|
||||
: null
|
||||
);
|
||||
}
|
||||
if (!entry !== !ts) return callback(INVALID);
|
||||
if (entry && entry.timestamp) {
|
||||
return callback(
|
||||
entry.timestamp !== ts ? INVALID : null
|
||||
);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
);
|
||||
}
|
||||
),
|
||||
asyncLib.each.bind(
|
||||
asyncLib,
|
||||
contextTimestamps,
|
||||
([dep, ts], callback) => {
|
||||
fileSystemInfo.getContextTimestamp(
|
||||
dep,
|
||||
(err, entry) => {
|
||||
if (err) return callback(err);
|
||||
if (ts === "error") {
|
||||
return callback(
|
||||
!entry || entry.safeTime > resolveTime
|
||||
? INVALID
|
||||
: null
|
||||
);
|
||||
}
|
||||
if (!entry !== !ts) return callback(INVALID);
|
||||
if (entry && entry.timestamp) {
|
||||
return callback(
|
||||
entry.timestamp !== ts ? INVALID : null
|
||||
);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
],
|
||||
err => {
|
||||
if (err) {
|
||||
fileSystemInfo.checkSnapshotValid(
|
||||
cacheEntry.snapshot,
|
||||
(err, valid) => {
|
||||
if (err || !valid) {
|
||||
return doRealResolve(
|
||||
identifier,
|
||||
type,
|
||||
|
|
@ -229,7 +148,22 @@ class ResolverCachePlugin {
|
|||
callback
|
||||
);
|
||||
}
|
||||
callback(null, result);
|
||||
if (resolveContext.missing) {
|
||||
for (const item of cacheEntry.missing) {
|
||||
resolveContext.missing.add(item);
|
||||
}
|
||||
}
|
||||
if (resolveContext.fileDependencies) {
|
||||
for (const item of cacheEntry.fileDependencies) {
|
||||
resolveContext.fileDependencies.add(item);
|
||||
}
|
||||
}
|
||||
if (resolveContext.contextDependencies) {
|
||||
for (const item of cacheEntry.contextDependencies) {
|
||||
resolveContext.contextDependencies.add(item);
|
||||
}
|
||||
}
|
||||
callback(null, cacheEntry.result);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
|
@ -242,7 +176,8 @@ class ResolverCachePlugin {
|
|||
callback
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
cache.get(identifier, null, processCacheResult);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,13 @@ module.exports = class HarmonyDetectionParserPlugin {
|
|||
const isStrictHarmony = parser.state.module.type === "javascript/esm";
|
||||
const isHarmony =
|
||||
isStrictHarmony ||
|
||||
ast.body.some(statement => {
|
||||
return /^(Import|Export).*Declaration$/.test(statement.type);
|
||||
});
|
||||
ast.body.some(
|
||||
statement =>
|
||||
statement.type === "ImportDeclaration" ||
|
||||
statement.type === "ExportDefaultDeclaration" ||
|
||||
statement.type === "ExportNamedDeclaration" ||
|
||||
statement.type === "ExportAllDeclaration"
|
||||
);
|
||||
if (isHarmony) {
|
||||
const module = parser.state.module;
|
||||
const compatDep = new HarmonyCompatibilityDependency();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ class NodeTemplatePlugin {
|
|||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
const ChunkLoadingRuntimeModule = this.asyncChunkLoading
|
||||
? ReadFileChunkLoadingRuntimeModule
|
||||
: RequireChunkLoadingRuntimeModule;
|
||||
|
||||
compiler.hooks.thisCompilation.tap("NodeTemplatePlugin", compilation => {
|
||||
new NodeChunkTemplatePlugin(compilation).apply(compilation.chunkTemplate);
|
||||
|
||||
|
|
@ -31,17 +35,10 @@ class NodeTemplatePlugin {
|
|||
if (onceForChunkSet.has(chunk)) return;
|
||||
onceForChunkSet.add(chunk);
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
if (this.asyncChunkLoading) {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new ReadFileChunkLoadingRuntimeModule(chunk, set)
|
||||
);
|
||||
} else {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new RequireChunkLoadingRuntimeModule(chunk, set)
|
||||
);
|
||||
}
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new ChunkLoadingRuntimeModule(chunk, set)
|
||||
);
|
||||
};
|
||||
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
"use strict";
|
||||
|
||||
const Watchpack = require("watchpack");
|
||||
const objectToMap = require("../util/objectToMap");
|
||||
|
||||
class NodeWatchFileSystem {
|
||||
constructor(inputFileSystem) {
|
||||
|
|
@ -48,31 +47,19 @@ class NodeWatchFileSystem {
|
|||
const cachedFiles = files;
|
||||
const cachedDirs = dirs;
|
||||
this.watcher.once("aggregated", (changes, removals) => {
|
||||
changes = changes.concat(removals);
|
||||
if (this.inputFileSystem && this.inputFileSystem.purge) {
|
||||
this.inputFileSystem.purge(changes);
|
||||
for (const item of changes) {
|
||||
this.inputFileSystem.purge(item);
|
||||
}
|
||||
for (const item of removals) {
|
||||
this.inputFileSystem.purge(item);
|
||||
}
|
||||
}
|
||||
const times = objectToMap(this.watcher.getTimes());
|
||||
files = new Set(files);
|
||||
dirs = new Set(dirs);
|
||||
missing = new Set(missing);
|
||||
removals = new Set(removals.filter(file => files.has(file)));
|
||||
callback(
|
||||
null,
|
||||
changes.filter(file => files.has(file)).sort(),
|
||||
changes.filter(file => dirs.has(file)).sort(),
|
||||
changes.filter(file => missing.has(file)).sort(),
|
||||
times,
|
||||
times,
|
||||
removals
|
||||
);
|
||||
const times = this.watcher.getTimeInfoEntries();
|
||||
callback(null, times, times, removals);
|
||||
});
|
||||
|
||||
this.watcher.watch(
|
||||
cachedFiles.concat(missing),
|
||||
cachedDirs.concat(missing),
|
||||
startTime
|
||||
);
|
||||
this.watcher.watch(cachedFiles.concat(missing), cachedDirs, startTime);
|
||||
|
||||
if (oldWatcher) {
|
||||
oldWatcher.close();
|
||||
|
|
@ -89,16 +76,16 @@ class NodeWatchFileSystem {
|
|||
this.watcher.pause();
|
||||
}
|
||||
},
|
||||
getFileTimestamps: () => {
|
||||
getFileTimeInfoEntries: () => {
|
||||
if (this.watcher) {
|
||||
return objectToMap(this.watcher.getTimes());
|
||||
return this.watcher.getTimeInfoEntries();
|
||||
} else {
|
||||
return new Map();
|
||||
}
|
||||
},
|
||||
getContextTimestamps: () => {
|
||||
getContextInfoEntries: () => {
|
||||
if (this.watcher) {
|
||||
return objectToMap(this.watcher.getTimes());
|
||||
return this.watcher.getTimeInfoEntries();
|
||||
} else {
|
||||
return new Map();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class SideEffectsFlagPlugin {
|
|||
} else if (data.settings.sideEffects === true) {
|
||||
module.factoryMeta.sideEffectFree = false;
|
||||
}
|
||||
return module;
|
||||
});
|
||||
});
|
||||
compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ const {
|
|||
compareIds,
|
||||
concatComparators,
|
||||
compareSelect,
|
||||
compareModulesById
|
||||
compareModulesById,
|
||||
compareModulesByIdOrIdentifier
|
||||
} = require("../util/comparators");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
|
|
@ -509,6 +510,15 @@ const SIMPLE_EXTRACTORS = {
|
|||
moduleName: reason.originModule
|
||||
? reason.originModule.readableIdentifier(requestShortener)
|
||||
: null,
|
||||
resolvedModuleId: reason.resolvedOriginModule
|
||||
? chunkGraph.getModuleId(reason.resolvedOriginModule)
|
||||
: null,
|
||||
resolvedModuleIdentifier: reason.resolvedOriginModule
|
||||
? reason.resolvedOriginModule.identifier()
|
||||
: null,
|
||||
resolvedModule: reason.resolvedOriginModule
|
||||
? reason.resolvedOriginModule.readableIdentifier(requestShortener)
|
||||
: null,
|
||||
type: reason.dependency ? reason.dependency.type : null,
|
||||
explanation: reason.explanation,
|
||||
userRequest:
|
||||
|
|
@ -796,6 +806,12 @@ const SORTERS = {
|
|||
comparators.push(
|
||||
compareSelect(x => x.originModule, compareModulesById(chunkGraph))
|
||||
);
|
||||
comparators.push(
|
||||
compareSelect(
|
||||
x => x.resolvedOriginModule,
|
||||
compareModulesByIdOrIdentifier(chunkGraph)
|
||||
)
|
||||
);
|
||||
comparators.push(
|
||||
compareSelect(
|
||||
x => x.dependency,
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ const SIMPLE_PRINTERS = {
|
|||
"moduleReason.module": (module, { magenta }) => magenta(module),
|
||||
"moduleReason.loc": loc => loc,
|
||||
"moduleReason.explanation": (explanation, { cyan }) => cyan(explanation),
|
||||
"moduleReason.resolvedModule": (module, { magenta }) => magenta(module),
|
||||
|
||||
"module.profile.total": (value, { formatTime }) => formatTime(value),
|
||||
"module.profile.resolving": (value, { formatTime }) =>
|
||||
|
|
@ -509,6 +510,7 @@ const PREFERED_ORDERS = {
|
|||
"userRequest",
|
||||
"moduleId",
|
||||
"module",
|
||||
"resolvedModule",
|
||||
"loc",
|
||||
"explanation"
|
||||
],
|
||||
|
|
@ -762,6 +764,11 @@ const SIMPLE_ELEMENT_JOINERS = {
|
|||
case "module":
|
||||
if (hasName) return false;
|
||||
break;
|
||||
case "resolvedModule":
|
||||
return (
|
||||
moduleReason.module !== moduleReason.resolvedModule &&
|
||||
item.content
|
||||
);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
const { SyncHook, AsyncSeriesHook } = require("tapable");
|
||||
|
||||
const QUEUED_STATE = 0;
|
||||
const PROCESSING_STATE = 1;
|
||||
const DONE_STATE = 2;
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @callback Callback<T>
|
||||
|
|
@ -14,6 +18,28 @@ const { SyncHook, AsyncSeriesHook } = require("tapable");
|
|||
* @param {T=} result
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template K
|
||||
* @template R
|
||||
*/
|
||||
class AsyncQueueEntry {
|
||||
/**
|
||||
* @param {T} item the item
|
||||
* @param {Callback<R>} callback the callback
|
||||
*/
|
||||
constructor(item, callback) {
|
||||
this.item = item;
|
||||
/** @type {typeof QUEUED_STATE | typeof PROCESSING_STATE | typeof DONE_STATE} */
|
||||
this.state = QUEUED_STATE;
|
||||
this.callback = callback;
|
||||
/** @type {Callback<R>[] | undefined} */
|
||||
this.callbacks = undefined;
|
||||
this.result = undefined;
|
||||
this.error = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template K
|
||||
|
|
@ -33,14 +59,10 @@ class AsyncQueue {
|
|||
this._processor = processor;
|
||||
this._getKey =
|
||||
getKey || /** @type {(T) => K} */ (item => /** @type {any} */ (item));
|
||||
/** @type {Map<K, Callback<R>[]>} */
|
||||
this._callbacks = new Map();
|
||||
/** @type {Set<T>} */
|
||||
this._queued = new Set();
|
||||
/** @type {Set<K>} */
|
||||
this._processing = new Set();
|
||||
/** @type {Map<K, [Error, R]>} */
|
||||
this._results = new Map();
|
||||
/** @type {Map<K, AsyncQueueEntry<T, K, R>>} */
|
||||
this._entries = new Map();
|
||||
/** @type {AsyncQueueEntry<T, K, R>[]} */
|
||||
this._queued = [];
|
||||
this._activeTasks = 0;
|
||||
this._willEnsureProcessing = false;
|
||||
this._stopped = false;
|
||||
|
|
@ -69,24 +91,25 @@ class AsyncQueue {
|
|||
return;
|
||||
}
|
||||
const key = this._getKey(item);
|
||||
const result = this._results.get(key);
|
||||
if (result !== undefined) {
|
||||
process.nextTick(() => callback(result[0], result[1]));
|
||||
const entry = this._entries.get(key);
|
||||
if (entry !== undefined) {
|
||||
if (entry.state === DONE_STATE) {
|
||||
process.nextTick(() => callback(entry.error, entry.result));
|
||||
} else if (entry.callbacks === undefined) {
|
||||
entry.callbacks = [callback];
|
||||
} else {
|
||||
entry.callbacks.push(callback);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let callbacks = this._callbacks.get(key);
|
||||
if (callbacks !== undefined) {
|
||||
callbacks.push(callback);
|
||||
return;
|
||||
}
|
||||
callbacks = [callback];
|
||||
this._callbacks.set(key, callbacks);
|
||||
const newEntry = new AsyncQueueEntry(item, callback);
|
||||
if (this._stopped) {
|
||||
this.hooks.added.call(item);
|
||||
this._activeTasks++;
|
||||
this._handleResult(item, new Error("Queue was stopped"));
|
||||
this._handleResult(newEntry, new Error("Queue was stopped"));
|
||||
} else {
|
||||
this._queued.add(item);
|
||||
this._entries.set(key, newEntry);
|
||||
this._queued.push(newEntry);
|
||||
if (this._willEnsureProcessing === false) {
|
||||
this._willEnsureProcessing = true;
|
||||
process.nextTick(this._ensureProcessing);
|
||||
|
|
@ -102,7 +125,14 @@ class AsyncQueue {
|
|||
*/
|
||||
invalidate(item) {
|
||||
const key = this._getKey(item);
|
||||
this._results.delete(key);
|
||||
const entry = this._entries.get(key);
|
||||
this._entries.delete(key);
|
||||
if (entry.state === QUEUED_STATE) {
|
||||
const idx = this._queued.indexOf(entry);
|
||||
if (idx >= 0) {
|
||||
this._queued.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -110,10 +140,12 @@ class AsyncQueue {
|
|||
*/
|
||||
stop() {
|
||||
this._stopped = true;
|
||||
for (const item of this._queued) {
|
||||
const queue = this._queued;
|
||||
this._queued = [];
|
||||
for (const entry of queue) {
|
||||
this._entries.delete(this._getKey(entry.item));
|
||||
this._activeTasks++;
|
||||
this._queued.delete(item);
|
||||
this._handleResult(item, new Error("Queue was stopped"));
|
||||
this._handleResult(entry, new Error("Queue was stopped"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +154,7 @@ class AsyncQueue {
|
|||
*/
|
||||
increaseParallelism() {
|
||||
this._parallelism++;
|
||||
if (this._willEnsureProcessing === false && this._queued.size > 0) {
|
||||
if (this._willEnsureProcessing === false && this._queued.length > 0) {
|
||||
this._willEnsureProcessing = true;
|
||||
process.nextTick(this._ensureProcessing);
|
||||
}
|
||||
|
|
@ -141,7 +173,8 @@ class AsyncQueue {
|
|||
*/
|
||||
isProcessing(item) {
|
||||
const key = this._getKey(item);
|
||||
return this._processing.has(key);
|
||||
const entry = this._entries.get(key);
|
||||
return entry !== undefined && entry.state === PROCESSING_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -149,7 +182,9 @@ class AsyncQueue {
|
|||
* @returns {boolean} true, if the item is currently queued
|
||||
*/
|
||||
isQueued(item) {
|
||||
return this._queued.has(item);
|
||||
const key = this._getKey(item);
|
||||
const entry = this._entries.get(key);
|
||||
return entry !== undefined && entry.state === QUEUED_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -158,79 +193,79 @@ class AsyncQueue {
|
|||
*/
|
||||
isDone(item) {
|
||||
const key = this._getKey(item);
|
||||
return this._results.has(key);
|
||||
const entry = this._entries.get(key);
|
||||
return entry !== undefined && entry.state === DONE_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
_ensureProcessing() {
|
||||
if (this._activeTasks >= this._parallelism) {
|
||||
this._willEnsureProcessing = false;
|
||||
return;
|
||||
}
|
||||
for (const item of this._queued) {
|
||||
while (this._activeTasks < this._parallelism && this._queued.length > 0) {
|
||||
const entry = this._queued.pop();
|
||||
this._activeTasks++;
|
||||
const key = this._getKey(item);
|
||||
this._queued.delete(item);
|
||||
this._processing.add(key);
|
||||
this._startProcessing(item);
|
||||
if (this._activeTasks >= this._parallelism) {
|
||||
this._willEnsureProcessing = false;
|
||||
return;
|
||||
}
|
||||
entry.state = PROCESSING_STATE;
|
||||
this._startProcessing(entry);
|
||||
}
|
||||
this._willEnsureProcessing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @param {AsyncQueueEntry<T, K, R>} entry the entry
|
||||
* @returns {void}
|
||||
*/
|
||||
_startProcessing(item) {
|
||||
this.hooks.beforeStart.callAsync(item, err => {
|
||||
_startProcessing(entry) {
|
||||
this.hooks.beforeStart.callAsync(entry.item, err => {
|
||||
if (err) {
|
||||
this._handleResult(item, err);
|
||||
this._handleResult(entry, err);
|
||||
return;
|
||||
}
|
||||
let inCallback = false;
|
||||
try {
|
||||
this._processor(item, (e, r) => {
|
||||
process.nextTick(() => {
|
||||
this._handleResult(item, e, r);
|
||||
});
|
||||
this._processor(entry.item, (e, r) => {
|
||||
inCallback = true;
|
||||
this._handleResult(entry, e, r);
|
||||
});
|
||||
} catch (err) {
|
||||
this._handleResult(item, err, null);
|
||||
if (inCallback) throw err;
|
||||
this._handleResult(entry, err, null);
|
||||
}
|
||||
this.hooks.started.call(item);
|
||||
this.hooks.started.call(entry.item);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @param {AsyncQueueEntry<T, K, R>} entry the entry
|
||||
* @param {Error=} err error, if any
|
||||
* @param {R=} result result, if any
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleResult(item, err, result) {
|
||||
this.hooks.result.callAsync(item, err, result, hookError => {
|
||||
_handleResult(entry, err, result) {
|
||||
this.hooks.result.callAsync(entry.item, err, result, hookError => {
|
||||
const error = hookError || err;
|
||||
|
||||
const key = this._getKey(item);
|
||||
const callbacks = this._callbacks.get(key);
|
||||
this._processing.delete(key);
|
||||
this._results.set(key, [error, result]);
|
||||
this._callbacks.delete(key);
|
||||
const callback = entry.callback;
|
||||
const callbacks = entry.callbacks;
|
||||
entry.state = DONE_STATE;
|
||||
entry.callback = undefined;
|
||||
entry.callbacks = undefined;
|
||||
entry.result = result;
|
||||
entry.error = error;
|
||||
this._activeTasks--;
|
||||
|
||||
if (this._willEnsureProcessing === false && this._queued.size > 0) {
|
||||
if (this._willEnsureProcessing === false && this._queued.length > 0) {
|
||||
this._willEnsureProcessing = true;
|
||||
process.nextTick(this._ensureProcessing);
|
||||
}
|
||||
|
||||
for (const callback of callbacks) {
|
||||
process.nextTick(() => {
|
||||
callback(error, result);
|
||||
}
|
||||
if (callbacks !== undefined) {
|
||||
for (const callback of callbacks) {
|
||||
callback(error, result);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class DebugHash {
|
|||
if (data.startsWith("debug-digest-")) {
|
||||
data = Buffer.from(data.slice("debug-digest-".length), "hex").toString();
|
||||
}
|
||||
this.string += `[${data}](${new Error().stack.split("\n")[2]})\n`;
|
||||
this.string += `[${data}](${new Error().stack.split("\n", 3)[2]})\n`;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -176,7 +176,9 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
]),
|
||||
"}",
|
||||
prefetchChunks && prefetchChunks.length > 0
|
||||
? prefetchChunks.map(c => `\nprefetchChunk(${c});`)
|
||||
? prefetchChunks
|
||||
.map(c => `prefetchChunk(${JSON.stringify(c)});`)
|
||||
.join("\n")
|
||||
: ""
|
||||
])
|
||||
: "// no prefetching",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "webpack",
|
||||
"version": "5.0.0-alpha.3",
|
||||
"version": "5.0.0-alpha.5",
|
||||
"author": "Tobias Koppers @sokra",
|
||||
"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
|
||||
"license": "MIT",
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
"schema-utils": "^0.4.4",
|
||||
"tapable": "^1.1.0",
|
||||
"terser-webpack-plugin": "^1.2.1",
|
||||
"watchpack": "^1.5.0",
|
||||
"watchpack": "2.0.0-beta.2",
|
||||
"webpack-sources": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -683,4 +683,25 @@ describe("Compiler", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
it("should call the failed-hook on error", done => {
|
||||
const failedSpy = jest.fn();
|
||||
const compiler = webpack({
|
||||
bail: true,
|
||||
context: __dirname,
|
||||
mode: "production",
|
||||
entry: "./missing",
|
||||
output: {
|
||||
path: "/",
|
||||
filename: "bundle.js"
|
||||
},
|
||||
});
|
||||
compiler.hooks.failed.tap('CompilerTest', failedSpy);
|
||||
compiler.outputFileSystem = new MemoryFs();
|
||||
compiler.run((err, stats) => {
|
||||
expect(err).toBeTruthy();
|
||||
expect(failedSpy).toHaveBeenCalledTimes(1);
|
||||
expect(failedSpy).toHaveBeenCalledWith(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ const webpack = require("../");
|
|||
const rimraf = require("rimraf");
|
||||
|
||||
describe("Profiling Plugin", function() {
|
||||
jest.setTimeout(15000);
|
||||
|
||||
it("should handle output path with folder creation", done => {
|
||||
const finalPath = "test/js/profilingPath/events.json";
|
||||
const outputPath = path.join(__dirname, "/js/profilingPath");
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -181,12 +181,16 @@ const describeCases = config => {
|
|||
rimraf(cacheDirectory, done);
|
||||
});
|
||||
if (config.cache) {
|
||||
it(`${testName} should pre-compile to fill disk cache`, done => {
|
||||
const compiler = webpack(options, err => {
|
||||
it(`${testName} should pre-compile to fill disk cache (1st)`, done => {
|
||||
webpack(options, err => {
|
||||
if (err) return done(err);
|
||||
compiler.close(() => {
|
||||
done();
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
it(`${testName} should pre-compile to fill disk cache (2nd)`, done => {
|
||||
webpack(options, err => {
|
||||
if (err) return done(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1452,6 +1452,21 @@ If you don't want to include a polyfill, you can use an empty module like this:
|
|||
"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for module-reasons 1`] = `
|
||||
"Hash: 3584c47f06ef83e85f02
|
||||
Time: Xms
|
||||
Built at: Thu Jan 01 1970 00:00:00 GMT
|
||||
Asset Size Chunks Chunk Names
|
||||
main.js 2.75 KiB {404} [emitted] main
|
||||
Entrypoint main = main.js
|
||||
[523] ./index.js + 2 modules 102 bytes {404} [built]
|
||||
entry ./index main
|
||||
[911] ./c.js 8 bytes {404} [built]
|
||||
cjs require ./c [523] ./index.js + 2 modules ./a.js 1:0-14
|
||||
cjs require ./c [523] ./index.js + 2 modules ./b.js 1:0-14
|
||||
+ 2 hidden modules"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for module-trace-disabled-in-error 1`] = `
|
||||
"Time: Xms
|
||||
Built at: Thu Jan 01 1970 00:00:00 GMT
|
||||
|
|
@ -2357,20 +2372,20 @@ Entrypoint main = main.js
|
|||
| ./main.js 144 bytes [built]
|
||||
[1] ./components/src/CompAB/CompA.js 89 bytes {0} [built]
|
||||
[only some exports used: default]
|
||||
harmony import specifier ./components [0] ./main.js + 1 modules 3:15-20 (skipped side-effect-free modules)
|
||||
harmony import specifier ./components [0] ./main.js + 1 modules ./main.js 3:15-20 (skipped side-effect-free modules)
|
||||
harmony import specifier ./components [3] ./foo.js 3:20-25 (skipped side-effect-free modules)
|
||||
harmony side effect evaluation ./CompA ./components/src/CompAB/index.js 1:0-43
|
||||
harmony export imported specifier ./CompA ./components/src/CompAB/index.js 1:0-43
|
||||
[2] ./components/src/CompAB/utils.js 97 bytes {0} [built]
|
||||
harmony side effect evaluation ./utils [0] ./main.js + 1 modules 1:0-30
|
||||
harmony import specifier ./utils [0] ./main.js + 1 modules 5:2-5
|
||||
harmony side effect evaluation ./utils [0] ./main.js + 1 modules ./components/src/CompAB/CompB.js 1:0-30
|
||||
harmony import specifier ./utils [0] ./main.js + 1 modules ./components/src/CompAB/CompB.js 5:2-5
|
||||
harmony side effect evaluation ./utils [1] ./components/src/CompAB/CompA.js 1:0-35
|
||||
harmony import specifier ./utils [1] ./components/src/CompAB/CompA.js 5:5-12
|
||||
[3] ./foo.js 101 bytes {1} [built]
|
||||
import() ./foo [0] ./main.js + 1 modules 6:0-15
|
||||
import() ./foo [0] ./main.js + 1 modules ./main.js 6:0-15
|
||||
./components/src/index.js 84 bytes [orphan] [built]
|
||||
[module unused]
|
||||
harmony side effect evaluation ./components [0] ./main.js + 1 modules 1:0-44
|
||||
harmony side effect evaluation ./components [0] ./main.js + 1 modules ./main.js 1:0-44
|
||||
harmony side effect evaluation ./components [3] ./foo.js 1:0-37
|
||||
./components/src/CompAB/index.js 87 bytes [orphan] [built]
|
||||
[module unused]
|
||||
|
|
@ -2409,14 +2424,14 @@ Entrypoint main = main.js
|
|||
| ./index.js 55 bytes [built]
|
||||
./node_modules/pmodule/a.js 60 bytes [orphan] [built]
|
||||
[module unused]
|
||||
harmony side effect evaluation ./a [690] ./index.js + 2 modules 1:0-20
|
||||
harmony export imported specifier ./a [690] ./index.js + 2 modules 1:0-20
|
||||
harmony side effect evaluation ./a [690] ./index.js + 2 modules ./node_modules/pmodule/index.js 1:0-20
|
||||
harmony export imported specifier ./a [690] ./index.js + 2 modules ./node_modules/pmodule/index.js 1:0-20
|
||||
./node_modules/pmodule/b.js 69 bytes [orphan] [built]
|
||||
[module unused]
|
||||
harmony side effect evaluation ./b [690] ./index.js + 2 modules 2:0-30
|
||||
harmony export imported specifier ./b [690] ./index.js + 2 modules 2:0-30
|
||||
harmony export imported specifier ./b [690] ./index.js + 2 modules 2:0-30
|
||||
harmony export imported specifier ./b [690] ./index.js + 2 modules 2:0-30
|
||||
harmony side effect evaluation ./b [690] ./index.js + 2 modules ./node_modules/pmodule/index.js 2:0-30
|
||||
harmony export imported specifier ./b [690] ./index.js + 2 modules ./node_modules/pmodule/index.js 2:0-30
|
||||
harmony export imported specifier ./b [690] ./index.js + 2 modules ./node_modules/pmodule/index.js 2:0-30
|
||||
harmony export imported specifier ./b [690] ./index.js + 2 modules ./node_modules/pmodule/index.js 2:0-30
|
||||
+ 2 hidden modules"
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
it("should compile a long module chain fine", () => {
|
||||
require.resolveWeak("./module?800"); // this is orphan
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
if(__resourceQuery === "?0") {
|
||||
module.exports = "module";
|
||||
} else {
|
||||
module.exports = require("./module?" + (+__resourceQuery.substr(1) - 1));
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
it("should compile", () => {})
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
const Compiler = require('../../../../lib/Compiler');
|
||||
|
||||
module.exports = {
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
{
|
||||
apply(compiler) {
|
||||
expect(compiler).toBeInstanceOf(Compiler);
|
||||
},
|
||||
},
|
||||
function(compiler) {
|
||||
expect(compiler).toBe(this);
|
||||
expect(compiler).toBeInstanceOf(Compiler);
|
||||
}
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
module.exports = {
|
||||
target: "web",
|
||||
node: {
|
||||
global: true
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
module.exports = {
|
||||
target: "web",
|
||||
node: {
|
||||
global: true
|
||||
}
|
||||
target: "web"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
require("./c");
|
||||
export const a = "a";
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
require("./c");
|
||||
export const b = "b";
|
||||
|
|
@ -0,0 +1 @@
|
|||
// empty
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import "./a";
|
||||
import "./b";
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
mode: "production",
|
||||
entry: "./index",
|
||||
stats: {
|
||||
modules: true,
|
||||
reasons: true,
|
||||
}
|
||||
};
|
||||
121
yarn.lock
121
yarn.lock
|
|
@ -550,11 +550,6 @@ astral-regex@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
|
||||
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
|
||||
|
||||
async-each@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
|
||||
integrity sha1-GdOGodntxufByF04iu28xW0zYC0=
|
||||
|
||||
async-limiter@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
|
||||
|
|
@ -839,11 +834,6 @@ big.js@^3.1.3:
|
|||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
|
||||
integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
|
||||
|
||||
binary-extensions@^1.0.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
|
||||
integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=
|
||||
|
||||
bluebird@^3.5.0, bluebird@^3.5.x:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
||||
|
|
@ -878,7 +868,7 @@ braces@^1.8.2:
|
|||
preserve "^0.2.0"
|
||||
repeat-element "^1.1.2"
|
||||
|
||||
braces@^2.3.0, braces@^2.3.1:
|
||||
braces@^2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
|
||||
integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
|
||||
|
|
@ -1081,25 +1071,6 @@ chardet@^0.7.0:
|
|||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||
|
||||
chokidar@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176"
|
||||
integrity sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==
|
||||
dependencies:
|
||||
anymatch "^2.0.0"
|
||||
async-each "^1.0.0"
|
||||
braces "^2.3.0"
|
||||
glob-parent "^3.1.0"
|
||||
inherits "^2.0.1"
|
||||
is-binary-path "^1.0.0"
|
||||
is-glob "^4.0.0"
|
||||
normalize-path "^2.1.1"
|
||||
path-is-absolute "^1.0.0"
|
||||
readdirp "^2.0.0"
|
||||
upath "^1.0.0"
|
||||
optionalDependencies:
|
||||
fsevents "^1.1.2"
|
||||
|
||||
chownr@^1.0.1, chownr@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
|
||||
|
|
@ -2555,14 +2526,6 @@ fs.realpath@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
fsevents@^1.1.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.2.tgz#4f598f0f69b273188ef4a62ca4e9e08ace314bbf"
|
||||
integrity sha512-iownA+hC4uHFp+7gwP/y5SzaiUo7m2vpa0dhpzw8YuKtiZsz7cIXsFbXpLEeBM6WuCQyw1MH4RRe6XI8GFUctQ==
|
||||
dependencies:
|
||||
nan "^2.9.2"
|
||||
node-pre-gyp "^0.9.0"
|
||||
|
||||
fsevents@^1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
|
||||
|
|
@ -2658,14 +2621,6 @@ glob-parent@^2.0.0:
|
|||
dependencies:
|
||||
is-glob "^2.0.0"
|
||||
|
||||
glob-parent@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
|
||||
integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
|
||||
dependencies:
|
||||
is-glob "^3.1.0"
|
||||
path-dirname "^1.0.0"
|
||||
|
||||
glob@^5.0.15:
|
||||
version "5.0.15"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
|
||||
|
|
@ -3094,13 +3049,6 @@ is-arrayish@^0.2.1:
|
|||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
|
||||
|
||||
is-binary-path@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
|
||||
integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
|
||||
dependencies:
|
||||
binary-extensions "^1.0.0"
|
||||
|
||||
is-buffer@^1.1.5:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
|
|
@ -3211,7 +3159,7 @@ is-extglob@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
|
||||
integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
|
||||
|
||||
is-extglob@^2.1.0, is-extglob@^2.1.1:
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
|
||||
|
|
@ -3247,13 +3195,6 @@ is-glob@^2.0.0, is-glob@^2.0.1:
|
|||
dependencies:
|
||||
is-extglob "^1.0.0"
|
||||
|
||||
is-glob@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
|
||||
integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
|
||||
dependencies:
|
||||
is-extglob "^2.1.0"
|
||||
|
||||
is-glob@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
|
||||
|
|
@ -4697,7 +4638,7 @@ mimic-fn@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
|
||||
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
|
||||
|
||||
"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
|
||||
"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
|
|
@ -4828,7 +4769,7 @@ natural-compare@^1.4.0:
|
|||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
needle@^2.2.0, needle@^2.2.1:
|
||||
needle@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
|
||||
integrity sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q==
|
||||
|
|
@ -4891,22 +4832,6 @@ node-pre-gyp@^0.10.0:
|
|||
semver "^5.3.0"
|
||||
tar "^4"
|
||||
|
||||
node-pre-gyp@^0.9.0:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0"
|
||||
integrity sha1-8RwHUW3ZL4cZnbx+GDjqt81WyeA=
|
||||
dependencies:
|
||||
detect-libc "^1.0.2"
|
||||
mkdirp "^0.5.1"
|
||||
needle "^2.2.0"
|
||||
nopt "^4.0.1"
|
||||
npm-packlist "^1.1.6"
|
||||
npmlog "^4.0.2"
|
||||
rc "^1.1.7"
|
||||
rimraf "^2.6.1"
|
||||
semver "^5.3.0"
|
||||
tar "^4"
|
||||
|
||||
nopt@3.x:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
|
||||
|
|
@ -5249,11 +5174,6 @@ pascalcase@^0.1.1:
|
|||
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
|
||||
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
|
||||
|
||||
path-dirname@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
|
||||
integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
|
||||
|
||||
path-exists@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
|
||||
|
|
@ -5946,7 +5866,7 @@ raw-loader@~0.5.0, raw-loader@~0.5.1:
|
|||
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
|
||||
integrity sha1-DD0L6u2KAclm2Xh793goElKpeao=
|
||||
|
||||
rc@^1.1.7, rc@^1.2.7:
|
||||
rc@^1.2.7:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
|
|
@ -6003,7 +5923,7 @@ read-pkg@^4.0.1:
|
|||
parse-json "^4.0.0"
|
||||
pify "^3.0.0"
|
||||
|
||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@~2.3.6:
|
||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@~2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
|
|
@ -6016,16 +5936,6 @@ read-pkg@^4.0.1:
|
|||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readdirp@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
|
||||
integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
minimatch "^3.0.2"
|
||||
readable-stream "^2.0.2"
|
||||
set-immediate-shim "^1.0.1"
|
||||
|
||||
realpath-native@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.1.tgz#07f40a0cce8f8261e2e8b7ebebf5c95965d7b633"
|
||||
|
|
@ -6458,11 +6368,6 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
set-immediate-shim@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
|
||||
integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
|
||||
|
||||
set-value@^0.4.3:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
|
||||
|
|
@ -7212,11 +7117,6 @@ unset-value@^1.0.0:
|
|||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
upath@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.5.tgz#02cab9ecebe95bbec6d5fc2566325725ab6d1a73"
|
||||
integrity sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
|
||||
|
|
@ -7327,12 +7227,11 @@ watch@~0.18.0:
|
|||
exec-sh "^0.2.0"
|
||||
minimist "^1.2.0"
|
||||
|
||||
watchpack@^1.5.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
||||
integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==
|
||||
watchpack@2.0.0-beta.2:
|
||||
version "2.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.0.0-beta.2.tgz#357ed627767dd16ed80500f49c5d4029b49248cb"
|
||||
integrity sha512-dzFk3sOzcuIC9s+6Qek6Y0cQmk+N8VvUSY1BtB9wCEpfbcUFOQS7tlD1wRnwq2gv+orBYB/td4hO59Z4lg6ELQ==
|
||||
dependencies:
|
||||
chokidar "^2.0.2"
|
||||
graceful-fs "^4.1.2"
|
||||
neo-async "^2.5.0"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue