apex-auditor 0.2.6 → 0.2.8
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 +46 -100
- package/dist/route-detectors.js +52 -0
- package/dist/wizard-cli.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,144 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
ApexAuditor is a small, framework-agnostic Lighthouse runner that gives you **fast, structured insights** across multiple pages and devices.
|
|
4
4
|
|
|
5
|
-
It
|
|
5
|
+
It focuses on:
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
|
|
12
|
-
> V1 focuses on a solid, single-project core. Route auto-detection and monorepo orchestration will land in later versions.
|
|
7
|
+
- **Multi-page, multi-device audits**: run Lighthouse across your key flows in one shot.
|
|
8
|
+
- **Framework flexibility**: works with any stack that serves HTTP (Next.js, Remix, Vite/React, SvelteKit, Rails, static sites, etc.).
|
|
9
|
+
- **Smart route discovery**: auto-detects routes for Next.js (App/Pages), Remix, SvelteKit, and can crawl generic SPAs.
|
|
10
|
+
- **Developer-friendly reports**: readable console output, Markdown tables, and JSON summaries for CI.
|
|
13
11
|
|
|
14
12
|
---
|
|
15
13
|
|
|
16
|
-
##
|
|
14
|
+
## Example output
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
Terminal summary:
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+

|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
pnpm install
|
|
24
|
-
```
|
|
20
|
+

|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
Wizard route selection:
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+

|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
pnpm start
|
|
32
|
-
# or: pnpm dev, npm run dev, etc.
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Make sure the app is reachable at the `baseUrl` you will configure (default example: `http://localhost:3000`).
|
|
26
|
+
---
|
|
36
27
|
|
|
37
|
-
|
|
28
|
+
## Installation
|
|
38
29
|
|
|
39
|
-
|
|
30
|
+
Install as a dev dependency (recommended):
|
|
40
31
|
|
|
41
32
|
```bash
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
pnpm add -D apex-auditor
|
|
34
|
+
# or
|
|
35
|
+
npm install --save-dev apex-auditor
|
|
45
36
|
```
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
### 4. Configure pages (wizard-friendly)
|
|
50
|
-
|
|
51
|
-
Run the guided wizard to scaffold `apex.config.json` and optionally auto-discover routes:
|
|
38
|
+
You can also run it without installing by using your package manager's "dlx"/"npx" style command, for example:
|
|
52
39
|
|
|
53
40
|
```bash
|
|
54
|
-
pnpm wizard
|
|
41
|
+
pnpm dlx apex-auditor@latest wizard
|
|
55
42
|
```
|
|
56
43
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```jsonc
|
|
60
|
-
{
|
|
61
|
-
"baseUrl": "http://localhost:3000",
|
|
62
|
-
"query": "?lhci=1",
|
|
63
|
-
"chromePort": 9222,
|
|
64
|
-
"runs": 1,
|
|
65
|
-
"pages": [
|
|
66
|
-
{ "path": "/", "label": "home", "devices": ["mobile", "desktop"] },
|
|
67
|
-
{ "path": "/blog", "label": "blog", "devices": ["mobile", "desktop"] },
|
|
68
|
-
{ "path": "/contact", "label": "contact", "devices": ["mobile"] }
|
|
69
|
-
]
|
|
70
|
-
}
|
|
71
|
-
```
|
|
44
|
+
---
|
|
72
45
|
|
|
73
|
-
|
|
46
|
+
## Common commands
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
- `query` (optional): query string appended to every URL (for example `?lhci=1` to disable analytics).
|
|
77
|
-
- `chromePort` (optional): remote debugging port (defaults to `9222`).
|
|
78
|
-
- `runs` (optional): how many times to run Lighthouse per page/device (results are averaged).
|
|
79
|
-
- `pages`: list of paths and devices to audit.
|
|
48
|
+
All commands are available as a CLI named `apex-auditor` once installed.
|
|
80
49
|
|
|
81
|
-
###
|
|
50
|
+
### Quickstart (auto-detect routes and run a one-off audit)
|
|
82
51
|
|
|
83
52
|
```bash
|
|
84
|
-
|
|
53
|
+
apex-auditor quickstart --base-url http://localhost:3000
|
|
85
54
|
```
|
|
86
55
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- Run Lighthouse for every `page × device` defined in `apex.config.json`.
|
|
90
|
-
- Write structured results to `.apex-auditor/summary.json`.
|
|
91
|
-
- Write a human-readable table to `.apex-auditor/summary.md`.
|
|
92
|
-
- Print the same table to the terminal.
|
|
56
|
+
### Wizard (interactive config with route auto-detection)
|
|
93
57
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```text
|
|
97
|
-
| Label | Path | Device | P | A | BP | SEO | LCP (s) | FCP (s) | TBT (ms) | CLS | Top issues |
|
|
98
|
-
|-------|------|---------|----|----|----|-----|---------|---------|----------|-------|-----------|
|
|
99
|
-
| home | / | mobile | 95 |100 |100 |100 | 2.9 | 0.9 | 160 | 0.002 | render-blocking-resources (140ms); unused-javascript (55KB) |
|
|
100
|
-
| home | / | desktop |100 |100 |100 |100 | 0.6 | 0.4 | 0 | 0.016 | unused-javascript (55KB) |
|
|
58
|
+
```bash
|
|
59
|
+
apex-auditor wizard
|
|
101
60
|
```
|
|
102
61
|
|
|
103
|
-
|
|
62
|
+
The wizard can detect routes for:
|
|
104
63
|
|
|
105
|
-
|
|
64
|
+
- Next.js (App Router / Pages Router)
|
|
65
|
+
- Remix
|
|
66
|
+
- SvelteKit
|
|
67
|
+
- Single Page Apps (Vite/CRA/etc., via HTML crawl)
|
|
68
|
+
|
|
69
|
+
### Audit (run using an existing config)
|
|
106
70
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
// apex.config.json (TypeScript shape)
|
|
111
|
-
interface ApexPageConfig {
|
|
112
|
-
path: string; // URL path, must start with "/"
|
|
113
|
-
label: string; // short label for reports
|
|
114
|
-
devices: ("mobile" | "desktop")[];
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
interface ApexConfig {
|
|
118
|
-
baseUrl: string; // e.g. "http://localhost:3000"
|
|
119
|
-
query?: string; // e.g. "?lhci=1"
|
|
120
|
-
chromePort?: number; // default: 9222
|
|
121
|
-
runs?: number; // default: 1
|
|
122
|
-
pages: ApexPageConfig[];
|
|
123
|
-
}
|
|
71
|
+
```bash
|
|
72
|
+
apex-auditor audit --config apex.config.json
|
|
124
73
|
```
|
|
125
74
|
|
|
126
|
-
|
|
75
|
+
Useful flags:
|
|
127
76
|
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
-
|
|
77
|
+
- `--ci` – enable CI mode with budgets and non-zero exit codes.
|
|
78
|
+
- `--no-color` / `--color` – control ANSI colours in console output.
|
|
79
|
+
- `--log-level <silent|error|info|verbose>` – override Lighthouse log level.
|
|
131
80
|
|
|
132
81
|
---
|
|
133
82
|
|
|
134
|
-
##
|
|
135
|
-
|
|
136
|
-
The codebase is intentionally small and modular:
|
|
83
|
+
## Further documentation
|
|
137
84
|
|
|
138
|
-
|
|
139
|
-
- `src/config.ts` – loads and validates `apex.config.json`.
|
|
140
|
-
- `src/lighthouse-runner.ts` – runs Lighthouse for each page/device and normalises results.
|
|
141
|
-
- `src/cli.ts` – CLI entry point; orchestrates config + runner, writes JSON/Markdown.
|
|
85
|
+
For detailed guides, configuration options, and CI examples, see the `docs/` directory:
|
|
142
86
|
|
|
143
|
-
|
|
87
|
+
- `docs/getting-started.md` – installation, quickstart, wizard, and audit flows.
|
|
88
|
+
- `docs/configuration-and-routes.md` – `apex.config.json` schema and route detection details.
|
|
89
|
+
- `docs/cli-and-ci.md` – CLI flags, CI mode, budgets, and example workflows.
|
|
144
90
|
|
|
145
|
-
|
|
91
|
+
For the longer-term vision and planned features, see `ROADMAP.md`.
|
package/dist/route-detectors.js
CHANGED
|
@@ -6,11 +6,13 @@ const DEFAULT_LIMIT = 200;
|
|
|
6
6
|
const SOURCE_NEXT_APP = "next-app";
|
|
7
7
|
const SOURCE_NEXT_PAGES = "next-pages";
|
|
8
8
|
const SOURCE_REMIX = "remix-routes";
|
|
9
|
+
const SOURCE_SVELTEKIT = "sveltekit-routes";
|
|
9
10
|
const SOURCE_SPA = "spa-html";
|
|
10
11
|
const ROUTE_DETECTORS = [
|
|
11
12
|
createNextAppDetector(),
|
|
12
13
|
createNextPagesDetector(),
|
|
13
14
|
createRemixRoutesDetector(),
|
|
15
|
+
createSvelteKitRoutesDetector(),
|
|
14
16
|
createSpaHtmlDetector(),
|
|
15
17
|
];
|
|
16
18
|
export async function detectRoutes(options) {
|
|
@@ -60,6 +62,19 @@ function createNextAppDetector() {
|
|
|
60
62
|
},
|
|
61
63
|
};
|
|
62
64
|
}
|
|
65
|
+
function createSvelteKitRoutesDetector() {
|
|
66
|
+
return {
|
|
67
|
+
id: SOURCE_SVELTEKIT,
|
|
68
|
+
canDetect: async (options) => {
|
|
69
|
+
const routesRoot = join(options.projectRoot, "src", "routes");
|
|
70
|
+
return pathExists(routesRoot);
|
|
71
|
+
},
|
|
72
|
+
detect: async (options) => {
|
|
73
|
+
const routesRoot = join(options.projectRoot, "src", "routes");
|
|
74
|
+
return detectSvelteKitRoutes(routesRoot, options.limit);
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
63
78
|
function createNextPagesDetector() {
|
|
64
79
|
return {
|
|
65
80
|
id: SOURCE_NEXT_PAGES,
|
|
@@ -191,6 +206,10 @@ async function detectRemixRoutes(routesRoot, limit) {
|
|
|
191
206
|
const files = await collectRouteFiles(routesRoot, limit, isRemixRouteFile);
|
|
192
207
|
return files.map((file) => buildRoute(file, routesRoot, formatRemixRoutePath, SOURCE_REMIX));
|
|
193
208
|
}
|
|
209
|
+
async function detectSvelteKitRoutes(routesRoot, limit) {
|
|
210
|
+
const files = await collectRouteFiles(routesRoot, limit, isSvelteKitPageFile);
|
|
211
|
+
return files.map((file) => buildRoute(file, routesRoot, formatSvelteKitRoutePath, SOURCE_SVELTEKIT));
|
|
212
|
+
}
|
|
194
213
|
async function detectSpaRoutes(projectRoot, limit) {
|
|
195
214
|
const htmlPath = await findSpaHtml(projectRoot);
|
|
196
215
|
if (!htmlPath) {
|
|
@@ -270,6 +289,17 @@ function isRemixRouteFile(entry, relativePath) {
|
|
|
270
289
|
}
|
|
271
290
|
return !posixPath.split("/").some((segment) => segment.startsWith("__"));
|
|
272
291
|
}
|
|
292
|
+
function isSvelteKitPageFile(entry, relativePath) {
|
|
293
|
+
if (!entry.isFile()) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
const posixPath = normalisePath(relativePath);
|
|
297
|
+
return (posixPath.endsWith("+page.svelte") ||
|
|
298
|
+
posixPath.endsWith("+page.ts") ||
|
|
299
|
+
posixPath.endsWith("+page.js") ||
|
|
300
|
+
posixPath.endsWith("+page.tsx") ||
|
|
301
|
+
posixPath.endsWith("+page.jsx"));
|
|
302
|
+
}
|
|
273
303
|
function hasAllowedExtension(path) {
|
|
274
304
|
return PAGE_EXTENSIONS.some((extension) => path.endsWith(extension));
|
|
275
305
|
}
|
|
@@ -329,6 +359,28 @@ function formatRemixRoutePath(relativePath) {
|
|
|
329
359
|
.filter((segment) => segment.length > 0);
|
|
330
360
|
return parts.length === 0 ? "/" : normaliseRoute(parts.join("/"));
|
|
331
361
|
}
|
|
362
|
+
function formatSvelteKitRoutePath(relativePath) {
|
|
363
|
+
const cleanPath = relativePath.replace(/\\/g, "/");
|
|
364
|
+
const withoutFile = cleanPath.replace(/\/?\+page\.[^/]+$/, "");
|
|
365
|
+
const segments = withoutFile.split("/").filter((segment) => segment.length > 0);
|
|
366
|
+
const parts = segments
|
|
367
|
+
.filter((segment) => !(segment.startsWith("(") && segment.endsWith(")")))
|
|
368
|
+
.map((segment) => {
|
|
369
|
+
if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
370
|
+
const inner = segment.slice(1, -1);
|
|
371
|
+
const name = inner.replace(/^\.\.\./, "");
|
|
372
|
+
if (name.length === 0) {
|
|
373
|
+
return ":param";
|
|
374
|
+
}
|
|
375
|
+
return `:${name}`;
|
|
376
|
+
}
|
|
377
|
+
return segment;
|
|
378
|
+
});
|
|
379
|
+
if (parts.length === 0) {
|
|
380
|
+
return "/";
|
|
381
|
+
}
|
|
382
|
+
return normaliseRoute(parts.join("/"));
|
|
383
|
+
}
|
|
332
384
|
function normaliseRoute(path) {
|
|
333
385
|
const trimmed = path.replace(/^\/+/, "");
|
|
334
386
|
if (trimmed.length === 0) {
|
package/dist/wizard-cli.js
CHANGED
|
@@ -9,6 +9,7 @@ const PROFILE_TO_DETECTOR = {
|
|
|
9
9
|
"next-pages": "next-pages",
|
|
10
10
|
spa: "spa-html",
|
|
11
11
|
remix: "remix-routes",
|
|
12
|
+
sveltekit: "sveltekit-routes",
|
|
12
13
|
custom: undefined,
|
|
13
14
|
};
|
|
14
15
|
const DEFAULT_BASE_URL = "http://localhost:3000";
|
|
@@ -25,6 +26,7 @@ const profileQuestion = {
|
|
|
25
26
|
{ title: "Next.js (App Router)", value: "next-app" },
|
|
26
27
|
{ title: "Next.js (Pages Router)", value: "next-pages" },
|
|
27
28
|
{ title: "Remix", value: "remix" },
|
|
29
|
+
{ title: "SvelteKit", value: "sveltekit" },
|
|
28
30
|
{ title: "Single Page App (Vite/CRA/etc.)", value: "spa" },
|
|
29
31
|
{ title: "Custom/manual", value: "custom" },
|
|
30
32
|
],
|
|
@@ -113,6 +115,7 @@ const detectorChoiceQuestion = {
|
|
|
113
115
|
{ title: "Next.js (App Router)", value: "next-app" },
|
|
114
116
|
{ title: "Next.js (Pages Router)", value: "next-pages" },
|
|
115
117
|
{ title: "Remix", value: "remix-routes" },
|
|
118
|
+
{ title: "SvelteKit", value: "sveltekit-routes" },
|
|
116
119
|
{ title: "SPA Crawl", value: "spa-html" },
|
|
117
120
|
],
|
|
118
121
|
};
|