diff --git a/.changeset/calm-compilers-report.md b/.changeset/calm-compilers-report.md new file mode 100644 index 00000000..4fad95d3 --- /dev/null +++ b/.changeset/calm-compilers-report.md @@ -0,0 +1,5 @@ +--- +"webpack-bundle-analyzer": patch +--- + +Resolve bundle assets and report files against the correct compiler output path when a plugin instance is shared by multiple compilers. diff --git a/src/BundleAnalyzerPlugin.js b/src/BundleAnalyzerPlugin.js index 3dada6fb..00229a11 100644 --- a/src/BundleAnalyzerPlugin.js +++ b/src/BundleAnalyzerPlugin.js @@ -127,7 +127,10 @@ class BundleAnalyzerPlugin { if (this.opts.generateStatsFile) { actions.push(() => - this.generateStatsFile(stats.toJson(this.opts.statsOptions)), + this.generateStatsFile( + stats.toJson(this.opts.statsOptions), + compiler, + ), ); } @@ -138,15 +141,21 @@ class BundleAnalyzerPlugin { if (this.opts.analyzerMode === "server") { actions.push(() => - this.startAnalyzerServer(stats.toJson(analyzerStatsOptions)), + this.startAnalyzerServer( + stats.toJson(analyzerStatsOptions), + compiler, + ), ); } else if (this.opts.analyzerMode === "static") { actions.push(() => - this.generateStaticReport(stats.toJson(analyzerStatsOptions)), + this.generateStaticReport( + stats.toJson(analyzerStatsOptions), + compiler, + ), ); } else if (this.opts.analyzerMode === "json") { actions.push(() => - this.generateJSONReport(stats.toJson(analyzerStatsOptions)), + this.generateJSONReport(stats.toJson(analyzerStatsOptions), compiler), ); } @@ -175,12 +184,12 @@ class BundleAnalyzerPlugin { /** * @param {StatsCompilation} stats stats + * @param {Compiler} compiler compiler * @returns {Promise} */ - async generateStatsFile(stats) { + async generateStatsFile(stats, compiler) { const statsFilepath = path.resolve( - /** @type {Compiler} */ - (this.compiler).outputPath, + compiler.outputPath, this.opts.statsFilename, ); await fs.promises.mkdir(path.dirname(statsFilepath), { recursive: true }); @@ -200,11 +209,15 @@ class BundleAnalyzerPlugin { /** * @param {StatsCompilation} stats stats + * @param {Compiler} compiler compiler * @returns {Promise} */ - async startAnalyzerServer(stats) { + async startAnalyzerServer(stats, compiler) { if (this.server) { - (await this.server).updateChartData(stats); + (await this.server).updateChartData( + stats, + this.getBundleDirFromCompiler(compiler), + ); } else { this.server = viewer.startServer(stats, { openBrowser: this.opts.openAnalyzer, @@ -212,7 +225,7 @@ class BundleAnalyzerPlugin { port: this.opts.analyzerPort, reportTitle: this.opts.reportTitle, compressionAlgorithm: this.opts.compressionAlgorithm, - bundleDir: this.getBundleDirFromCompiler(), + bundleDir: this.getBundleDirFromCompiler(compiler), logger: this.logger, defaultSizes: this.opts.defaultSizes, excludeAssets: this.opts.excludeAssets, @@ -223,17 +236,17 @@ class BundleAnalyzerPlugin { /** * @param {StatsCompilation} stats stats + * @param {Compiler} compiler compiler * @returns {Promise} */ - async generateJSONReport(stats) { + async generateJSONReport(stats, compiler) { await viewer.generateJSONReport(stats, { reportFilename: path.resolve( - /** @type {Compiler} */ - (this.compiler).outputPath, + compiler.outputPath, this.opts.reportFilename || "report.json", ), compressionAlgorithm: this.opts.compressionAlgorithm, - bundleDir: this.getBundleDirFromCompiler(), + bundleDir: this.getBundleDirFromCompiler(compiler), logger: this.logger, excludeAssets: this.opts.excludeAssets, }); @@ -241,32 +254,36 @@ class BundleAnalyzerPlugin { /** * @param {StatsCompilation} stats stats + * @param {Compiler} compiler compiler * @returns {Promise} */ - async generateStaticReport(stats) { + async generateStaticReport(stats, compiler) { await viewer.generateReport(stats, { openBrowser: this.opts.openAnalyzer, reportFilename: path.resolve( - /** @type {Compiler} */ - (this.compiler).outputPath, + compiler.outputPath, this.opts.reportFilename || "report.html", ), reportTitle: this.opts.reportTitle, compressionAlgorithm: this.opts.compressionAlgorithm, - bundleDir: this.getBundleDirFromCompiler(), + bundleDir: this.getBundleDirFromCompiler(compiler), logger: this.logger, defaultSizes: this.opts.defaultSizes, excludeAssets: this.opts.excludeAssets, }); } - getBundleDirFromCompiler() { + /** + * @param {Compiler} compiler compiler + * @returns {string | null} bundle directory + */ + getBundleDirFromCompiler(compiler) { const outputFileSystemConstructor = /** @type {OutputFileSystem} */ - (/** @type {Compiler} */ (this.compiler).outputFileSystem).constructor; + (compiler.outputFileSystem).constructor; if (typeof outputFileSystemConstructor === "undefined") { - return /** @type {Compiler} */ (this.compiler).outputPath; + return compiler.outputPath; } switch (outputFileSystemConstructor.name) { case "MemoryFileSystem": @@ -276,7 +293,7 @@ class BundleAnalyzerPlugin { case "AsyncMFS": return null; default: - return /** @type {Compiler} */ (this.compiler).outputPath; + return compiler.outputPath; } } } diff --git a/src/viewer.js b/src/viewer.js index 2b372516..4484b145 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -115,7 +115,7 @@ function getChartData(analyzerOpts, bundleStats, bundleDir) { * @property {AnalyzerUrl} analyzerUrl analyzer url */ -/** @typedef {{ ws: WebSocketServer, http: Server, updateChartData: (bundleStats: StatsCompilation) => void }} ViewerServerObj */ +/** @typedef {{ ws: WebSocketServer, http: Server, updateChartData: (bundleStats: StatsCompilation, bundleDir?: string | null) => void }} ViewerServerObj */ /** * @param {StatsCompilation} bundleStats bundle stats @@ -207,9 +207,14 @@ async function startServer(bundleStats, opts) { /** * @param {StatsCompilation} bundleStats bundle stats + * @param {string | null=} updatedBundleDir bundle directory */ - function updateChartData(bundleStats) { - const newChartData = getChartData(analyzerOpts, bundleStats, bundleDir); + function updateChartData(bundleStats, updatedBundleDir = bundleDir) { + const newChartData = getChartData( + analyzerOpts, + bundleStats, + updatedBundleDir, + ); if (!newChartData) return; diff --git a/test/plugin.js b/test/plugin.js index 39b56baa..1a7547ef 100644 --- a/test/plugin.js +++ b/test/plugin.js @@ -129,6 +129,31 @@ describe("Plugin", () => { expect(chartData).toBeDefined(); }); + it("should use each compiler output path when a plugin instance is reused", async () => { + const plugin = new BundleAnalyzerPlugin({ + analyzerMode: "json", + logLevel: "error", + }); + const firstConfig = makeWebpackConfig(); + const secondConfig = makeWebpackConfig(); + + firstConfig.output.path = path.resolve(__dirname, "./output/first"); + firstConfig.plugins = [plugin]; + secondConfig.output.path = path.resolve(__dirname, "./output/second"); + secondConfig.plugins = [plugin]; + + await webpackCompile([firstConfig, secondConfig]); + + for (const output of ["first", "second"]) { + const reportPath = path.resolve( + __dirname, + `./output/${output}/report.json`, + ); + expect(fs.existsSync(reportPath)).toBe(true); + expect(JSON.parse(fs.readFileSync(reportPath, "utf8"))).not.toEqual([]); + } + }); + it("should support webpack config with `multi` module", async () => { const config = makeWebpackConfig();