Skip to content

Commit dcb8bc5

Browse files
committed
Use multiple tabs to speed up prerender
1 parent b6b5828 commit dcb8bc5

1 file changed

Lines changed: 70 additions & 40 deletions

File tree

prerender.js

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,43 @@ const getPremberUrls = require('./prember-urls');
66
const BASE_URL = 'http://127.0.0.1:8080';
77
const PRERENDER_DIR = 'prerender';
88

9-
async function prerenderVersion(urls) {
10-
const browser = await chromium.launch();
9+
async function prerenderPage(page, url) {
10+
try {
11+
// Use router transition
12+
await page.evaluate((path) => {
13+
return window.__router?.transitionTo(path);
14+
}, url);
15+
16+
// Check if we got a 404 by looking for common error indicators
17+
const is404 = await page.evaluate(() => {
18+
return document.title.includes('Page Not Found');
19+
});
20+
21+
if (is404) {
22+
return { url, status: 'not-found' };
23+
}
24+
25+
// Get the HTML content
26+
const html = await page.content();
27+
28+
// Convert URL to file path
29+
// e.g., /ember/release/classes/ApplicationInstance -> prerender/ember/release/classes/ApplicationInstance/index.html
30+
const filePath = join(PRERENDER_DIR, url, 'index.html');
31+
const dir = dirname(filePath);
32+
33+
// Create directory structure
34+
mkdirSync(dir, { recursive: true });
35+
36+
// Write HTML file
37+
writeFileSync(filePath, html, 'utf-8');
38+
39+
return { url, status: 'success' };
40+
} catch (error) {
41+
return { url, status: 'error', error: error.message };
42+
}
43+
}
44+
45+
async function initializePage(browser) {
1146
const page = await browser.newPage();
1247

1348
await page.addInitScript(() => {
@@ -26,57 +61,50 @@ async function prerenderVersion(urls) {
2661
return router && !router.currentRouteName?.includes('loading');
2762
});
2863

29-
let successCount = 0;
30-
let notFoundCount = 0;
64+
return page;
65+
}
3166

32-
for (let i = 0; i < urls.length; i++) {
33-
const url = urls[i];
67+
async function prerenderVersion(urls) {
68+
const browser = await chromium.launch();
69+
const CONCURRENCY = 5; // Number of parallel pages
3470

35-
try {
36-
// Subsequent URLs: use router transition
37-
await page.evaluate((path) => {
38-
return window.__router?.transitionTo(path);
39-
}, url);
71+
// Initialize multiple pages
72+
const pages = await Promise.all(
73+
Array.from({ length: CONCURRENCY }, () => initializePage(browser)),
74+
);
4075

41-
// Wait for network to be idle after transition
42-
await page.waitForLoadState('networkidle');
76+
let successCount = 0;
77+
let notFoundCount = 0;
78+
let errorCount = 0;
79+
let urlIndex = 0;
80+
81+
// Process URLs in parallel using a worker pool pattern
82+
const workers = pages.map(async (page) => {
83+
while (urlIndex < urls.length) {
84+
const currentIndex = urlIndex++;
85+
const url = urls[currentIndex];
4386

44-
// Check if we got a 404 by looking for common error indicators
45-
const is404 = await page.evaluate(() => {
46-
return document.title.includes('Page Not Found');
47-
});
87+
const result = await prerenderPage(page, url);
4888

49-
if (is404) {
89+
if (result.status === 'success') {
90+
successCount++;
91+
} else if (result.status === 'not-found') {
5092
console.log(`Not Found: ${url}`);
5193
notFoundCount++;
52-
continue;
94+
} else {
95+
console.error(`Error processing ${url}:`, result.error);
96+
errorCount++;
5397
}
5498

55-
// Get the HTML content
56-
const html = await page.content();
57-
58-
// Convert URL to file path
59-
// e.g., /ember/release/classes/ApplicationInstance -> prerender/ember/release/classes/ApplicationInstance/index.html
60-
const filePath = join(PRERENDER_DIR, url, 'index.html');
61-
const dir = dirname(filePath);
62-
63-
// Create directory structure
64-
mkdirSync(dir, { recursive: true });
65-
66-
// Write HTML file
67-
writeFileSync(filePath, html, 'utf-8');
68-
69-
successCount++;
70-
if ((i + 1) % 100 === 0) {
99+
if ((currentIndex + 1) % 100 === 0) {
71100
console.log(
72-
`Progress: ${i + 1}/${urls.length} (${successCount} saved, ${notFoundCount} not found)`,
101+
`Progress: ${currentIndex + 1}/${urls.length} (${successCount} saved, ${notFoundCount} not found, ${errorCount} errors)`,
73102
);
74103
}
75-
} catch (error) {
76-
console.error(`Error processing ${url}:`, error.message);
77104
}
78-
}
105+
});
79106

107+
await Promise.all(workers);
80108
await browser.close();
81109
}
82110
async function prerender() {
@@ -86,7 +114,9 @@ async function prerender() {
86114
0,
87115
);
88116

89-
console.log(`Prerendering ${totalUrls} URLs...`);
117+
console.log(
118+
`Prerendering ${totalUrls} URLs across ${urlsByVersion.size} versions...`,
119+
);
90120

91121
for (const [version, urls] of urlsByVersion.entries()) {
92122
await prerenderVersion(urls);

0 commit comments

Comments
 (0)