@ordojs/dev-tools
Version:
Advanced developer tools for OrdoJS with component inspector, AST explorer, and performance profiling
287 lines (284 loc) • 8.72 kB
JavaScript
;
var events = require('events');
// src/bundle-analyzer/index.ts
var BundleAnalyzer = class extends events.EventEmitter {
analyses;
isRunning;
port;
/**
* Create a new BundleAnalyzer instance
*
* @param port - WebSocket port for bundle analyzer
*/
constructor(port = 24682) {
super();
this.analyses = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
}
/**
* Start the bundle analyzer
*/
async start() {
if (this.isRunning) {
console.warn("Bundle analyzer is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`Bundle analyzer started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start bundle analyzer:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the bundle analyzer
*/
async stop() {
if (!this.isRunning) {
console.warn("Bundle analyzer is not running");
return;
}
try {
await this.stopWebSocketServer();
this.isRunning = false;
console.log("Bundle analyzer stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop bundle analyzer:", error);
this.emit("error", error);
throw error;
}
}
/**
* Analyze a bundle file
*
* @param bundlePath - Path to the bundle file
* @param bundleName - Name for the bundle analysis
* @returns Bundle analysis result
*/
async analyzeBundle(bundlePath, bundleName) {
try {
const analysis = {
size: 0,
gzippedSize: 0,
modules: [],
chunks: [],
dependencies: [],
warnings: [],
errors: []
};
await this.simulateBundleAnalysis(bundlePath, analysis);
this.analyses.set(bundleName, analysis);
this.emit("bundleAnalyzed", { bundleName, analysis });
return analysis;
} catch (error) {
console.error("Failed to analyze bundle:", error);
this.emit("error", error);
throw error;
}
}
/**
* Get bundle analysis by name
*
* @param bundleName - Bundle name
* @returns Bundle analysis or undefined
*/
getAnalysis(bundleName) {
return this.analyses.get(bundleName);
}
/**
* Get all bundle analyses
*
* @returns Array of all bundle analyses
*/
getAllAnalyses() {
return Array.from(this.analyses.values());
}
/**
* Compare two bundle analyses
*
* @param bundleName1 - First bundle name
* @param bundleName2 - Second bundle name
* @returns Comparison result
*/
compareBundles(bundleName1, bundleName2) {
const analysis1 = this.analyses.get(bundleName1);
const analysis2 = this.analyses.get(bundleName2);
if (!analysis1 || !analysis2) {
throw new Error("One or both bundle analyses not found");
}
const sizeDifference = analysis2.size - analysis1.size;
const sizeDifferencePercent = sizeDifference / analysis1.size * 100;
const moduleCountDifference = analysis2.modules.length - analysis1.modules.length;
const dependencyCountDifference = analysis2.dependencies.length - analysis1.dependencies.length;
const modules1 = new Set(analysis1.modules.map((m) => m.name));
const modules2 = new Set(analysis2.modules.map((m) => m.name));
const newModules = analysis2.modules.filter((m) => !modules1.has(m.name)).map((m) => m.name);
const removedModules = analysis1.modules.filter((m) => !modules2.has(m.name)).map((m) => m.name);
const deps1 = new Set(analysis1.dependencies.map((d) => d.name));
const deps2 = new Set(analysis2.dependencies.map((d) => d.name));
const newDependencies = analysis2.dependencies.filter((d) => !deps1.has(d.name)).map((d) => d.name);
const removedDependencies = analysis1.dependencies.filter((d) => !deps2.has(d.name)).map((d) => d.name);
return {
sizeDifference,
sizeDifferencePercent,
moduleCountDifference,
dependencyCountDifference,
newModules,
removedModules,
newDependencies,
removedDependencies
};
}
/**
* Get bundle optimization suggestions
*
* @param bundleName - Bundle name
* @returns Optimization suggestions
*/
getOptimizationSuggestions(bundleName) {
const analysis = this.analyses.get(bundleName);
if (!analysis) {
throw new Error("Bundle analysis not found");
}
const moduleCounts = /* @__PURE__ */ new Map();
for (const module of analysis.modules) {
moduleCounts.set(module.name, (moduleCounts.get(module.name) || 0) + 1);
}
const duplicateModules = Array.from(moduleCounts.entries()).filter(([_, count]) => count > 1).map(([name, _]) => name);
const largeModules = analysis.modules.filter((module) => module.size > 100 * 1024).map((module) => module.name);
const unusedDependencies = [];
const codeSplittingOpportunities = analysis.modules.filter((module) => module.size > 50 * 1024 && !module.name.includes("vendor")).map((module) => module.name);
const compressionOpportunities = analysis.modules.filter((module) => module.size > 10 * 1024).map((module) => module.name);
return {
duplicateModules,
largeModules,
unusedDependencies,
codeSplittingOpportunities,
compressionOpportunities
};
}
/**
* Get bundle statistics
*
* @param bundleName - Bundle name
* @returns Bundle statistics
*/
getBundleStats(bundleName) {
const analysis = this.analyses.get(bundleName);
if (!analysis) {
throw new Error("Bundle analysis not found");
}
const totalSize = analysis.size;
const gzippedSize = analysis.gzippedSize;
const moduleCount = analysis.modules.length;
const dependencyCount = analysis.dependencies.length;
const averageModuleSize = totalSize / moduleCount || 0;
const largestModule = analysis.modules.length > 0 ? analysis.modules.reduce(
(largest, current) => current.size > largest.size ? current : largest
) : null;
const largestModuleSize = largestModule ? largestModule.size : 0;
return {
totalSize,
gzippedSize,
moduleCount,
dependencyCount,
averageModuleSize,
largestModule: largestModule ? largestModule.name : "",
largestModuleSize
};
}
/**
* Clear all bundle analyses
*/
clearAnalyses() {
this.analyses.clear();
this.emit("analysesCleared");
}
/**
* Simulate bundle analysis (placeholder implementation)
*
* @param bundlePath - Path to bundle file
* @param analysis - Analysis object to populate
*/
async simulateBundleAnalysis(bundlePath, analysis) {
const fs = await import('fs/promises');
try {
const stats = await fs.stat(bundlePath);
analysis.size = stats.size;
analysis.gzippedSize = Math.round(analysis.size * 0.3);
analysis.modules = [
{
name: "main.js",
size: Math.round(analysis.size * 0.6),
dependencies: ["react", "react-dom"],
exports: ["App", "main"],
path: bundlePath
},
{
name: "vendor.js",
size: Math.round(analysis.size * 0.4),
dependencies: ["lodash", "moment"],
exports: ["vendor"],
path: bundlePath
}
];
analysis.chunks = [
{
name: "main",
size: analysis.modules[0]?.size || 0,
modules: ["main.js"],
entry: true
},
{
name: "vendor",
size: analysis.modules[1]?.size || 0,
modules: ["vendor.js"],
entry: false
}
];
analysis.dependencies = [
{
name: "react",
version: "18.2.0",
size: 100 * 1024,
type: "production"
},
{
name: "react-dom",
version: "18.2.0",
size: 150 * 1024,
type: "production"
},
{
name: "lodash",
version: "4.17.21",
size: 70 * 1024,
type: "production"
}
];
} catch (error) {
analysis.errors.push(`Failed to analyze bundle: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Start WebSocket server for bundle analyzer communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for bundle analyzer...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for bundle analyzer...");
}
};
exports.BundleAnalyzer = BundleAnalyzer;
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map