Skip to content

Commit 09bcfbb

Browse files
committed
chore(docs): use playwright in showcase script
+ ts and use node 22 to run it + qwik version + update after a week
1 parent 796be64 commit 09bcfbb

File tree

4 files changed

+87
-287
lines changed

4 files changed

+87
-287
lines changed

flake.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
bashInteractive
3131
gitMinimal
3232

33-
nodejs_20
34-
corepack_20
33+
nodejs_22
34+
corepack_22
3535

3636
# Playwright for the end-to-end tests
3737
playwright-driver.browsers

packages/docs/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"prettier": "3.6.2",
4444
"prism-themes": "1.9.0",
4545
"prismjs": "1.30.0",
46-
"puppeteer": "22.13.1",
46+
"playwright": "1.40.0",
4747
"qwik-image": "0.0.16",
4848
"react": "18.3.1",
4949
"react-dom": "18.3.1",
@@ -75,7 +75,7 @@
7575
"build.preview": "NODE_OPTIONS=--max-old-space-size=8192 vite build --ssr src/entry.preview.tsx",
7676
"build.repl-sw": "vite --config vite.config-repl-sw.mts build",
7777
"build.server": "NODE_OPTIONS=--max-old-space-size=8192 vite build -c adapters/cloudflare-pages/vite.config.mts",
78-
"build.showcase": "pnpm node scripts/showcase.js",
78+
"build.showcase": "node scripts/showcase.ts",
7979
"codesandbox.sync": "node codesandbox.sync.ts",
8080
"contributors": "node contributors.ts",
8181
"deploy": "wrangler pages publish ./dist",

