dinou 5.0.1 → 5.0.3
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/CHANGELOG.md +22 -0
- package/dinou/core/babel-esm-loader.js +48 -1
- package/dinou/core/client-error-webpack.jsx +194 -23
- package/dinou/core/client-error.jsx +194 -23
- package/dinou/core/client-webpack.jsx +111 -2
- package/dinou/core/client.jsx +117 -2
- package/dinou/core/generating-isg.js +15 -20
- package/dinou/core/get-error-jsx.js +1 -1
- package/dinou/core/get-jsx.js +1 -1
- package/dinou/core/path-utils.js +10 -0
- package/dinou/core/revalidating.js +15 -10
- package/dinou/core/server.js +232 -41
- package/dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs +3 -0
- package/dinou/package.json +1 -1
- package/dinou/webpack/loaders/server-functions-loader.js +6 -1
- package/dinou/webpack/plugins/manifest-generator-plugin.js +1 -1
- package/dinou/webpack/webpack.config.js +12 -1
- package/package.json +1 -1
|
@@ -5,11 +5,13 @@ import {
|
|
|
5
5
|
useTransition,
|
|
6
6
|
useLayoutEffect,
|
|
7
7
|
useMemo,
|
|
8
|
+
Component,
|
|
8
9
|
} from "react";
|
|
9
10
|
import { createFromFetch } from "react-server-dom-webpack/client";
|
|
10
11
|
import { hydrateRoot } from "react-dom/client";
|
|
11
12
|
import { RouterContext } from "./navigation.js";
|
|
12
13
|
import { resolveUrl, isExternalUrl } from "./navigation-utils.js";
|
|
14
|
+
import { createServerFunctionProxy } from "./server-function-proxy-webpack.js";
|
|
13
15
|
|
|
14
16
|
// ====================================================================
|
|
15
17
|
// 1. GLOBAL STATE (Outside the component)
|
|
@@ -81,11 +83,109 @@ const getRSCPayload = (rscKey, isPrefetch = false) => {
|
|
|
81
83
|
}
|
|
82
84
|
return res;
|
|
83
85
|
}),
|
|
86
|
+
{
|
|
87
|
+
callServer: async (id, args) => {
|
|
88
|
+
const proxy = createServerFunctionProxy(id);
|
|
89
|
+
return proxy(...args);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
84
92
|
);
|
|
85
93
|
cache.set(url, promise); // <--- KEY TO AVOID LOOP
|
|
86
94
|
return promise;
|
|
87
95
|
};
|
|
88
96
|
|
|
97
|
+
const getErrorRSCPayload = (route, error) => {
|
|
98
|
+
const url = route.split("::")[0];
|
|
99
|
+
const cacheKey = `error::${url}::${error.message || String(error)}`;
|
|
100
|
+
if (cache.has(cacheKey)) {
|
|
101
|
+
return cache.get(cacheKey);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const payloadUrl = "/____rsc_payload_error____" + url;
|
|
105
|
+
const promise = createFromFetch(
|
|
106
|
+
fetch(payloadUrl, {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: {
|
|
109
|
+
"Content-Type": "application/json",
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({
|
|
112
|
+
error: {
|
|
113
|
+
message: error.message || "Unknown Error",
|
|
114
|
+
name: error.name,
|
|
115
|
+
stack: error.stack,
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
}).then((res) => {
|
|
119
|
+
if (res.headers.has("x-rsc-redirect")) {
|
|
120
|
+
const redirectUrl = res.headers.get("x-rsc-redirect");
|
|
121
|
+
cache.delete(cacheKey);
|
|
122
|
+
if (window.__DINOU_ROUTER_NAVIGATE__) {
|
|
123
|
+
window.__DINOU_ROUTER_NAVIGATE__(redirectUrl, { replace: true });
|
|
124
|
+
} else {
|
|
125
|
+
window.location.href = redirectUrl;
|
|
126
|
+
}
|
|
127
|
+
return new Promise(() => {});
|
|
128
|
+
}
|
|
129
|
+
return res;
|
|
130
|
+
}),
|
|
131
|
+
{
|
|
132
|
+
callServer: async (id, args) => {
|
|
133
|
+
const proxy = createServerFunctionProxy(id);
|
|
134
|
+
return proxy(...args);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
cache.set(cacheKey, promise);
|
|
139
|
+
return promise;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
class ErrorBoundary extends Component {
|
|
143
|
+
constructor(props) {
|
|
144
|
+
super(props);
|
|
145
|
+
this.state = { hasError: false, error: null };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static getDerivedStateFromError(error) {
|
|
149
|
+
return { hasError: true, error };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
componentDidCatch(error, errorInfo) {
|
|
153
|
+
console.error("[Dinou] ErrorBoundary caught error:", error, errorInfo);
|
|
154
|
+
if (this.props.onError) {
|
|
155
|
+
this.props.onError(error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
render() {
|
|
160
|
+
if (this.state.hasError) {
|
|
161
|
+
if (this.props.fallback) {
|
|
162
|
+
return this.props.fallback(this.state.error);
|
|
163
|
+
}
|
|
164
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
165
|
+
return (
|
|
166
|
+
<div style={{ padding: "20px", fontFamily: "sans-serif" }}>
|
|
167
|
+
<h2>Application Error</h2>
|
|
168
|
+
<p>An unexpected error occurred on the client.</p>
|
|
169
|
+
<pre style={{ backgroundColor: "#f5f5f5", padding: "15px", borderRadius: "5px", overflowX: "auto" }}>
|
|
170
|
+
{isDev ? (
|
|
171
|
+
<>
|
|
172
|
+
<div style={{ fontWeight: "bold", marginBottom: "10px" }}>
|
|
173
|
+
{this.state.error?.name || "Error"}: {this.state.error?.message || String(this.state.error)}
|
|
174
|
+
</div>
|
|
175
|
+
<div>{this.state.error?.stack}</div>
|
|
176
|
+
</>
|
|
177
|
+
) : (
|
|
178
|
+
this.state.error?.message || String(this.state.error)
|
|
179
|
+
)}
|
|
180
|
+
</pre>
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return this.props.children;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
89
189
|
// ====================================================================
|
|
90
190
|
// 3. ROUTER COMPONENT
|
|
91
191
|
// ====================================================================
|
|
@@ -95,6 +195,7 @@ function Router() {
|
|
|
95
195
|
const [isPopState, setIsPopState] = useState(false);
|
|
96
196
|
const [isPending, startTransition] = useTransition();
|
|
97
197
|
const [version, setVersion] = useState(0);
|
|
198
|
+
const [navError, setNavError] = useState(null);
|
|
98
199
|
|
|
99
200
|
// 🧭 NAVIGATE FUNCTION (Core Logic)
|
|
100
201
|
const navigate = (href, options = {}) => {
|
|
@@ -138,6 +239,7 @@ function Router() {
|
|
|
138
239
|
startTransition(() => {
|
|
139
240
|
setIsPopState(false);
|
|
140
241
|
setRoute(finalPath);
|
|
242
|
+
setNavError(null);
|
|
141
243
|
});
|
|
142
244
|
};
|
|
143
245
|
|
|
@@ -174,6 +276,7 @@ function Router() {
|
|
|
174
276
|
startTransition(() => {
|
|
175
277
|
// 3. Increment version to force re-execution of useMemo
|
|
176
278
|
setVersion((v) => v + 1);
|
|
279
|
+
setNavError(null);
|
|
177
280
|
});
|
|
178
281
|
};
|
|
179
282
|
|
|
@@ -220,6 +323,7 @@ function Router() {
|
|
|
220
323
|
startTransition(() => {
|
|
221
324
|
setIsPopState(true);
|
|
222
325
|
setRoute(target);
|
|
326
|
+
setNavError(null);
|
|
223
327
|
});
|
|
224
328
|
};
|
|
225
329
|
|
|
@@ -265,7 +369,7 @@ function Router() {
|
|
|
265
369
|
|
|
266
370
|
// RSC Logic
|
|
267
371
|
const rscKey = route + "::" + version;
|
|
268
|
-
const content = getRSCPayload(rscKey);
|
|
372
|
+
const content = navError ? getErrorRSCPayload(route, navError) : getRSCPayload(rscKey);
|
|
269
373
|
|
|
270
374
|
const contextValue = useMemo(
|
|
271
375
|
() => ({
|
|
@@ -281,7 +385,12 @@ function Router() {
|
|
|
281
385
|
|
|
282
386
|
return (
|
|
283
387
|
<RouterContext.Provider value={contextValue}>
|
|
284
|
-
|
|
388
|
+
<ErrorBoundary
|
|
389
|
+
key={navError ? "error" : "normal"}
|
|
390
|
+
onError={setNavError}
|
|
391
|
+
>
|
|
392
|
+
{use(content)}
|
|
393
|
+
</ErrorBoundary>
|
|
285
394
|
</RouterContext.Provider>
|
|
286
395
|
);
|
|
287
396
|
}
|
package/dinou/core/client.jsx
CHANGED
|
@@ -6,11 +6,13 @@ import {
|
|
|
6
6
|
useTransition,
|
|
7
7
|
useLayoutEffect,
|
|
8
8
|
useMemo,
|
|
9
|
+
Component,
|
|
9
10
|
} from "react";
|
|
10
11
|
import { createFromFetch } from "@roggc/react-server-dom-esm/client";
|
|
11
12
|
import { hydrateRoot } from "react-dom/client";
|
|
12
13
|
import { RouterContext } from "./navigation.js";
|
|
13
14
|
import { resolveUrl, isExternalUrl } from "./navigation-utils.js";
|
|
15
|
+
import { createServerFunctionProxy } from "./server-function-proxy.js";
|
|
14
16
|
|
|
15
17
|
// ====================================================================
|
|
16
18
|
// 1. GLOBAL STATE (Outside the component)
|
|
@@ -64,6 +66,12 @@ const getRSCPayload = (rscKey, isPrefetch = false) => {
|
|
|
64
66
|
payloadUrl = "/____rsc_payload____" + url;
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
const buildId = window.__DINOU_BUILD_ID__;
|
|
70
|
+
if (buildId) {
|
|
71
|
+
payloadUrl += (payloadUrl.includes("?") ? "&" : "?") + "buildId=" + buildId;
|
|
72
|
+
window.__DINOU_BUILD_ID__ = undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
// 3. Fetch and Cache Storage
|
|
68
76
|
const promise = createFromFetch(
|
|
69
77
|
fetch(payloadUrl).then((res) => {
|
|
@@ -82,11 +90,109 @@ const getRSCPayload = (rscKey, isPrefetch = false) => {
|
|
|
82
90
|
}
|
|
83
91
|
return res;
|
|
84
92
|
}),
|
|
93
|
+
{
|
|
94
|
+
callServer: async (id, args) => {
|
|
95
|
+
const proxy = createServerFunctionProxy(id);
|
|
96
|
+
return proxy(...args);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
85
99
|
);
|
|
86
100
|
cache.set(url, promise); // <--- KEY TO AVOID LOOP
|
|
87
101
|
return promise;
|
|
88
102
|
};
|
|
89
103
|
|
|
104
|
+
const getErrorRSCPayload = (route, error) => {
|
|
105
|
+
const url = route.split("::")[0];
|
|
106
|
+
const cacheKey = `error::${url}::${error.message || String(error)}`;
|
|
107
|
+
if (cache.has(cacheKey)) {
|
|
108
|
+
return cache.get(cacheKey);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const payloadUrl = "/____rsc_payload_error____" + url;
|
|
112
|
+
const promise = createFromFetch(
|
|
113
|
+
fetch(payloadUrl, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
},
|
|
118
|
+
body: JSON.stringify({
|
|
119
|
+
error: {
|
|
120
|
+
message: error.message || "Unknown Error",
|
|
121
|
+
name: error.name,
|
|
122
|
+
stack: error.stack,
|
|
123
|
+
},
|
|
124
|
+
}),
|
|
125
|
+
}).then((res) => {
|
|
126
|
+
if (res.headers.has("x-rsc-redirect")) {
|
|
127
|
+
const redirectUrl = res.headers.get("x-rsc-redirect");
|
|
128
|
+
cache.delete(cacheKey);
|
|
129
|
+
if (window.__DINOU_ROUTER_NAVIGATE__) {
|
|
130
|
+
window.__DINOU_ROUTER_NAVIGATE__(redirectUrl, { replace: true });
|
|
131
|
+
} else {
|
|
132
|
+
window.location.href = redirectUrl;
|
|
133
|
+
}
|
|
134
|
+
return new Promise(() => {});
|
|
135
|
+
}
|
|
136
|
+
return res;
|
|
137
|
+
}),
|
|
138
|
+
{
|
|
139
|
+
callServer: async (id, args) => {
|
|
140
|
+
const proxy = createServerFunctionProxy(id);
|
|
141
|
+
return proxy(...args);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
cache.set(cacheKey, promise);
|
|
146
|
+
return promise;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
class ErrorBoundary extends Component {
|
|
150
|
+
constructor(props) {
|
|
151
|
+
super(props);
|
|
152
|
+
this.state = { hasError: false, error: null };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static getDerivedStateFromError(error) {
|
|
156
|
+
return { hasError: true, error };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
componentDidCatch(error, errorInfo) {
|
|
160
|
+
console.error("[Dinou] ErrorBoundary caught error:", error, errorInfo);
|
|
161
|
+
if (this.props.onError) {
|
|
162
|
+
this.props.onError(error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
render() {
|
|
167
|
+
if (this.state.hasError) {
|
|
168
|
+
if (this.props.fallback) {
|
|
169
|
+
return this.props.fallback(this.state.error);
|
|
170
|
+
}
|
|
171
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
172
|
+
return (
|
|
173
|
+
<div style={{ padding: "20px", fontFamily: "sans-serif" }}>
|
|
174
|
+
<h2>Application Error</h2>
|
|
175
|
+
<p>An unexpected error occurred on the client.</p>
|
|
176
|
+
<pre style={{ backgroundColor: "#f5f5f5", padding: "15px", borderRadius: "5px", overflowX: "auto" }}>
|
|
177
|
+
{isDev ? (
|
|
178
|
+
<>
|
|
179
|
+
<div style={{ fontWeight: "bold", marginBottom: "10px" }}>
|
|
180
|
+
{this.state.error?.name || "Error"}: {this.state.error?.message || String(this.state.error)}
|
|
181
|
+
</div>
|
|
182
|
+
<div>{this.state.error?.stack}</div>
|
|
183
|
+
</>
|
|
184
|
+
) : (
|
|
185
|
+
this.state.error?.message || String(this.state.error)
|
|
186
|
+
)}
|
|
187
|
+
</pre>
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return this.props.children;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
90
196
|
// ====================================================================
|
|
91
197
|
// 3. ROUTER COMPONENT
|
|
92
198
|
// ====================================================================
|
|
@@ -96,6 +202,7 @@ function Router() {
|
|
|
96
202
|
const [isPopState, setIsPopState] = useState(false);
|
|
97
203
|
const [isPending, startTransition] = useTransition();
|
|
98
204
|
const [version, setVersion] = useState(0);
|
|
205
|
+
const [navError, setNavError] = useState(null);
|
|
99
206
|
|
|
100
207
|
// 🧭 NAVIGATE FUNCTION (Core Logic)
|
|
101
208
|
const navigate = (href, options = {}) => {
|
|
@@ -139,6 +246,7 @@ function Router() {
|
|
|
139
246
|
startTransition(() => {
|
|
140
247
|
setIsPopState(false);
|
|
141
248
|
setRoute(finalPath);
|
|
249
|
+
setNavError(null);
|
|
142
250
|
});
|
|
143
251
|
};
|
|
144
252
|
|
|
@@ -175,6 +283,7 @@ function Router() {
|
|
|
175
283
|
startTransition(() => {
|
|
176
284
|
// 3. Increment version to force re-execution of useMemo
|
|
177
285
|
setVersion((v) => v + 1);
|
|
286
|
+
setNavError(null);
|
|
178
287
|
});
|
|
179
288
|
};
|
|
180
289
|
|
|
@@ -221,6 +330,7 @@ function Router() {
|
|
|
221
330
|
startTransition(() => {
|
|
222
331
|
setIsPopState(true);
|
|
223
332
|
setRoute(target);
|
|
333
|
+
setNavError(null);
|
|
224
334
|
});
|
|
225
335
|
};
|
|
226
336
|
|
|
@@ -266,7 +376,7 @@ function Router() {
|
|
|
266
376
|
|
|
267
377
|
// RSC Logic
|
|
268
378
|
const rscKey = route + "::" + version;
|
|
269
|
-
const content = getRSCPayload(rscKey);
|
|
379
|
+
const content = navError ? getErrorRSCPayload(route, navError) : getRSCPayload(rscKey);
|
|
270
380
|
|
|
271
381
|
const contextValue = useMemo(
|
|
272
382
|
() => ({
|
|
@@ -282,7 +392,12 @@ function Router() {
|
|
|
282
392
|
|
|
283
393
|
return (
|
|
284
394
|
<RouterContext.Provider value={contextValue}>
|
|
285
|
-
|
|
395
|
+
<ErrorBoundary
|
|
396
|
+
key={navError ? "error" : "normal"}
|
|
397
|
+
onError={setNavError}
|
|
398
|
+
>
|
|
399
|
+
{use(content)}
|
|
400
|
+
</ErrorBoundary>
|
|
286
401
|
</RouterContext.Provider>
|
|
287
402
|
);
|
|
288
403
|
}
|
|
@@ -41,33 +41,28 @@ function generatingISG(reqPath, isDynamicFromServer) {
|
|
|
41
41
|
return; // 👋 We exit without doing anything, the page is dynamic
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
// B. Generate HTML and RSC (
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (pageResult.success && rscResult.success) {
|
|
52
|
-
await safeRename(pageResult.tempPath, pageResult.finalPath);
|
|
44
|
+
// B. Generate HTML and RSC sequentially (RSC first, then HTML)
|
|
45
|
+
const rscResult = await generateStaticRSC(reqPath);
|
|
46
|
+
if (!rscResult.success) {
|
|
47
|
+
console.warn(`⚠️ [ISG] RSC generation failed for ${reqPath}. Aborting.`);
|
|
48
|
+
await fs.unlink(rscResult.tempPath).catch(() => {});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
await safeRename(rscResult.tempPath, rscResult.finalPath);
|
|
57
|
-
// // Rename .tmp -> Final
|
|
58
|
-
// await fs.rename(pageResult.tempPath, pageResult.finalPath);
|
|
59
|
-
// await fs.rename(rscResult.tempPath, rscResult.finalPath);
|
|
52
|
+
// Commit the RSC payload immediately so that generateStaticPage can read it
|
|
53
|
+
await safeRename(rscResult.tempPath, rscResult.finalPath);
|
|
60
54
|
|
|
61
|
-
|
|
55
|
+
const pageResult = await generateStaticPage(reqPath);
|
|
56
|
+
if (pageResult.success) {
|
|
57
|
+
await safeRename(pageResult.tempPath, pageResult.finalPath);
|
|
62
58
|
updateStatus(reqPath, pageResult.status);
|
|
63
59
|
isDynamicFromServer.value = false;
|
|
64
60
|
console.log(`✅ [ISG] Successfully promoted ${reqPath} to static.`);
|
|
65
61
|
} else {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await fs.unlink(rscResult.tempPath).catch(() => { });
|
|
69
|
-
console.warn(`⚠️ [ISG] Failed to generate HTML/RSC for ${reqPath}`);
|
|
62
|
+
await fs.unlink(pageResult.tempPath).catch(() => {});
|
|
63
|
+
console.warn(`⚠️ [ISG] HTML generation failed for ${reqPath}. Aborting commit.`);
|
|
70
64
|
}
|
|
65
|
+
|
|
71
66
|
} catch (e) {
|
|
72
67
|
console.error(`[ISG] Critical error promoting ${reqPath}:`, e);
|
|
73
68
|
} finally {
|
|
@@ -140,7 +140,7 @@ async function getErrorJSX(reqPath, query, error, isDevelopment = false) {
|
|
|
140
140
|
);
|
|
141
141
|
|
|
142
142
|
if (slotErrorPath) {
|
|
143
|
-
const slotErrorModule =
|
|
143
|
+
const slotErrorModule = await importModule(slotErrorPath);
|
|
144
144
|
const SlotError = slotErrorModule.default ?? slotErrorModule;
|
|
145
145
|
|
|
146
146
|
const serializedError = {
|
package/dinou/core/get-jsx.js
CHANGED
|
@@ -196,7 +196,7 @@ async function getJSX(
|
|
|
196
196
|
);
|
|
197
197
|
|
|
198
198
|
if (slotErrorPath) {
|
|
199
|
-
const slotErrorModule =
|
|
199
|
+
const slotErrorModule = await importModule(slotErrorPath);
|
|
200
200
|
const SlotError = slotErrorModule.default ?? slotErrorModule;
|
|
201
201
|
|
|
202
202
|
const serializedError = {
|
|
@@ -37,7 +37,9 @@ function revalidating(reqPath, isDynamicFromServer) {
|
|
|
37
37
|
path.join(dist2Folder, reqPath, "rsc.rsc"),
|
|
38
38
|
path.join(dist2Folder, reqPath, "rsc._old.rsc")
|
|
39
39
|
);
|
|
40
|
-
} catch (e) {
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.error("[ISR] copyFileSync error:", e);
|
|
42
|
+
}
|
|
41
43
|
|
|
42
44
|
regenerating.add(reqPath);
|
|
43
45
|
|
|
@@ -55,14 +57,19 @@ function revalidating(reqPath, isDynamicFromServer) {
|
|
|
55
57
|
return;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const rscResult = await generateStaticRSC(reqPath);
|
|
61
|
+
if (!rscResult.success) {
|
|
62
|
+
console.warn(`⚠️ [ISR] RSC generation failed for ${reqPath}. Aborting.`);
|
|
63
|
+
await fs.unlink(rscResult.tempPath).catch(() => {});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
// Commit the RSC payload immediately so that generateStaticPage can read it
|
|
68
|
+
await safeRename(rscResult.tempPath, rscResult.finalPath);
|
|
69
|
+
|
|
70
|
+
const pageResult = await generateStaticPage(reqPath);
|
|
71
|
+
if (pageResult.success) {
|
|
64
72
|
await safeRename(pageResult.tempPath, pageResult.finalPath);
|
|
65
|
-
await safeRename(rscResult.tempPath, rscResult.finalPath);
|
|
66
73
|
updateStatus(reqPath, pageResult.status);
|
|
67
74
|
isDynamicFromServer.value = false;
|
|
68
75
|
console.log(
|
|
@@ -70,11 +77,9 @@ function revalidating(reqPath, isDynamicFromServer) {
|
|
|
70
77
|
);
|
|
71
78
|
} else {
|
|
72
79
|
console.warn(
|
|
73
|
-
`⚠️ [ISR]
|
|
80
|
+
`⚠️ [ISR] HTML generation failed for ${reqPath}. Aborting commit.`
|
|
74
81
|
);
|
|
75
|
-
|
|
76
82
|
await fs.unlink(pageResult.tempPath).catch(() => {});
|
|
77
|
-
await fs.unlink(rscResult.tempPath).catch(() => {});
|
|
78
83
|
}
|
|
79
84
|
} catch (e) {
|
|
80
85
|
console.error(`[ISR] Critical error regenerating ${reqPath}:`, e);
|