diff --git a/src/Webpack5Cache.js b/src/Webpack5Cache.js index 897a938..5b8c770 100644 --- a/src/Webpack5Cache.js +++ b/src/Webpack5Cache.js @@ -14,7 +14,7 @@ export default class Cache { async get(task) { // eslint-disable-next-line no-param-reassign task.cacheIdent = - task.cacheIdent || `${task.file}|${serialize(task.cacheKeys)}`; + task.cacheIdent || `${task.name}|${serialize(task.cacheKeys)}`; // eslint-disable-next-line no-param-reassign task.cacheETag = task.cacheETag || this.cache.getLazyHashedEtag(task.assetSource); diff --git a/src/index.js b/src/index.js index 25cf36a..cda8764 100644 --- a/src/index.js +++ b/src/index.js @@ -171,8 +171,38 @@ class CssMinimizerPlugin { : Math.min(Number(parallel) || 0, cpus.length - 1); } - *taskGenerator(compiler, compilation, file) { - const assetSource = compilation.assets[file]; + // eslint-disable-next-line consistent-return + static getAsset(compilation, name) { + // New API + if (compilation.getAsset) { + return compilation.getAsset(name); + } + + if (compilation.assets[name]) { + return { name, source: compilation.assets[name], info: {} }; + } + } + + static updateAsset(compilation, name, newSource, assetInfo) { + // New API + if (compilation.updateAsset) { + compilation.updateAsset(name, newSource, assetInfo); + } + + // eslint-disable-next-line no-param-reassign + compilation.assets[name] = newSource; + } + + *taskGenerator(compiler, compilation, name) { + const { info, source: assetSource } = CssMinimizerPlugin.getAsset( + compilation, + name + ); + + // Skip double minimize assets from child compilation + if (info.minimized) { + yield false; + } let input; let inputSourceMap; @@ -190,7 +220,7 @@ class CssMinimizerPlugin { inputSourceMap = map; compilation.warnings.push( - new Error(`${file} contains invalid source map`) + new Error(`${name} contains invalid source map`) ); } } @@ -222,7 +252,7 @@ class CssMinimizerPlugin { compilation.errors.push( CssMinimizerPlugin.buildError( error, - file, + name, sourceMap, new RequestShortener(compiler.context) ) @@ -236,7 +266,7 @@ class CssMinimizerPlugin { if (map) { outputSource = new SourceMapSource( code, - file, + name, map, input, inputSourceMap, @@ -246,16 +276,17 @@ class CssMinimizerPlugin { outputSource = new RawSource(code); } - // Updating assets - // eslint-disable-next-line no-param-reassign - compilation.assets[file] = outputSource; + CssMinimizerPlugin.updateAsset(compilation, name, outputSource, { + ...info, + minimized: true, + }); // Handling warnings if (warnings && warnings.length > 0) { warnings.forEach((warning) => { const builtWarning = CssMinimizerPlugin.buildWarning( warning, - file, + name, sourceMap, new RequestShortener(compiler.context), this.options.warningsFilter @@ -269,7 +300,7 @@ class CssMinimizerPlugin { }; const task = { - file, + name, input, inputSourceMap, map: this.options.sourceMap, @@ -299,11 +330,11 @@ class CssMinimizerPlugin { 'css-minimizer-webpack-plugin': require('../package.json').version, 'css-minimizer-webpack-plugin-options': this.options, nodeVersion: process.version, - filename: file, + filename: name, contentHash: digest.substr(0, hashDigestLength), }; - task.cacheKeys = this.options.cacheKeys(defaultCacheKeys, file); + task.cacheKeys = this.options.cacheKeys(defaultCacheKeys, name); } } else { // For webpack@5 cache diff --git a/src/minify.js b/src/minify.js index e1a4397..99620f2 100644 --- a/src/minify.js +++ b/src/minify.js @@ -10,7 +10,7 @@ function warningsToString(warnings) { const minify = async (options) => { const { - file, + name, input, minimizerOptions, map, @@ -18,7 +18,7 @@ const minify = async (options) => { minify: minifyFn, } = options; - const postcssOptions = { to: file, from: file }; + const postcssOptions = { to: name, from: name }; if (minifyFn) { const result = await minifyFn( diff --git a/test/CssMinimizerPlugin.test.js b/test/CssMinimizerPlugin.test.js index 32991cc..e72e919 100644 --- a/test/CssMinimizerPlugin.test.js +++ b/test/CssMinimizerPlugin.test.js @@ -340,4 +340,35 @@ describe('CssMinimizerPlugin', () => { } }); }); + + it('should work with child compilation', async () => { + const compiler = getCompiler({ + entry: { + entry: `${__dirname}/fixtures/entry.js`, + }, + module: { + rules: [ + { + test: /entry.js$/i, + use: [ + { + loader: path.resolve(__dirname, './helpers/preLoader'), + }, + ], + }, + { + test: /.s?css$/i, + use: [MiniCssExtractPlugin.loader, 'css-loader'], + }, + ], + }, + }); + new CssMinimizerPlugin().apply(compiler); + + const stats = await compile(compiler); + + expect(readAssets(compiler, stats, '.css')).toMatchSnapshot('assets'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + }); }); diff --git a/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack4 b/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack4 index 80bfccc..b241ee6 100644 --- a/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack4 +++ b/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack4 @@ -66,6 +66,16 @@ exports[`CssMinimizerPlugin should work with assets using querystring: entry.css /*# sourceMappingURL=entry.css.map?v=test*/" `; +exports[`CssMinimizerPlugin should work with child compilation: assets 1`] = ` +Object { + "entry.css": ".entry{text-align:center}", +} +`; + +exports[`CssMinimizerPlugin should work with child compilation: errors 1`] = `Array []`; + +exports[`CssMinimizerPlugin should work with child compilation: warnings 1`] = `Array []`; + exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: assets 1`] = ` Object { "one.css": ".minify {};", diff --git a/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack5 b/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack5 index 80bfccc..b241ee6 100644 --- a/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack5 +++ b/test/__snapshots__/CssMinimizerPlugin.test.js.snap.webpack5 @@ -66,6 +66,16 @@ exports[`CssMinimizerPlugin should work with assets using querystring: entry.css /*# sourceMappingURL=entry.css.map?v=test*/" `; +exports[`CssMinimizerPlugin should work with child compilation: assets 1`] = ` +Object { + "entry.css": ".entry{text-align:center}", +} +`; + +exports[`CssMinimizerPlugin should work with child compilation: errors 1`] = `Array []`; + +exports[`CssMinimizerPlugin should work with child compilation: warnings 1`] = `Array []`; + exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: assets 1`] = ` Object { "one.css": ".minify {};", diff --git a/test/helpers/preLoader.js b/test/helpers/preLoader.js new file mode 100644 index 0000000..46bba79 --- /dev/null +++ b/test/helpers/preLoader.js @@ -0,0 +1,42 @@ +import { RawSource } from 'webpack-sources'; + +class PreCopyPlugin { + constructor(options = {}) { + this.options = options.options || {}; + } + + // eslint-disable-next-line class-methods-use-this + apply(compiler) { + const plugin = { name: 'PreCopyPlugin' }; + + compiler.hooks.compilation.tap(plugin, (compilation) => { + compilation.hooks.additionalAssets.tapAsync(plugin, (callback) => { + compilation.emitAsset( + 'entry.css', + new RawSource('.entry {\n text-align: center;\n}\n\n') + ); + + callback(); + }); + }); + } +} + +export default function loader() { + const callback = this.async(); + + const childCompiler = this._compilation.createChildCompiler( + `preloader`, + this.options + ); + + new PreCopyPlugin().apply(childCompiler); + + childCompiler.runAsChild((error) => { + if (error) { + return callback(error); + } + + return callback(null, 'export default 1'); + }); +} diff --git a/test/worker.test.js b/test/worker.test.js index 09f995e..9466921 100644 --- a/test/worker.test.js +++ b/test/worker.test.js @@ -7,7 +7,7 @@ import { normalizeErrors } from './helpers'; describe('worker', () => { it('should minify css', async () => { const options = { - file: 'entry.css', + name: 'entry.css', input: '.foo{color:red;}\n.bar{color:coral;}', inputSourceMap: { version: 3, @@ -27,7 +27,7 @@ describe('worker', () => { it('should work inputSourceMap as prev', async () => { const options = { - file: 'entry.css', + name: 'entry.css', input: '.foo{color:red;}\n.bar{color:coral;}', minimizerOptions: { discardComments: false }, inputSourceMap: { @@ -47,7 +47,7 @@ describe('worker', () => { it('should work options.minify function', async () => { const options = { - file: 'entry.css', + name: 'entry.css', input: '.foo{color:red;}\n.bar{color:coral;}', minimizerOptions: { discardComments: false }, minify: () => { @@ -62,7 +62,7 @@ describe('worker', () => { it('should emit error', async () => { const options = { - file: 'entry.css', + name: 'entry.css', input: false, }; @@ -79,7 +79,7 @@ describe('worker', () => { it('should emit minimizer error', async () => { const options = { - file: 'entry.css', + name: 'entry.css', input: false, minify: () => { return { error: new Error('css minimizer error') };