-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprerender.js
More file actions
180 lines (152 loc) Β· 5.21 KB
/
Copy pathprerender.js
File metadata and controls
180 lines (152 loc) Β· 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import puppeteer from 'puppeteer';
import fetch from 'node-fetch';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// API endpoint (production URL since this runs at build time)
const API_URL = 'https://api.iosas.online';
const BUILD_DIR = path.join(__dirname, 'dist');
const DEV_SERVER_URL = 'http://localhost:4173'; // Vite preview server
async function getRoutesToPrerender() {
const routes = [
'/',
'/about',
'/forms',
'/calendar',
'/developers',
'/organizations',
'/faqs',
'/bug',
'/privacy-policy',
'/terms-of-service',
'/auth-complete'
];
console.log('\nπ Fetching dynamic routes for prerendering...\n');
try {
// Fetch announcements with timeout
const announcementsRes = await Promise.race([
fetch(`${API_URL}/announcements`),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 10000)
)
]);
if (announcementsRes.ok) {
const data = await announcementsRes.json();
if (data.announcements && Array.isArray(data.announcements)) {
data.announcements.forEach(announcement => {
routes.push(`/announcements/${announcement.id}`);
});
console.log(`β Found ${data.announcements.length} announcements to prerender`);
}
} else {
console.warn('β Could not fetch announcements for prerendering (non-200 response)');
}
} catch (error) {
console.warn('β Error fetching announcements:', error.message);
console.warn(' β Building without announcement routes (will use client-side rendering)');
}
try {
// Fetch organizations with timeout
const organizationsRes = await Promise.race([
fetch(`${API_URL}/organizations`),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 10000)
)
]);
if (organizationsRes.ok) {
const data = await organizationsRes.json();
if (data.organizations && Array.isArray(data.organizations)) {
data.organizations.forEach(org => {
routes.push(`/organizations/${org.id}`);
});
console.log(`β Found ${data.organizations.length} organizations to prerender`);
}
} else {
console.warn('β Could not fetch organizations for prerendering (non-200 response)');
}
} catch (error) {
console.warn('β Error fetching organizations:', error.message);
console.warn(' β Building without organization routes (will use client-side rendering)');
}
console.log(`\nπ Total routes to prerender: ${routes.length}\n`);
return routes;
}
async function prerenderRoute(browser, route) {
const page = await browser.newPage();
try {
const url = `${DEV_SERVER_URL}${route}`;
console.log(` Rendering: ${route}`);
// Navigate to page
await page.goto(url, { waitUntil: 'networkidle0', timeout: 30000 });
// For dynamic routes (announcements, organizations), wait longer for metadata updates
const isDynamicRoute = route.includes('/announcements/') || route.includes('/organizations/');
const waitTime = isDynamicRoute ? 5000 : 2000;
// Wait for API calls and metadata updates to complete
await new Promise(resolve => setTimeout(resolve, waitTime));
// Additional check: wait for metadata to be updated (for dynamic routes)
if (isDynamicRoute) {
try {
// Wait for og:title to be updated (indicates metadata is ready)
await page.waitForFunction(
() => {
const ogTitle = document.querySelector('meta[property="og:title"]');
return ogTitle && !ogTitle.content.includes('Office of Student Affairs and Services | Colegio de Montalban');
},
{ timeout: 5000 }
);
} catch (e) {
// Metadata might not update, continue anyway
console.log(` β Metadata may not be fully updated`);
}
}
// Get the rendered HTML
const html = await page.content();
// Create directory structure
const routePath = route === '/' ? '/index' : route;
const filePath = path.join(BUILD_DIR, routePath, 'index.html');
const dirPath = path.dirname(filePath);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
// Write the HTML file
fs.writeFileSync(filePath, html);
console.log(` β Saved: ${filePath}`);
return true;
} catch (error) {
console.error(` β Error rendering ${route}:`, error.message);
return false;
} finally {
await page.close();
}
}
async function main() {
console.log('\nπ¨ Starting pre-rendering process...\n');
console.log(`π Build directory: ${BUILD_DIR}\n`);
// Check if dist directory exists
if (!fs.existsSync(BUILD_DIR)) {
console.error('β Build directory not found! Run `npm run build` first.');
process.exit(1);
}
// Get routes to prerender
const routes = await getRoutesToPrerender();
// Launch browser
console.log('\nπ Launching browser...\n');
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
try {
// Prerender each route
let successCount = 0;
for (const route of routes) {
const success = await prerenderRoute(browser, route);
if (success) successCount++;
}
console.log(`\nβ
Pre-rendering complete!`);
console.log(` ${successCount}/${routes.length} routes successfully rendered\n`);
} finally {
await browser.close();
}
}
main().catch(console.error);