Skip to content

Commit 84e367b

Browse files
fix: compatibility with webpack@5
1 parent 506fe12 commit 84e367b

8 files changed

+476
-270
lines changed

package-lock.json

Lines changed: 277 additions & 191 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
},
5050
"devDependencies": {
5151
"@babel/cli": "^7.10.5",
52-
"@babel/core": "^7.11.1",
52+
"@babel/core": "^7.11.4",
5353
"@babel/preset-env": "^7.11.0",
54-
"@commitlint/cli": "^9.1.2",
54+
"@commitlint/cli": "^10.0.0",
5555
"@commitlint/config-conventional": "^10.0.0",
5656
"@gfx/zopfli": "^1.0.15",
5757
"@webpack-contrib/defaults": "^6.3.0",
@@ -65,7 +65,7 @@
6565
"eslint-plugin-import": "^2.22.0",
6666
"file-loader": "^6.0.0",
6767
"husky": "^4.2.5",
68-
"jest": "^26.4.0",
68+
"jest": "^26.4.1",
6969
"lint-staged": "^10.2.11",
7070
"memfs": "^3.2.0",
7171
"npm-run-all": "^4.1.5",

src/Webpack4Cache.js

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,59 @@ import findCacheDir from 'find-cache-dir';
55
import serialize from 'serialize-javascript';
66

77
export default class Webpack4Cache {
8-
constructor(compilation, options) {
9-
this.cacheDir =
8+
constructor(compilation, options, weakCache) {
9+
this.cache =
1010
options.cache === true
1111
? Webpack4Cache.getCacheDirectory()
1212
: options.cache;
13+
this.weakCache = weakCache;
1314
}
1415

1516
static getCacheDirectory() {
1617
return findCacheDir({ name: 'compression-webpack-plugin' }) || os.tmpdir();
1718
}
1819

19-
isEnabled() {
20-
return Boolean(this.cacheDir);
21-
}
20+
async get(task, sources) {
21+
const weakOutput = this.weakCache.get(task.assetSource);
22+
23+
if (weakOutput) {
24+
return weakOutput;
25+
}
26+
27+
if (!this.cache) {
28+
// eslint-disable-next-line no-undefined
29+
return undefined;
30+
}
2231

23-
async get(task) {
2432
// eslint-disable-next-line no-param-reassign
2533
task.cacheIdent = task.cacheIdent || serialize(task.cacheKeys);
2634

2735
let cachedResult;
2836

2937
try {
30-
cachedResult = await cacache.get(this.cacheDir, task.cacheIdent);
38+
cachedResult = await cacache.get(this.cache, task.cacheIdent);
3139
} catch (ignoreError) {
3240
// eslint-disable-next-line no-undefined
3341
return undefined;
3442
}
3543

36-
return Buffer.from(JSON.parse(cachedResult.data).data);
44+
return new sources.RawSource(
45+
Buffer.from(JSON.parse(cachedResult.data).data)
46+
);
3747
}
3848

3949
async store(task) {
40-
return cacache.put(
41-
this.cacheDir,
42-
task.cacheIdent,
43-
JSON.stringify(task.output)
44-
);
50+
if (!this.weakCache.has(task.assetSource)) {
51+
this.weakCache.set(task.assetSource, task.output);
52+
}
53+
54+
if (!this.cache) {
55+
// eslint-disable-next-line no-undefined
56+
return undefined;
57+
}
58+
59+
const { cacheIdent, output } = task;
60+
61+
return cacache.put(this.cache, cacheIdent, JSON.stringify(output.source()));
4562
}
4663
}

src/Webpack5Cache.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
export default class Cache {
2-
// eslint-disable-next-line no-unused-vars
3-
constructor(compilation, ignored) {
2+
constructor(compilation) {
43
this.cache = compilation.getCache('CompressionWebpackPlugin');
54
}
65

7-
// eslint-disable-next-line class-methods-use-this
8-
isEnabled() {
9-
return true;
10-
}
11-
126
async get(task) {
137
// eslint-disable-next-line no-param-reassign
148
task.eTag = task.eTag || this.cache.getLazyHashedEtag(task.assetSource);

src/index.js

Lines changed: 40 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ import crypto from 'crypto';
77
import url from 'url';
88
import path from 'path';
99

10-
import RawSource from 'webpack-sources/lib/RawSource';
11-
import { ModuleFilenameHelpers, version as webpackVersion } from 'webpack';
10+
import webpack, {
11+
ModuleFilenameHelpers,
12+
version as webpackVersion,
13+
} from 'webpack';
1214
import validateOptions from 'schema-utils';
1315

1416
import schema from './options.json';
1517

18+
const { RawSource } =
19+
// eslint-disable-next-line global-require
20+
webpack.sources || require('webpack-sources');
21+
1622
class CompressionPlugin {
1723
constructor(options = {}) {
1824
validateOptions(schema, options, {
@@ -203,29 +209,20 @@ class CompressionPlugin {
203209
yield task;
204210
}
205211

206-
afterTask(compilation, task, weakCache) {
212+
afterTask(compilation, task) {
207213
const { output, input } = task;
208214

209-
if (output.length / input.length > this.options.minRatio) {
215+
if (output.source().length / input.length > this.options.minRatio) {
210216
return;
211217
}
212218

213219
const { assetSource, assetName } = task;
214-
215-
let weakOutput = weakCache.get(assetSource);
216-
217-
if (!weakOutput) {
218-
weakOutput = new RawSource(output);
219-
220-
weakCache.set(assetSource, weakOutput);
221-
}
222-
223220
const newAssetName = CompressionPlugin.interpolateName(
224221
assetName,
225222
this.options.filename
226223
);
227224

228-
CompressionPlugin.emitAsset(compilation, newAssetName, weakOutput, {
225+
CompressionPlugin.emitAsset(compilation, newAssetName, output, {
229226
compressed: true,
230227
});
231228

@@ -241,28 +238,15 @@ class CompressionPlugin {
241238

242239
async runTasks(compilation, assetNames, CacheEngine, weakCache) {
243240
const scheduledTasks = [];
244-
const cache = new CacheEngine(compilation, {
245-
cache: this.options.cache,
246-
});
241+
const cache = new CacheEngine(
242+
compilation,
243+
{
244+
cache: this.options.cache,
245+
},
246+
weakCache
247+
);
247248

248249
for (const assetName of assetNames) {
249-
const enqueue = async (task) => {
250-
try {
251-
// eslint-disable-next-line no-param-reassign
252-
task.output = await this.compress(task.input);
253-
} catch (error) {
254-
compilation.errors.push(error);
255-
256-
return;
257-
}
258-
259-
if (cache.isEnabled()) {
260-
await cache.store(task);
261-
}
262-
263-
this.afterTask(compilation, task, weakCache);
264-
};
265-
266250
scheduledTasks.push(
267251
(async () => {
268252
const task = this.getTask(compilation, assetName).next().value;
@@ -271,23 +255,24 @@ class CompressionPlugin {
271255
return Promise.resolve();
272256
}
273257

274-
if (cache.isEnabled()) {
258+
task.output = await cache.get(task, { RawSource });
259+
260+
if (!task.output) {
275261
try {
276-
task.output = await cache.get(task);
277-
} catch (ignoreError) {
278-
return enqueue(task);
279-
}
262+
// eslint-disable-next-line no-param-reassign
263+
task.output = new RawSource(await this.compress(task.input));
264+
} catch (error) {
265+
compilation.errors.push(error);
280266

281-
if (!task.output) {
282-
return enqueue(task);
267+
return Promise.resolve();
283268
}
284269

285-
this.afterTask(compilation, task, weakCache);
286-
287-
return Promise.resolve();
270+
await cache.store(task);
288271
}
289272

290-
return enqueue(task);
273+
this.afterTask(compilation, task);
274+
275+
return Promise.resolve();
291276
})()
292277
);
293278
}
@@ -306,8 +291,12 @@ class CompressionPlugin {
306291
undefined,
307292
this.options
308293
);
309-
const weakCache = new WeakMap();
310-
const compressionFn = async (compilation, CacheEngine, assets) => {
294+
const compressionFn = async (
295+
compilation,
296+
assets,
297+
CacheEngine,
298+
weakCache
299+
) => {
311300
const assetNames = Object.keys(
312301
typeof assets === 'undefined' ? compilation.assets : assets
313302
).filter((assetName) => matchObject(assetName));
@@ -324,11 +313,11 @@ class CompressionPlugin {
324313
if (CompressionPlugin.isWebpack4()) {
325314
// eslint-disable-next-line global-require
326315
const CacheEngine = require('./Webpack4Cache').default;
316+
const weakCache = new WeakMap();
327317

328-
compiler.hooks.emit.tapPromise(
329-
{ name: pluginName },
318+
compiler.hooks.emit.tapPromise({ name: pluginName }, (compilation) =>
330319
// eslint-disable-next-line no-undefined
331-
(compilation) => compressionFn(compilation, CacheEngine)
320+
compressionFn(compilation, undefined, CacheEngine, weakCache)
332321
);
333322
} else {
334323
// eslint-disable-next-line global-require
@@ -343,7 +332,7 @@ class CompressionPlugin {
343332
name: pluginName,
344333
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER,
345334
},
346-
(assets) => compressionFn(compilation, CacheEngine, assets)
335+
(assets) => compressionFn(compilation, assets, CacheEngine)
347336
);
348337

349338
compilation.hooks.statsPrinter.tap(pluginName, (stats) => {

test/CompressionPlugin.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,34 @@ describe('CompressionPlugin', () => {
213213
resolve();
214214
});
215215
});
216+
217+
it('should work in watch mode when "cache" is "false"', async () => {
218+
if (getCompiler.isWebpack4()) {
219+
expect(true).toBe(true);
220+
} else {
221+
const compiler = getCompiler('./entry.js', {
222+
cache: false,
223+
});
224+
225+
new CompressionPlugin().apply(compiler);
226+
227+
const stats = await compile(compiler);
228+
229+
expect(stats.compilation.emittedAssets.size).toBe(7);
230+
expect(getAssetsNameAndSize(stats)).toMatchSnapshot('assets');
231+
expect(getWarnings(stats)).toMatchSnapshot('errors');
232+
expect(getErrors(stats)).toMatchSnapshot('warnings');
233+
234+
await new Promise(async (resolve) => {
235+
const newStats = await compile(compiler);
236+
237+
expect(newStats.compilation.emittedAssets.size).toBe(0);
238+
expect(getAssetsNameAndSize(newStats)).toMatchSnapshot('assets');
239+
expect(getWarnings(newStats)).toMatchSnapshot('errors');
240+
expect(getErrors(newStats)).toMatchSnapshot('warnings');
241+
242+
resolve();
243+
});
244+
}
245+
});
216246
});

0 commit comments

Comments
 (0)