packages/docs/scripts/showcase.js renamed to packages/docs/scripts/showcase.ts

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,72 @@
1-
/* eslint-disable no-console */
2-
3-
const fs = require('fs');
4-
const puppeteer = require('puppeteer');
5-
const pages = require('./pages.json');
6-
1+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
2+
import { chromium, type Page } from 'playwright';
3+
import { fetch } from 'undici';
4+
import pages from './pages.json' with { type: 'json' };
5+
6+
type InputPageData = {
7+
href: string;
8+
tags: string[];
9+
size: 'small' | 'large';
10+
repo?: string;
11+
};
12+
type PageData = InputPageData & {
13+
title?: string;
14+
imgSrc?: string;
15+
perf?: {
16+
score?: number;
17+
inpMs?: number;
18+
clsScore?: number;
19+
ttfbMs?: number;
20+
fcpDisplay?: string;
21+
fcpScore?: number;
22+
lcpDisplay?: string;
23+
lcpScore?: number;
24+
ttiDisplay?: string;
25+
ttiScore?: number;
26+
ttiTime?: number;
27+
};
28+
version?: string;
29+
ts: number;
30+
};
731
const OUTPUT_JSON = 'src/routes/(ecosystem)/showcase/generated-pages.json';
832
async function captureMultipleScreenshots() {
9-
if (!fs.existsSync('public/showcases')) {
10-
fs.mkdirSync('public/showcases');
33+
if (!existsSync('public/showcases')) {
34+
mkdirSync('public/showcases');
1135
}
1236

1337
let browser = null;
1438
const output = [];
1539
try {
1640
// launch headless Chromium browser
17-
browser = await puppeteer.launch({
41+
browser = await chromium.launch({
1842
headless: true,
19-
incognito: true,
2043
});
21-
const incognito = await browser.createBrowserContext();
22-
let existingJson = [];
44+
const context = await browser.newContext();
45+
let existingJson: PageData[] = [];
2346
try {
24-
const data = fs.readFileSync(OUTPUT_JSON, 'utf8');
25-
existingJson = JSON.parse(data);
47+
const data = readFileSync(OUTPUT_JSON, 'utf8');
48+
existingJson = JSON.parse(data) as PageData[];
2649
} catch {
2750
// ignore
2851
}
2952

3053
for (const pageData of pages) {
31-
let page;
54+
let page: Page;
3255
try {
33-
page = await incognito.newPage();
34-
page.setUserAgent(
35-
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
36-
);
56+
page = await context.newPage();
57+
// page.setUserAgent(
58+
// 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
59+
// );
3760

3861
// set viewport width and height
39-
await page.setViewport({
62+
await page.setViewportSize({
4063
width: 1440,
4164
height: 980,
4265
});
4366

4467
const href = pageData.href;
4568
const existing = existingJson.find((item) => item.href === href);
46-
if (existing) {
69+
if (existing && existing.ts - Date.now() < 1000 * 60 * 60 * 24 * 7) {
4770
console.log('Skipping page', href);
4871

4972
output.push({
@@ -58,12 +81,13 @@ async function captureMultipleScreenshots() {
5881
await page.goto(href);
5982

6083
const title = await page.title();
61-
const html = await page.$('html');
84+
const html = page.locator('html');
6285
const hasContainer = await html.evaluate((node) => node.hasAttribute('q:container'));
6386
if (!hasContainer) {
6487
console.warn('❌ Not Qwik Site', href);
6588
continue;
6689
}
90+
const version = await html.getAttribute('q:version');
6791
const filename = href
6892
.replace('https://', '')
6993
.replace('/', '_')
@@ -72,12 +96,12 @@ async function captureMultipleScreenshots() {
7296
.toLowerCase();
7397

7498
await wait(5000);
75-
const path = `public/showcases/${filename}.webp`;
99+
const path = `public/showcases/${filename}.jpeg`;
76100
const [pagespeedOutput, _] = await Promise.all([
77101
getPagespeedData(href),
78102
page.screenshot({
79103
path: path,
80-
type: 'webp',
104+
type: 'jpeg',
81105
quality: 50,
82106
}),
83107
]);
@@ -119,33 +143,34 @@ async function captureMultipleScreenshots() {
119143
ttiTime,
120144
};
121145
output.push({
146+
...pageData,
147+
ts: Date.now(),
122148
title,
123-
imgSrc: `/showcases/${filename}.webp`,
149+
imgSrc: `/showcases/${filename}.jpeg`,
124150
perf,
125-
...pageData,
151+
version,
126152
});
127153
console.log(`✅ ${title} - (${href})`);
128154
} catch (err) {
129155
console.error(err);
130156
} finally {
131-
if (page) {
157+
if (page!) {
132158
await page.close();
133159
}
134160
}
135161
}
136162
} catch (err) {
137-
console.log(`❌ Error: ${err.message}`);
163+
console.log(`❌ Error: ${(err as Error)?.message || err}`);
138164
} finally {
139165
if (browser) {
140166
await browser.close();
141167
}
142168
console.log(`\n🎉 ${pages.length} screenshots captured.`);
143169
}
144-
fs.writeFileSync(OUTPUT_JSON, JSON.stringify(output, undefined, 2) + '\n');
170+
writeFileSync(OUTPUT_JSON, JSON.stringify(output, undefined, 2) + '\n');
145171
}
146172

147-
async function getPagespeedData(url) {
148-
const { fetch } = await import('undici');
173+
async function getPagespeedData(url: string) {
149174
const requestURL = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(
150175
url
151176
)}&key=AIzaSyApBC9gblaCzWrtEBgHnZkd_B37OF49BfM&category=PERFORMANCE&strategy=MOBILE`;
@@ -157,11 +182,15 @@ async function getPagespeedData(url) {
157182
if (!res.ok) {
158183
throw new Error(await res.text());
159184
}
160-
return res.json();
185+
return res.json() as Promise<{
186+
lighthouseResult: any;
187+
loadingExperience: any;
188+
pagespeedResult: any;
189+
}>;
161190
});
162191
}
163192
captureMultipleScreenshots();
164193

165-
function wait(ms) {
194+
function wait(ms: number) {
166195
return new Promise((resolve) => setTimeout(resolve, ms));
167196
}

0 commit comments

Comments
 (0)