diff --git a/README.md b/README.md index 371cffc..7389074 100644 --- a/README.md +++ b/README.md @@ -738,7 +738,7 @@ Default: `undefined` Allows you to modify the contents of multiple files and save the result to one file. -> ℹ️ The `to` option must specify to a file. It is allowed to use only `[contenthash]` and `[fullhash]` template strings. +> ℹ️ The `to` option must be specified and point to a file. It is allowed to use only `[contenthash]` and `[fullhash]` template strings. **webpack.config.js** diff --git a/src/index.js b/src/index.js index 43a40d2..c19b954 100644 --- a/src/index.js +++ b/src/index.js @@ -359,7 +359,6 @@ class CopyPlugin { filename, force: pattern.force, info, - toType, }; // If this came from a glob or dir, add it to the file dependencies @@ -645,6 +644,16 @@ class CopyPlugin { if (assets && assets.length > 0) { if (item.transformAll) { + if (typeof item.to === "undefined") { + compilation.errors.push( + new Error( + `Invalid "pattern.to" for the "pattern.from": "${item.from}" and "pattern.transformAll" function. The "to" option must be specified.` + ) + ); + + return; + } + assets.sort((a, b) => a.absoluteFilename > b.absoluteFilename ? 1 @@ -672,6 +681,8 @@ class CopyPlugin { const cacheKeys = `transformAll|${serialize({ version, + from: item.from, + to: item.to, transform: item.transformAll, })}`; const eTag = cache.getLazyHashedEtag(mergedEtag); @@ -681,7 +692,9 @@ class CopyPlugin { if (!transformedAsset) { const { RawSource } = compiler.webpack.sources; - transformedAsset = {}; + transformedAsset = { + filename: item.to, + }; try { transformedAsset.source = new RawSource( @@ -693,30 +706,34 @@ class CopyPlugin { return; } - let mergedFilename = assets[0].filename; - - if (assets[0].toType === "template") { - const mergedContentHash = CopyPlugin.getContentHash( + if (template.test(item.to)) { + const contentHash = CopyPlugin.getContentHash( compiler, compilation, transformedAsset.source.source() ); - const { contenthash: oldContentHash } = assets[0].info; - const regExp = new RegExp(oldContentHash, "gi"); - mergedFilename = mergedFilename.replace( - regExp, - mergedContentHash + const data = { + contentHash, + chunk: { + hash: contentHash, + contentHash, + }, + }; + + const { + path: interpolatedFilename, + info: assetInfo, + } = compilation.getPathWithInfo( + normalizePath(item.to), + data ); - transformedAsset.info = { - contenthash: mergedContentHash, - fullhash: assets[0].info.fullhash, - }; + transformedAsset.filename = interpolatedFilename; + transformedAsset.info = assetInfo; } transformedAsset.force = item.force; - transformedAsset.filename = mergedFilename; await cacheItem.storePromise(transformedAsset); } diff --git a/test/transformAll-option.test.js b/test/transformAll-option.test.js index aa0faed..a7186a9 100644 --- a/test/transformAll-option.test.js +++ b/test/transformAll-option.test.js @@ -10,6 +10,7 @@ describe("transformAll option", () => { patterns: [ { from: "file.txt", + to: "file.txt", transformAll(assets) { expect(assets).toBeDefined(); @@ -109,6 +110,27 @@ describe("transformAll option", () => { .catch(done); }); + it('should warn when "to" option is not defined', (done) => { + runEmit({ + expectedAssetKeys: [], + expectedErrors: [ + new Error( + `Invalid "pattern.to" for the "pattern.from": "file.txt" and "pattern.transformAll" function. The "to" option must be specified.` + ), + ], + patterns: [ + { + from: "file.txt", + transformAll() { + return ""; + }, + }, + ], + }) + .then(done) + .catch(done); + }); + it("should warn when function throw error", (done) => { runEmit({ expectedAssetKeys: [],