diff --git a/lib/Compilation.js b/lib/Compilation.js index 2047c585d78..63291744d5b 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -37,11 +37,11 @@ const compareLocations = require("./compareLocations"); const { Logger, LogType } = require("./logging/Logger"); const ErrorHelpers = require("./ErrorHelpers"); const buildChunkGraph = require("./buildChunkGraph"); +const WebpackError = require("./WebpackError"); /** @typedef {import("./Module")} Module */ /** @typedef {import("./Compiler")} Compiler */ /** @typedef {import("webpack-sources").Source} Source */ -/** @typedef {import("./WebpackError")} WebpackError */ /** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */ /** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */ /** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */ @@ -221,6 +221,25 @@ const addAllToSet = (set, otherSet) => { } }; +/** + * @param {Source} a a source + * @param {Source} b another source + * @returns {boolean} true, when both sources are equal + */ +const isSourceEqual = (a, b) => { + if (a === b) return true; + // TODO webpack 5: check .buffer() instead, it's called anyway during emit + /** @type {Buffer|string} */ + let aSource = a.source(); + /** @type {Buffer|string} */ + let bSource = b.source(); + if (aSource === bSource) return true; + if (typeof aSource === "string" && typeof bSource === "string") return false; + if (!Buffer.isBuffer(aSource)) aSource = Buffer.from(aSource, "utf-8"); + if (!Buffer.isBuffer(bSource)) bSource = Buffer.from(bSource, "utf-8"); + return aSource.equals(bSource); +}; + class Compilation extends Tapable { /** * Creates an instance of Compilation. @@ -1990,10 +2009,16 @@ class Compilation extends Tapable { */ emitAsset(file, source, assetInfo = {}) { if (this.assets[file]) { - if (this.assets[file] !== source) { - throw new Error( - `Conflict: Multiple assets emit to the same filename ${file}` + if (!isSourceEqual(this.assets[file], source)) { + // TODO webpack 5: make this an error instead + this.warnings.push( + new WebpackError( + `Conflict: Multiple assets emit different content to the same filename ${file}` + ) ); + this.assets[file] = source; + this.assetsInfo.set(file, assetInfo); + return; } const oldInfo = this.assetsInfo.get(file); this.assetsInfo.set(file, Object.assign({}, oldInfo, assetInfo)); diff --git a/test/configCases/emit-asset/different-source/index.js b/test/configCases/emit-asset/different-source/index.js new file mode 100644 index 00000000000..a03fbd7bd6c --- /dev/null +++ b/test/configCases/emit-asset/different-source/index.js @@ -0,0 +1,4 @@ +it("should compile without warnings", () => { + require("./test1.txt"); + require("./test2.txt"); +}); diff --git a/test/configCases/emit-asset/different-source/test1.txt b/test/configCases/emit-asset/different-source/test1.txt new file mode 100644 index 00000000000..557db03de99 --- /dev/null +++ b/test/configCases/emit-asset/different-source/test1.txt @@ -0,0 +1 @@ +Hello World diff --git a/test/configCases/emit-asset/different-source/test2.txt b/test/configCases/emit-asset/different-source/test2.txt new file mode 100644 index 00000000000..299d09ff310 --- /dev/null +++ b/test/configCases/emit-asset/different-source/test2.txt @@ -0,0 +1 @@ +Something else diff --git a/test/configCases/emit-asset/different-source/warnings.js b/test/configCases/emit-asset/different-source/warnings.js new file mode 100644 index 00000000000..4ca3183d5ae --- /dev/null +++ b/test/configCases/emit-asset/different-source/warnings.js @@ -0,0 +1,7 @@ +module.exports = [ + [ + /Conflict/, + /Multiple assets emit different content to the same filename/, + /same-name\.txt/ + ] +]; diff --git a/test/configCases/emit-asset/different-source/webpack.config.js b/test/configCases/emit-asset/different-source/webpack.config.js new file mode 100644 index 00000000000..48a8987ca97 --- /dev/null +++ b/test/configCases/emit-asset/different-source/webpack.config.js @@ -0,0 +1,15 @@ +module.exports = { + module: { + rules: [ + { + test: /\.txt$/, + use: { + loader: "file-loader", + options: { + name: "same-name.txt" + } + } + } + ] + } +}; diff --git a/test/configCases/emit-asset/equal-source/index.js b/test/configCases/emit-asset/equal-source/index.js new file mode 100644 index 00000000000..a03fbd7bd6c --- /dev/null +++ b/test/configCases/emit-asset/equal-source/index.js @@ -0,0 +1,4 @@ +it("should compile without warnings", () => { + require("./test1.txt"); + require("./test2.txt"); +}); diff --git a/test/configCases/emit-asset/equal-source/test1.txt b/test/configCases/emit-asset/equal-source/test1.txt new file mode 100644 index 00000000000..557db03de99 --- /dev/null +++ b/test/configCases/emit-asset/equal-source/test1.txt @@ -0,0 +1 @@ +Hello World diff --git a/test/configCases/emit-asset/equal-source/test2.txt b/test/configCases/emit-asset/equal-source/test2.txt new file mode 100644 index 00000000000..557db03de99 --- /dev/null +++ b/test/configCases/emit-asset/equal-source/test2.txt @@ -0,0 +1 @@ +Hello World diff --git a/test/configCases/emit-asset/equal-source/webpack.config.js b/test/configCases/emit-asset/equal-source/webpack.config.js new file mode 100644 index 00000000000..48a8987ca97 --- /dev/null +++ b/test/configCases/emit-asset/equal-source/webpack.config.js @@ -0,0 +1,15 @@ +module.exports = { + module: { + rules: [ + { + test: /\.txt$/, + use: { + loader: "file-loader", + options: { + name: "same-name.txt" + } + } + } + ] + } +};