@svelte-vitals/vite 0.15.0 → 0.16.0

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.
Files changed (3) hide show
  1. package/README.md +13 -3
  2. package/dist/index.js +83 -2
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -2,9 +2,12 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@svelte-vitals/vite)](https://www.npmjs.com/package/@svelte-vitals/vite)
4
4
 
5
- Vite/SvelteKit plugin for [svelte-vitals](https://github.com/oekazuma/svelte-vitals). It piggybacks on `vite build`, parses the **prerendered HTML's `<head>`**, and runs the same SEO rules as the CLI — library-agnostic, because it inspects the real output. Fails the build when findings reach `failOn`.
5
+ Vite/SvelteKit plugin for [svelte-vitals](https://github.com/oekazuma/svelte-vitals). Two things in one package:
6
6
 
7
- > **ESM-only** (Node 18+). Ships ES modules only; `require()` is unsupported by design.
7
+ - **Build-time gate** — piggybacks on `vite build`, parses the **prerendered HTML's `<head>`**, and runs the same rule engine as the CLI (SEO, Performance, Correctness, Security, Architecture) — library-agnostic, because it inspects the real output. Fails the build when findings reach `failOn`.
8
+ - **Live dev dashboard** — on by default during `vite dev`: a searchable, filterable code-health dashboard at `/__svelte-vitals/`, covering the whole project from startup via static analysis, refined to real rendered values as you browse.
9
+
10
+ > **ESM-only** (Node 22.13+). Ships ES modules only; `require()` is unsupported by design.
8
11
 
9
12
  ## Usage
10
13
 
@@ -18,15 +21,22 @@ export default {
18
21
  };
19
22
  ```
20
23
 
24
+ `vite dev` prints the dashboard's URL next to its own `Local:`/`Network:` lines. Add the `svelteVitalsHandle` hook (from `@svelte-vitals/vite/hooks`) to `src/hooks.server.ts` for per-route `measured` accuracy as you browse — the dashboard works without it too, from whole-project static analysis alone.
25
+
21
26
  ## Options
22
27
 
23
28
  - `failOn` — minimum severity that fails the build (default `critical`).
24
29
  - `report` — `'console' | 'json' | false` (default `console`).
25
30
  - `outFile` — write the JSON report to a path.
26
31
  - `rules` / `metaComponents` / `treatDynamicAs` — same as the CLI/core config.
32
+ - `weights` — per-category weight overrides for the combined Health score.
27
33
  - `prerenderDir` — override the prerendered-pages directory.
34
+ - `cwd` — project root (defaults to the Vite config root).
35
+ - `ui` — serve the live dev dashboard (default `true`); pass `false` to keep only the build-time gate.
36
+
37
+ Only **prerendered** routes are analyzed at build time; for SSR/dynamic routes use the `svelte-vitals` CLI, or browse them in the live dashboard during `vite dev`.
28
38
 
29
- Only **prerendered** routes are analyzed; for SSR/dynamic routes use the `svelte-vitals` CLI.
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.
30
40
 
31
41
  ## License
32
42
 
package/dist/index.js CHANGED
@@ -294,6 +294,16 @@ body{background:var(--ground);color:var(--ink);font-family:var(--sans);line-heig
294
294
  .tok-pn{color:#8da0bd}
295
295
  .dv-f-link{display:inline-block;margin-top:12px;font-size:13px;font-weight:600;color:var(--accent);text-decoration:none}
296
296
  .dv-f-link:hover{text-decoration:underline}
297
+ .dv-ai-prompt{margin-top:12px;border:1px solid var(--line);border-radius:8px;overflow:hidden}
298
+ .dv-ai-prompt>summary{cursor:pointer;list-style:none;padding:8px 12px;font-size:12px;font-weight:600;color:var(--muted);display:flex;align-items:center;gap:6px;user-select:none}
299
+ .dv-ai-prompt>summary::-webkit-details-marker{display:none}
300
+ .dv-ai-prompt>summary::before{content:"\u25B8";display:inline-block;transition:transform .15s ease}
301
+ .dv-ai-prompt[open]>summary::before{transform:rotate(90deg)}
302
+ .dv-ai-prompt-body{padding:0 12px 12px;display:flex;flex-direction:column;gap:8px}
303
+ .dv-ai-prompt-pre{margin:0;padding:10px 12px;background:var(--code-bg);color:var(--code-ink);border-radius:8px;font-family:var(--mono);font-size:12px;line-height:1.6;white-space:pre-wrap;word-break:break-word;max-height:280px;overflow-y:auto}
304
+ .dv-ai-copy-btn{align-self:flex-start;font:inherit;font-size:12px;font-weight:600;cursor:pointer;background:var(--panel);border:1px solid var(--line-strong);color:var(--ink);padding:5px 12px;border-radius:999px}
305
+ .dv-ai-copy-btn:hover{border-color:var(--faint)}
306
+ .dv-ai-copy-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
297
307
  .dv-empty{color:var(--muted);font-size:13px}
298
308
  @media (max-width:640px){.dv-app{grid-template-columns:1fr;grid-template-areas:"top" "main"}.dv-menu-toggle{display:inline-flex}.dv-sidebar{position:fixed;inset:0 20% 0 0;transform:translateX(-100%);transition:transform .2s ease;z-index:10}.dv-sidebar.open{transform:translateX(0)}}
299
309
  @media (prefers-reduced-motion:reduce){*{transition:none!important}}
@@ -406,6 +416,76 @@ var DASHBOARD_SCRIPT = `
406
416
  return pre;
407
417
  }
408
418
 
419
+ // Plain-text, copy-pasteable prompt for a single finding \u2014 same ingredients as the
420
+ // agent reporter's per-finding block (rule id, location, recommendation, fix, docs),
421
+ // reshaped for a standalone request rather than a whole-project remediation doc.
422
+ function buildAiPrompt(issue, route) {
423
+ var lines = ['Fix this svelte-vitals finding:', ''];
424
+ lines.push('- Rule: ' + issue.id + ' \u2014 ' + issue.title + ' (' + issue.severity + ')');
425
+ if (route) lines.push('- Route: ' + route);
426
+ if (issue.location) {
427
+ lines.push('- Location: ' + issue.location + (issue.line !== undefined ? ':' + issue.line : ''));
428
+ }
429
+ if (issue.recommendation) lines.push('- Recommendation: ' + issue.recommendation);
430
+ if (issue.fix) {
431
+ lines.push('- Fix: ' + issue.fix.description);
432
+ if (issue.fix.snippet) {
433
+ lines.push('', '\`\`\`' + (issue.fix.lang || 'svelte'), issue.fix.snippet, '\`\`\`');
434
+ }
435
+ }
436
+ if (issue.docsUrl) lines.push('- Docs: ' + issue.docsUrl);
437
+ lines.push(
438
+ '',
439
+ 'After fixing, re-run \`svelte-vitals --diff\` (or revisit this route) to confirm ' +
440
+ issue.id +
441
+ ' passes' +
442
+ (route ? ' for ' + route : '') +
443
+ '.'
444
+ );
445
+ return lines.join('\\n');
446
+ }
447
+
448
+ function copyToClipboard(text, btn) {
449
+ var original = 'Copy';
450
+ function reset(label) {
451
+ btn.textContent = label;
452
+ setTimeout(function () { btn.textContent = original; }, 1500);
453
+ }
454
+ function done() { reset('Copied!'); }
455
+ function fail() { reset('Copy failed'); }
456
+ function fallbackCopy() {
457
+ var ta = document.createElement('textarea');
458
+ ta.value = text;
459
+ ta.setAttribute('readonly', '');
460
+ ta.style.position = 'fixed';
461
+ ta.style.opacity = '0';
462
+ document.body.appendChild(ta);
463
+ ta.select();
464
+ var ok = false;
465
+ try { ok = document.execCommand('copy'); } catch (e) {}
466
+ document.body.removeChild(ta);
467
+ return ok;
468
+ }
469
+ if (navigator.clipboard && navigator.clipboard.writeText) {
470
+ navigator.clipboard.writeText(text).then(done, function () { fallbackCopy() ? done() : fail(); });
471
+ } else {
472
+ fallbackCopy() ? done() : fail();
473
+ }
474
+ }
475
+
476
+ function renderAiPrompt(issue, route) {
477
+ var text = buildAiPrompt(issue, route);
478
+ var btn = h('button', { type: 'button', class: 'dv-ai-copy-btn', text: 'Copy' }, []);
479
+ btn.addEventListener('click', function () { copyToClipboard(text, btn); });
480
+ return h('details', { class: 'dv-ai-prompt' }, [
481
+ h('summary', { text: 'AI Prompt' }, []),
482
+ h('div', { class: 'dv-ai-prompt-body' }, [
483
+ h('pre', { class: 'dv-ai-prompt-pre', text: text }, []),
484
+ btn
485
+ ])
486
+ ]);
487
+ }
488
+
409
489
  var state = {
410
490
  snapshot: null,
411
491
  selected: 'overview',
@@ -593,7 +673,7 @@ var DASHBOARD_SCRIPT = `
593
673
 
594
674
  var SEVERITY_ORDER = { critical: 0, warning: 1, info: 2 };
595
675
 
596
- function renderFinding(issue, route) {
676
+ function renderFinding(issue, route, promptRoute) {
597
677
  var kids = [
598
678
  h('div', { class: 'dv-f-head' }, [
599
679
  h('span', { class: 'dv-ruleid', text: issue.id }, []),
@@ -616,6 +696,7 @@ var DASHBOARD_SCRIPT = `
616
696
  if (issue.docsUrl) {
617
697
  kids.push(h('a', { class: 'dv-f-link', href: issue.docsUrl, text: 'Learn more' }, []));
618
698
  }
699
+ kids.push(renderAiPrompt(issue, promptRoute !== undefined ? promptRoute : route));
619
700
  return h('article', { class: 'dv-finding dv-finding-' + issue.severity }, kids);
620
701
  }
621
702
 
@@ -690,7 +771,7 @@ var DASHBOARD_SCRIPT = `
690
771
  var chips = renderFilterChips(state.snapshot.report.categories);
691
772
  var findings = route.issues.filter(passesFilter);
692
773
  var body = findings.length
693
- ? findings.map(function (issue) { return renderFinding(issue); })
774
+ ? findings.map(function (issue) { return renderFinding(issue, undefined, route.route); })
694
775
  : [h('p', { class: 'dv-empty', text: 'No issues match the current filter.' }, [])];
695
776
  return h('div', { class: 'dv-route-detail' }, [header, chips].concat(body));
696
777
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svelte-vitals/vite",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Vite/SvelteKit plugin for svelte-vitals — analyzes prerendered HTML during vite build.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,8 +42,8 @@
42
42
  "esm-env": "^1.2.2",
43
43
  "node-html-parser": "^9.0.0",
44
44
  "tinyglobby": "^0.2.17",
45
- "@svelte-vitals/core": "0.24.0",
46
- "svelte-vitals": "0.25.0"
45
+ "svelte-vitals": "0.27.0",
46
+ "@svelte-vitals/core": "0.24.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@sveltejs/kit": "^2.69.2",