@svelte-vitals/vite 0.29.7 → 0.30.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/README.md +1 -1
- package/dist/{chunk-EHCC47NO.js → chunk-6FDRI4Q6.js} +105 -3
- package/dist/hooks/index.js +27 -12
- package/dist/index.js +31 -64
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Vite/SvelteKit plugin for [svelte-vitals](https://github.com/oekazuma/svelte-vitals). Two things in one package:
|
|
6
6
|
|
|
7
|
-
- **Build-time gate** — piggybacks on `vite build`, parses the **prerendered HTML
|
|
7
|
+
- **Build-time gate** — piggybacks on `vite build`, parses the **prerendered HTML** (head metadata, images, headings, landmarks and ids), and runs the same rule engine as the CLI (SEO, Performance, Correctness, Security, Architecture, Accessibility) — library-agnostic, because it inspects the real output. Fails the build when findings reach `failOn`.
|
|
8
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
9
|
|
|
10
10
|
> **ESM-only** (Node 22.13+). Ships ES modules only; `require()` is unsupported by design.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/providers/rendered/parse-html.ts
|
|
2
2
|
import { parse } from "node-html-parser";
|
|
3
|
+
import { decodeFragmentId, splitTokens, isTopFragment, LANDMARK_ROLES, IDREF_ATTRS } from "@svelte-vitals/core";
|
|
3
4
|
function attrValue(v) {
|
|
4
5
|
return v !== void 0 && v.trim().length > 0 ? "static" : "absent";
|
|
5
6
|
}
|
|
@@ -26,6 +27,49 @@ function isClassicScriptType(type) {
|
|
|
26
27
|
const normalized = type.trim().toLowerCase();
|
|
27
28
|
return normalized === "" || JS_MIME_TYPES.has(normalized);
|
|
28
29
|
}
|
|
30
|
+
var SECTIONING_TAGS = /* @__PURE__ */ new Set(["article", "aside", "main", "nav", "section"]);
|
|
31
|
+
function collectA11y(root) {
|
|
32
|
+
const landmarks = [];
|
|
33
|
+
const nestedLandmarks = [];
|
|
34
|
+
const ids = [];
|
|
35
|
+
const idRefs = [];
|
|
36
|
+
const walk = (el, ctx) => {
|
|
37
|
+
const tag = el.rawTagName?.toLowerCase();
|
|
38
|
+
const roleAttr = el.getAttribute("role");
|
|
39
|
+
let landmark;
|
|
40
|
+
if (roleAttr !== void 0) {
|
|
41
|
+
const role = splitTokens(roleAttr)[0];
|
|
42
|
+
landmark = role && LANDMARK_ROLES.has(role) ? role : void 0;
|
|
43
|
+
} else if (tag === "main") {
|
|
44
|
+
landmark = "main";
|
|
45
|
+
} else if ((tag === "header" || tag === "footer") && ctx.sectioning === 0) {
|
|
46
|
+
landmark = tag === "header" ? "banner" : "contentinfo";
|
|
47
|
+
}
|
|
48
|
+
if (landmark) {
|
|
49
|
+
landmarks.push(landmark);
|
|
50
|
+
const within = ctx.landmarks.at(-1);
|
|
51
|
+
if (within) nestedLandmarks.push({ kind: landmark, within });
|
|
52
|
+
}
|
|
53
|
+
const id = el.getAttribute("id");
|
|
54
|
+
if (id && id.trim()) ids.push(id);
|
|
55
|
+
const href = el.getAttribute("href");
|
|
56
|
+
if (href && href.startsWith("#") && href.length > 1) {
|
|
57
|
+
const fragment = decodeFragmentId(href.slice(1));
|
|
58
|
+
if (!isTopFragment(fragment)) idRefs.push({ id: fragment, attr: "href" });
|
|
59
|
+
}
|
|
60
|
+
for (const attr of IDREF_ATTRS) {
|
|
61
|
+
for (const token of splitTokens(el.getAttribute(attr) ?? void 0)) idRefs.push({ id: token, attr });
|
|
62
|
+
}
|
|
63
|
+
if (tag === "template") return;
|
|
64
|
+
const nextCtx = {
|
|
65
|
+
sectioning: ctx.sectioning + (SECTIONING_TAGS.has(tag) ? 1 : 0),
|
|
66
|
+
landmarks: landmark ? [...ctx.landmarks, landmark] : ctx.landmarks
|
|
67
|
+
};
|
|
68
|
+
for (const child of el.children) walk(child, nextCtx);
|
|
69
|
+
};
|
|
70
|
+
for (const child of root.children) walk(child, { sectioning: 0, landmarks: [] });
|
|
71
|
+
return { landmarks, nestedLandmarks, ids, idRefs };
|
|
72
|
+
}
|
|
29
73
|
function parseHtmlHead(html) {
|
|
30
74
|
const root = parse(html);
|
|
31
75
|
const head = root.querySelector("head") ?? root;
|
|
@@ -63,9 +107,9 @@ function parseHtmlHead(html) {
|
|
|
63
107
|
});
|
|
64
108
|
}
|
|
65
109
|
for (const link of head.querySelectorAll("link")) {
|
|
66
|
-
const rel = link.getAttribute("rel");
|
|
110
|
+
const rel = link.getAttribute("rel")?.toLowerCase();
|
|
67
111
|
if (!rel) continue;
|
|
68
|
-
const asAttr = link.getAttribute("as");
|
|
112
|
+
const asAttr = link.getAttribute("as")?.toLowerCase();
|
|
69
113
|
const hasCrossorigin = link.hasAttribute("crossorigin");
|
|
70
114
|
const hreflang = link.getAttribute("hreflang");
|
|
71
115
|
const href = link.getAttribute("href");
|
|
@@ -118,7 +162,63 @@ function parseHtmlHead(html) {
|
|
|
118
162
|
hasSrcset: img.hasAttribute("srcset"),
|
|
119
163
|
line: 0
|
|
120
164
|
}));
|
|
121
|
-
|
|
165
|
+
const a11y = collectA11y(root);
|
|
166
|
+
return { tags, htmlLang, headings, images, ...a11y };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/providers/rendered/collect.ts
|
|
170
|
+
import { readFile } from "fs/promises";
|
|
171
|
+
import { join } from "path";
|
|
172
|
+
import { glob } from "tinyglobby";
|
|
173
|
+
function toOccurrenceMap(keys, file) {
|
|
174
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
175
|
+
for (const key of keys) (out[key] ??= []).push({ file, line: 0 });
|
|
176
|
+
return out;
|
|
177
|
+
}
|
|
178
|
+
function deriveRouteFromHtmlPath(relPath) {
|
|
179
|
+
let p = relPath.replace(/\\/g, "/").replace(/\.html$/, "");
|
|
180
|
+
if (p === "index") return "/";
|
|
181
|
+
if (p.endsWith("/index")) p = p.slice(0, -"/index".length);
|
|
182
|
+
return "/" + p;
|
|
183
|
+
}
|
|
184
|
+
async function collectRenderedHeads(prerenderPagesDir) {
|
|
185
|
+
const files = (await glob("**/*.html", { cwd: prerenderPagesDir })).sort();
|
|
186
|
+
const parsedFiles = await Promise.all(
|
|
187
|
+
files.map(async (rel) => ({ rel, parsed: parseHtmlHead(await readFile(join(prerenderPagesDir, rel), "utf8")) }))
|
|
188
|
+
);
|
|
189
|
+
const heads = [];
|
|
190
|
+
const headings = [];
|
|
191
|
+
const images = [];
|
|
192
|
+
const a11y = [];
|
|
193
|
+
let htmlLang = { presence: "none", value: "absent" };
|
|
194
|
+
for (const { rel, parsed } of parsedFiles) {
|
|
195
|
+
if (htmlLang.presence === "none" && parsed.htmlLang.presence === "own") htmlLang = parsed.htmlLang;
|
|
196
|
+
const route = deriveRouteFromHtmlPath(rel);
|
|
197
|
+
heads.push({
|
|
198
|
+
route,
|
|
199
|
+
source: "rendered",
|
|
200
|
+
tags: parsed.tags,
|
|
201
|
+
file: rel
|
|
202
|
+
});
|
|
203
|
+
headings.push({
|
|
204
|
+
route,
|
|
205
|
+
// Rendered mode does not track source lines (line 0 = unknown); file is the HTML path.
|
|
206
|
+
headings: parsed.headings.map((level) => ({ level, line: 0, file: rel }))
|
|
207
|
+
});
|
|
208
|
+
images.push({ route, images: parsed.images.map((img) => ({ ...img, file: rel })) });
|
|
209
|
+
a11y.push({
|
|
210
|
+
route,
|
|
211
|
+
landmarks: toOccurrenceMap(parsed.landmarks, rel),
|
|
212
|
+
nestedLandmarks: parsed.nestedLandmarks.map((n) => ({ ...n, file: rel, line: 0 })),
|
|
213
|
+
ids: toOccurrenceMap(parsed.ids, rel),
|
|
214
|
+
idRefs: parsed.idRefs.map((r) => ({ ...r, file: rel, line: 0 })),
|
|
215
|
+
idCandidates: [...new Set(parsed.ids)],
|
|
216
|
+
// The prerendered document IS the closed world: every id/landmark/reference it can ever
|
|
217
|
+
// have is already in it, unlike source mode which may hit an unresolved component.
|
|
218
|
+
fullyResolved: true
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return { heads, headings, images, a11y, htmlLang };
|
|
122
222
|
}
|
|
123
223
|
|
|
124
224
|
// src/loopback.ts
|
|
@@ -133,5 +233,7 @@ function isLoopbackOrigin(origin) {
|
|
|
133
233
|
|
|
134
234
|
export {
|
|
135
235
|
parseHtmlHead,
|
|
236
|
+
toOccurrenceMap,
|
|
237
|
+
collectRenderedHeads,
|
|
136
238
|
isLoopbackOrigin
|
|
137
239
|
};
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isLoopbackOrigin,
|
|
3
|
-
parseHtmlHead
|
|
4
|
-
|
|
3
|
+
parseHtmlHead,
|
|
4
|
+
toOccurrenceMap
|
|
5
|
+
} from "../chunk-6FDRI4Q6.js";
|
|
5
6
|
|
|
6
7
|
// src/hooks/handle.ts
|
|
7
8
|
import { DEV } from "esm-env";
|
|
@@ -42,17 +43,38 @@ async function postIngest(origin, route, results, failedRuleIds) {
|
|
|
42
43
|
}
|
|
43
44
|
async function analyzeAndIngest(html, route, origin, rules, config, lastSignature) {
|
|
44
45
|
try {
|
|
45
|
-
const {
|
|
46
|
+
const {
|
|
47
|
+
tags,
|
|
48
|
+
htmlLang,
|
|
49
|
+
headings: levels,
|
|
50
|
+
images: imgs,
|
|
51
|
+
landmarks,
|
|
52
|
+
nestedLandmarks,
|
|
53
|
+
ids,
|
|
54
|
+
idRefs
|
|
55
|
+
} = parseHtmlHead(html);
|
|
46
56
|
const head = { route, source: "rendered", tags, file: route };
|
|
47
57
|
const headings = [
|
|
48
58
|
{ route, headings: levels.map((level) => ({ level, line: 0, file: route })) }
|
|
49
59
|
];
|
|
50
60
|
const images = [{ route, images: imgs.map((img) => ({ ...img, file: route })) }];
|
|
61
|
+
const a11y = [
|
|
62
|
+
{
|
|
63
|
+
route,
|
|
64
|
+
landmarks: toOccurrenceMap(landmarks, route),
|
|
65
|
+
nestedLandmarks: nestedLandmarks.map((n) => ({ ...n, file: route, line: 0 })),
|
|
66
|
+
ids: toOccurrenceMap(ids, route),
|
|
67
|
+
idRefs: idRefs.map((r) => ({ ...r, file: route, line: 0 })),
|
|
68
|
+
idCandidates: [...new Set(ids)],
|
|
69
|
+
fullyResolved: true
|
|
70
|
+
}
|
|
71
|
+
];
|
|
51
72
|
const project = { hasRobotsTxt: true, hasSitemap: true, htmlLang };
|
|
52
73
|
const { results: ruleResults, failedRules } = await runRules(rules, {
|
|
53
74
|
heads: [head],
|
|
54
75
|
headings,
|
|
55
76
|
images,
|
|
77
|
+
a11y,
|
|
56
78
|
project,
|
|
57
79
|
config
|
|
58
80
|
});
|
|
@@ -84,15 +106,8 @@ function svelteVitalsHandle(options = {}) {
|
|
|
84
106
|
return resolve(event, {
|
|
85
107
|
transformPageChunk: ({ html, done }) => {
|
|
86
108
|
buffer += html;
|
|
87
|
-
if (done)
|
|
88
|
-
void analyzeAndIngest(
|
|
89
|
-
buffer,
|
|
90
|
-
event.route.id ?? event.url.pathname,
|
|
91
|
-
event.url.origin,
|
|
92
|
-
rules,
|
|
93
|
-
config,
|
|
94
|
-
lastSignature
|
|
95
|
-
);
|
|
109
|
+
if (done && event.route.id != null)
|
|
110
|
+
void analyzeAndIngest(buffer, event.route.id, event.url.origin, rules, config, lastSignature);
|
|
96
111
|
return html;
|
|
97
112
|
}
|
|
98
113
|
});
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-
|
|
2
|
+
collectRenderedHeads,
|
|
3
|
+
isLoopbackOrigin
|
|
4
|
+
} from "./chunk-6FDRI4Q6.js";
|
|
5
5
|
|
|
6
6
|
// src/plugin.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
8
8
|
import { writeFile, mkdir } from "fs/promises";
|
|
9
|
-
import { join as
|
|
9
|
+
import { join as join3, isAbsolute, dirname, relative as relative3, basename, sep as sep2 } from "path";
|
|
10
10
|
import {
|
|
11
11
|
CATEGORIES as CATEGORIES2,
|
|
12
12
|
defaultConfig,
|
|
@@ -35,47 +35,9 @@ import {
|
|
|
35
35
|
} from "@svelte-vitals/core";
|
|
36
36
|
import { loadConfigFile } from "svelte-vitals";
|
|
37
37
|
|
|
38
|
-
// src/providers/rendered/collect.ts
|
|
39
|
-
import { readFile } from "fs/promises";
|
|
40
|
-
import { join } from "path";
|
|
41
|
-
import { glob } from "tinyglobby";
|
|
42
|
-
function deriveRouteFromHtmlPath(relPath) {
|
|
43
|
-
let p = relPath.replace(/\\/g, "/").replace(/\.html$/, "");
|
|
44
|
-
if (p === "index") return "/";
|
|
45
|
-
if (p.endsWith("/index")) p = p.slice(0, -"/index".length);
|
|
46
|
-
return "/" + p;
|
|
47
|
-
}
|
|
48
|
-
async function collectRenderedHeads(prerenderPagesDir) {
|
|
49
|
-
const files = (await glob("**/*.html", { cwd: prerenderPagesDir })).sort();
|
|
50
|
-
const parsedFiles = await Promise.all(
|
|
51
|
-
files.map(async (rel) => ({ rel, parsed: parseHtmlHead(await readFile(join(prerenderPagesDir, rel), "utf8")) }))
|
|
52
|
-
);
|
|
53
|
-
const heads = [];
|
|
54
|
-
const headings = [];
|
|
55
|
-
const images = [];
|
|
56
|
-
let htmlLang = { presence: "none", value: "absent" };
|
|
57
|
-
for (const { rel, parsed } of parsedFiles) {
|
|
58
|
-
if (htmlLang.presence === "none" && parsed.htmlLang.presence === "own") htmlLang = parsed.htmlLang;
|
|
59
|
-
const route = deriveRouteFromHtmlPath(rel);
|
|
60
|
-
heads.push({
|
|
61
|
-
route,
|
|
62
|
-
source: "rendered",
|
|
63
|
-
tags: parsed.tags,
|
|
64
|
-
file: rel
|
|
65
|
-
});
|
|
66
|
-
headings.push({
|
|
67
|
-
route,
|
|
68
|
-
// Rendered mode does not track source lines (line 0 = unknown); file is the HTML path.
|
|
69
|
-
headings: parsed.headings.map((level) => ({ level, line: 0, file: rel }))
|
|
70
|
-
});
|
|
71
|
-
images.push({ route, images: parsed.images.map((img) => ({ ...img, file: rel })) });
|
|
72
|
-
}
|
|
73
|
-
return { heads, headings, images, htmlLang };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
38
|
// src/providers/rendered/project.ts
|
|
77
|
-
import { access, readFile
|
|
78
|
-
import { join
|
|
39
|
+
import { access, readFile } from "fs/promises";
|
|
40
|
+
import { join } from "path";
|
|
79
41
|
import {
|
|
80
42
|
ROBOTS_SOURCE_PATHS,
|
|
81
43
|
SITEMAP_SOURCE_PATHS,
|
|
@@ -93,22 +55,22 @@ async function exists(path) {
|
|
|
93
55
|
}
|
|
94
56
|
}
|
|
95
57
|
async function existsAny(cwd, paths) {
|
|
96
|
-
const found = await Promise.all(paths.map((p) => exists(
|
|
58
|
+
const found = await Promise.all(paths.map((p) => exists(join(cwd, p))));
|
|
97
59
|
return found.some(Boolean);
|
|
98
60
|
}
|
|
99
61
|
async function robotsRefsSitemap(cwd) {
|
|
100
62
|
try {
|
|
101
|
-
return /^\s*sitemap:/im.test(await
|
|
63
|
+
return /^\s*sitemap:/im.test(await readFile(join(cwd, "static/robots.txt"), "utf8"));
|
|
102
64
|
} catch {
|
|
103
65
|
return void 0;
|
|
104
66
|
}
|
|
105
67
|
}
|
|
106
68
|
async function readFirstConfig(cwd, files) {
|
|
107
69
|
for (const file of files) {
|
|
108
|
-
const path =
|
|
70
|
+
const path = join(cwd, file);
|
|
109
71
|
if (!await exists(path)) continue;
|
|
110
72
|
try {
|
|
111
|
-
return { file, source: await
|
|
73
|
+
return { file, source: await readFile(path, "utf8") };
|
|
112
74
|
} catch {
|
|
113
75
|
return void 0;
|
|
114
76
|
}
|
|
@@ -136,16 +98,16 @@ async function collectRenderedProject(cwd, htmlLang) {
|
|
|
136
98
|
}
|
|
137
99
|
|
|
138
100
|
// src/providers/source/components.ts
|
|
139
|
-
import { readFile as
|
|
140
|
-
import { join as
|
|
141
|
-
import { glob
|
|
101
|
+
import { readFile as readFile2, access as access2 } from "fs/promises";
|
|
102
|
+
import { join as join2 } from "path";
|
|
103
|
+
import { glob } from "tinyglobby";
|
|
142
104
|
import {
|
|
143
105
|
collectComponentFacts as collect,
|
|
144
106
|
collectKitModuleFacts as collectKit,
|
|
145
107
|
collectSourceFiles as collectFiles
|
|
146
108
|
} from "@svelte-vitals/core";
|
|
147
109
|
var nodeRuntime = {
|
|
148
|
-
readFile: (path) =>
|
|
110
|
+
readFile: (path) => readFile2(path, "utf8"),
|
|
149
111
|
async exists(path) {
|
|
150
112
|
try {
|
|
151
113
|
await access2(path);
|
|
@@ -154,8 +116,8 @@ var nodeRuntime = {
|
|
|
154
116
|
return false;
|
|
155
117
|
}
|
|
156
118
|
},
|
|
157
|
-
glob: (pattern, cwd) =>
|
|
158
|
-
join: (...parts) =>
|
|
119
|
+
glob: (pattern, cwd) => glob(pattern, { cwd, dot: false }),
|
|
120
|
+
join: (...parts) => join2(...parts)
|
|
159
121
|
};
|
|
160
122
|
function collectComponentFacts(root) {
|
|
161
123
|
return collect(nodeRuntime, root);
|
|
@@ -207,7 +169,7 @@ async function resolveConfig(cwd, options) {
|
|
|
207
169
|
}
|
|
208
170
|
async function analyze(prerenderPagesDir, cwd, options, extraProjectFacts, resolved) {
|
|
209
171
|
const { config, warnings } = resolved ?? await resolveConfig(cwd, options);
|
|
210
|
-
const [{ heads, headings, images, htmlLang }, components, sourceFiles] = await Promise.all([
|
|
172
|
+
const [{ heads, headings, images, a11y, htmlLang }, components, sourceFiles] = await Promise.all([
|
|
211
173
|
collectRenderedHeads(prerenderPagesDir),
|
|
212
174
|
collectComponentFacts(cwd),
|
|
213
175
|
collectSourceFiles(cwd)
|
|
@@ -226,6 +188,7 @@ async function analyze(prerenderPagesDir, cwd, options, extraProjectFacts, resol
|
|
|
226
188
|
heads,
|
|
227
189
|
headings,
|
|
228
190
|
images,
|
|
191
|
+
a11y,
|
|
229
192
|
project,
|
|
230
193
|
components,
|
|
231
194
|
config,
|
|
@@ -242,7 +205,7 @@ async function analyze(prerenderPagesDir, cwd, options, extraProjectFacts, resol
|
|
|
242
205
|
const summary = summarize(results, scoringConfig);
|
|
243
206
|
const failed = hasFailureAtOrAbove(summary, scoringConfig.failOn);
|
|
244
207
|
const coverageNote = `Analyzed ${heads.length} prerendered route(s). SSR/dynamic routes are not covered \u2014 run \`npx svelte-vitals\` for those.
|
|
245
|
-
Scanned ${components.length} component(s) under src/ for Correctness/Security/Architecture/Bundle findings.`;
|
|
208
|
+
Scanned ${components.length} component(s) under src/ for Correctness/Security/Architecture/Accessibility/Bundle findings.`;
|
|
246
209
|
const consoleReport = formatConsoleReport(results, scoringConfig, { mode: "rendered / plugin" }) + "\n" + coverageNote + "\n";
|
|
247
210
|
const jsonReport = formatJsonReport(
|
|
248
211
|
results,
|
|
@@ -265,7 +228,7 @@ Scanned ${components.length} component(s) under src/ for Correctness/Security/Ar
|
|
|
265
228
|
}
|
|
266
229
|
|
|
267
230
|
// src/minify-flag.ts
|
|
268
|
-
import { readFile as
|
|
231
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
269
232
|
import { relative } from "path";
|
|
270
233
|
import { findMinifyDisabled } from "@svelte-vitals/core";
|
|
271
234
|
async function resolveMinifyDisabled(minify, configFile, root) {
|
|
@@ -275,7 +238,7 @@ async function resolveMinifyDisabled(minify, configFile, root) {
|
|
|
275
238
|
const file = rel === "" ? configFile.split("\\").join("/") : rel;
|
|
276
239
|
let line;
|
|
277
240
|
try {
|
|
278
|
-
line = findMinifyDisabled(await
|
|
241
|
+
line = findMinifyDisabled(await readFile3(configFile, "utf8"))?.line;
|
|
279
242
|
} catch {
|
|
280
243
|
}
|
|
281
244
|
return { file, ...line !== void 0 ? { line } : {} };
|
|
@@ -626,23 +589,27 @@ function svelteVitals(options = {}) {
|
|
|
626
589
|
validateRulesOption(options.rules);
|
|
627
590
|
validateOverridesOption(options.overrides, options.rules);
|
|
628
591
|
let root = options.cwd ?? process.cwd();
|
|
629
|
-
let
|
|
592
|
+
let minify;
|
|
593
|
+
let configFile;
|
|
630
594
|
const buildPlugin = {
|
|
631
595
|
name: "svelte-vitals",
|
|
632
596
|
apply: "build",
|
|
633
597
|
enforce: "post",
|
|
598
|
+
config(userConfig) {
|
|
599
|
+
minify = userConfig.build?.minify;
|
|
600
|
+
},
|
|
634
601
|
configResolved(config) {
|
|
635
602
|
if (!options.cwd) root = config.root;
|
|
636
|
-
|
|
603
|
+
configFile = config.configFile;
|
|
637
604
|
},
|
|
638
605
|
async closeBundle() {
|
|
639
|
-
const pagesDir = options.prerenderDir ? options.prerenderDir :
|
|
640
|
-
const resolved = isAbsolute(pagesDir) ? pagesDir :
|
|
606
|
+
const pagesDir = options.prerenderDir ? options.prerenderDir : join3(root, DEFAULT_PRERENDER_DIR);
|
|
607
|
+
const resolved = isAbsolute(pagesDir) ? pagesDir : join3(root, pagesDir);
|
|
641
608
|
if (!existsSync(resolved)) return;
|
|
642
609
|
const resolvedConfig = await resolveConfig(root, options);
|
|
643
610
|
let result;
|
|
644
611
|
try {
|
|
645
|
-
const viteMinifyDisabled =
|
|
612
|
+
const viteMinifyDisabled = await resolveMinifyDisabled(minify, configFile, root);
|
|
646
613
|
result = await analyze(
|
|
647
614
|
resolved,
|
|
648
615
|
root,
|
|
@@ -661,7 +628,7 @@ function svelteVitals(options = {}) {
|
|
|
661
628
|
console.log(out);
|
|
662
629
|
}
|
|
663
630
|
if (options.outFile) {
|
|
664
|
-
const outPath = isAbsolute(options.outFile) ? options.outFile :
|
|
631
|
+
const outPath = isAbsolute(options.outFile) ? options.outFile : join3(root, options.outFile);
|
|
665
632
|
await mkdir(dirname(outPath), { recursive: true });
|
|
666
633
|
await writeFile(outPath, result.jsonReport);
|
|
667
634
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svelte-vitals/vite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.1",
|
|
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",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"esm-env": "^1.2.2",
|
|
43
43
|
"node-html-parser": "^9.0.1",
|
|
44
44
|
"tinyglobby": "^0.2.17",
|
|
45
|
-
"@svelte-vitals/core": "0.
|
|
46
|
-
"svelte-vitals": "0.
|
|
45
|
+
"@svelte-vitals/core": "0.43.1",
|
|
46
|
+
"svelte-vitals": "0.47.1"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@sveltejs/kit": "^2.70.2",
|