Skip to content

Commit 83a8ee5

Browse files
authored
fix: preserve compiler paths for shared plugin instances (#725)
* fix: preserve compiler paths for shared plugin instances * refactor: require explicit compiler argument in report methods
1 parent 97d2ef8 commit 83a8ee5

4 files changed

Lines changed: 77 additions & 25 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack-bundle-analyzer": patch
3+
---
4+
5+
Resolve bundle assets and report files against the correct compiler output path when a plugin instance is shared by multiple compilers.

‎src/BundleAnalyzerPlugin.js‎

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ class BundleAnalyzerPlugin {
127127

128128
if (this.opts.generateStatsFile) {
129129
actions.push(() =>
130-
this.generateStatsFile(stats.toJson(this.opts.statsOptions)),
130+
this.generateStatsFile(
131+
stats.toJson(this.opts.statsOptions),
132+
compiler,
133+
),
131134
);
132135
}
133136

@@ -138,15 +141,21 @@ class BundleAnalyzerPlugin {
138141

139142
if (this.opts.analyzerMode === "server") {
140143
actions.push(() =>
141-
this.startAnalyzerServer(stats.toJson(analyzerStatsOptions)),
144+
this.startAnalyzerServer(
145+
stats.toJson(analyzerStatsOptions),
146+
compiler,
147+
),
142148
);
143149
} else if (this.opts.analyzerMode === "static") {
144150
actions.push(() =>
145-
this.generateStaticReport(stats.toJson(analyzerStatsOptions)),
151+
this.generateStaticReport(
152+
stats.toJson(analyzerStatsOptions),
153+
compiler,
154+
),
146155
);
147156
} else if (this.opts.analyzerMode === "json") {
148157
actions.push(() =>
149-
this.generateJSONReport(stats.toJson(analyzerStatsOptions)),
158+
this.generateJSONReport(stats.toJson(analyzerStatsOptions), compiler),
150159
);
151160
}
152161

@@ -175,12 +184,12 @@ class BundleAnalyzerPlugin {
175184

176185
/**
177186
* @param {StatsCompilation} stats stats
187+
* @param {Compiler} compiler compiler
178188
* @returns {Promise<void>}
179189
*/
180-
async generateStatsFile(stats) {
190+
async generateStatsFile(stats, compiler) {
181191
const statsFilepath = path.resolve(
182-
/** @type {Compiler} */
183-
(this.compiler).outputPath,
192+
compiler.outputPath,
184193
this.opts.statsFilename,
185194
);
186195
await fs.promises.mkdir(path.dirname(statsFilepath), { recursive: true });
@@ -200,19 +209,23 @@ class BundleAnalyzerPlugin {
200209

201210
/**
202211
* @param {StatsCompilation} stats stats
212+
* @param {Compiler} compiler compiler
203213
* @returns {Promise<void>}
204214
*/
205-
async startAnalyzerServer(stats) {
215+
async startAnalyzerServer(stats, compiler) {
206216
if (this.server) {
207-
(await this.server).updateChartData(stats);
217+
(await this.server).updateChartData(
218+
stats,
219+
this.getBundleDirFromCompiler(compiler),
220+
);
208221
} else {
209222
this.server = viewer.startServer(stats, {
210223
openBrowser: this.opts.openAnalyzer,
211224
host: this.opts.analyzerHost,
212225
port: this.opts.analyzerPort,
213226
reportTitle: this.opts.reportTitle,
214227
compressionAlgorithm: this.opts.compressionAlgorithm,
215-
bundleDir: this.getBundleDirFromCompiler(),
228+
bundleDir: this.getBundleDirFromCompiler(compiler),
216229
logger: this.logger,
217230
defaultSizes: this.opts.defaultSizes,
218231
excludeAssets: this.opts.excludeAssets,
@@ -223,50 +236,54 @@ class BundleAnalyzerPlugin {
223236

224237
/**
225238
* @param {StatsCompilation} stats stats
239+
* @param {Compiler} compiler compiler
226240
* @returns {Promise<void>}
227241
*/
228-
async generateJSONReport(stats) {
242+
async generateJSONReport(stats, compiler) {
229243
await viewer.generateJSONReport(stats, {
230244
reportFilename: path.resolve(
231-
/** @type {Compiler} */
232-
(this.compiler).outputPath,
245+
compiler.outputPath,
233246
this.opts.reportFilename || "report.json",
234247
),
235248
compressionAlgorithm: this.opts.compressionAlgorithm,
236-
bundleDir: this.getBundleDirFromCompiler(),
249+
bundleDir: this.getBundleDirFromCompiler(compiler),
237250
logger: this.logger,
238251
excludeAssets: this.opts.excludeAssets,
239252
});
240253
}
241254

242255
/**
243256
* @param {StatsCompilation} stats stats
257+
* @param {Compiler} compiler compiler
244258
* @returns {Promise<void>}
245259
*/
246-
async generateStaticReport(stats) {
260+
async generateStaticReport(stats, compiler) {
247261
await viewer.generateReport(stats, {
248262
openBrowser: this.opts.openAnalyzer,
249263
reportFilename: path.resolve(
250-
/** @type {Compiler} */
251-
(this.compiler).outputPath,
264+
compiler.outputPath,
252265
this.opts.reportFilename || "report.html",
253266
),
254267
reportTitle: this.opts.reportTitle,
255268
compressionAlgorithm: this.opts.compressionAlgorithm,
256-
bundleDir: this.getBundleDirFromCompiler(),
269+
bundleDir: this.getBundleDirFromCompiler(compiler),
257270
logger: this.logger,
258271
defaultSizes: this.opts.defaultSizes,
259272
excludeAssets: this.opts.excludeAssets,
260273
});
261274
}
262275

263-
getBundleDirFromCompiler() {
276+
/**
277+
* @param {Compiler} compiler compiler
278+
* @returns {string | null} bundle directory
279+
*/
280+
getBundleDirFromCompiler(compiler) {
264281
const outputFileSystemConstructor =
265282
/** @type {OutputFileSystem} */
266-
(/** @type {Compiler} */ (this.compiler).outputFileSystem).constructor;
283+
(compiler.outputFileSystem).constructor;
267284

268285
if (typeof outputFileSystemConstructor === "undefined") {
269-
return /** @type {Compiler} */ (this.compiler).outputPath;
286+
return compiler.outputPath;
270287
}
271288
switch (outputFileSystemConstructor.name) {
272289
case "MemoryFileSystem":
@@ -276,7 +293,7 @@ class BundleAnalyzerPlugin {
276293
case "AsyncMFS":
277294
return null;
278295
default:
279-
return /** @type {Compiler} */ (this.compiler).outputPath;
296+
return compiler.outputPath;
280297
}
281298
}
282299
}

‎src/viewer.js‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ function getChartData(analyzerOpts, bundleStats, bundleDir) {
115115
* @property {AnalyzerUrl} analyzerUrl analyzer url
116116
*/
117117

118-
/** @typedef {{ ws: WebSocketServer, http: Server, updateChartData: (bundleStats: StatsCompilation) => void }} ViewerServerObj */
118+
/** @typedef {{ ws: WebSocketServer, http: Server, updateChartData: (bundleStats: StatsCompilation, bundleDir?: string | null) => void }} ViewerServerObj */
119119

120120
/**
121121
* @param {StatsCompilation} bundleStats bundle stats
@@ -207,9 +207,14 @@ async function startServer(bundleStats, opts) {
207207

208208
/**
209209
* @param {StatsCompilation} bundleStats bundle stats
210+
* @param {string | null=} updatedBundleDir bundle directory
210211
*/
211-
function updateChartData(bundleStats) {
212-
const newChartData = getChartData(analyzerOpts, bundleStats, bundleDir);
212+
function updateChartData(bundleStats, updatedBundleDir = bundleDir) {
213+
const newChartData = getChartData(
214+
analyzerOpts,
215+
bundleStats,
216+
updatedBundleDir,
217+
);
213218

214219
if (!newChartData) return;
215220

‎test/plugin.js‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,31 @@ describe("Plugin", () => {
129129
expect(chartData).toBeDefined();
130130
});
131131

132+
it("should use each compiler output path when a plugin instance is reused", async () => {
133+
const plugin = new BundleAnalyzerPlugin({
134+
analyzerMode: "json",
135+
logLevel: "error",
136+
});
137+
const firstConfig = makeWebpackConfig();
138+
const secondConfig = makeWebpackConfig();
139+
140+
firstConfig.output.path = path.resolve(__dirname, "./output/first");
141+
firstConfig.plugins = [plugin];
142+
secondConfig.output.path = path.resolve(__dirname, "./output/second");
143+
secondConfig.plugins = [plugin];
144+
145+
await webpackCompile([firstConfig, secondConfig]);
146+
147+
for (const output of ["first", "second"]) {
148+
const reportPath = path.resolve(
149+
__dirname,
150+
`./output/${output}/report.json`,
151+
);
152+
expect(fs.existsSync(reportPath)).toBe(true);
153+
expect(JSON.parse(fs.readFileSync(reportPath, "utf8"))).not.toEqual([]);
154+
}
155+
});
156+
132157
it("should support webpack config with `multi` module", async () => {
133158
const config = makeWebpackConfig();
134159

0 commit comments

Comments
 (0)