@svelte-vitals/vite 0.54.5 → 0.54.6
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/README.md +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +57 -6
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ export default {
|
|
|
34
34
|
- `cwd`: project root (defaults to the Vite config root).
|
|
35
35
|
- `ui`: serve the live dev dashboard (default `true`); pass `false` to keep only the build-time gate.
|
|
36
36
|
|
|
37
|
-
At build time the HTML check covers prerendered routes only; the source scan applies project-wide.
|
|
37
|
+
At build time the HTML check covers prerendered routes only; the source scan applies project-wide. Routes that are not prerendered (server-rendered, or dynamic routes without prerendered entries) have no build output, so nothing checks their rendered HTML here. A prerendered route with `ssr = false` has build output, but only the empty app shell, so the HTML check skips it too (a `+layout` with `ssr = false` skips its subtree) and prints one warning listing the skipped routes. The `svelte-vitals` CLI covers them by source analysis, and browsing them during `vite dev` gets the live dashboard a rendered reading.
|
|
38
38
|
|
|
39
39
|
See [Live dashboard](https://oekazuma.github.io/svelte-vitals/guides/dev-dashboard/) and [Plugin mode](https://oekazuma.github.io/svelte-vitals/guides/plugin-mode/) for the full picture.
|
|
40
40
|
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -14,6 +14,6 @@ interface SvelteVitalsHookOptions {
|
|
|
14
14
|
* route's dashboard findings from static (source-only) to `measured` (real rendered
|
|
15
15
|
* HTML). Add it to `src/hooks.server.ts`, e.g. `sequence(svelteVitalsHandle())`.
|
|
16
16
|
*/
|
|
17
|
-
declare function svelteVitalsHandle(options?: SvelteVitalsHookOptions): Handle;
|
|
17
|
+
export declare function svelteVitalsHandle(options?: SvelteVitalsHookOptions): Handle;
|
|
18
18
|
//#endregion
|
|
19
|
-
export {
|
|
19
|
+
export type { SvelteVitalsHookOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,6 @@ interface SvelteVitalsOptions {
|
|
|
28
28
|
ui?: boolean;
|
|
29
29
|
}
|
|
30
30
|
/** svelte-vitals Vite/SvelteKit plugin. */
|
|
31
|
-
declare function svelteVitals(options?: SvelteVitalsOptions): Plugin | Plugin[];
|
|
31
|
+
export declare function svelteVitals(options?: SvelteVitalsOptions): Plugin | Plugin[];
|
|
32
32
|
//#endregion
|
|
33
|
-
export {
|
|
33
|
+
export type { SvelteVitalsOptions };
|
package/dist/index.js
CHANGED
|
@@ -222,6 +222,43 @@ async function resolveConfig(cwd, options) {
|
|
|
222
222
|
};
|
|
223
223
|
}
|
|
224
224
|
/**
|
|
225
|
+
* `ssr` is a page option: only `+page`/`+layout` modules (universal or server) can set it. Same
|
|
226
|
+
* file set as `PAGE_OPTION_FILE_RE` in core's `rules/seo/ssr-disabled.ts`, which reports the fact.
|
|
227
|
+
*/
|
|
228
|
+
const PAGE_OPTION_FILE_RE = /^src\/routes\/(.*?)\/?\+(page|layout)(?:\.server)?\.[jt]s$/;
|
|
229
|
+
function escapeRegExp(s) {
|
|
230
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
231
|
+
}
|
|
232
|
+
/** One route directory segment as a pattern over the rendered (concrete) route path, leading `/` included. */
|
|
233
|
+
function segmentPattern(segment) {
|
|
234
|
+
if (/^\[\.\.\.[^\]]+\]$/.test(segment)) return "(?:/.*)?";
|
|
235
|
+
if (/^\[\[[^\]]+\]\]$/.test(segment)) return "(?:/[^/]+)?";
|
|
236
|
+
return "/" + segment.split(/\[[^\]]+\]/).map(escapeRegExp).join("[^/]+");
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Routes whose prerendered HTML is the app shell rather than the page: SvelteKit still writes a
|
|
240
|
+
* file for an `ssr = false` route, but its `<head>` and body only exist once the client renders,
|
|
241
|
+
* so every rendered head/heading/landmark check would report the page as empty. A `+layout`
|
|
242
|
+
* covers its whole subtree, a `+page` only its own route; `(group)` directories are not URL
|
|
243
|
+
* segments. Two ceilings: a child route re-enabling `ssr = true` under a disabled layout is not
|
|
244
|
+
* tracked, and Kit's route precedence is not modelled, so a `[param]` route also claims a literal
|
|
245
|
+
* sibling (`/docs/[slug]` matches a prerendered `/docs/intro`) — the warning lists the skipped
|
|
246
|
+
* routes so a wrong skip is visible.
|
|
247
|
+
*/
|
|
248
|
+
function ssrDisabledRouteMatcher(kitModules) {
|
|
249
|
+
const patterns = [];
|
|
250
|
+
for (const m of kitModules) {
|
|
251
|
+
const match = m.ssrDisabled ? PAGE_OPTION_FILE_RE.exec(m.file) : null;
|
|
252
|
+
if (!match) continue;
|
|
253
|
+
const path = match[1].split("/").filter((s) => s !== "" && !/^\(.+\)$/.test(s)).map(segmentPattern).join("");
|
|
254
|
+
patterns.push(new RegExp(match[2] === "layout" ? `^${path}(?:/.*)?$` : `^${path}$`));
|
|
255
|
+
}
|
|
256
|
+
return (route) => {
|
|
257
|
+
const r = route === "/" ? "" : route;
|
|
258
|
+
return patterns.some((p) => p.test(r));
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
225
262
|
* Collect prerendered heads + project facts + component facts, run the core pipeline, and
|
|
226
263
|
* format reports. Config precedence: see `resolveConfig`. Pass `resolved` when the caller
|
|
227
264
|
* already resolved config itself (build mode resolves it outside `analyze`'s try/catch so a
|
|
@@ -229,17 +266,29 @@ async function resolveConfig(cwd, options) {
|
|
|
229
266
|
*/
|
|
230
267
|
async function analyze(prerenderPagesDir, cwd, options, extraProjectFacts, resolved) {
|
|
231
268
|
const { config, warnings } = resolved ?? await resolveConfig(cwd, options);
|
|
232
|
-
const [
|
|
269
|
+
const [rendered, components, sourceFiles] = await Promise.all([
|
|
233
270
|
collectRenderedHeads(prerenderPagesDir),
|
|
234
271
|
collectComponentFacts$1(cwd),
|
|
235
272
|
collectSourceFiles$1(cwd)
|
|
236
273
|
]);
|
|
237
274
|
const project = {
|
|
238
|
-
...await collectRenderedProject(cwd, htmlLang),
|
|
275
|
+
...await collectRenderedProject(cwd, rendered.htmlLang),
|
|
239
276
|
...extraProjectFacts
|
|
240
277
|
};
|
|
241
278
|
const kitModules = await collectKitModuleFacts$1(cwd, project.kitAliases);
|
|
279
|
+
const isShell = ssrDisabledRouteMatcher(kitModules);
|
|
280
|
+
const keep = (items) => items.filter((i) => !isShell(i.route));
|
|
281
|
+
const heads = keep(rendered.heads);
|
|
282
|
+
const headings = keep(rendered.headings);
|
|
283
|
+
const images = keep(rendered.images);
|
|
284
|
+
const a11y = keep(rendered.a11y);
|
|
285
|
+
const shells = rendered.heads.filter((h) => isShell(h.route)).map((h) => h.route).sort();
|
|
242
286
|
const selected = selectRules(allRules, config);
|
|
287
|
+
if (shells.length > 0) {
|
|
288
|
+
const shown = shells.slice(0, 10);
|
|
289
|
+
const list = shells.length > shown.length ? `${shown.join(", ")}, … and ${shells.length - shown.length} more` : shown.join(", ");
|
|
290
|
+
warnings.push(`skipped ${shells.length} prerendered route(s) with ssr = false — their HTML is the app shell, not the page; run \`npx svelte-vitals\` to check them from source: ${list}`);
|
|
291
|
+
}
|
|
243
292
|
if (selected.some((r) => r.id === "a11y/unverified-id-ref")) warnings.push("a11y/unverified-id-ref has no effect in rendered mode — the prerendered document is always fully resolved.");
|
|
244
293
|
const directives = /* @__PURE__ */ new Map();
|
|
245
294
|
addFactsDirectives(directives, {
|
|
@@ -264,7 +313,7 @@ async function analyze(prerenderPagesDir, cwd, options, extraProjectFacts, resol
|
|
|
264
313
|
const { score } = computeScore(results, scoringConfig);
|
|
265
314
|
const summary = summarize(results, scoringConfig);
|
|
266
315
|
const failed = hasFailureAtOrAbove(summary, scoringConfig.failOn);
|
|
267
|
-
const coverageNote = `Analyzed ${heads.length} prerendered route(s). SSR/dynamic routes are not covered — run \`npx svelte-vitals\` for those.
|
|
316
|
+
const coverageNote = `Analyzed ${heads.length} prerendered route(s)${shells.length > 0 ? ` (skipped ${shells.length} with ssr = false)` : ""}. SSR/dynamic routes are not covered — run \`npx svelte-vitals\` for those.
|
|
268
317
|
Scanned ${components.length} component(s) under src/ for Correctness/Security/Architecture/Accessibility/Bundle findings.`;
|
|
269
318
|
return {
|
|
270
319
|
score,
|
|
@@ -272,7 +321,7 @@ Scanned ${components.length} component(s) under src/ for Correctness/Security/Ar
|
|
|
272
321
|
results,
|
|
273
322
|
consoleReport: formatConsoleReport(results, scoringConfig, { mode: "rendered / plugin" }) + "\n" + coverageNote + "\n",
|
|
274
323
|
jsonReport: formatJsonReport(results, scoringConfig, { version: readPackageVersion() }, selected.map((r) => r.id), examined),
|
|
275
|
-
routeCount: heads.length,
|
|
324
|
+
routeCount: rendered.heads.length,
|
|
276
325
|
failed,
|
|
277
326
|
failOn: scoringConfig.failOn,
|
|
278
327
|
warnings
|
|
@@ -613,8 +662,10 @@ function createAnalysisRunner(opts) {
|
|
|
613
662
|
parseCache
|
|
614
663
|
});
|
|
615
664
|
const { results, failedRuleIds } = result;
|
|
616
|
-
if (!stopped)
|
|
617
|
-
|
|
665
|
+
if (!stopped) {
|
|
666
|
+
if (failedRuleIds !== void 0) opts.onResults(results, failedRuleIds);
|
|
667
|
+
else opts.onResults(results);
|
|
668
|
+
}
|
|
618
669
|
const warnings = result.warnings ?? [];
|
|
619
670
|
const key = warnings.join("\n");
|
|
620
671
|
if (!stopped && warnings.length > 0 && key !== lastWarningsKey) opts.onWarnings?.(warnings);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svelte-vitals/vite",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.6",
|
|
4
4
|
"description": "Vite/SvelteKit plugin for svelte-vitals — analyzes prerendered HTML during vite build, plus a live dev dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"esm-env": "^1.2.2",
|
|
43
|
-
"node-html-parser": "^9.0.
|
|
43
|
+
"node-html-parser": "^9.0.4"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@svelte-vitals/core": "^0.54.
|
|
46
|
+
"@svelte-vitals/core": "^0.54.6",
|
|
47
47
|
"@sveltejs/kit": "^2.70.3",
|
|
48
|
-
"svelte-vitals": "^0.54.
|
|
49
|
-
"vite": "^8.
|
|
48
|
+
"svelte-vitals": "^0.54.6",
|
|
49
|
+
"vite": "^8.3.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependenciesMeta": {
|
|
52
52
|
"@sveltejs/kit": {
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@svelte-vitals/core": "0.54.
|
|
57
|
+
"@svelte-vitals/core": "0.54.6",
|
|
58
58
|
"@sveltejs/kit": "^2.70.3",
|
|
59
|
-
"@types/node": "^24.13.
|
|
60
|
-
"happy-dom": "^20.
|
|
59
|
+
"@types/node": "^24.13.4",
|
|
60
|
+
"happy-dom": "^20.14.3",
|
|
61
61
|
"svelte": "^5.57.0",
|
|
62
|
-
"svelte-vitals": "0.54.
|
|
63
|
-
"vite": "^8.
|
|
62
|
+
"svelte-vitals": "0.54.6",
|
|
63
|
+
"vite": "^8.3.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "tsdown",
|