plugins_analyze_analyzer.js

/**
 * @file src/plugins/analyze/analyzer.js
 * @copyright @spmhome @_2025
 * @author Scott Meesseman @spmeesseman
 *//** */

const { release } = require("os");
const { platform } = require("process");
const WpwAnalyzePlugin = require("./base");
const { execFile } = require("child_process");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

/**
 * @class WpwAnalyzerAnalyzePlugin
 * @augments WpwAnalyzePlugin
 * @since 1.2.1
 */
class WpwAnalyzerAnalyzePlugin extends WpwAnalyzePlugin
{
    /**
	 * @private
     * @type {string}
     */
    reportFile;
    /**
	 * @private
     * @type {string}
     */
    statsFile;


    /**
     * @param {WpwPluginOptions} options Plugin options to be applied
     */
	constructor(options)
	{
		super(options);
        this.buildOptions = /** @type {WpwAnalyzerAnalyzePluginOptions} */(this.buildOptions);
		this.statsFile = this._path_.joinPath(this.build.virtualEntry.dir, "analyzer_stats.html");
		this.reportFile = this._path_.joinPath(this.build.virtualEntry.dir, "analyzer_report.html");
		if (this._fs_.existsSync(this.statsFile)) {
			this._fs_.deleteFileSync(this.statsFile);
		}
		if (this._fs_.existsSync(this.reportFile)) {
			this._fs_.deleteFileSync(this.reportFile);
		}
	}


	/**
     * @override
     */
	static create = WpwAnalyzerAnalyzePlugin.wrap.bind(this);


    /**
     * @override
     * @returns {WpwPluginTapOptions<any, any, boolean> | undefined}
     */
    onApply()
    {
		if (this.buildOptions.open)
		{
			return {
				openAnalyzerResults: {
					async: true,
					hook: "done",
					callback: this.openAnalyzerResults.bind(this)
				}
			};
		}
    }


	/**
	 * @override
	 * @param {WebpackCompiler} _compiler
	 * @param {boolean} firstPass
	 * @returns {BundleAnalyzerPlugin | undefined}
	 */
	getVendorPlugin(_compiler, firstPass)
	{
		if (!firstPass)
		{   const build = this.build,
				  logLevel = build.logger.level,
				  buildOptions = this.buildOptions;
			return new BundleAnalyzerPlugin(
			{   statsOptions: null,
				excludeAssets: null,
				openAnalyzer: false,
				analyzerPort: "auto",
				analyzerMode: "static",
				generateStatsFile: true,
				statsFilename: this.statsFile,
				reportFilename: this.reportFile,
				defaultSizes: buildOptions.size || "stat",
      			reportTitle: `Bundle Analysis - ${this._str_.toTitleCase(build.name)}`,
				logLevel: buildOptions.verbose ? "info" : (logLevel <= 1 ? "error" : (logLevel <= 3 ? "warn" : "info"))
			});
		}
	}


	/**
	 * @private
	 */
	async openAnalyzerResults()
	{
		this.hookstart();
		const uri = `file://${this._path_.fwdSlash(this.reportFile.replace(/ /g, "%20"))}`;
		try
		{   let cmd = "", prg = "";
			let p = platform === "linux" && release().includes("Microsoft") ? platform : "win32";
			if (this.buildOptions.browser && p === "win32")
			{
				cmd = `cmd /c "${this.buildOptions.browser}"`,
				prg = this._path_.basename(this.buildOptions.browser).replace(/\.[a-z0-9]{2,6}$/i, "");
			}
			else
			{   cmd = prg = p === "win32" ? "cmd.exe" : (p === "linux" ? "xdg-open" : "open")
				if (platform === "win32") {cmd += ` /c start ""`; }
			}
			// queueMicrotask(() => { this.exec(cmd, prg, true, { detached: true }); });
			await this.exec(`${cmd} ${uri}`, prg, true, { detached: true });
		}
		catch (e)
		{   this.addMessage({
				exception: e,code: this.MsgCode.ERROR_PLUGIN_FAILED,
				message: `failed to open analyzer results`, detail: `file location @ url ${uri}`
			})
		}
		this.hookdone();
	}
}


module.exports = WpwAnalyzerAnalyzePlugin.create;