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
|
keepOriginalOrder
|
||||||
} = require("./util/comparators");
|
} = require("./util/comparators");
|
||||||
const createHash = require("./util/createHash");
|
const createHash = require("./util/createHash");
|
||||||
|
const { join } = require("./util/fs");
|
||||||
const { contextify } = require("./util/identifier");
|
const { contextify } = require("./util/identifier");
|
||||||
const makeSerializable = require("./util/makeSerializable");
|
const makeSerializable = require("./util/makeSerializable");
|
||||||
|
const memoize = require("./util/memoize");
|
||||||
|
|
||||||
/** @typedef {import("source-map").RawSourceMap} SourceMap */
|
/** @typedef {import("source-map").RawSourceMap} SourceMap */
|
||||||
/** @typedef {import("webpack-sources").Source} Source */
|
/** @typedef {import("webpack-sources").Source} Source */
|
||||||
|
|
@ -61,6 +63,12 @@ const makeSerializable = require("./util/makeSerializable");
|
||||||
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
|
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
|
||||||
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
|
/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
|
||||||
|
|
||||||
|
const getInvalidDependenciesModuleWarning = memoize(() =>
|
||||||
|
require("./InvalidDependenciesModuleWarning")
|
||||||
|
);
|
||||||
|
|
||||||
|
const ABSOLUTE_PATH_REGEX = /^([a-zA-Z]:\\|\\\\|\/)/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} LoaderItem
|
* @typedef {Object} LoaderItem
|
||||||
* @property {string} loader
|
* @property {string} loader
|
||||||
|
|
@ -814,6 +822,44 @@ class NormalModule extends Module {
|
||||||
if (!this.buildInfo.cacheable || !snapshotOptions) {
|
if (!this.buildInfo.cacheable || !snapshotOptions) {
|
||||||
return callback();
|
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
|
// convert file/context/missingDependencies into filesystem snapshot
|
||||||
compilation.fileSystemInfo.createSnapshot(
|
compilation.fileSystemInfo.createSnapshot(
|
||||||
startTime,
|
startTime,
|
||||||
|
|
|
||||||
|
|
@ -497,6 +497,9 @@ module.exports = mergeExports(fn, {
|
||||||
},
|
},
|
||||||
get cleverMerge() {
|
get cleverMerge() {
|
||||||
return require("./util/cleverMerge").cachedCleverMerge;
|
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: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
VALUE: webpack.DefinePlugin.runtimeValue(() => read("123.txt"), [
|
VALUE: webpack.DefinePlugin.runtimeValue(() => read("123.txt"), [
|
||||||
"./123.txt"
|
join(__dirname, "./123.txt")
|
||||||
])
|
])
|
||||||
}),
|
}),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
VALUE: webpack.DefinePlugin.runtimeValue(() => read("321.txt"), [
|
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;
|
formatTime?: (time: number, boldQuantity?: boolean) => string;
|
||||||
chunkGroupKind?: string;
|
chunkGroupKind?: string;
|
||||||
}
|
}
|
||||||
declare abstract class LazySet<T> {
|
declare class LazySet<T> {
|
||||||
|
constructor(iterable?: Iterable<T>);
|
||||||
readonly size: number;
|
readonly size: number;
|
||||||
add(item: T): LazySet<T>;
|
add(item: T): LazySet<T>;
|
||||||
addAll(iterable: LazySet<T> | Iterable<T>): LazySet<T>;
|
addAll(iterable: LazySet<T> | Iterable<T>): LazySet<T>;
|
||||||
|
|
@ -4774,6 +4775,7 @@ declare abstract class LazySet<T> {
|
||||||
[Symbol.iterator](): IterableIterator<T>;
|
[Symbol.iterator](): IterableIterator<T>;
|
||||||
readonly [Symbol.toStringTag]: string;
|
readonly [Symbol.toStringTag]: string;
|
||||||
serialize(__0: { write: any }): void;
|
serialize(__0: { write: any }): void;
|
||||||
|
static deserialize(__0: { read: any }): LazySet<any>;
|
||||||
}
|
}
|
||||||
declare interface LibIdentOptions {
|
declare interface LibIdentOptions {
|
||||||
/**
|
/**
|
||||||
|
|
@ -10784,6 +10786,7 @@ declare namespace exports {
|
||||||
export { MEASURE_START_OPERATION, MEASURE_END_OPERATION };
|
export { MEASURE_START_OPERATION, MEASURE_END_OPERATION };
|
||||||
}
|
}
|
||||||
export const cleverMerge: <T, O>(first: T, second: O) => T | O | (T & O);
|
export const cleverMerge: <T, O>(first: T, second: O) => T | O | (T & O);
|
||||||
|
export { LazySet };
|
||||||
}
|
}
|
||||||
export namespace sources {
|
export namespace sources {
|
||||||
export {
|
export {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue