Skip to content

Commit a102dd0

Browse files
fix: a minimizer named by path keeps its helpers and its own identity
The helpers are on the loaded function, so a module reference ran at the default stage and its flag never reached stats; and two paths reporting no version shared one cache entry.
1 parent 2575275 commit a102dd0

6 files changed

Lines changed: 115 additions & 25 deletions

File tree

‎src/index.js‎

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ class MinimizerPlugin {
659659
* @param {Compiler} compiler compiler
660660
* @param {Compilation} compilation compilation
661661
* @param {Record<string, import("webpack").sources.Source>} assets assets
662-
* @param {{ availableNumberOfCores: number, only?: number[], cacheSuffix?: string, written: Map<string, Set<string>> }} optimizeOptions how many may run at once, which minimizers this pass runs, what keeps its cache apart from another pass over the same asset, and what an earlier pass of this plugin already wrote onto each asset
662+
* @param {{ availableNumberOfCores: number, only?: number[], cacheSuffix?: string, written: Map<string, Set<string>> }} optimizeOptions how many may run at once, which minimizers this pass runs, what keeps its cache apart from another pass over the same asset and from a run under different minimizers, and what an earlier pass of this plugin already wrote onto each asset
663663
* @returns {Promise<void>}
664664
*/
665665
async optimize(compiler, compilation, assets, optimizeOptions) {
@@ -1537,11 +1537,10 @@ class MinimizerPlugin {
15371537
assetFlags() {
15381538
const flags = new Set();
15391539

1540-
for (const flag of declaredFlags(
1541-
this.options.minimizer.implementation,
1542-
"minimized",
1543-
)) {
1544-
flags.add(flag);
1540+
for (const { fn } of this.getMinimizerSlots()) {
1541+
for (const flag of declaredFlags(fn, "minimized")) {
1542+
flags.add(flag);
1543+
}
15451544
}
15461545

15471546
// Only the generators that write a file: an `import` one rewrites a module
@@ -1915,16 +1914,15 @@ class MinimizerPlugin {
19151914
* @returns {Map<number, number[]>} the indices, by stage
19161915
*/
19171916
minimizersByStage(compiler) {
1918-
const { implementation } = this.options.minimizer;
1919-
const each = Array.isArray(implementation)
1920-
? implementation
1921-
: [implementation];
1917+
// The loaded functions rather than what was configured: a module reference
1918+
// carries none of the helpers that say where its minimizer runs.
1919+
const each = this.getMinimizerSlots();
19221920
const fallback = this.defaultStage(compiler);
19231921
/** @type {Map<number, number[]>} */
19241922
const byStage = new Map();
19251923

19261924
for (let i = 0; i < each.length; i++) {
1927-
const asked = declaredStage(compiler, each[i]);
1925+
const asked = declaredStage(compiler, each[i].fn);
19281926
const at = typeof asked === "number" ? asked : fallback;
19291927
const already = byStage.get(at);
19301928

@@ -2419,20 +2417,22 @@ class MinimizerPlugin {
24192417
const getVersion = (impl) => {
24202418
// Path refs need a load; functions already carry helpers. Preset maps
24212419
// and other shapes are not a single minimizer — keep the prior "0.0.0".
2420+
const ref = getImplementationModuleRef(impl);
24222421
const fn =
24232422
typeof impl === "function"
24242423
? impl
2425-
: getImplementationModuleRef(impl)
2424+
: ref
24262425
? loadImplementation(impl)
24272426
: undefined;
2428-
2429-
if (!fn) {
2430-
return "0.0.0";
2431-
}
2432-
2433-
return typeof fn.getMinimizerVersion !== "undefined"
2434-
? fn.getMinimizerVersion() || "0.0.0"
2435-
: "0.0.0";
2427+
const version =
2428+
fn && typeof fn.getMinimizerVersion !== "undefined"
2429+
? fn.getMinimizerVersion() || "0.0.0"
2430+
: "0.0.0";
2431+
2432+
// Which module it is, not only what version it reports: two paths that
2433+
// report none are otherwise one identity, and a warm cache would answer
2434+
// for whichever ran first.
2435+
return ref ? `${version}|${ref.path}|${ref.export || ""}` : version;
24362436
};
24372437
const data = getSerializeJavascript()({
24382438
minimizer: Array.isArray(this.options.minimizer.implementation)
@@ -2443,6 +2443,11 @@ class MinimizerPlugin {
24432443
),
24442444
options: this.options.minimizer.options,
24452445
});
2446+
const identity = crypto
2447+
.createHash("sha256")
2448+
.update(data)
2449+
.digest("hex")
2450+
.slice(0, 16);
24462451

24472452
hooks.chunkHash.tap(pluginName, (chunk, hash) => {
24482453
// Nothing minifying rewrites nothing, so no name owes it a hash of its
@@ -2563,7 +2568,10 @@ class MinimizerPlugin {
25632568
written,
25642569
// Only where a second pass exists to be confused with: one pass
25652570
// keeps the cache keys every earlier release wrote.
2566-
cacheSuffix: minimizersByStage.size > 1 ? `|${at}` : "",
2571+
// The minimizers and their options answer for what is cached
2572+
// under an asset's name, which otherwise varies only with its
2573+
// source.
2574+
cacheSuffix: `${minimizersByStage.size > 1 ? `|${at}` : ""}|${identity}`,
25672575
}),
25682576
);
25692577
}

‎test/__snapshots__/MinimizerPlugin.test.js.snap‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ exports[`MinimizerPlugin should work and do not use memory cache when the "cache
182182
exports[`MinimizerPlugin should work and generate real content hash: assets 1`] = `
183183
{
184184
"389.__hash3__.__hash4__.__hash2__.js": ""use strict";(self.webpackChunkminimizer_webpack_plugin=self.webpackChunkminimizer_webpack_plugin||[]).push([[389],{389(e,i,p){p.r(i);p.d(i,["default",0,"async-dep"])}}]);",
185-
"app.__hash0__.__hash1__.__hash2__.js": "(()=>{"use strict";var e={};const t={};function r(o){const n=t[o];if(void 0!==n)return n.exports;const i=t[o]={exports:{}};return e[o](i,i.exports,r),i.exports}r.m=e,r.d=(e,t)=>{if(Array.isArray(t))for(var o=0;o<t.length;){var n=t[o++],i=t[o++];r.o(e,n)?0===i&&o++:0===i?Object.defineProperty(e,n,{enumerable:!0,value:t[o++]}):Object.defineProperty(e,n,{enumerable:!0,get:i})}else for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>e+".__hash3__.__hash4__."+r.h()+".js",r.h=()=>"__hash2__",r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{const e={},t="minimizer-webpack-plugin:";r.l=(o,n,i,a)=>{if(e[o])return void e[o].push(n);let c,l;if(void 0!==i){const e=document.getElementsByTagName("script");for(var s=0;s<e.length;s++){const r=e[s];if(r.getAttribute("src")==o||r.getAttribute("data-webpack")==t+i){c=r;break}}}c||(l=!0,c=document.createElement("script"),c.charset="utf-8",r.nc&&c.setAttribute("nonce",r.nc),c.setAttribute("data-webpack",t+i),c.src=o),e[o]=[n];const u=(t,r)=>{c.onerror=c.onload=null,clearTimeout(p);const n=e[o];if(delete e[o],c.parentNode?.removeChild(c),n?.forEach(e=>e(r)),t)return t(r)},p=setTimeout(u.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=u.bind(null,c.onerror),c.onload=u.bind(null,c.onload),l&&document.head.appendChild(c)}})(),r.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{let e;r.g.importScripts&&(e=r.g.location+"");const t=r.g.document;if(!e&&t&&("SCRIPT"===t.currentScript?.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){const r=t.getElementsByTagName("script");if(r.length){let t=r.length-1;for(;t>-1&&(!e||!/^http(s?):/.test(e));)e=r[t--].src}}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\\?.*$/,"").replace(/\\/[^\\/]+$/,"/"),r.p=e})(),(()=>{const e={524:0};r.f.j=(t,o)=>{let n=r.o(e,t)?e[t]:void 0;if(0!==n)if(n)o.push(n[2]);else{const i=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=i);const a=r.p+r.u(t),c=new Error,l=o=>{if(r.o(e,t)&&(n=e[t],0!==n&&(e[t]=void 0),n)){const e=o&&("load"===o.type?"missing":o.type),r=o&&o.target&&o.target.src;c.message="Loading chunk "+t+" failed.\\n("+e+": "+r+")",c.name="ChunkLoadError",c.type=e,c.request=r,c.event=o,n[1](c)}};r.l(a,l,"chunk-"+t,t)}};const t=(t,o)=>{let[n,i,a]=o;var c,l,s=0;if(n.some(t=>0!==e[t])){for(c in i)r.o(i,c)&&(r.m[c]=i[c]);if(a)a(r)}for(t&&t(o);s<n.length;s++)l=n[s],r.o(e,l)&&e[l]&&e[l][0](),e[l]=0},o=self.webpackChunkminimizer_webpack_plugin=self.webpackChunkminimizer_webpack_plugin||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})(),r.e(389).then(r.bind(r,389)).then(()=>{console.log("Good")})})();",
185+
"app.__hash0__.__hash1__.__hash2__.js": "(()=>{"use strict";var e={};const t={};function r(o){const n=t[o];if(void 0!==n)return n.exports;const i=t[o]={exports:{}};return e[o](i,i.exports,r),i.exports}r.m=e,r.d=(e,t)=>{if(Array.isArray(t))for(var o=0;o<t.length;){var n=t[o++],i=t[o++];r.o(e,n)?0===i&&o++:0===i?Object.defineProperty(e,n,{enumerable:!0,value:t[o++]}):Object.defineProperty(e,n,{enumerable:!0,get:i})}else for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>e+".__hash3__.__hash4__."+r.h()+".js",r.h=()=>"__hash2__",r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{const e={},t="minimizer-webpack-plugin:";r.l=(o,n,i,c)=>{if(e[o])return void e[o].push(n);let a,l;if(void 0!==i){const e=document.getElementsByTagName("script");for(var s=0;s<e.length;s++){const r=e[s];if(r.getAttribute("src")==o||r.getAttribute("data-webpack")==t+i){a=r;break}}}a||(l=!0,a=document.createElement("script"),a.charset="utf-8",r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",t+i),a.src=o),e[o]=[n];const u=(t,r)=>{a.onerror=a.onload=null,clearTimeout(p);const n=e[o];if(delete e[o],a.parentNode?.removeChild(a),n?.forEach(e=>e(r)),t)return t(r)},p=setTimeout(u.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=u.bind(null,a.onerror),a.onload=u.bind(null,a.onload),l&&document.head.appendChild(a)}})(),r.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{let e;r.g.importScripts&&(e=r.g.location+"");const t=r.g.document;if(!e&&t&&("SCRIPT"===t.currentScript?.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){const r=t.getElementsByTagName("script");if(r.length){let t=r.length-1;for(;t>-1&&(!e||!/^http(s?):/.test(e));)e=r[t--].src}}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\\?.*$/,"").replace(/\\/[^\\/]+$/,"/"),r.p=e})(),(()=>{const e={524:0};r.f.j=(t,o)=>{let n=r.o(e,t)?e[t]:void 0;if(0!==n)if(n)o.push(n[2]);else{const i=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=i);const c=r.p+r.u(t),a=new Error,l=o=>{if(r.o(e,t)&&(n=e[t],0!==n&&(e[t]=void 0),n)){const e=o&&("load"===o.type?"missing":o.type),r=o&&o.target&&o.target.src;a.message="Loading chunk "+t+" failed.\\n("+e+": "+r+")",a.name="ChunkLoadError",a.type=e,a.request=r,a.event=o,n[1](a)}};r.l(c,l,"chunk-"+t,t)}};const t=(t,o)=>{let[n,i,c]=o;var a,l,s=0;if(n.some(t=>0!==e[t])){for(a in i)r.o(i,a)&&(r.m[a]=i[a]);if(c)c(r)}for(t&&t(o);s<n.length;s++)l=n[s],r.o(e,l)&&e[l]&&e[l][0](),e[l]=0},o=self.webpackChunkminimizer_webpack_plugin=self.webpackChunkminimizer_webpack_plugin||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})(),r.e(389).then(r.bind(r,389)).then(()=>{console.log("Good")})})();",
186186
}
187187
`;
188188

0 commit comments

Comments
 (0)