@flexireact/core 3.0.1 → 3.0.2
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/dist/cli/index.js +1514 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/client/index.js +373 -0
- package/dist/core/client/index.js.map +1 -0
- package/dist/core/index.js +6415 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/server/index.js +3094 -0
- package/dist/core/server/index.js.map +1 -0
- package/package.json +80 -80
- package/bin/flexireact.js +0 -23
- package/cli/generators.ts +0 -616
- package/cli/index.ts +0 -1182
- package/core/actions/index.ts +0 -364
- package/core/api.ts +0 -143
- package/core/build/index.ts +0 -425
- package/core/cli/logger.ts +0 -353
- package/core/client/Link.tsx +0 -345
- package/core/client/hydration.ts +0 -147
- package/core/client/index.ts +0 -12
- package/core/client/islands.ts +0 -143
- package/core/client/navigation.ts +0 -212
- package/core/client/runtime.ts +0 -52
- package/core/config.ts +0 -116
- package/core/context.ts +0 -83
- package/core/dev.ts +0 -47
- package/core/devtools/index.ts +0 -644
- package/core/edge/cache.ts +0 -344
- package/core/edge/fetch-polyfill.ts +0 -247
- package/core/edge/handler.ts +0 -248
- package/core/edge/index.ts +0 -81
- package/core/edge/ppr.ts +0 -264
- package/core/edge/runtime.ts +0 -161
- package/core/font/index.ts +0 -306
- package/core/helpers.ts +0 -494
- package/core/image/index.ts +0 -413
- package/core/index.ts +0 -218
- package/core/islands/index.ts +0 -293
- package/core/loader.ts +0 -111
- package/core/logger.ts +0 -242
- package/core/metadata/index.ts +0 -622
- package/core/middleware/index.ts +0 -416
- package/core/plugins/index.ts +0 -373
- package/core/render/index.ts +0 -1243
- package/core/render.ts +0 -136
- package/core/router/index.ts +0 -551
- package/core/router.ts +0 -141
- package/core/rsc/index.ts +0 -199
- package/core/server/index.ts +0 -779
- package/core/server.ts +0 -203
- package/core/ssg/index.ts +0 -346
- package/core/start-dev.ts +0 -6
- package/core/start-prod.ts +0 -6
- package/core/tsconfig.json +0 -30
- package/core/types.ts +0 -239
- package/core/utils.ts +0 -176
package/core/server.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import http from 'http';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
import { buildRoutes, matchRoute } from './router.js';
|
|
8
|
-
import { render, renderError } from './render.js';
|
|
9
|
-
import { handleApiRoute } from './api.js';
|
|
10
|
-
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
const __dirname = path.dirname(__filename);
|
|
13
|
-
|
|
14
|
-
// Configuration
|
|
15
|
-
const PORT = process.env.PORT || 3000;
|
|
16
|
-
const HOST = process.env.HOST || 'localhost';
|
|
17
|
-
|
|
18
|
-
// Determine the project root (where the user's app is)
|
|
19
|
-
const PROJECT_ROOT = process.cwd();
|
|
20
|
-
const PAGES_DIR = path.join(PROJECT_ROOT, 'pages');
|
|
21
|
-
|
|
22
|
-
// MIME types for static files
|
|
23
|
-
const MIME_TYPES = {
|
|
24
|
-
'.html': 'text/html',
|
|
25
|
-
'.css': 'text/css',
|
|
26
|
-
'.js': 'application/javascript',
|
|
27
|
-
'.json': 'application/json',
|
|
28
|
-
'.png': 'image/png',
|
|
29
|
-
'.jpg': 'image/jpeg',
|
|
30
|
-
'.jpeg': 'image/jpeg',
|
|
31
|
-
'.gif': 'image/gif',
|
|
32
|
-
'.svg': 'image/svg+xml',
|
|
33
|
-
'.ico': 'image/x-icon',
|
|
34
|
-
'.woff': 'font/woff',
|
|
35
|
-
'.woff2': 'font/woff2',
|
|
36
|
-
'.ttf': 'font/ttf'
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Creates and starts the FlexiReact dev server
|
|
41
|
-
*/
|
|
42
|
-
interface ServerOptions {
|
|
43
|
-
port?: number;
|
|
44
|
-
host?: string;
|
|
45
|
-
pagesDir?: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function createServer(options: ServerOptions = {}) {
|
|
49
|
-
const {
|
|
50
|
-
port = PORT,
|
|
51
|
-
host = HOST,
|
|
52
|
-
pagesDir = PAGES_DIR
|
|
53
|
-
} = options;
|
|
54
|
-
|
|
55
|
-
const server = http.createServer(async (req, res) => {
|
|
56
|
-
const startTime = Date.now();
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
// Parse URL
|
|
60
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
61
|
-
const pathname = url.pathname;
|
|
62
|
-
|
|
63
|
-
// Log request
|
|
64
|
-
console.log(`${req.method} ${pathname}`);
|
|
65
|
-
|
|
66
|
-
// Try to serve static files from public directory
|
|
67
|
-
const publicPath = path.join(PROJECT_ROOT, 'public', pathname);
|
|
68
|
-
if (fs.existsSync(publicPath) && fs.statSync(publicPath).isFile()) {
|
|
69
|
-
return serveStaticFile(res, publicPath);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Build routes (rebuild on each request for hot reload)
|
|
73
|
-
const routes = buildRoutes(pagesDir);
|
|
74
|
-
|
|
75
|
-
// Check for API routes first
|
|
76
|
-
const apiRoute = matchRoute(pathname, routes.api);
|
|
77
|
-
if (apiRoute) {
|
|
78
|
-
return await handleApiRoute(req, res, apiRoute);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check for page routes
|
|
82
|
-
const pageRoute = matchRoute(pathname, routes.pages);
|
|
83
|
-
if (pageRoute) {
|
|
84
|
-
return await handlePageRoute(req, res, pageRoute);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// 404 Not Found
|
|
88
|
-
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
89
|
-
res.end(renderError(404, 'Page not found'));
|
|
90
|
-
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error('Server Error:', error);
|
|
93
|
-
|
|
94
|
-
if (!res.headersSent) {
|
|
95
|
-
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
96
|
-
res.end(renderError(500, process.env.NODE_ENV === 'development'
|
|
97
|
-
? error.message
|
|
98
|
-
: 'Internal Server Error'));
|
|
99
|
-
}
|
|
100
|
-
} finally {
|
|
101
|
-
const duration = Date.now() - startTime;
|
|
102
|
-
console.log(` └─ ${res.statusCode} (${duration}ms)`);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
server.listen(port as number, host as string, () => {
|
|
107
|
-
console.log('');
|
|
108
|
-
console.log(' ⚡ FlexiReact Dev Server');
|
|
109
|
-
console.log(' ─────────────────────────');
|
|
110
|
-
console.log(` → Local: http://${host}:${port}`);
|
|
111
|
-
console.log(` → Pages: ${pagesDir}`);
|
|
112
|
-
console.log('');
|
|
113
|
-
console.log(' Ready for requests...');
|
|
114
|
-
console.log('');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
return server;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Handles page route requests with SSR
|
|
122
|
-
*/
|
|
123
|
-
async function handlePageRoute(req, res, route) {
|
|
124
|
-
try {
|
|
125
|
-
// Import the page component with cache busting for hot reload
|
|
126
|
-
const modulePath = `file://${route.filePath.replace(/\\/g, '/')}?t=${Date.now()}`;
|
|
127
|
-
const pageModule = await import(modulePath);
|
|
128
|
-
|
|
129
|
-
// Get the component (default export)
|
|
130
|
-
const Component = pageModule.default;
|
|
131
|
-
|
|
132
|
-
if (!Component) {
|
|
133
|
-
throw new Error(`No default export found in ${route.filePath}`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Get page props if getServerSideProps exists
|
|
137
|
-
let props = { params: route.params };
|
|
138
|
-
|
|
139
|
-
if (pageModule.getServerSideProps) {
|
|
140
|
-
const context = {
|
|
141
|
-
params: route.params,
|
|
142
|
-
req,
|
|
143
|
-
res,
|
|
144
|
-
query: Object.fromEntries(new URL(req.url, `http://${req.headers.host}`).searchParams)
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const result = await pageModule.getServerSideProps(context);
|
|
148
|
-
|
|
149
|
-
if (result.redirect) {
|
|
150
|
-
res.writeHead(result.redirect.statusCode || 302, {
|
|
151
|
-
Location: result.redirect.destination
|
|
152
|
-
});
|
|
153
|
-
res.end();
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (result.notFound) {
|
|
158
|
-
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
159
|
-
res.end(renderError(404, 'Page not found'));
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
props = { ...props, ...result.props };
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Get page title if defined
|
|
167
|
-
const title = pageModule.title || 'FlexiReact App';
|
|
168
|
-
|
|
169
|
-
// Render the page
|
|
170
|
-
const html = render(Component, props, { title });
|
|
171
|
-
|
|
172
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
173
|
-
res.end(html);
|
|
174
|
-
|
|
175
|
-
} catch (error) {
|
|
176
|
-
console.error('Page Render Error:', error);
|
|
177
|
-
throw error;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Serves static files
|
|
183
|
-
*/
|
|
184
|
-
function serveStaticFile(res, filePath) {
|
|
185
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
186
|
-
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
|
187
|
-
|
|
188
|
-
const content = fs.readFileSync(filePath);
|
|
189
|
-
res.writeHead(200, { 'Content-Type': contentType });
|
|
190
|
-
res.end(content);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Auto-start server when run directly
|
|
194
|
-
const scriptPath = process.argv[1];
|
|
195
|
-
|
|
196
|
-
// Check if running directly (handles symlinks on Windows)
|
|
197
|
-
const isDirectRun = scriptPath && scriptPath.endsWith('server.js');
|
|
198
|
-
|
|
199
|
-
if (isDirectRun) {
|
|
200
|
-
createServer();
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export default createServer;
|
package/core/ssg/index.ts
DELETED
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FlexiReact Static Site Generation (SSG)
|
|
3
|
-
*
|
|
4
|
-
* SSG pre-renders pages at build time, generating static HTML files.
|
|
5
|
-
* This provides the fastest possible page loads and enables CDN caching.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* - Export getStaticProps() from a page to fetch data at build time
|
|
9
|
-
* - Export getStaticPaths() for dynamic routes to specify which paths to pre-render
|
|
10
|
-
* - Pages without these exports are rendered as static HTML
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import fs from 'fs';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import { pathToFileURL } from 'url';
|
|
16
|
-
import { renderPage } from '../render/index.js';
|
|
17
|
-
import { ensureDir, cleanDir } from '../utils.js';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* SSG Build Result
|
|
21
|
-
*/
|
|
22
|
-
interface SSGPage {
|
|
23
|
-
path: string;
|
|
24
|
-
file: string;
|
|
25
|
-
size: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface SSGError {
|
|
29
|
-
path: string;
|
|
30
|
-
error: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class SSGResult {
|
|
34
|
-
pages: SSGPage[];
|
|
35
|
-
errors: SSGError[];
|
|
36
|
-
duration: number;
|
|
37
|
-
|
|
38
|
-
constructor() {
|
|
39
|
-
this.pages = [];
|
|
40
|
-
this.errors = [];
|
|
41
|
-
this.duration = 0;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
addPage(pagePath: string, file: string, size: number) {
|
|
45
|
-
this.pages.push({ path: pagePath, file, size });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
addError(pagePath: string, error: Error) {
|
|
49
|
-
this.errors.push({ path: pagePath, error: error.message });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
get success() {
|
|
53
|
-
return this.errors.length === 0;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
get totalSize() {
|
|
57
|
-
return this.pages.reduce((sum, p) => sum + p.size, 0);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Generates static pages for all routes
|
|
63
|
-
*/
|
|
64
|
-
export async function generateStaticSite(options) {
|
|
65
|
-
const {
|
|
66
|
-
routes,
|
|
67
|
-
outDir,
|
|
68
|
-
config,
|
|
69
|
-
loadModule
|
|
70
|
-
} = options;
|
|
71
|
-
|
|
72
|
-
const result = new SSGResult();
|
|
73
|
-
const startTime = Date.now();
|
|
74
|
-
|
|
75
|
-
// Clean and create output directory
|
|
76
|
-
const staticDir = path.join(outDir, 'static');
|
|
77
|
-
cleanDir(staticDir);
|
|
78
|
-
|
|
79
|
-
console.log('\n📦 Generating static pages...\n');
|
|
80
|
-
|
|
81
|
-
for (const route of routes) {
|
|
82
|
-
try {
|
|
83
|
-
await generateRoutePage(route, staticDir, loadModule, result, config);
|
|
84
|
-
} catch (error) {
|
|
85
|
-
console.error(` ✗ ${route.path}: ${error.message}`);
|
|
86
|
-
result.addError(route.path, error);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
result.duration = Date.now() - startTime;
|
|
91
|
-
|
|
92
|
-
// Generate summary
|
|
93
|
-
console.log('\n' + '─'.repeat(50));
|
|
94
|
-
console.log(` Generated ${result.pages.length} pages in ${result.duration}ms`);
|
|
95
|
-
if (result.errors.length > 0) {
|
|
96
|
-
console.log(` ${result.errors.length} errors occurred`);
|
|
97
|
-
}
|
|
98
|
-
console.log('─'.repeat(50) + '\n');
|
|
99
|
-
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Generates a single route's static page(s)
|
|
105
|
-
*/
|
|
106
|
-
async function generateRoutePage(route, outDir, loadModule, result, config) {
|
|
107
|
-
const module = await loadModule(route.filePath);
|
|
108
|
-
const Component = module.default;
|
|
109
|
-
|
|
110
|
-
if (!Component) {
|
|
111
|
-
throw new Error(`No default export in ${route.filePath}`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Check for getStaticPaths (dynamic routes)
|
|
115
|
-
let paths = [{ params: {} }];
|
|
116
|
-
|
|
117
|
-
if (route.path.includes(':') || route.path.includes('*')) {
|
|
118
|
-
if (!module.getStaticPaths) {
|
|
119
|
-
console.log(` ⊘ ${route.path} (dynamic, no getStaticPaths)`);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const staticPaths = await module.getStaticPaths();
|
|
124
|
-
paths = staticPaths.paths || [];
|
|
125
|
-
|
|
126
|
-
if (staticPaths.fallback === false && paths.length === 0) {
|
|
127
|
-
console.log(` ⊘ ${route.path} (no paths to generate)`);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Generate page for each path
|
|
133
|
-
for (const pathConfig of paths) {
|
|
134
|
-
const params = pathConfig.params || {};
|
|
135
|
-
const actualPath = substituteParams(route.path, params);
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
// Get static props
|
|
139
|
-
let props = { params };
|
|
140
|
-
|
|
141
|
-
if (module.getStaticProps) {
|
|
142
|
-
const staticProps = await module.getStaticProps({ params });
|
|
143
|
-
|
|
144
|
-
if (staticProps.notFound) {
|
|
145
|
-
console.log(` ⊘ ${actualPath} (notFound)`);
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (staticProps.redirect) {
|
|
150
|
-
// Generate redirect HTML
|
|
151
|
-
await generateRedirectPage(actualPath, staticProps.redirect, outDir, result);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
props = { ...props, ...staticProps.props };
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Render the page
|
|
159
|
-
const html = await renderPage({
|
|
160
|
-
Component,
|
|
161
|
-
props,
|
|
162
|
-
title: module.title || module.metadata?.title || 'FlexiReact App',
|
|
163
|
-
meta: module.metadata || {},
|
|
164
|
-
isSSG: true
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Write to file
|
|
168
|
-
const filePath = getOutputPath(actualPath, outDir);
|
|
169
|
-
ensureDir(path.dirname(filePath));
|
|
170
|
-
fs.writeFileSync(filePath, html);
|
|
171
|
-
|
|
172
|
-
const size = Buffer.byteLength(html, 'utf8');
|
|
173
|
-
result.addPage(actualPath, filePath, size);
|
|
174
|
-
|
|
175
|
-
console.log(` ✓ ${actualPath} (${formatSize(size)})`);
|
|
176
|
-
|
|
177
|
-
} catch (error) {
|
|
178
|
-
result.addError(actualPath, error);
|
|
179
|
-
console.error(` ✗ ${actualPath}: ${error.message}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Generates a redirect page
|
|
186
|
-
*/
|
|
187
|
-
async function generateRedirectPage(fromPath, redirect, outDir, result) {
|
|
188
|
-
const { destination, permanent = false } = redirect;
|
|
189
|
-
const statusCode = permanent ? 301 : 302;
|
|
190
|
-
|
|
191
|
-
const html = `<!DOCTYPE html>
|
|
192
|
-
<html>
|
|
193
|
-
<head>
|
|
194
|
-
<meta charset="utf-8">
|
|
195
|
-
<meta http-equiv="refresh" content="0;url=${destination}">
|
|
196
|
-
<link rel="canonical" href="${destination}">
|
|
197
|
-
<title>Redirecting...</title>
|
|
198
|
-
</head>
|
|
199
|
-
<body>
|
|
200
|
-
<p>Redirecting to <a href="${destination}">${destination}</a></p>
|
|
201
|
-
<script>window.location.href = "${destination}";</script>
|
|
202
|
-
</body>
|
|
203
|
-
</html>`;
|
|
204
|
-
|
|
205
|
-
const filePath = getOutputPath(fromPath, outDir);
|
|
206
|
-
ensureDir(path.dirname(filePath));
|
|
207
|
-
fs.writeFileSync(filePath, html);
|
|
208
|
-
|
|
209
|
-
const size = Buffer.byteLength(html, 'utf8');
|
|
210
|
-
result.addPage(fromPath, filePath, size);
|
|
211
|
-
|
|
212
|
-
console.log(` ↪ ${fromPath} → ${destination}`);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Substitutes route params into path
|
|
217
|
-
*/
|
|
218
|
-
function substituteParams(routePath, params) {
|
|
219
|
-
let result = routePath;
|
|
220
|
-
|
|
221
|
-
for (const [key, value] of Object.entries(params)) {
|
|
222
|
-
result = result.replace(`:${key}`, value);
|
|
223
|
-
result = result.replace(`*${key}`, value);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return result;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Gets the output file path for a route
|
|
231
|
-
*/
|
|
232
|
-
function getOutputPath(routePath, outDir) {
|
|
233
|
-
if (routePath === '/') {
|
|
234
|
-
return path.join(outDir, 'index.html');
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Remove leading slash and add index.html
|
|
238
|
-
const cleanPath = routePath.replace(/^\//, '');
|
|
239
|
-
return path.join(outDir, cleanPath, 'index.html');
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Formats file size
|
|
244
|
-
*/
|
|
245
|
-
function formatSize(bytes) {
|
|
246
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
247
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
248
|
-
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Incremental Static Regeneration (ISR) support
|
|
253
|
-
* Allows pages to be regenerated after a specified interval
|
|
254
|
-
*/
|
|
255
|
-
interface ISRCacheEntry {
|
|
256
|
-
html: string;
|
|
257
|
-
generatedAt: number;
|
|
258
|
-
revalidateAfter: number | null;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export class ISRManager {
|
|
262
|
-
cache: Map<string, ISRCacheEntry>;
|
|
263
|
-
revalidating: Set<string>;
|
|
264
|
-
defaultRevalidate: number;
|
|
265
|
-
|
|
266
|
-
constructor(options: { defaultRevalidate?: number } = {}) {
|
|
267
|
-
this.cache = new Map();
|
|
268
|
-
this.revalidating = new Set();
|
|
269
|
-
this.defaultRevalidate = options.defaultRevalidate || 60; // seconds
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Gets a cached page or regenerates it
|
|
274
|
-
*/
|
|
275
|
-
async getPage(routePath, generator) {
|
|
276
|
-
const cached = this.cache.get(routePath);
|
|
277
|
-
const now = Date.now();
|
|
278
|
-
|
|
279
|
-
if (cached) {
|
|
280
|
-
// Check if revalidation is needed
|
|
281
|
-
if (cached.revalidateAfter && now > cached.revalidateAfter) {
|
|
282
|
-
// Trigger background revalidation
|
|
283
|
-
this.revalidateInBackground(routePath, generator);
|
|
284
|
-
}
|
|
285
|
-
return cached.html;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Generate fresh page
|
|
289
|
-
const result = await generator();
|
|
290
|
-
this.cache.set(routePath, {
|
|
291
|
-
html: result.html,
|
|
292
|
-
generatedAt: now,
|
|
293
|
-
revalidateAfter: result.revalidate
|
|
294
|
-
? now + (result.revalidate * 1000)
|
|
295
|
-
: null
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
return result.html;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Revalidates a page in the background
|
|
303
|
-
*/
|
|
304
|
-
async revalidateInBackground(routePath, generator) {
|
|
305
|
-
if (this.revalidating.has(routePath)) return;
|
|
306
|
-
|
|
307
|
-
this.revalidating.add(routePath);
|
|
308
|
-
|
|
309
|
-
try {
|
|
310
|
-
const result = await generator();
|
|
311
|
-
const now = Date.now();
|
|
312
|
-
|
|
313
|
-
this.cache.set(routePath, {
|
|
314
|
-
html: result.html,
|
|
315
|
-
generatedAt: now,
|
|
316
|
-
revalidateAfter: result.revalidate
|
|
317
|
-
? now + (result.revalidate * 1000)
|
|
318
|
-
: null
|
|
319
|
-
});
|
|
320
|
-
} catch (error) {
|
|
321
|
-
console.error(`ISR revalidation failed for ${routePath}:`, error);
|
|
322
|
-
} finally {
|
|
323
|
-
this.revalidating.delete(routePath);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Invalidates a cached page
|
|
329
|
-
*/
|
|
330
|
-
invalidate(routePath) {
|
|
331
|
-
this.cache.delete(routePath);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Clears all cached pages
|
|
336
|
-
*/
|
|
337
|
-
clear() {
|
|
338
|
-
this.cache.clear();
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export default {
|
|
343
|
-
generateStaticSite,
|
|
344
|
-
SSGResult,
|
|
345
|
-
ISRManager
|
|
346
|
-
};
|
package/core/start-dev.ts
DELETED
package/core/start-prod.ts
DELETED
package/core/tsconfig.json
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
-
"jsx": "react-jsx",
|
|
8
|
-
"outDir": "./dist",
|
|
9
|
-
"rootDir": ".",
|
|
10
|
-
"strict": false,
|
|
11
|
-
"noImplicitAny": false,
|
|
12
|
-
"strictPropertyInitialization": false,
|
|
13
|
-
"useUnknownInCatchVariables": false,
|
|
14
|
-
"esModuleInterop": true,
|
|
15
|
-
"skipLibCheck": true,
|
|
16
|
-
"forceConsistentCasingInFileNames": true,
|
|
17
|
-
"resolveJsonModule": true,
|
|
18
|
-
"declaration": false,
|
|
19
|
-
"sourceMap": true,
|
|
20
|
-
"allowJs": true,
|
|
21
|
-
"checkJs": false,
|
|
22
|
-
"noEmit": true
|
|
23
|
-
},
|
|
24
|
-
"include": [
|
|
25
|
-
"*.ts",
|
|
26
|
-
"**/*.ts",
|
|
27
|
-
"**/*.tsx"
|
|
28
|
-
],
|
|
29
|
-
"exclude": ["node_modules", "dist"]
|
|
30
|
-
}
|