Bundle analysis and monitoring

This commit is contained in:
adilallo
2025-10-07 17:08:57 -06:00
parent 2ed878af81
commit 104208c7df
15 changed files with 1554 additions and 46938 deletions
+114
View File
@@ -0,0 +1,114 @@
import { NextResponse } from "next/server";
import fs from "fs";
import path from "path";
const WEB_VITALS_DIR = path.join(process.cwd(), ".next", "web-vitals");
// Ensure web-vitals directory exists
if (!fs.existsSync(WEB_VITALS_DIR)) {
fs.mkdirSync(WEB_VITALS_DIR, { recursive: true });
}
export async function POST(request) {
try {
const { metric, data, url, userAgent, timestamp } = await request.json();
// Store the metric data
const vitalsData = {
metric,
data,
url,
userAgent,
timestamp: new Date(timestamp).toISOString(),
receivedAt: new Date().toISOString(),
};
// Save to file (in production, you would save to a database)
const filePath = path.join(WEB_VITALS_DIR, `${metric}.json`);
let existingData = [];
if (fs.existsSync(filePath)) {
try {
existingData = JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch (error) {
console.warn("Could not parse existing vitals data:", error.message);
}
}
existingData.push(vitalsData);
// Keep only last 100 entries per metric
if (existingData.length > 100) {
existingData = existingData.slice(-100);
}
fs.writeFileSync(filePath, JSON.stringify(existingData, null, 2));
// Log for monitoring
console.log(
`Web Vital received: ${metric} = ${data.value}ms (${data.rating})`
);
return NextResponse.json({ success: true });
} catch (error) {
console.error("Error processing web vital:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
export async function GET() {
try {
const metrics = {};
if (fs.existsSync(WEB_VITALS_DIR)) {
const files = fs.readdirSync(WEB_VITALS_DIR);
files.forEach((file) => {
if (file.endsWith(".json")) {
const metric = file.replace(".json", "");
const data = JSON.parse(
fs.readFileSync(path.join(WEB_VITALS_DIR, file), "utf8")
);
if (data.length > 0) {
const values = data
.map((d) => d.data.value)
.filter((v) => v !== undefined);
const ratings = data
.map((d) => d.data.rating)
.filter((r) => r !== undefined);
metrics[metric] = {
count: data.length,
average:
values.length > 0
? Math.round(
values.reduce((a, b) => a + b, 0) / values.length
)
: 0,
min: values.length > 0 ? Math.min(...values) : 0,
max: values.length > 0 ? Math.max(...values) : 0,
goodCount: ratings.filter((r) => r === "good").length,
needsImprovementCount: ratings.filter(
(r) => r === "needs-improvement"
).length,
poorCount: ratings.filter((r) => r === "poor").length,
lastUpdated: data[data.length - 1]?.receivedAt,
};
}
}
});
}
return NextResponse.json({ metrics });
} catch (error) {
console.error("Error fetching web vitals:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}