mirror of https://github.com/webpack/webpack.git
add warning when invalid dependencies are reported by loaders/plugins
add automatic workaround for invalid dependencies #12340 #12283
This commit is contained in:
parent
6b2ca40b63
commit
09862aacf8
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const WebpackError = require("./WebpackError");
|
||||
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
module.exports = class InvalidDependenciesModuleWarning extends WebpackError {
|
||||
/**
|
||||
* @param {Module} module module tied to dependency
|
||||
* @param {Iterable<string>} deps invalid dependencies
|
||||
*/
|
||||
constructor(module, deps) {
|
||||
const orderedDeps = Array.from(deps).sort();
|
||||
const depsList = orderedDeps.map(dep => ` * ${JSON.stringify(dep)}`);
|
||||
super(`Invalid dependencies have been reported by plugins or loaders for this module. All reported dependencies need to be absolute paths.
|
||||
Invalid dependencies may lead to broken watching and caching.
|
||||
As best effort we try to convert all invalid values to absolute paths and converting globs into context dependencies, but this is deprecated behavior.
|
||||
Loaders: Pass absolute paths to this.addDependency (existing files), this.addMissingDependency (not existing files), and this.addContextDependency (directories).
|
||||
Plugins: Pass absolute paths to fileDependencies (existing files), missingDependencies (not existing files), and contextDependencies (directories).
|
||||
Globs: They are not supported. Pass absolute path to the directory as context dependencies.
|
||||
The following invalid values have been reported:
|
||||
${depsList.slice(0, 3).join("\n")}${
|
||||
depsList.length > 3 ? "\n * and more ..." : ""
|
||||
}`);
|
||||
|
||||
this.name = "InvalidDependenciesModuleWarning";
|
||||
this.details = depsList.slice(3).join("\n");
|
||||
this.module = module;
|
||||
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
};
|
||||
|
|
@ -36,8 +36,10 @@ const {
|
|||
keepOriginalOrder
|
||||
} = require("./util/comparators");
|
||||
const createHash = require("./util/createHash");
|
||||
const { join } = require("./util/fs");
|
||||
const { contextify } = require("./util/identifier");
|
||||
const makeSerializable = require("./util/makeSerializable");
|
||||
const memoize = require("./util/memoize");
|
||||
|
||||
/** @typedef {import("source-map").RawSourceMap} SourceMap */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
|
|
@ -61,6 +63,12 @@ const makeSerializable = require("./util/makeSerializable");
|
|||
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
|
||||
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
|
||||
|
||||
const getInvalidDependenciesModuleWarning = memoize(() =>
|
||||
require("./InvalidDependenciesModuleWarning")
|
||||
);
|
||||
|
||||
const ABSOLUTE_PATH_REGEX = /^([a-zA-Z]:\\|\\\\|\/)/;
|
||||
|
||||
/**
|
||||
* @typedef {Object} LoaderItem
|
||||
* @property {string} loader
|
||||
|
|
@ -814,6 +822,44 @@ class NormalModule extends Module {
|
|||
if (!this.buildInfo.cacheable || !snapshotOptions) {
|
||||
return callback();
|
||||
}
|
||||
// add warning for all non-absolute paths in fileDependencies, etc
|
||||
// This makes it easier to find problems with watching and/or caching
|
||||
let nonAbsoluteDependencies = undefined;
|
||||
const checkDependencies = deps => {
|
||||
for (const dep of deps) {
|
||||
if (!ABSOLUTE_PATH_REGEX.test(dep)) {
|
||||
if (nonAbsoluteDependencies === undefined)
|
||||
nonAbsoluteDependencies = new Set();
|
||||
nonAbsoluteDependencies.add(dep);
|
||||
deps.delete(dep);
|
||||
try {
|
||||
const depWithoutGlob = dep.replace(/[\\/]?\*.*$/, "");
|
||||
const absolute = join(
|
||||
compilation.fileSystemInfo.fs,
|
||||
this.context,
|
||||
depWithoutGlob
|
||||
);
|
||||
if (absolute !== dep && ABSOLUTE_PATH_REGEX.test(absolute)) {
|
||||
(depWithoutGlob !== dep
|
||||
? this.buildInfo.contextDependencies
|
||||
: deps
|
||||
).add(absolute);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
checkDependencies(this.buildInfo.fileDependencies);
|
||||
checkDependencies(this.buildInfo.missingDependencies);
|
||||
checkDependencies(this.buildInfo.contextDependencies);
|
||||
if (nonAbsoluteDependencies !== undefined) {
|
||||
const InvalidDependenciesModuleWarning = getInvalidDependenciesModuleWarning();
|
||||
this.addWarning(
|
||||
new InvalidDependenciesModuleWarning(this, nonAbsoluteDependencies)
|
||||
);
|
||||
}
|
||||
// convert file/context/missingDependencies into filesystem snapshot
|
||||
compilation.fileSystemInfo.createSnapshot(
|
||||
startTime,
|
||||
|
|
|
|||
|
|
@ -497,6 +497,9 @@ module.exports = mergeExports(fn, {
|
|||
},
|
||||
get cleverMerge() {
|
||||
return require("./util/cleverMerge").cachedCleverMerge;
|
||||
},
|
||||
get LazySet() {
|
||||
return require("./util/LazySet");
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
it("should compile", () => {});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
module.exports = function (source) {
|
||||
this.addDependency("loader.js");
|
||||
this.addDependency("../**/dir/*.js");
|
||||
this.addDependency("../**/file.js");
|
||||
this.addContextDependency(".");
|
||||
this.addMissingDependency("./missing1.js");
|
||||
this.addMissingDependency("missing2.js");
|
||||
this.addMissingDependency("missing3.js");
|
||||
this.addMissingDependency("missing4.js");
|
||||
return source;
|
||||
};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
module.exports = [
|
||||
[
|
||||
{ moduleName: /\.\/index\.js/ },
|
||||
/Invalid dependencies have been reported/,
|
||||
/"\."/,
|
||||
/"\.\.\/\*\*\/dir\/\*\.js"/,
|
||||
{ details: /"\.\/missing1\.js"/ },
|
||||
{ details: /"loader\.js"/ },
|
||||
/and more/,
|
||||
{ details: /"missing3\.js"/ }
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
const webpack = require("../../../../");
|
||||
const path = require("path");
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /index\.js$/,
|
||||
loader: "./loader.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
compiler => {
|
||||
compiler.hooks.compilation.tap("Test", compilation => {
|
||||
compilation.hooks.succeedModule.tap("Test", module => {
|
||||
const fileDeps = new webpack.util.LazySet();
|
||||
const contextDeps = new webpack.util.LazySet();
|
||||
const missingDeps = new webpack.util.LazySet();
|
||||
const buildDeps = new webpack.util.LazySet();
|
||||
module.addCacheDependencies(
|
||||
fileDeps,
|
||||
contextDeps,
|
||||
missingDeps,
|
||||
buildDeps
|
||||
);
|
||||
expect(Array.from(fileDeps).sort()).toEqual([
|
||||
path.join(__dirname, "index.js"),
|
||||
path.join(__dirname, "loader.js")
|
||||
]);
|
||||
expect(Array.from(contextDeps).sort()).toEqual([
|
||||
path.join(__dirname, ".."),
|
||||
__dirname
|
||||
]);
|
||||
expect(Array.from(missingDeps).sort()).toEqual([
|
||||
path.join(__dirname, "missing1.js"),
|
||||
path.join(__dirname, "missing2.js"),
|
||||
path.join(__dirname, "missing3.js"),
|
||||
path.join(__dirname, "missing4.js")
|
||||
]);
|
||||
expect(Array.from(fileDeps).sort()).toEqual([
|
||||
path.join(__dirname, "index.js"),
|
||||
path.join(__dirname, "loader.js")
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -45,12 +45,12 @@ module.exports = [
|
|||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
VALUE: webpack.DefinePlugin.runtimeValue(() => read("123.txt"), [
|
||||
"./123.txt"
|
||||
join(__dirname, "./123.txt")
|
||||
])
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
VALUE: webpack.DefinePlugin.runtimeValue(() => read("321.txt"), [
|
||||
"./321.txt"
|
||||
join(__dirname, "./321.txt")
|
||||
])
|
||||
})
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4757,7 +4757,8 @@ declare interface KnownStatsPrinterContext {
|
|||
formatTime?: (time: number, boldQuantity?: boolean) => string;
|
||||
chunkGroupKind?: string;
|
||||
}
|
||||
declare abstract class LazySet<T> {
|
||||
declare class LazySet<T> {
|
||||
constructor(iterable?: Iterable<T>);
|
||||
readonly size: number;
|
||||
add(item: T): LazySet<T>;
|
||||
addAll(iterable: LazySet<T> | Iterable<T>): LazySet<T>;
|
||||
|
|
@ -4774,6 +4775,7 @@ declare abstract class LazySet<T> {
|
|||
[Symbol.iterator](): IterableIterator<T>;
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
serialize(__0: { write: any }): void;
|
||||
static deserialize(__0: { read: any }): LazySet<any>;
|
||||
}
|
||||
declare interface LibIdentOptions {
|
||||
/**
|
||||
|
|
@ -10784,6 +10786,7 @@ declare namespace exports {
|
|||
export { MEASURE_START_OPERATION, MEASURE_END_OPERATION };
|
||||
}
|
||||
export const cleverMerge: <T, O>(first: T, second: O) => T | O | (T & O);
|
||||
export { LazySet };
|
||||
}
|
||||
export namespace sources {
|
||||
export {
|
||||
|
|
|
|||
Loading…
Reference in New Issue