@svelte-vitals/vite 0.11.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +181 -32
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
// src/plugin.ts
|
|
8
8
|
import { existsSync } from "fs";
|
|
9
9
|
import { writeFile, mkdir } from "fs/promises";
|
|
10
|
-
import { join as join4, isAbsolute, dirname } from "path";
|
|
10
|
+
import { join as join4, isAbsolute, dirname, relative, basename, sep } from "path";
|
|
11
11
|
import { defineConfig as defineConfig2 } from "@svelte-vitals/core";
|
|
12
12
|
|
|
13
13
|
// src/analyze.ts
|
|
@@ -131,6 +131,15 @@ function readPackageVersion() {
|
|
|
131
131
|
return "0.0.0";
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
+
function readCoreVersion() {
|
|
135
|
+
try {
|
|
136
|
+
const entry = import.meta.resolve("@svelte-vitals/core");
|
|
137
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", entry), "utf8"));
|
|
138
|
+
return pkg.version ?? "0.0.0";
|
|
139
|
+
} catch {
|
|
140
|
+
return "0.0.0";
|
|
141
|
+
}
|
|
142
|
+
}
|
|
134
143
|
|
|
135
144
|
// src/analyze.ts
|
|
136
145
|
async function analyze(prerenderPagesDir, cwd, options) {
|
|
@@ -166,28 +175,6 @@ Scanned ${components.length} component(s) under src/ for Correctness/Security/Ar
|
|
|
166
175
|
};
|
|
167
176
|
}
|
|
168
177
|
|
|
169
|
-
// src/ui/store.ts
|
|
170
|
-
function createStore() {
|
|
171
|
-
const byRoute = /* @__PURE__ */ new Map();
|
|
172
|
-
const subs = /* @__PURE__ */ new Set();
|
|
173
|
-
return {
|
|
174
|
-
set(route, results) {
|
|
175
|
-
byRoute.set(
|
|
176
|
-
route,
|
|
177
|
-
results.map((r) => r.route ? r : { ...r, route })
|
|
178
|
-
);
|
|
179
|
-
for (const fn of subs) fn();
|
|
180
|
-
},
|
|
181
|
-
snapshot() {
|
|
182
|
-
return [...byRoute.values()].flat();
|
|
183
|
-
},
|
|
184
|
-
subscribe(fn) {
|
|
185
|
-
subs.add(fn);
|
|
186
|
-
return () => subs.delete(fn);
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
178
|
// src/ui/serve.ts
|
|
192
179
|
import { buildHtmlDocument, buildJsonReport } from "@svelte-vitals/core";
|
|
193
180
|
var LIVE_SCRIPT = `<script data-live>
|
|
@@ -205,8 +192,12 @@ var LIVE_SCRIPT = `<script data-live>
|
|
|
205
192
|
});
|
|
206
193
|
})();
|
|
207
194
|
</script>`;
|
|
208
|
-
function renderDashboard(results, config, meta) {
|
|
209
|
-
const html = buildHtmlDocument(
|
|
195
|
+
function renderDashboard(results, config, meta, badges) {
|
|
196
|
+
const html = buildHtmlDocument(
|
|
197
|
+
buildJsonReport(results, config, meta),
|
|
198
|
+
meta,
|
|
199
|
+
badges ? { routeBadges: badges } : void 0
|
|
200
|
+
);
|
|
210
201
|
return html.replace("</body>", LIVE_SCRIPT + "</body>");
|
|
211
202
|
}
|
|
212
203
|
|
|
@@ -223,8 +214,7 @@ function isResultLike(x) {
|
|
|
223
214
|
const f = r.fix;
|
|
224
215
|
return typeof r.id === "string" && typeof r.message === "string" && typeof r.severity === "string" && SEVERITIES.has(r.severity) && typeof d === "object" && d !== null && typeof d.presence === "string" && typeof d.value === "string" && (r.category === void 0 || typeof r.category === "string" && CATEGORIES.has(r.category)) && isOptionalString(r.location) && isOptionalString(r.recommendation) && isOptionalString(r.docsUrl) && (f === void 0 || typeof f === "object" && f !== null && typeof f.description === "string" && isOptionalString(f.snippet) && isOptionalString(f.lang)) && (r.line === void 0 || typeof r.line === "number") && isOptionalString(r.route);
|
|
225
216
|
}
|
|
226
|
-
function installUiMiddleware(server, config, version) {
|
|
227
|
-
const store = createStore();
|
|
217
|
+
function installUiMiddleware(server, config, version, store, coreVersion) {
|
|
228
218
|
const clients = /* @__PURE__ */ new Set();
|
|
229
219
|
store.subscribe(() => {
|
|
230
220
|
for (const res of clients) {
|
|
@@ -277,7 +267,7 @@ function installUiMiddleware(server, config, version) {
|
|
|
277
267
|
return;
|
|
278
268
|
}
|
|
279
269
|
try {
|
|
280
|
-
const html = renderDashboard(store.snapshot(), config, { version });
|
|
270
|
+
const html = renderDashboard(store.snapshot(), config, { version, coreVersion }, store.badges());
|
|
281
271
|
res.setHeader("Content-Type", "text/html");
|
|
282
272
|
res.end(html);
|
|
283
273
|
} catch {
|
|
@@ -287,7 +277,150 @@ function installUiMiddleware(server, config, version) {
|
|
|
287
277
|
});
|
|
288
278
|
}
|
|
289
279
|
|
|
280
|
+
// src/ui/store.ts
|
|
281
|
+
function composeSnapshot(staticResults, liveByRoute) {
|
|
282
|
+
const staticByRoute = /* @__PURE__ */ new Map();
|
|
283
|
+
const routeless = [];
|
|
284
|
+
for (const r of staticResults) {
|
|
285
|
+
if (r.route) {
|
|
286
|
+
const bucket = staticByRoute.get(r.route);
|
|
287
|
+
if (bucket) bucket.push(r);
|
|
288
|
+
else staticByRoute.set(r.route, [r]);
|
|
289
|
+
} else {
|
|
290
|
+
routeless.push(r);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const out = [...routeless];
|
|
294
|
+
for (const [route, live] of liveByRoute) {
|
|
295
|
+
const liveIds = new Set(live.map((r) => r.id));
|
|
296
|
+
const staticForRoute = staticByRoute.get(route) ?? [];
|
|
297
|
+
out.push(...staticForRoute.filter((r) => !liveIds.has(r.id)), ...live);
|
|
298
|
+
staticByRoute.delete(route);
|
|
299
|
+
}
|
|
300
|
+
for (const remaining of staticByRoute.values()) out.push(...remaining);
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
function composeBadges(staticResults, liveByRoute) {
|
|
304
|
+
const badges = {};
|
|
305
|
+
for (const r of staticResults) {
|
|
306
|
+
if (r.route) badges[r.route] = "static";
|
|
307
|
+
}
|
|
308
|
+
for (const route of liveByRoute.keys()) badges[route] = "measured";
|
|
309
|
+
return badges;
|
|
310
|
+
}
|
|
311
|
+
function createStore() {
|
|
312
|
+
let staticResults = [];
|
|
313
|
+
const liveByRoute = /* @__PURE__ */ new Map();
|
|
314
|
+
const subs = /* @__PURE__ */ new Set();
|
|
315
|
+
function notify() {
|
|
316
|
+
for (const fn of subs) fn();
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
set(route, results) {
|
|
320
|
+
liveByRoute.set(
|
|
321
|
+
route,
|
|
322
|
+
results.map((r) => r.route ? r : { ...r, route })
|
|
323
|
+
);
|
|
324
|
+
notify();
|
|
325
|
+
},
|
|
326
|
+
setStatic(results) {
|
|
327
|
+
staticResults = results;
|
|
328
|
+
notify();
|
|
329
|
+
},
|
|
330
|
+
snapshot() {
|
|
331
|
+
return composeSnapshot(staticResults, liveByRoute);
|
|
332
|
+
},
|
|
333
|
+
badges() {
|
|
334
|
+
return composeBadges(staticResults, liveByRoute);
|
|
335
|
+
},
|
|
336
|
+
subscribe(fn) {
|
|
337
|
+
subs.add(fn);
|
|
338
|
+
return () => subs.delete(fn);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/ui/analysis.ts
|
|
344
|
+
function createAnalysisRunner(opts) {
|
|
345
|
+
const debounceMs = opts.debounceMs ?? 500;
|
|
346
|
+
let cachedAnalyze = opts.analyze;
|
|
347
|
+
let stopped = false;
|
|
348
|
+
let running = false;
|
|
349
|
+
let pending = false;
|
|
350
|
+
let timer;
|
|
351
|
+
async function getAnalyze() {
|
|
352
|
+
if (cachedAnalyze) return cachedAnalyze;
|
|
353
|
+
const mod = await import("svelte-vitals");
|
|
354
|
+
const fn = (o) => mod.analyzeProject(o);
|
|
355
|
+
cachedAnalyze = fn;
|
|
356
|
+
return fn;
|
|
357
|
+
}
|
|
358
|
+
async function runOnce() {
|
|
359
|
+
if (stopped) return;
|
|
360
|
+
running = true;
|
|
361
|
+
try {
|
|
362
|
+
const analyze2 = await getAnalyze();
|
|
363
|
+
const { results } = await analyze2({
|
|
364
|
+
cwd: opts.root,
|
|
365
|
+
treatDynamicAs: opts.treatDynamicAs,
|
|
366
|
+
metaComponents: opts.metaComponents,
|
|
367
|
+
rules: opts.rules,
|
|
368
|
+
failOn: opts.failOn
|
|
369
|
+
});
|
|
370
|
+
if (!stopped) opts.onResults(results);
|
|
371
|
+
} catch (err) {
|
|
372
|
+
if (!stopped) opts.onError(err);
|
|
373
|
+
} finally {
|
|
374
|
+
running = false;
|
|
375
|
+
if (!stopped && pending) {
|
|
376
|
+
pending = false;
|
|
377
|
+
void runOnce();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
start() {
|
|
383
|
+
if (stopped) return;
|
|
384
|
+
void runOnce();
|
|
385
|
+
},
|
|
386
|
+
notifyChange() {
|
|
387
|
+
if (stopped) return;
|
|
388
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
389
|
+
timer = setTimeout(() => {
|
|
390
|
+
timer = void 0;
|
|
391
|
+
if (stopped) return;
|
|
392
|
+
if (running) pending = true;
|
|
393
|
+
else void runOnce();
|
|
394
|
+
}, debounceMs);
|
|
395
|
+
},
|
|
396
|
+
stop() {
|
|
397
|
+
stopped = true;
|
|
398
|
+
if (timer !== void 0) {
|
|
399
|
+
clearTimeout(timer);
|
|
400
|
+
timer = void 0;
|
|
401
|
+
}
|
|
402
|
+
pending = false;
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
290
407
|
// src/plugin.ts
|
|
408
|
+
var CONFIG_BASENAMES = /* @__PURE__ */ new Set([
|
|
409
|
+
"svelte.config.js",
|
|
410
|
+
"svelte.config.ts",
|
|
411
|
+
"svelte-vitals.config.mjs",
|
|
412
|
+
"svelte-vitals.config.js",
|
|
413
|
+
"svelte-vitals.config.ts"
|
|
414
|
+
]);
|
|
415
|
+
var IGNORED_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", ".svelte-kit", "build", "dist"]);
|
|
416
|
+
function isRelevant(file, root) {
|
|
417
|
+
const rel = relative(root, file);
|
|
418
|
+
if (rel === "" || rel.startsWith("..")) return false;
|
|
419
|
+
const segments = rel.split(sep);
|
|
420
|
+
if (segments.some((s) => IGNORED_SEGMENTS.has(s))) return false;
|
|
421
|
+
if (CONFIG_BASENAMES.has(basename(file))) return true;
|
|
422
|
+
return segments[0] === "src" || segments[0] === "static";
|
|
423
|
+
}
|
|
291
424
|
var DEFAULT_PRERENDER_DIR = ".svelte-kit/output/prerendered/pages";
|
|
292
425
|
function svelteVitals(options = {}) {
|
|
293
426
|
let root = options.cwd ?? process.cwd();
|
|
@@ -330,16 +463,32 @@ function svelteVitals(options = {}) {
|
|
|
330
463
|
apply: "serve",
|
|
331
464
|
configureServer(server) {
|
|
332
465
|
process.env.SVELTE_VITALS_UI = "1";
|
|
333
|
-
server.httpServer?.once("close", () => {
|
|
334
|
-
delete process.env.SVELTE_VITALS_UI;
|
|
335
|
-
});
|
|
336
466
|
const config = defineConfig2({
|
|
337
467
|
treatDynamicAs: options.treatDynamicAs ?? "pass",
|
|
338
468
|
metaComponents: options.metaComponents ?? [],
|
|
339
469
|
rules: options.rules ?? {},
|
|
340
470
|
failOn: options.failOn ?? "critical"
|
|
341
471
|
});
|
|
342
|
-
|
|
472
|
+
const store = createStore();
|
|
473
|
+
const uiRoot = options.cwd ?? server.config.root;
|
|
474
|
+
const runner = createAnalysisRunner({
|
|
475
|
+
root: uiRoot,
|
|
476
|
+
treatDynamicAs: options.treatDynamicAs,
|
|
477
|
+
metaComponents: options.metaComponents,
|
|
478
|
+
rules: options.rules,
|
|
479
|
+
failOn: options.failOn,
|
|
480
|
+
onResults: (results) => store.setStatic(results),
|
|
481
|
+
onError: (err) => console.warn("[svelte-vitals] dev analysis failed:", err)
|
|
482
|
+
});
|
|
483
|
+
runner.start();
|
|
484
|
+
server.watcher?.on("all", (_event, file) => {
|
|
485
|
+
if (isRelevant(file, uiRoot)) runner.notifyChange(file);
|
|
486
|
+
});
|
|
487
|
+
server.httpServer?.once("close", () => {
|
|
488
|
+
delete process.env.SVELTE_VITALS_UI;
|
|
489
|
+
runner.stop();
|
|
490
|
+
});
|
|
491
|
+
installUiMiddleware(server, config, readPackageVersion(), store, readCoreVersion());
|
|
343
492
|
}
|
|
344
493
|
};
|
|
345
494
|
return [buildPlugin, uiPlugin];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svelte-vitals/vite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Vite/SvelteKit plugin for svelte-vitals — analyzes prerendered HTML during vite build.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,9 +40,10 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"esm-env": "^1.2.2",
|
|
43
|
-
"node-html-parser": "^
|
|
43
|
+
"node-html-parser": "^9.0.0",
|
|
44
44
|
"tinyglobby": "^0.2.17",
|
|
45
|
-
"@svelte-vitals/core": "0.
|
|
45
|
+
"@svelte-vitals/core": "0.22.0",
|
|
46
|
+
"svelte-vitals": "0.22.0"
|
|
46
47
|
},
|
|
47
48
|
"peerDependencies": {
|
|
48
49
|
"@sveltejs/kit": "^2.69.1",
|