diff --git a/src/index.js b/src/index.js index 147d63a5..f2b8b651 100644 --- a/src/index.js +++ b/src/index.js @@ -110,15 +110,21 @@ class CopyPlugin { return; } - const info = compilation.getAsset(targetPath); + const existingAsset = compilation.getAsset(targetPath); - if (info) { + if (existingAsset) { if (force) { logger.log( `force updating '${webpackTo}' to compilation assets from '${absoluteFrom}'` ); - compilation.updateAsset(targetPath, source, { copied: true }); + const info = { copied: true }; + + if (asset.immutable) { + info.immutable = true; + } + + compilation.updateAsset(targetPath, source, info); return; } @@ -134,7 +140,13 @@ class CopyPlugin { `writing '${webpackTo}' to compilation assets from '${absoluteFrom}'` ); - compilation.emitAsset(targetPath, source, { copied: true }); + const info = { copied: true }; + + if (asset.immutable) { + info.immutable = true; + } + + compilation.emitAsset(targetPath, source, info); }); logger.debug('end to adding additional assets'); diff --git a/src/postProcessPattern.js b/src/postProcessPattern.js index 13e79206..d7d96e06 100644 --- a/src/postProcessPattern.js +++ b/src/postProcessPattern.js @@ -95,6 +95,10 @@ export default async function postProcessPattern(globalRef, pattern, file) { file.webpackTo = file.webpackTo.replace(/\.?\[ext]/g, ''); } + file.immutable = /\[(?:([^:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi.test( + file.webpackTo + ); + file.webpackTo = loaderUtils.interpolateName( { resourcePath: file.absoluteFrom }, file.webpackTo, @@ -113,6 +117,7 @@ export default async function postProcessPattern(globalRef, pattern, file) { `transforming path '${file.webpackTo}' for '${file.absoluteFrom}'` ); + file.immutable = false; file.webpackTo = await pattern.transformPath( file.webpackTo, file.absoluteFrom diff --git a/test/CopyPlugin.test.js b/test/CopyPlugin.test.js index 776bbf4f..a83b73b5 100644 --- a/test/CopyPlugin.test.js +++ b/test/CopyPlugin.test.js @@ -304,6 +304,50 @@ describe('CopyPlugin', () => { .catch(done); }); + it('should copy files with "copied" flags', (done) => { + expect.assertions(5); + + const expectedAssetKeys = [ + 'directoryfile.5d7817ed5bc246756d73d6a4c8e94c33.txt', + '.dottedfile.5e294e270db6734a42f014f0dd18d9ac', + 'nested/nestedfile.31d6cfe0d16ae931b73c59d7e0c089c0.txt', + 'nested/deep-nested/deepnested.31d6cfe0d16ae931b73c59d7e0c089c0.txt', + ]; + + run({ + preCopy: { + additionalAssets: [ + { + name: 'directoryfile.5d7817ed5bc246756d73d6a4c8e94c33.txt', + data: 'Content', + info: { custom: true }, + }, + ], + }, + expectedAssetKeys, + patterns: [ + { + from: 'directory', + to: '[path][name].[contenthash].[ext]', + force: true, + }, + ], + }) + .then(({ stats }) => { + for (const name of expectedAssetKeys) { + const info = stats.compilation.assetsInfo.get(name); + + expect(info.immutable).toBe(true); + + if (name === 'directoryfile.5d7817ed5bc246756d73d6a4c8e94c33.txt') { + expect(info.immutable).toBe(true); + } + } + }) + .then(done) + .catch(done); + }); + it('should copy files and print "copied" in the string representation ', (done) => { const isWebpack4 = webpack.version[0] === '4';