Skip to content

Commit 42bfb62

Browse files
committed
feat(cli): add viewport presets with mobile as default
Replace the hardcoded desktop viewport with named presets (mobile, tablet, desktop). Mobile (375×812) is now the default, matching real-world usage. The --viewport flag lets callers select a preset from the CLI.
1 parent df66419 commit 42bfb62

2 files changed

Lines changed: 17 additions & 3 deletions

File tree

cli/src/bin.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env node
22
import { parseArgs } from "node:util";
33
import { loadSnippet } from "./load-snippet.js";
4-
import { runSnippets } from "./runner.js";
4+
import { runSnippets, VIEWPORT_PRESETS } from "./runner.js";
55
import { cwvWorkflow } from "./workflows/cwv.js";
66
import { nextSteps } from "./decision-tree.js";
77
import { reportHuman } from "./reporters/human.js";
@@ -25,6 +25,7 @@ Options:
2525
--workflow <name> Workflow to run (default: core-web-vitals)
2626
--snippet <name> Run a single snippet (e.g. LCP, CLS, or Category/Name)
2727
--json Output JSON instead of formatted text
28+
--viewport <preset> Viewport preset: mobile (default), tablet, desktop
2829
--wait <ms> Post-load wait before evaluating (default: 3000)
2930
--budget-lcp <ms> Exit 1 if LCP exceeds this value
3031
--budget-cls <score> Exit 1 if CLS exceeds this value
@@ -90,6 +91,7 @@ async function main() {
9091
wait: { type: "string" },
9192
"budget-lcp": { type: "string" },
9293
"budget-cls": { type: "string" },
94+
viewport: { type: "string" },
9395
headed: { type: "boolean" },
9496
help: { type: "boolean", short: "h" },
9597
},
@@ -114,12 +116,18 @@ async function main() {
114116

115117
const items = buildItems(values);
116118
const waitMs = values.wait ? Number(values.wait) : 3000;
119+
const viewportName = values.viewport ?? "mobile";
120+
const viewport = VIEWPORT_PRESETS[viewportName];
121+
if (!viewport) {
122+
fail(`Unknown viewport preset: "${viewportName}". Choose from: ${Object.keys(VIEWPORT_PRESETS).join(", ")}`);
123+
}
117124

118125
const initial = await runSnippets({
119126
url,
120127
items,
121128
waitMs,
122129
headless: !values.headed,
130+
viewport,
123131
});
124132

125133
// Apply decision tree to spawn follow-up steps.
@@ -139,6 +147,7 @@ async function main() {
139147
items: followItems,
140148
waitMs,
141149
headless: !values.headed,
150+
viewport,
142151
});
143152
// Carry forward the human-readable reason so reporters can show it.
144153
followUpRun.results = followUpRun.results.map((r) => {

cli/src/runner.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { chromium } from "playwright";
22

3-
const DEFAULT_VIEWPORT = { width: 1280, height: 800 };
3+
export const VIEWPORT_PRESETS = {
4+
mobile: { width: 375, height: 812 },
5+
tablet: { width: 768, height: 1024 },
6+
desktop: { width: 1280, height: 800 },
7+
};
8+
49
const DEFAULT_NAV_TIMEOUT = 30000;
510

611
// Snippets are IIFEs. Playwright evaluates a string as an expression, so we
@@ -15,7 +20,7 @@ export async function runSnippets({
1520
items,
1621
waitMs = 3000,
1722
headless = true,
18-
viewport = DEFAULT_VIEWPORT,
23+
viewport = VIEWPORT_PRESETS.mobile,
1924
navTimeout = DEFAULT_NAV_TIMEOUT,
2025
}) {
2126
const browser = await chromium.launch({ headless });

0 commit comments

Comments
 (0)