dinou 5.0.0 → 5.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/CHANGELOG.md +18 -0
- package/dinou/core/client.jsx +6 -0
- 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/navigation.js +42 -27
- package/dinou/core/revalidating.js +15 -10
- package/dinou/core/server.js +136 -6
- package/dinou/package.json +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [5.0.2] - 2026-07-08
|
|
9
|
+
|
|
10
|
+
### 🛡️ Security & Route Control
|
|
11
|
+
* **Route Validation in RSC Payload Endpoints**: Unified security checks across endpoints. Direct requests to fetch RSC payloads (`/____rsc_payload____/*`) now enforce `validateParams()` and `allowISG()` checks matching the main HTML document loader behavior. This prevents direct payload scraping or scanning of blocked/invalid dynamic route parameters.
|
|
12
|
+
|
|
13
|
+
### 🐛 Bug Fixes
|
|
14
|
+
* **Sequential Compilation in ISR & ISG**: Resolved a critical race condition that caused disk cache desynchronization and persistent hydration mismatch errors.
|
|
15
|
+
* **Issue**: `Promise.all` compiled the RSC payload and HTML page in parallel. The HTML generator read the `rsc.rsc` file from disk before the new payload finished writing, saving a stale timestamp/state in the static HTML file.
|
|
16
|
+
* **Solution**: Refactored `revalidating.js` and `generating-isg.js` to execute sequentially. The RSC payload is compiled and committed first, ensuring the HTML compiler reads the freshly generated RSC file.
|
|
17
|
+
* **ESM Loader Compatibility for Slot Error Boundaries (`importModule` vs `require`)**: Fixed a server-side crash when using React client hooks inside slot error components (`error.tsx`).
|
|
18
|
+
* **Issue**: The framework used CommonJS `require()` to import the slot error components, bypassing the registered ESM custom loader (`register-loader.mjs`). This caused `"use client"` components to be evaluated as Server Components, failing with `useState is not a function`.
|
|
19
|
+
* **Solution**: Updated `get-jsx.js` and `get-error-jsx.js` to load slot error modules using `await importModule()`, ensuring they are correctly resolved as Client Component References.
|
|
20
|
+
|
|
21
|
+
## [5.0.1] - 2026-07-07
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **ESM SSR Navigation Context Resolution**: Replaced direct `require` with a dynamic loader hook (`__dinou_require__` or `module.require`) in `navigation.js` to resolve the request context inside ESM SSR execution trees (e.g., Esbuild and Rollup client bundlers), preventing `ReferenceError: require is not defined` and resolving client component hydration mismatches during route resolution.
|
|
25
|
+
|
|
8
26
|
## [5.0.0] - 2026-07-05
|
|
9
27
|
|
|
10
28
|
### Added
|
package/dinou/core/client.jsx
CHANGED
|
@@ -64,6 +64,12 @@ const getRSCPayload = (rscKey, isPrefetch = false) => {
|
|
|
64
64
|
payloadUrl = "/____rsc_payload____" + url;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
const buildId = window.__DINOU_BUILD_ID__;
|
|
68
|
+
if (buildId) {
|
|
69
|
+
payloadUrl += (payloadUrl.includes("?") ? "&" : "?") + "buildId=" + buildId;
|
|
70
|
+
window.__DINOU_BUILD_ID__ = undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
// 3. Fetch and Cache Storage
|
|
68
74
|
const promise = createFromFetch(
|
|
69
75
|
fetch(payloadUrl).then((res) => {
|
|
@@ -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 = {
|
package/dinou/core/navigation.js
CHANGED
|
@@ -58,11 +58,11 @@ export function useRouter() {
|
|
|
58
58
|
if (!context) {
|
|
59
59
|
// On the server we return empty functions to not break the rendering
|
|
60
60
|
return {
|
|
61
|
-
push: () => {},
|
|
62
|
-
replace: () => {},
|
|
63
|
-
back: () => {},
|
|
64
|
-
forward: () => {},
|
|
65
|
-
refresh: () => {},
|
|
61
|
+
push: () => { },
|
|
62
|
+
replace: () => { },
|
|
63
|
+
back: () => { },
|
|
64
|
+
forward: () => { },
|
|
65
|
+
refresh: () => { },
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -95,16 +95,24 @@ export function usePathname() {
|
|
|
95
95
|
// 🟢 1. SERVER LOGIC (SSR)
|
|
96
96
|
if (typeof window === "undefined") {
|
|
97
97
|
try {
|
|
98
|
-
const dynamicRequire =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
|
|
98
|
+
const dynamicRequire =
|
|
99
|
+
typeof __dinou_require__ !== "undefined"
|
|
100
|
+
? __dinou_require__
|
|
101
|
+
: typeof module !== "undefined" && typeof module.require === "function"
|
|
102
|
+
? module.require.bind(module)
|
|
103
|
+
: null;
|
|
104
|
+
if (dynamicRequire) {
|
|
105
|
+
const { getContext } = dynamicRequire(
|
|
106
|
+
/* webpackIgnore: true */ "./request-context.js"
|
|
107
|
+
);
|
|
108
|
+
const ctx = getContext();
|
|
109
|
+
if (ctx && ctx.req) {
|
|
110
|
+
return normalizePath(ctx.req.path);
|
|
111
|
+
}
|
|
106
112
|
}
|
|
107
|
-
} catch (e) {
|
|
113
|
+
} catch (e) {
|
|
114
|
+
console.log("error getContext usePathname", e);
|
|
115
|
+
}
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
// 🔵 2. CLIENT LOGIC
|
|
@@ -126,20 +134,27 @@ export function useSearchParams() {
|
|
|
126
134
|
// 🟢 1. SERVER LOGIC
|
|
127
135
|
if (typeof window === "undefined") {
|
|
128
136
|
try {
|
|
129
|
-
const dynamicRequire =
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
const dynamicRequire =
|
|
138
|
+
typeof __dinou_require__ !== "undefined"
|
|
139
|
+
? __dinou_require__
|
|
140
|
+
: typeof module !== "undefined" && typeof module.require === "function"
|
|
141
|
+
? module.require.bind(module)
|
|
142
|
+
: null;
|
|
143
|
+
if (dynamicRequire) {
|
|
144
|
+
const { getContext } = dynamicRequire(
|
|
145
|
+
/* webpackIgnore: true */ "./request-context.js"
|
|
146
|
+
);
|
|
147
|
+
const ctx = getContext();
|
|
148
|
+
if (ctx && ctx.req && ctx.req.query) {
|
|
149
|
+
const params = new URLSearchParams();
|
|
150
|
+
Object.entries(ctx.req.query).forEach(([key, val]) => {
|
|
151
|
+
if (Array.isArray(val)) val.forEach((v) => params.append(key, v));
|
|
152
|
+
else if (val) params.append(key, val);
|
|
153
|
+
});
|
|
154
|
+
return params;
|
|
155
|
+
}
|
|
141
156
|
}
|
|
142
|
-
} catch (e) {}
|
|
157
|
+
} catch (e) { }
|
|
143
158
|
}
|
|
144
159
|
|
|
145
160
|
// 🔵 2. CLIENT LOGIC
|
|
@@ -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);
|
package/dinou/core/server.js
CHANGED
|
@@ -621,11 +621,28 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
|
|
|
621
621
|
// reqPath
|
|
622
622
|
// );
|
|
623
623
|
if ((!isDevelopment && !dynamicState.value) || isStatic) {
|
|
624
|
+
let currentGeneratedAt = null;
|
|
625
|
+
try {
|
|
626
|
+
const metadataPath = path.join("dist2", reqPath, "metadata.json");
|
|
627
|
+
if (existsSync(metadataPath)) {
|
|
628
|
+
const metaObj = JSON.parse(readFileSync(metadataPath, "utf8"));
|
|
629
|
+
currentGeneratedAt = metaObj.generatedAt || null;
|
|
630
|
+
}
|
|
631
|
+
} catch (e) {}
|
|
632
|
+
|
|
633
|
+
const useOld =
|
|
634
|
+
isOld ||
|
|
635
|
+
regenerating.has(reqPath) ||
|
|
636
|
+
(req.query.buildId &&
|
|
637
|
+
currentGeneratedAt &&
|
|
638
|
+
req.query.buildId !== String(currentGeneratedAt));
|
|
639
|
+
|
|
624
640
|
const payloadPath = path.resolve(
|
|
625
641
|
"dist2",
|
|
626
642
|
reqPath.replace(/^\//, ""),
|
|
627
|
-
|
|
643
|
+
useOld ? "rsc._old.rsc" : "rsc.rsc",
|
|
628
644
|
);
|
|
645
|
+
|
|
629
646
|
const distDir = path.resolve("dist2");
|
|
630
647
|
|
|
631
648
|
if (!payloadPath.startsWith(distDir)) {
|
|
@@ -633,6 +650,7 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
|
|
|
633
650
|
}
|
|
634
651
|
if (existsSync(payloadPath)) {
|
|
635
652
|
res.setHeader("Content-Type", "application/octet-stream");
|
|
653
|
+
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
636
654
|
try {
|
|
637
655
|
const buffer = readFileSync(payloadPath);
|
|
638
656
|
return res.send(buffer);
|
|
@@ -642,6 +660,103 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
|
|
|
642
660
|
}
|
|
643
661
|
}
|
|
644
662
|
}
|
|
663
|
+
let isPathBlocked = false;
|
|
664
|
+
const reqSegments = reqPath.split("/").filter(Boolean);
|
|
665
|
+
const srcFolder = path.resolve(process.cwd(), "src");
|
|
666
|
+
const [pagePath, dynamicParams] = getFilePathAndDynamicParams(
|
|
667
|
+
reqSegments,
|
|
668
|
+
req.query,
|
|
669
|
+
srcFolder,
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
if (pagePath) {
|
|
673
|
+
let cachedConfig = pageFunctionsConfigCache.get(pagePath);
|
|
674
|
+
if (!cachedConfig) {
|
|
675
|
+
const pageFolder = path.dirname(pagePath);
|
|
676
|
+
const [pageFunctionsPath] = getFilePathAndDynamicParams(
|
|
677
|
+
reqSegments,
|
|
678
|
+
req.query,
|
|
679
|
+
pageFolder,
|
|
680
|
+
"page_functions",
|
|
681
|
+
true,
|
|
682
|
+
true,
|
|
683
|
+
undefined,
|
|
684
|
+
reqSegments.length,
|
|
685
|
+
);
|
|
686
|
+
|
|
687
|
+
if (pageFunctionsPath) {
|
|
688
|
+
const pageFunctionsModule = await importModule(pageFunctionsPath);
|
|
689
|
+
const allowISGValue = pageFunctionsModule.allowISG
|
|
690
|
+
? await pageFunctionsModule.allowISG()
|
|
691
|
+
: true;
|
|
692
|
+
|
|
693
|
+
let staticPathsSet = null;
|
|
694
|
+
if (pageFunctionsModule.getStaticPaths) {
|
|
695
|
+
const paths = await pageFunctionsModule.getStaticPaths();
|
|
696
|
+
staticPathsSet = new Set(
|
|
697
|
+
(paths || []).map((pathObj) => {
|
|
698
|
+
const sortedEntries = Object.entries(pathObj).sort((a, b) =>
|
|
699
|
+
a[0].localeCompare(b[0])
|
|
700
|
+
);
|
|
701
|
+
return JSON.stringify(sortedEntries);
|
|
702
|
+
})
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
cachedConfig = {
|
|
707
|
+
allowISG: allowISGValue,
|
|
708
|
+
staticPathsSet,
|
|
709
|
+
validateParams: pageFunctionsModule.validateParams || null,
|
|
710
|
+
};
|
|
711
|
+
} else {
|
|
712
|
+
cachedConfig = {
|
|
713
|
+
allowISG: true,
|
|
714
|
+
staticPathsSet: null,
|
|
715
|
+
validateParams: null,
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (!isDevelopment) {
|
|
720
|
+
pageFunctionsConfigCache.set(pagePath, cachedConfig);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const { allowISG: allowISGValue, staticPathsSet, validateParams: validateParamsFn } = cachedConfig;
|
|
725
|
+
const hasParams = Object.keys(dynamicParams || {}).length > 0;
|
|
726
|
+
if (hasParams) {
|
|
727
|
+
if (validateParamsFn) {
|
|
728
|
+
const isValid = await validateParamsFn(dynamicParams);
|
|
729
|
+
if (!isValid) {
|
|
730
|
+
isPathBlocked = true;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (!isPathBlocked && allowISGValue === false) {
|
|
735
|
+
let isPathAllowed = false;
|
|
736
|
+
if (staticPathsSet) {
|
|
737
|
+
const sortedQueryEntries = Object.entries(dynamicParams)
|
|
738
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
739
|
+
.map(([k, v]) => {
|
|
740
|
+
if (Array.isArray(v)) return [k, v.join(",")];
|
|
741
|
+
return [k, String(v)];
|
|
742
|
+
});
|
|
743
|
+
const serializedQuery = JSON.stringify(sortedQueryEntries);
|
|
744
|
+
isPathAllowed = staticPathsSet.has(serializedQuery);
|
|
745
|
+
}
|
|
746
|
+
if (!isPathAllowed) {
|
|
747
|
+
if (isDevelopment) {
|
|
748
|
+
isPathBlocked = true;
|
|
749
|
+
} else {
|
|
750
|
+
const htmlPath = path.join("dist2", reqPath, "index.html");
|
|
751
|
+
if (!existsSync(htmlPath)) {
|
|
752
|
+
isPathBlocked = true;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
645
760
|
const context = getContext(req, res);
|
|
646
761
|
const isNotFound = {};
|
|
647
762
|
await requestStorage.run(context, async () => {
|
|
@@ -650,6 +765,7 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
|
|
|
650
765
|
{ ...req.query },
|
|
651
766
|
isNotFound,
|
|
652
767
|
isDevelopment,
|
|
768
|
+
isPathBlocked,
|
|
653
769
|
);
|
|
654
770
|
|
|
655
771
|
if (isNotFound.value) {
|
|
@@ -868,6 +984,7 @@ app.get(/^\/.*\/?$/, async (req, res) => {
|
|
|
868
984
|
|
|
869
985
|
if (existsSync(fileToRead) && !dynamicState.value) {
|
|
870
986
|
res.setHeader("Content-Type", "text/html");
|
|
987
|
+
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
871
988
|
const meta = getStatus[reqPath];
|
|
872
989
|
|
|
873
990
|
if (meta && meta.status) {
|
|
@@ -876,13 +993,26 @@ app.get(/^\/.*\/?$/, async (req, res) => {
|
|
|
876
993
|
res.statusCode = 200; // Default
|
|
877
994
|
}
|
|
878
995
|
try {
|
|
879
|
-
|
|
880
|
-
|
|
996
|
+
let htmlContent = readFileSync(fileToRead, "utf8");
|
|
997
|
+
let buildId = "";
|
|
998
|
+
try {
|
|
999
|
+
const metadataPath = path.join("dist2", reqPath, "metadata.json");
|
|
1000
|
+
if (existsSync(metadataPath)) {
|
|
1001
|
+
const metaObj = JSON.parse(readFileSync(metadataPath, "utf8"));
|
|
1002
|
+
buildId = metaObj.generatedAt || "";
|
|
1003
|
+
}
|
|
1004
|
+
} catch (e) {}
|
|
1005
|
+
|
|
1006
|
+
let scripts = `<script>window.__DINOU_USE_STATIC__=true;</script>`;
|
|
881
1007
|
if (htmlPathOld) {
|
|
882
|
-
|
|
1008
|
+
scripts += `<script>window.__DINOU_USE_OLD_RSC__=true;</script>`;
|
|
883
1009
|
}
|
|
884
|
-
|
|
885
|
-
|
|
1010
|
+
if (buildId) {
|
|
1011
|
+
scripts += `<script>window.__DINOU_BUILD_ID__="${buildId}";</script>`;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
htmlContent = htmlContent.replace("</head>", `${scripts}</head>`);
|
|
1015
|
+
res.send(htmlContent);
|
|
886
1016
|
} catch (err) {
|
|
887
1017
|
console.error("Error reading HTML file:", err);
|
|
888
1018
|
if (!res.headersSent) res.status(500).send("Server Error");
|
package/dinou/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dinou",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Lightweight-Ejectable Full-Stack React 19 Framework with support for React Server Components (RSC), Server Functions, Server-Side Rendering (SSR), Static Generation (SSG), Incremental Static Generation (ISG), and Incremental Static Regeneration (ISR)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -96,4 +96,4 @@
|
|
|
96
96
|
"react": ">=19.2.3",
|
|
97
97
|
"react-dom": ">=19.2.3"
|
|
98
98
|
}
|
|
99
|
-
}
|
|
99
|
+
}
|