Skip to content

Commit

Permalink
perf: fix
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored Dec 18, 2020
1 parent 5d54128 commit 8f3fadb
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 90 deletions.
157 changes: 76 additions & 81 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,86 +104,72 @@ class CompressionPlugin {

async compress(compiler, compilation, assets) {
const cache = compilation.getCache("CompressionWebpackPlugin");
const assetsForMinify = await Promise.all(
Object.keys(assets).reduce((accumulator, name) => {
const { info, source } = compilation.getAsset(name);
const assetsForMinify = (
await Promise.all(
Object.keys(assets).map(async (name) => {
const { info, source } = compilation.getAsset(name);

// Skip double minimize assets from child compilation
if (info.compressed) {
return accumulator;
}

if (
!compiler.webpack.ModuleFilenameHelpers.matchObject.bind(
// eslint-disable-next-line no-undefined
undefined,
this.options
)(name)
) {
return accumulator;
}

let input = source.source();
if (info.compressed) {
return false;
}

if (!Buffer.isBuffer(input)) {
input = Buffer.from(input);
}
if (
!compiler.webpack.ModuleFilenameHelpers.matchObject.bind(
// eslint-disable-next-line no-undefined
undefined,
this.options
)(name)
) {
return false;
}

if (input.length < this.options.threshold) {
return accumulator;
}
let relatedName;

let relatedName;
if (typeof this.options.algorithm === "function") {
let filenameForRelatedName = this.options.filename;

if (typeof this.options.algorithm === "function") {
let filenameForRelatedName = this.options.filename;
const index = filenameForRelatedName.indexOf("?");

const index = filenameForRelatedName.lastIndexOf("?");
if (index >= 0) {
filenameForRelatedName = filenameForRelatedName.substr(0, index);
}

if (index >= 0) {
filenameForRelatedName = filenameForRelatedName.substr(0, index);
relatedName = `${path.extname(filenameForRelatedName).slice(1)}ed`;
} else if (this.options.algorithm === "gzip") {
relatedName = "gzipped";
} else {
relatedName = `${this.options.algorithm}ed`;
}

relatedName = `${path.extname(filenameForRelatedName).slice(1)}ed`;
} else if (this.options.algorithm === "gzip") {
relatedName = "gzipped";
} else {
relatedName = `${this.options.algorithm}ed`;
}
if (info.related && info.related[relatedName]) {
return false;
}

if (info.related && info.related[relatedName]) {
return accumulator;
}
const cacheItem = cache.getItemCache(
serialize({
name,
algorithm: this.options.algorithm,
compressionOptions: this.options.compressionOptions,
}),
cache.getLazyHashedEtag(source)
);
const output = (await cacheItem.getPromise()) || {};

const eTag = cache.getLazyHashedEtag(source);
const cacheItem = cache.getItemCache(
serialize({
name,
algorithm: this.options.algorithm,
compressionOptions: this.options.compressionOptions,
}),
eTag
);
let buffer;

accumulator.push(
(async () => {
const output = await cacheItem.getPromise();
// No need original buffer for cached files
if (!output.source) {
buffer = source.buffer();

return {
name,
inputSource: source,
info,
input,
output,
cacheItem,
relatedName,
};
})()
);
if (buffer.length < this.options.threshold) {
return false;
}
}

return accumulator;
}, [])
);
return { name, source, info, buffer, output, cacheItem, relatedName };
})
)
).filter((assetForMinify) => Boolean(assetForMinify));

const { RawSource } = compiler.webpack.sources;
const scheduledTasks = [];
Expand All @@ -193,28 +179,37 @@ class CompressionPlugin {
(async () => {
const {
name,
inputSource,
input,
source,
buffer,
output,
cacheItem,
info,
relatedName,
} = asset;
let { output } = asset;

if (!output) {
try {
output = new RawSource(await this.runCompressionAlgorithm(input));
} catch (error) {
compilation.errors.push(error);
if (!output.source) {
if (!output.compressed) {
try {
output.compressed = await this.runCompressionAlgorithm(buffer);
} catch (error) {
compilation.errors.push(error);

return;
}
}

if (
output.compressed.length / buffer.length >
this.options.minRatio
) {
await cacheItem.storePromise({ compressed: output.compressed });

return;
}

await cacheItem.storePromise(output);
}
output.source = new RawSource(output.compressed);

if (output.source().length / input.length > this.options.minRatio) {
return;
await cacheItem.storePromise(output);
}

const match = /^([^?#]*)(\?[^#]*)?(#.*)?$/.exec(name);
Expand Down Expand Up @@ -260,19 +255,19 @@ class CompressionPlugin {

if (this.options.deleteOriginalAssets) {
if (this.options.deleteOriginalAssets === "keep-source-map") {
compilation.updateAsset(name, inputSource, {
compilation.updateAsset(name, source, {
related: { sourceMap: null },
});
}

compilation.deleteAsset(name);
} else {
compilation.updateAsset(name, inputSource, {
compilation.updateAsset(name, source, {
related: { [relatedName]: newName },
});
}

compilation.emitAsset(newName, output, newInfo);
compilation.emitAsset(newName, output.source, newInfo);
})()
);
}
Expand Down
51 changes: 50 additions & 1 deletion test/CompressionPlugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,56 @@ describe("CompressionPlugin", () => {
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");

new ModifyExistingAsset({ name: "main.js" }).apply(compiler);
new ModifyExistingAsset({
name: "main.js",
content: "function changed() { /*! CHANGED */ }",
}).apply(compiler);

await new Promise(async (resolve) => {
const newStats = await compile(compiler);

expect(newStats.compilation.emittedAssets.size).toBe(2);

expect(getAssetsNameAndSize(newStats, compiler)).toMatchSnapshot(
"assets"
);
expect(getWarnings(newStats)).toMatchSnapshot("errors");
expect(getErrors(newStats)).toMatchSnapshot("warnings");

resolve();
});
});

it('should work and use memory cache when the "cache" option is "true" and the asset has been changed which filtered by the "minRation" option', async () => {
const compiler = getCompiler(
"./entry.js",
{
name: "[name].[ext]",
},
{
cache: true,
output: {
path: path.resolve(__dirname, "./outputs"),
filename: "[name].js",
chunkFilename: "[id].js",
},
}
);

new CompressionPlugin().apply(compiler);

const stats = await compile(compiler);

expect(stats.compilation.emittedAssets.size).toBe(7);

expect(getAssetsNameAndSize(stats, compiler)).toMatchSnapshot("assets");
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");

new ModifyExistingAsset({
name: "icon.png",
content: `1q!Q2w@W3e#e4r$r`.repeat(1000),
}).apply(compiler);

await new Promise(async (resolve) => {
const newStats = await compile(compiler);
Expand Down
Loading

0 comments on commit 8f3fadb

Please sign in to comment.