dinou 6.1.1 → 7.0.0

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.
Files changed (135) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +9461 -1080
  3. package/cli.js +392 -169
  4. package/dinou/adapters/bun.js +62 -0
  5. package/dinou/adapters/cloudflare.js +65 -0
  6. package/dinou/adapters/deno.js +48 -0
  7. package/dinou/adapters/netlify.js +85 -0
  8. package/dinou/adapters/node.mjs +31 -0
  9. package/dinou/bun/build.mjs +1077 -0
  10. package/dinou/cloudflare/build.mjs +1121 -0
  11. package/dinou/cloudflare/shims/child_process.js +14 -0
  12. package/dinou/cloudflare/shims/empty.js +2 -0
  13. package/dinou/cloudflare/shims/fs.js +99 -0
  14. package/dinou/cloudflare/shims/os.js +29 -0
  15. package/dinou/config.js +1 -0
  16. package/dinou/config.mjs +2 -0
  17. package/dinou/constants.js +29 -4
  18. package/dinou/core/babel-esm-loader.js +66 -37
  19. package/dinou/core/bailout-proxy.js +61 -0
  20. package/dinou/core/build-static-pages.js +309 -157
  21. package/dinou/core/cache-revalidate.js +471 -144
  22. package/dinou/core/cache-slot.js +387 -0
  23. package/dinou/core/client-redirect.jsx +12 -7
  24. package/dinou/core/client-webpack.jsx +457 -82
  25. package/dinou/core/client.jsx +452 -82
  26. package/dinou/core/config.js +11 -0
  27. package/dinou/core/dinou-paths.js +52 -0
  28. package/dinou/core/edge-ssr.js +122 -0
  29. package/dinou/core/export-static.mjs +64 -0
  30. package/dinou/core/generate-route-types.js +252 -0
  31. package/dinou/core/generate-static-page.js +55 -94
  32. package/dinou/core/generate-static-rsc.js +47 -15
  33. package/dinou/core/generate-static.js +212 -10
  34. package/dinou/core/generating-isg.js +5 -0
  35. package/dinou/core/get-asset-from-manifest.js +9 -3
  36. package/dinou/core/get-error-jsx.js +221 -41
  37. package/dinou/core/get-file-path-and-dynamic-params.js +9 -13
  38. package/dinou/core/get-jsx.js +172 -95
  39. package/dinou/core/handler.js +2296 -0
  40. package/dinou/core/http-adapter.js +115 -0
  41. package/dinou/core/import-module.js +83 -53
  42. package/dinou/core/layout-functions.js +181 -0
  43. package/dinou/core/link.jsx +18 -6
  44. package/dinou/core/load-dinou-config.js +60 -0
  45. package/dinou/core/manifest-provider.js +261 -0
  46. package/dinou/core/navigation-utils.js +4 -0
  47. package/dinou/core/navigation.js +50 -39
  48. package/dinou/core/parse-exports.js +207 -2
  49. package/dinou/core/ppr-context.js +105 -0
  50. package/dinou/core/ppr-runtime.js +263 -0
  51. package/dinou/core/redirect.jsx +20 -19
  52. package/dinou/core/render-jsx-to-client-jsx.js +133 -15
  53. package/dinou/core/request-context.js +47 -13
  54. package/dinou/core/resolve-module-ppr.js +32 -0
  55. package/dinou/core/revalidating.js +28 -9
  56. package/dinou/core/route-generator.js +107 -0
  57. package/dinou/core/rsc-renderer.js +90 -0
  58. package/dinou/core/run-ssg.js +19 -0
  59. package/dinou/core/scan-dependency-components.js +218 -0
  60. package/dinou/core/server-function-proxy-webpack.js +3 -0
  61. package/dinou/core/server-function-proxy.js +3 -0
  62. package/dinou/core/slot.js +302 -0
  63. package/dinou/core/status-manifest.js +41 -1
  64. package/dinou/core/storage-adapter.js +522 -0
  65. package/dinou/core/url-resolver.js +16 -16
  66. package/dinou/core/vfs.js +139 -68
  67. package/dinou/deno/build.mjs +1112 -0
  68. package/dinou/deno/seed-kv.js +115 -0
  69. package/dinou/esbuild/build.mjs +51 -1
  70. package/dinou/esbuild/dev.mjs +290 -224
  71. package/dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs +3 -2
  72. package/dinou/esbuild/helpers-esbuild/get-config-esbuild.mjs +104 -16
  73. package/dinou/esbuild/helpers-esbuild/get-esbuild-entries.mjs +31 -19
  74. package/dinou/esbuild/helpers-esbuild/strip-namespace.mjs +9 -0
  75. package/dinou/esbuild/helpers-esbuild/swc-disk-cache.mjs +225 -0
  76. package/dinou/esbuild/helpers-esbuild/update-manifest-for-module.mjs +7 -0
  77. package/dinou/esbuild/helpers-esbuild/write.mjs +111 -2
  78. package/dinou/esbuild/plugins-esbuild/assets-plugin.mjs +236 -161
  79. package/dinou/esbuild/plugins-esbuild/css-processor-plugin.mjs +101 -5
  80. package/dinou/esbuild/plugins-esbuild/react-client-manifest-plugin.mjs +63 -24
  81. package/dinou/esbuild/plugins-esbuild/server-functions-plugin.mjs +177 -56
  82. package/dinou/esbuild/plugins-esbuild/skip-missing-entry-points-plugin.mjs +3 -0
  83. package/dinou/esbuild/plugins-esbuild/stable-chunk-names-and-maps-plugin.mjs +182 -137
  84. package/dinou/esbuild/plugins-postcss/postcss-extract-plugin.js +38 -11
  85. package/dinou/esbuild/react-refresh/esm-hmr/client.mjs +55 -8
  86. package/dinou/esbuild/react-refresh/esm-hmr/server.js +1 -1
  87. package/dinou/esbuild/react-refresh/esm-hmr-plugin.mjs +238 -101
  88. package/dinou/esbuild/react-refresh/is-react-refresh-boundary.mjs +18 -4
  89. package/dinou/index.d.ts +315 -11
  90. package/dinou/index.js +12 -6
  91. package/dinou/index.mjs +9 -0
  92. package/dinou/node/build.mjs +195 -0
  93. package/dinou/node/bundle-dual-engine.mjs +1012 -0
  94. package/dinou/node/dev.mjs +2589 -0
  95. package/dinou/node/port-selector.mjs +164 -0
  96. package/dinou/node/terminal-status.mjs +345 -0
  97. package/dinou/package.json +16 -14
  98. package/dinou/rollup/react-refresh/esm-hmr/client.js +66 -10
  99. package/dinou/rollup/react-refresh/esm-hmr/server.js +1 -1
  100. package/dinou/rollup/react-refresh/is-react-refresh-boundary.js +24 -5
  101. package/dinou/rollup/react-refresh/react-refresh-runtime.js +13 -6
  102. package/dinou/rollup/react-refresh/react-refresh-wrap-modules.js +56 -11
  103. package/dinou/rollup/react-refresh/rollup-plugin-esm-hmr.js +176 -48
  104. package/dinou/rollup/rollup-plugins/dinou-asset-plugin.js +9 -5
  105. package/dinou/rollup/rollup-plugins/rollup-plugin-memory.js +66 -0
  106. package/dinou/rollup/rollup-plugins/rollup-plugin-react-client-manifest.js +468 -123
  107. package/dinou/rollup/rollup-plugins/rollup-plugin-server-functions.js +44 -12
  108. package/dinou/rollup/rollup-plugins/rollup-plugin-swc.js +100 -0
  109. package/dinou/rollup/rollup.config.js +155 -43
  110. package/dinou/server.d.ts +114 -12
  111. package/dinou/server.js +35 -10
  112. package/dinou/server.mjs +30 -9
  113. package/dinou/webpack/helpers/get-webpack-entries.js +14 -19
  114. package/dinou/webpack/loaders/server-functions-loader.js +22 -1
  115. package/dinou/webpack/loaders/swc-loader.js +76 -0
  116. package/dinou/webpack/plugins/manifest-generator-plugin.js +1 -0
  117. package/dinou/webpack/plugins/server-functions-plugin.js +75 -19
  118. package/dinou/webpack/plugins/webpack-memory-plugin.js +66 -0
  119. package/dinou/webpack/webpack.config.js +227 -29
  120. package/eject.js +173 -94
  121. package/package.json +110 -108
  122. package/dinou/core/asset-require-hook.js +0 -58
  123. package/dinou/core/client-error-webpack.jsx +0 -432
  124. package/dinou/core/client-error.jsx +0 -432
  125. package/dinou/core/concurrency-manager.js +0 -48
  126. package/dinou/core/context-proxy.js +0 -68
  127. package/dinou/core/generate-static-pages.js +0 -130
  128. package/dinou/core/generate-static-rscs.js +0 -151
  129. package/dinou/core/get-ssg-metadata.js +0 -31
  130. package/dinou/core/register-loader.mjs +0 -11
  131. package/dinou/core/register-paths.js +0 -27
  132. package/dinou/core/render-app-to-html.js +0 -430
  133. package/dinou/core/render-html.js +0 -407
  134. package/dinou/core/server.js +0 -1542
  135. package/dinou/esbuild/plugins-esbuild/write-metafile-plugin.mjs +0 -16
@@ -0,0 +1,1121 @@
1
+ // dinou/cloudflare/build.mjs
2
+ // Dual-Bundle Build script for packaging Dinou v7 for Cloudflare Workers.
3
+ // Pass A: RSC Engine (conditions: ["workerd", "worker", "react-server"])
4
+ // Pass B: Native Streaming HTML SSR Engine (conditions: ["workerd", "worker", "browser"])
5
+ // Pass C: Main Worker Orchestrator (worker.js)
6
+
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import esbuild from "esbuild";
10
+ import { createRequire } from "node:module";
11
+ import { fileURLToPath, pathToFileURL } from "node:url";
12
+
13
+ const require = createRequire(import.meta.url);
14
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
+ const { generateRouteModulesCode, generateRouteTypes } = require("../core/route-generator.js");
16
+ const parseExports = require("../core/parse-exports.js");
17
+ const { useClientRegex, useServerRegex } = require("../constants.js");
18
+ const {
19
+ isSupportedClientModule,
20
+ scanProjectDependenciesForClientComponents,
21
+ } = require("../core/scan-dependency-components.js");
22
+
23
+ const projectRoot = process.cwd();
24
+ const cloudflareDir = path.resolve(projectRoot, ".dinou/cloudflare");
25
+ fs.mkdirSync(cloudflareDir, { recursive: true });
26
+
27
+ try {
28
+ generateRouteTypes(projectRoot);
29
+ } catch (e) {}
30
+
31
+ // Locate dinou root: ejected in project or in package directory
32
+ const dinouDir = fs.existsSync(path.resolve(projectRoot, "dinou"))
33
+ ? path.resolve(projectRoot, "dinou")
34
+ : path.resolve(__dirname, "..");
35
+ const dinouDirSlash = dinouDir.replace(/\\/g, "/");
36
+
37
+ const candidateDinouRoots = [
38
+ dinouDir,
39
+ path.resolve(projectRoot, "dinou"),
40
+ path.resolve(projectRoot, "node_modules/dinou/dinou"),
41
+ path.resolve(projectRoot, "node_modules/dinou"),
42
+ path.resolve(__dirname, ".."),
43
+ ];
44
+
45
+ const candidateLinkPaths = new Set();
46
+ const candidateRedirectPaths = new Set();
47
+ const candidateSlotPaths = new Set();
48
+
49
+ for (const r of candidateDinouRoots) {
50
+ candidateLinkPaths.add(path.resolve(r, "core/link.jsx"));
51
+ candidateRedirectPaths.add(path.resolve(r, "core/client-redirect.jsx"));
52
+ candidateSlotPaths.add(path.resolve(r, "core/slot.js"));
53
+ }
54
+
55
+ function copyRecursive(src, dest) {
56
+ if (!fs.existsSync(src)) return 0;
57
+ let count = 0;
58
+ const entries = fs.readdirSync(src, { withFileTypes: true });
59
+ for (const entry of entries) {
60
+ const srcPath = path.join(src, entry.name);
61
+ const destPath = path.join(dest, entry.name);
62
+ if (entry.isDirectory()) {
63
+ fs.mkdirSync(destPath, { recursive: true });
64
+ count += copyRecursive(srcPath, destPath);
65
+ } else {
66
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
67
+ fs.copyFileSync(srcPath, destPath);
68
+ count++;
69
+ }
70
+ }
71
+ return count;
72
+ }
73
+
74
+ const isWebpackBuild = process.env.DINOU_BUILD_TOOL === "webpack";
75
+ const bundlerName = isWebpackBuild ? "webpack" : (process.env.DINOU_BUILD_TOOL || "esbuild");
76
+
77
+ const dist2Dir = path.resolve(projectRoot, ".dinou/dist2");
78
+ const dist3Dir = path.resolve(projectRoot, ".dinou/dist3");
79
+ console.log(`\nšŸ¦– Dinou v7 (Cloudflare Workers • ${bundlerName})`);
80
+ if (fs.existsSync(dist2Dir)) {
81
+ const copiedCount = copyRecursive(dist2Dir, dist3Dir);
82
+ console.log(` šŸ“„ Synchronized ${copiedCount} pre-rendered static route(s) to .dinou/dist3`);
83
+ }
84
+ console.log(" ⚔ Generating route modules & manifests...");
85
+ const routeModulesCode = generateRouteModulesCode(projectRoot, "../..");
86
+ const routeModulesPath = path.join(cloudflareDir, "route-modules.js");
87
+ fs.writeFileSync(routeModulesPath, routeModulesCode, "utf8");
88
+
89
+ function findManifest(filename, fallbackFolder) {
90
+ const candidates = isWebpackBuild
91
+ ? [
92
+ path.resolve(projectRoot, ".dinou/dist3", filename),
93
+ path.resolve(projectRoot, ".dinou/public", filename),
94
+ path.resolve(projectRoot, ".dinou", fallbackFolder, filename),
95
+ ]
96
+ : [
97
+ path.resolve(projectRoot, ".dinou", fallbackFolder, filename),
98
+ path.resolve(projectRoot, ".dinou/dist3", filename),
99
+ path.resolve(projectRoot, ".dinou/public", filename),
100
+ ];
101
+ for (const c of candidates) {
102
+ if (fs.existsSync(c)) return c;
103
+ }
104
+ return null;
105
+ }
106
+
107
+ const clientManifestPath = findManifest("react-client-manifest.json", "react_client_manifest");
108
+ const sfManifestPath = findManifest("server-functions-manifest.json", "server_functions_manifest");
109
+
110
+ let parsedClientManifest = {};
111
+ if (clientManifestPath && fs.existsSync(clientManifestPath)) {
112
+ try {
113
+ parsedClientManifest = JSON.parse(fs.readFileSync(clientManifestPath, "utf8"));
114
+ } catch (e) {}
115
+ }
116
+
117
+ let parsedServerFunctionsManifest = {};
118
+ if (sfManifestPath && fs.existsSync(sfManifestPath)) {
119
+ try {
120
+ parsedServerFunctionsManifest = JSON.parse(fs.readFileSync(sfManifestPath, "utf8"));
121
+ } catch (e) {}
122
+ }
123
+
124
+ // ====================================================================
125
+ // Discovery of Client Components for SSR Engine & RSC Manifest
126
+ // ====================================================================
127
+ if (process.env.DINOU_DEBUG) {
128
+ console.log("šŸ” [Dinou Cloudflare] Discovering client components for SSR Engine...");
129
+ }
130
+ const srcDir = path.resolve(projectRoot, "src");
131
+
132
+
133
+ function findClientComponents() {
134
+ const clientFiles = new Set();
135
+ function walk(dir) {
136
+ if (!fs.existsSync(dir)) return;
137
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
138
+ for (const entry of entries) {
139
+ const full = path.join(dir, entry.name);
140
+ if (entry.isDirectory()) {
141
+ walk(full);
142
+ } else if (/\.[jt]sx?$/.test(entry.name)) {
143
+ try {
144
+ const content = fs.readFileSync(full, "utf8");
145
+ if (useClientRegex.test(content.trim()) && isSupportedClientModule(full, content)) {
146
+ clientFiles.add(path.resolve(full));
147
+ }
148
+ } catch (e) {}
149
+ }
150
+ }
151
+ }
152
+ walk(srcDir);
153
+
154
+ const coreCandidates = [
155
+ ...Array.from(candidateLinkPaths),
156
+ ...Array.from(candidateRedirectPaths),
157
+ ];
158
+ for (const f of coreCandidates) {
159
+ if (fs.existsSync(f)) {
160
+ clientFiles.add(path.resolve(f));
161
+ }
162
+ }
163
+
164
+ // Also scan external dependencies from package.json for "use client" components (e.g. react-enhanced-suspense)
165
+ scanProjectDependenciesForClientComponents(projectRoot, clientFiles, useClientRegex);
166
+
167
+ for (const k of Object.keys(parsedClientManifest)) {
168
+ const fileUrl = k.split("#")[0];
169
+ if (fileUrl.startsWith("file:///")) {
170
+ try {
171
+ const filePath = fileURLToPath(fileUrl);
172
+ const baseName = path.basename(filePath);
173
+ if (baseName === "client.jsx" || baseName === "client-webpack.jsx") {
174
+ continue;
175
+ }
176
+ if (fs.existsSync(filePath) && isSupportedClientModule(filePath)) {
177
+ clientFiles.add(path.resolve(filePath));
178
+ }
179
+ } catch (e) {}
180
+ }
181
+ }
182
+
183
+ return Array.from(clientFiles);
184
+ }
185
+
186
+ const clientComponents = findClientComponents();
187
+ if (process.env.DINOU_DEBUG) {
188
+ console.log(` Found ${clientComponents.length} client component(s) for Native SSR.`);
189
+ }
190
+
191
+ let manifestInlines = "";
192
+ const normalizedManifest = { ...parsedClientManifest };
193
+ for (const [k, v] of Object.entries(parsedClientManifest)) {
194
+ if (k.startsWith("file:///c:/")) {
195
+ normalizedManifest["file:///C:/" + k.slice(11)] = v;
196
+ } else if (k.startsWith("file:///C:/")) {
197
+ normalizedManifest["file:///c:/" + k.slice(11)] = v;
198
+ }
199
+ }
200
+
201
+ function generateAllUrlVariants(absPath) {
202
+ const norm = absPath.replace(/\\/g, "/");
203
+ const fileUrl = pathToFileURL(absPath).href;
204
+ const urls = new Set([fileUrl]);
205
+ urls.add(fileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + d.toLowerCase() + ':'));
206
+ urls.add(fileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + d.toUpperCase() + ':'));
207
+ urls.add("file:///" + norm);
208
+ urls.add("file://" + norm);
209
+ return Array.from(urls);
210
+ }
211
+
212
+
213
+ let linkChunkId = null;
214
+ let redirectChunkId = null;
215
+ let slotChunkId = null;
216
+ let linkEntry = null;
217
+ let redirectEntry = null;
218
+ let slotEntry = null;
219
+
220
+ for (const [k, v] of Object.entries(parsedClientManifest)) {
221
+ if (k.includes("/core/link.jsx") || k.includes("dinouLink")) {
222
+ if (v && v.id) {
223
+ linkChunkId = v.id;
224
+ linkEntry = v;
225
+ }
226
+ }
227
+ if (k.includes("/core/client-redirect.jsx") || k.includes("dinouClientRedirect")) {
228
+ if (v && v.id) {
229
+ redirectChunkId = v.id;
230
+ redirectEntry = v;
231
+ }
232
+ }
233
+ if (k.includes("/core/slot.") || k.includes("dinouSlot")) {
234
+ if (v && v.id) {
235
+ slotChunkId = v.id;
236
+ slotEntry = v;
237
+ }
238
+ }
239
+ }
240
+
241
+ if (linkChunkId) {
242
+ const linkChunks = isWebpackBuild
243
+ ? (linkEntry?.chunks || [linkChunkId])
244
+ : "Link";
245
+ const linkDefaultChunks = isWebpackBuild
246
+ ? (linkEntry?.chunks || [linkChunkId])
247
+ : "default";
248
+
249
+ for (const lp of candidateLinkPaths) {
250
+ for (const url of generateAllUrlVariants(lp)) {
251
+ normalizedManifest[`${url}#Link`] = { id: linkChunkId, chunks: linkChunks, name: "Link" };
252
+ normalizedManifest[`${url}#default`] = { id: linkChunkId, chunks: linkDefaultChunks, name: "default" };
253
+ normalizedManifest[url] = { id: linkChunkId, chunks: linkDefaultChunks, name: "default" };
254
+ }
255
+ }
256
+ }
257
+
258
+ if (redirectChunkId) {
259
+ const redirectChunks = isWebpackBuild
260
+ ? (redirectEntry?.chunks || [redirectChunkId])
261
+ : "ClientRedirect";
262
+ const redirectDefaultChunks = isWebpackBuild
263
+ ? (redirectEntry?.chunks || [redirectChunkId])
264
+ : "default";
265
+
266
+ for (const rp of candidateRedirectPaths) {
267
+ for (const url of generateAllUrlVariants(rp)) {
268
+ normalizedManifest[`${url}#ClientRedirect`] = { id: redirectChunkId, chunks: redirectChunks, name: "ClientRedirect" };
269
+ normalizedManifest[`${url}#default`] = { id: redirectChunkId, chunks: redirectDefaultChunks, name: "default" };
270
+ normalizedManifest[url] = { id: redirectChunkId, chunks: redirectDefaultChunks, name: "default" };
271
+ }
272
+ }
273
+ }
274
+
275
+ if (slotChunkId) {
276
+ const slotChunks = isWebpackBuild
277
+ ? (slotEntry?.chunks || [slotChunkId])
278
+ : "DinouPageSlot";
279
+ const slotBoundaryChunks = isWebpackBuild
280
+ ? (slotEntry?.chunks || [slotChunkId])
281
+ : "DinouCacheSlotBoundary";
282
+ const slotDefaultChunks = isWebpackBuild
283
+ ? (slotEntry?.chunks || [slotChunkId])
284
+ : "default";
285
+
286
+ for (const sp of candidateSlotPaths) {
287
+ for (const url of generateAllUrlVariants(sp)) {
288
+ normalizedManifest[`${url}#DinouPageSlot`] = { id: slotChunkId, chunks: slotChunks, name: "DinouPageSlot" };
289
+ normalizedManifest[`${url}#DinouCacheSlotBoundary`] = { id: slotChunkId, chunks: slotBoundaryChunks, name: "DinouCacheSlotBoundary" };
290
+ normalizedManifest[`${url}#default`] = { id: slotChunkId, chunks: slotDefaultChunks, name: "default" };
291
+ normalizedManifest[url] = { id: slotChunkId, chunks: slotDefaultChunks, name: "default" };
292
+ }
293
+ }
294
+ }
295
+
296
+ for (const comp of clientComponents) {
297
+ const fileUrl = pathToFileURL(comp).href;
298
+ const fileUrlLower = fileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + d.toLowerCase() + ':');
299
+ const fileUrlUpper = fileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + d.toUpperCase() + ':');
300
+ const compResolved = path.resolve(comp);
301
+ const isCoreLink = candidateLinkPaths.has(compResolved);
302
+ const isCoreRedirect = candidateRedirectPaths.has(compResolved);
303
+ const isCoreSlot = candidateSlotPaths.has(compResolved);
304
+
305
+ if (!normalizedManifest[fileUrlLower]) {
306
+ if (isCoreLink && linkChunkId) {
307
+ normalizedManifest[fileUrlLower] = {
308
+ id: linkChunkId,
309
+ chunks: isWebpackBuild ? (linkEntry?.chunks || [linkChunkId]) : "default",
310
+ name: "default",
311
+ };
312
+ } else if (isCoreRedirect && redirectChunkId) {
313
+ normalizedManifest[fileUrlLower] = {
314
+ id: redirectChunkId,
315
+ chunks: isWebpackBuild ? (redirectEntry?.chunks || [redirectChunkId]) : "default",
316
+ name: "default",
317
+ };
318
+ } else if (isCoreSlot && slotChunkId) {
319
+ normalizedManifest[fileUrlLower] = {
320
+ id: slotChunkId,
321
+ chunks: isWebpackBuild ? (slotEntry?.chunks || [slotChunkId]) : "default",
322
+ name: "default",
323
+ };
324
+ } else {
325
+ normalizedManifest[fileUrlLower] = { id: fileUrlLower, chunks: [], name: "*" };
326
+ }
327
+ }
328
+ if (!normalizedManifest[fileUrlUpper]) {
329
+ if (isCoreLink && linkChunkId) {
330
+ normalizedManifest[fileUrlUpper] = {
331
+ id: linkChunkId,
332
+ chunks: isWebpackBuild ? (linkEntry?.chunks || [linkChunkId]) : "default",
333
+ name: "default",
334
+ };
335
+ } else if (isCoreRedirect && redirectChunkId) {
336
+ normalizedManifest[fileUrlUpper] = {
337
+ id: redirectChunkId,
338
+ chunks: isWebpackBuild ? (redirectEntry?.chunks || [redirectChunkId]) : "default",
339
+ name: "default",
340
+ };
341
+ } else if (isCoreSlot && slotChunkId) {
342
+ normalizedManifest[fileUrlUpper] = {
343
+ id: slotChunkId,
344
+ chunks: isWebpackBuild ? (slotEntry?.chunks || [slotChunkId]) : "default",
345
+ name: "default",
346
+ };
347
+ } else {
348
+ normalizedManifest[fileUrlUpper] = { id: fileUrlLower, chunks: [], name: "*" };
349
+ }
350
+ }
351
+ }
352
+
353
+ manifestInlines += `\nglobalThis.__DINOU_CLIENT_MANIFEST__ = ${JSON.stringify(normalizedManifest)};\n`;
354
+
355
+ if (sfManifestPath && fs.existsSync(sfManifestPath)) {
356
+ const content = fs.readFileSync(sfManifestPath, "utf8");
357
+ manifestInlines += `\nglobalThis.__DINOU_SERVER_FUNCTIONS_MANIFEST__ = ${content};\n`;
358
+ } else {
359
+ manifestInlines += `\nglobalThis.__DINOU_SERVER_FUNCTIONS_MANIFEST__ = {};\n`;
360
+ }
361
+
362
+ const assetManifestPath = findManifest("manifest.json", "dist3");
363
+ if (assetManifestPath && fs.existsSync(assetManifestPath)) {
364
+ const content = fs.readFileSync(assetManifestPath, "utf8");
365
+ manifestInlines += `\nglobalThis.__DINOU_ASSET_MANIFEST__ = ${content};\n`;
366
+ } else {
367
+ manifestInlines += `\nglobalThis.__DINOU_ASSET_MANIFEST__ = {};\n`;
368
+ }
369
+
370
+ let importMapHtml = "";
371
+ if (!isWebpackBuild && Object.keys(parsedClientManifest).length > 0) {
372
+ const imports = {};
373
+ const moduleBasePath = pathToFileURL(projectRoot).href + "/";
374
+
375
+ for (const [key, val] of Object.entries(parsedClientManifest)) {
376
+ let specifier = key;
377
+ if (specifier.startsWith(moduleBasePath)) {
378
+ specifier = specifier.slice(moduleBasePath.length);
379
+ }
380
+ const hashIdx = specifier.indexOf("#");
381
+ if (hashIdx !== -1) {
382
+ specifier = specifier.slice(0, hashIdx);
383
+ }
384
+ imports[specifier] = val.id;
385
+
386
+ const srcIdx = key.indexOf("/src/");
387
+ if (srcIdx !== -1) {
388
+ const srcRel = "src/" + key.slice(srcIdx + 5).split("#")[0];
389
+ imports[srcRel] = val.id;
390
+ imports["/" + srcRel] = val.id;
391
+ imports["./" + srcRel] = val.id;
392
+ }
393
+ const dinouIdx = key.lastIndexOf("/dinou/");
394
+ if (dinouIdx !== -1) {
395
+ const dinouRel = "dinou/" + key.slice(dinouIdx + 7).split("#")[0];
396
+ imports[dinouRel] = val.id;
397
+ imports["/" + dinouRel] = val.id;
398
+ imports["./" + dinouRel] = val.id;
399
+ }
400
+ }
401
+
402
+ if (linkChunkId) {
403
+ imports["dinou/core/link.jsx"] = linkChunkId;
404
+ imports["dinou/core/link"] = linkChunkId;
405
+ imports["/dinou/core/link.jsx"] = linkChunkId;
406
+ imports["./dinou/core/link.jsx"] = linkChunkId;
407
+ for (const lp of candidateLinkPaths) {
408
+ for (const u of generateAllUrlVariants(lp)) {
409
+ imports[u] = linkChunkId;
410
+ }
411
+ }
412
+ }
413
+ if (redirectChunkId) {
414
+ imports["dinou/core/client-redirect.jsx"] = redirectChunkId;
415
+ imports["dinou/core/client-redirect"] = redirectChunkId;
416
+ imports["/dinou/core/client-redirect.jsx"] = redirectChunkId;
417
+ imports["./dinou/core/client-redirect.jsx"] = redirectChunkId;
418
+ for (const rp of candidateRedirectPaths) {
419
+ for (const u of generateAllUrlVariants(rp)) {
420
+ imports[u] = redirectChunkId;
421
+ }
422
+ }
423
+ }
424
+
425
+ importMapHtml = `<script type="importmap">{"imports":${JSON.stringify(imports)}}</script>`;
426
+ }
427
+
428
+ manifestInlines += `\nglobalThis.__DINOU_IMPORT_MAP_HTML__ = ${JSON.stringify(importMapHtml)};\n`;
429
+
430
+ const discoveredLayouts = [];
431
+ function findLayoutRoutes(dir, rel = "") {
432
+ if (!fs.existsSync(dir)) return;
433
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
434
+ for (const entry of entries) {
435
+ if (entry.isDirectory()) {
436
+ findLayoutRoutes(path.join(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
437
+ } else if (/^layout\.[jt]sx?$/.test(entry.name)) {
438
+ discoveredLayouts.push(rel);
439
+ }
440
+ }
441
+ }
442
+ findLayoutRoutes(srcDir);
443
+ manifestInlines += `\nglobalThis.__DINOU_LAYOUTS__ = ${JSON.stringify(discoveredLayouts)};\n`;
444
+
445
+ if (process.env.DINOU_DEBUG) {
446
+
447
+ console.log("⚔ [Dinou Cloudflare] Building in-memory VFS for Edge routing...");
448
+ }
449
+ const vfsSnapshot = {};
450
+ function walkVfs(dir) {
451
+ if (!fs.existsSync(dir)) return;
452
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
453
+ const children = [];
454
+ for (const entry of entries) {
455
+ const isDir = entry.isDirectory();
456
+ children.push({ name: entry.name, isDirectory: isDir });
457
+ const fullPath = path.join(dir, entry.name);
458
+ const relFromSrc = path.relative(srcDir, fullPath).replace(/\\/g, "/");
459
+ const edgePath = "/src/" + relFromSrc;
460
+ const slashPath = fullPath.replace(/\\/g, "/");
461
+ if (isDir) {
462
+ walkVfs(fullPath);
463
+ } else {
464
+ vfsSnapshot[edgePath] = { type: "file" };
465
+ vfsSnapshot[slashPath] = { type: "file" };
466
+ if (slashPath.length > 2 && slashPath[1] === ":") {
467
+ vfsSnapshot[slashPath.slice(2)] = { type: "file" };
468
+ }
469
+ vfsSnapshot["src/" + relFromSrc] = { type: "file" };
470
+ }
471
+ }
472
+ const dirRel = path.relative(srcDir, dir).replace(/\\/g, "/");
473
+ const edgeDir = dirRel ? "/src/" + dirRel : "/src";
474
+ const dirSlash = dir.replace(/\\/g, "/");
475
+ vfsSnapshot[edgeDir] = { type: "directory", children };
476
+ vfsSnapshot[dirSlash] = { type: "directory", children };
477
+ if (dirSlash.length > 2 && dirSlash[1] === ":") {
478
+ vfsSnapshot[dirSlash.slice(2)] = { type: "directory", children };
479
+ }
480
+ vfsSnapshot[dirRel ? "src/" + dirRel : "src"] = { type: "directory", children };
481
+ }
482
+ walkVfs(srcDir);
483
+
484
+ const envSetupContent = `// Auto-generated environment setup
485
+ if (typeof globalThis.__webpack_require__ === 'undefined') {
486
+ globalThis.__webpack_require__ = function(id) {
487
+ if (globalThis.__webpack_modules__ && globalThis.__webpack_modules__[id]) {
488
+ return globalThis.__webpack_modules__[id];
489
+ }
490
+ return {};
491
+ };
492
+ }
493
+ if (typeof globalThis.__webpack_require__.u === 'undefined') {
494
+ globalThis.__webpack_require__.u = function(chunkId) { return '' + chunkId + '.js'; };
495
+ }
496
+ if (typeof globalThis.__webpack_chunk_load__ === 'undefined') {
497
+ globalThis.__webpack_chunk_load__ = () => Promise.resolve();
498
+ }
499
+ ${manifestInlines}
500
+ globalThis.__DINOU_VFS__ = ${JSON.stringify(vfsSnapshot)};
501
+ `;
502
+ const envSetupPath = path.join(cloudflareDir, "env-setup.js");
503
+ fs.writeFileSync(envSetupPath, envSetupContent, "utf8");
504
+
505
+ // Generate ssr-client-manifest.js
506
+ let ssrManifestCode = `// Auto-generated client modules registry for Native Edge SSR\n`;
507
+ clientComponents.forEach((compPath, index) => {
508
+ const normPath = compPath.replace(/\\/g, "/");
509
+ ssrManifestCode += `import * as mod_${index} from ${JSON.stringify(normPath)};\n`;
510
+ });
511
+
512
+ const serverFunctionFiles = Object.keys(parsedServerFunctionsManifest);
513
+ serverFunctionFiles.forEach((relPath, index) => {
514
+ const absPath = path.resolve(projectRoot, relPath).replace(/\\/g, "/");
515
+ ssrManifestCode += `import * as sf_${index} from ${JSON.stringify(absPath)};\n`;
516
+ });
517
+
518
+ ssrManifestCode += `\nexport const clientModules = {\n`;
519
+ const emittedClientModules = new Set();
520
+ function addClientModule(key, valueExpr) {
521
+ if (!emittedClientModules.has(key)) {
522
+ emittedClientModules.add(key);
523
+ ssrManifestCode += ` ${JSON.stringify(key)}: ${valueExpr},\n`;
524
+ }
525
+ }
526
+
527
+ clientComponents.forEach((compPath, index) => {
528
+ const fileUrl = pathToFileURL(compPath).href;
529
+ const altFileUrl = fileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + (d === d.toLowerCase() ? d.toUpperCase() : d.toLowerCase()) + ':');
530
+ addClientModule(fileUrl, `mod_${index}`);
531
+ if (altFileUrl !== fileUrl) {
532
+ addClientModule(altFileUrl, `mod_${index}`);
533
+ }
534
+ });
535
+
536
+ for (const [k, v] of Object.entries(parsedClientManifest)) {
537
+ const fileUrl = k.split("#")[0];
538
+ if (fileUrl.startsWith("file:///")) {
539
+ try {
540
+ const filePath = fileURLToPath(fileUrl);
541
+ if (fs.existsSync(filePath) && !isSupportedClientModule(filePath)) continue;
542
+ } catch (e) {}
543
+ }
544
+ const compIndex = clientComponents.findIndex(
545
+ (c) => pathToFileURL(c).href === fileUrl || pathToFileURL(c).href.toLowerCase() === fileUrl.toLowerCase()
546
+ );
547
+ if (compIndex !== -1) {
548
+ if (v && v.id) addClientModule(v.id, `mod_${compIndex}`);
549
+ addClientModule(fileUrl, `mod_${compIndex}`);
550
+ }
551
+ }
552
+
553
+ if (linkChunkId) {
554
+ const linkCompIndex = clientComponents.findIndex((c) => candidateLinkPaths.has(path.resolve(c)));
555
+ if (linkCompIndex !== -1) {
556
+ addClientModule(linkChunkId, `mod_${linkCompIndex}`);
557
+ for (const lp of candidateLinkPaths) {
558
+ for (const u of generateAllUrlVariants(lp)) {
559
+ addClientModule(u, `mod_${linkCompIndex}`);
560
+ }
561
+ }
562
+ }
563
+ }
564
+ if (redirectChunkId) {
565
+ const redirectCompIndex = clientComponents.findIndex((c) => candidateRedirectPaths.has(path.resolve(c)));
566
+ if (redirectCompIndex !== -1) {
567
+ addClientModule(redirectChunkId, `mod_${redirectCompIndex}`);
568
+ for (const rp of candidateRedirectPaths) {
569
+ for (const u of generateAllUrlVariants(rp)) {
570
+ addClientModule(u, `mod_${redirectCompIndex}`);
571
+ }
572
+ }
573
+ }
574
+ }
575
+
576
+ serverFunctionFiles.forEach((relPath, index) => {
577
+ const normRel = relPath.replace(/\\/g, "/");
578
+ const relFileUrl = "file:///" + normRel;
579
+ const absPath = path.resolve(projectRoot, relPath);
580
+ const fullFileUrl = pathToFileURL(absPath).href;
581
+ const altFullFileUrl = fullFileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + (d === d.toLowerCase() ? d.toUpperCase() : d.toLowerCase()) + ':');
582
+
583
+ addClientModule(relFileUrl, `sf_${index}`);
584
+ addClientModule(fullFileUrl, `sf_${index}`);
585
+ if (altFullFileUrl !== fullFileUrl) {
586
+ addClientModule(altFullFileUrl, `sf_${index}`);
587
+ }
588
+ });
589
+ ssrManifestCode += `};\n\n`;
590
+
591
+ ssrManifestCode += `export const ssrConsumerManifest = {\n moduleMap: {\n`;
592
+ const emittedModuleMap = new Set();
593
+ function addModuleMap(key, valueObjStr) {
594
+ if (!emittedModuleMap.has(key)) {
595
+ emittedModuleMap.add(key);
596
+ ssrManifestCode += ` ${JSON.stringify(key)}: ${valueObjStr},\n`;
597
+ }
598
+ }
599
+
600
+ clientComponents.forEach((compPath) => {
601
+ const fileUrl = pathToFileURL(compPath).href;
602
+ const altFileUrl = fileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + (d === d.toLowerCase() ? d.toUpperCase() : d.toLowerCase()) + ':');
603
+ addModuleMap(fileUrl, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
604
+ if (altFileUrl !== fileUrl) {
605
+ addModuleMap(altFileUrl, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
606
+ }
607
+ });
608
+
609
+ for (const [k, v] of Object.entries(parsedClientManifest)) {
610
+ const fileUrl = k.split("#")[0];
611
+ if (fileUrl.startsWith("file:///")) {
612
+ try {
613
+ const filePath = fileURLToPath(fileUrl);
614
+ if (fs.existsSync(filePath) && !isSupportedClientModule(filePath)) continue;
615
+ } catch (e) {}
616
+ }
617
+ if (v && v.id) {
618
+ addModuleMap(v.id, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
619
+ }
620
+ }
621
+
622
+ if (linkChunkId) {
623
+ const linkCompIndex = clientComponents.findIndex((c) => candidateLinkPaths.has(path.resolve(c)));
624
+ if (linkCompIndex !== -1) {
625
+ const fileUrl = pathToFileURL(clientComponents[linkCompIndex]).href;
626
+ addModuleMap(linkChunkId, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
627
+ for (const lp of candidateLinkPaths) {
628
+ for (const u of generateAllUrlVariants(lp)) {
629
+ addModuleMap(u, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
630
+ }
631
+ }
632
+ }
633
+ }
634
+ if (redirectChunkId) {
635
+ const redirectCompIndex = clientComponents.findIndex((c) => candidateRedirectPaths.has(path.resolve(c)));
636
+ if (redirectCompIndex !== -1) {
637
+ const fileUrl = pathToFileURL(clientComponents[redirectCompIndex]).href;
638
+ addModuleMap(redirectChunkId, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
639
+ for (const rp of candidateRedirectPaths) {
640
+ for (const u of generateAllUrlVariants(rp)) {
641
+ addModuleMap(u, `{ "*": { id: ${JSON.stringify(fileUrl)}, chunks: [], name: "*" } }`);
642
+ }
643
+ }
644
+ }
645
+ }
646
+ ssrManifestCode += ` },\n serverModuleMap: {\n`;
647
+
648
+ const emittedServerModuleMap = new Set();
649
+ function addServerModuleMap(key, valueObjStr) {
650
+ if (!emittedServerModuleMap.has(key)) {
651
+ emittedServerModuleMap.add(key);
652
+ ssrManifestCode += ` ${JSON.stringify(key)}: ${valueObjStr},\n`;
653
+ }
654
+ }
655
+
656
+ serverFunctionFiles.forEach((relPath) => {
657
+ const normRel = relPath.replace(/\\/g, "/");
658
+ const relFileUrl = "file:///" + normRel;
659
+ const absPath = path.resolve(projectRoot, relPath);
660
+ const fullFileUrl = pathToFileURL(absPath).href;
661
+ const altFullFileUrl = fullFileUrl.replace(/file:\/\/\/([a-zA-Z]):/, (m, d) => 'file:///' + (d === d.toLowerCase() ? d.toUpperCase() : d.toLowerCase()) + ':');
662
+
663
+ addServerModuleMap(relFileUrl, `{ id: ${JSON.stringify(relFileUrl)}, chunks: [], name: "*" }`);
664
+ addServerModuleMap(fullFileUrl, `{ id: ${JSON.stringify(relFileUrl)}, chunks: [], name: "*" }`);
665
+ if (altFullFileUrl !== fullFileUrl) {
666
+ addServerModuleMap(altFullFileUrl, `{ id: ${JSON.stringify(relFileUrl)}, chunks: [], name: "*" }`);
667
+ }
668
+
669
+ const fns = parsedServerFunctionsManifest[relPath] || [];
670
+ for (const fn of fns) {
671
+ addServerModuleMap(relFileUrl + "#" + fn, `{ id: ${JSON.stringify(relFileUrl)}, chunks: [], name: ${JSON.stringify(fn)} }`);
672
+ addServerModuleMap(fullFileUrl + "#" + fn, `{ id: ${JSON.stringify(relFileUrl)}, chunks: [], name: ${JSON.stringify(fn)} }`);
673
+ if (altFullFileUrl !== fullFileUrl) {
674
+ addServerModuleMap(altFullFileUrl + "#" + fn, `{ id: ${JSON.stringify(relFileUrl)}, chunks: [], name: ${JSON.stringify(fn)} }`);
675
+ }
676
+ }
677
+ });
678
+
679
+ ssrManifestCode += ` },\n moduleLoading: null,\n};\n`;
680
+
681
+ const ssrClientManifestPath = path.join(cloudflareDir, "ssr-client-manifest.js");
682
+ fs.writeFileSync(ssrClientManifestPath, ssrManifestCode, "utf8");
683
+
684
+ // ====================================================================
685
+ // Entry Files Generation
686
+ // ====================================================================
687
+ // 1. RSC Engine Entry
688
+ const rscEntryContent = `// Auto-generated RSC Engine entry for Cloudflare Workers
689
+ import "./env-setup.js";
690
+ import "./route-modules.js";
691
+ export { handleRequest } from "${dinouDirSlash}/core/handler.js";
692
+ `;
693
+ const rscEntryPath = path.join(cloudflareDir, "rsc-entry.js");
694
+ fs.writeFileSync(rscEntryPath, rscEntryContent, "utf8");
695
+
696
+ // 2. SSR Engine Entry
697
+ const ssrEntryContent = `// Auto-generated SSR Engine entry for Cloudflare Workers
698
+ import { renderRscStreamToHtmlStream } from "${dinouDirSlash}/core/edge-ssr.js";
699
+ import { clientModules, ssrConsumerManifest } from "./ssr-client-manifest.js";
700
+
701
+ const lowerMap = new Map();
702
+ globalThis.__webpack_require__ = (id) => {
703
+ if (clientModules[id]) return clientModules[id];
704
+ if (typeof id === "string") {
705
+ if (lowerMap.size === 0) {
706
+ for (const k of Object.keys(clientModules)) lowerMap.set(k.toLowerCase(), clientModules[k]);
707
+ }
708
+ const lowerVal = lowerMap.get(id.toLowerCase());
709
+ if (lowerVal) return lowerVal;
710
+ }
711
+ console.error("[SSR Engine] Module not found in __webpack_require__:", id);
712
+ return {};
713
+ };
714
+ globalThis.__webpack_require__.u = (chunkId) => "" + chunkId + ".js";
715
+ globalThis.__webpack_chunk_load__ = () => Promise.resolve();
716
+
717
+ export async function renderHtml(rscStream, options = {}) {
718
+ return renderRscStreamToHtmlStream(rscStream, ssrConsumerManifest, options);
719
+ }
720
+ `;
721
+ const ssrEntryPath = path.join(cloudflareDir, "ssr-entry.js");
722
+ fs.writeFileSync(ssrEntryPath, ssrEntryContent, "utf8");
723
+
724
+ // 3. Worker Orchestrator Entry
725
+ const workerEntryContent = `// Auto-generated main worker entry for Cloudflare Workers (Dual-Bundle)
726
+ import { handleRequest } from "./rsc-engine.js";
727
+ import { renderHtml } from "./ssr-engine.js";
728
+ import {
729
+ getStorageAdapter,
730
+ setStorageAdapter,
731
+ CloudflareKVStorage,
732
+ MemoryStorage,
733
+ } from "${dinouDirSlash}/core/storage-adapter.js";
734
+
735
+ if (typeof globalThis !== "undefined") {
736
+ globalThis.__DINOU_RUNTIME__ = "edge";
737
+ }
738
+
739
+ let storageInitialized = false;
740
+
741
+ export default {
742
+ async fetch(request, env, ctx) {
743
+ const url = new URL(request.url);
744
+ if (url.pathname.startsWith("/cdn-cgi/")) {
745
+ return new Response(null, { status: 404 });
746
+ }
747
+
748
+ if (!storageInitialized) {
749
+ if (env && env.DINOU_CACHE) {
750
+ setStorageAdapter(new CloudflareKVStorage(env.DINOU_CACHE));
751
+ } else {
752
+ setStorageAdapter(new MemoryStorage());
753
+ }
754
+ storageInitialized = true;
755
+ }
756
+
757
+ const isRSCPayload = url.pathname.includes("____rsc_");
758
+ const isServerFunction =
759
+ url.pathname.includes("____server_function____") ||
760
+ request.headers.get("x-server-function-call") === "1";
761
+
762
+ const staticExtRegex = /\\.(js|mjs|cjs|css|png|jpg|jpeg|gif|svg|ico|webp|avif|woff|woff2|ttf|eot|otf|wasm|map|txt|webmanifest)$/i;
763
+ const isStaticAsset =
764
+ staticExtRegex.test(url.pathname) ||
765
+ url.pathname.startsWith("/assets/") ||
766
+ url.pathname.startsWith("/_dinou/");
767
+
768
+ if (!isRSCPayload && !isServerFunction && isStaticAsset && env && env.ASSETS && (request.method === "GET" || request.method === "HEAD")) {
769
+ try {
770
+ const assetRes = await env.ASSETS.fetch(request.clone ? request.clone() : request);
771
+ if (assetRes && assetRes.status < 400) {
772
+ return assetRes;
773
+ }
774
+ } catch (e) {}
775
+ }
776
+
777
+ return handleRequest(request, {
778
+ env,
779
+ ctx,
780
+ runtime: "edge",
781
+ renderHtmlStream: renderHtml,
782
+ });
783
+ },
784
+ };
785
+ `;
786
+ const workerEntryPath = path.join(cloudflareDir, "worker-entry.js");
787
+ fs.writeFileSync(workerEntryPath, workerEntryContent, "utf8");
788
+
789
+ // ====================================================================
790
+ // Build Configuration
791
+ // ====================================================================
792
+ const supportedNodeModules = [
793
+ "assert", "assert/strict",
794
+ "async_hooks",
795
+ "buffer",
796
+ "crypto",
797
+ "diagnostics_channel",
798
+ "events",
799
+ "module",
800
+ "path", "path/posix", "path/win32",
801
+ "process",
802
+ "stream", "stream/consumers", "stream/promises", "stream/web",
803
+ "string_decoder",
804
+ "timers", "timers/promises",
805
+ "url",
806
+ "util", "util/types",
807
+ "zlib",
808
+ ];
809
+
810
+ const externalList = [
811
+ "cloudflare:*",
812
+ ...supportedNodeModules,
813
+ ...supportedNodeModules.map((b) => "node:" + b),
814
+ ];
815
+
816
+ const shimsDir = path.resolve(__dirname, "shims");
817
+
818
+ const commonAlias = {
819
+ "@": path.resolve(projectRoot, "src"),
820
+ "dinou/config": path.resolve(dinouDir, "core/config.js"),
821
+ dinou: dinouDir,
822
+ fs: path.resolve(shimsDir, "fs.js"),
823
+ "node:fs": path.resolve(shimsDir, "fs.js"),
824
+ "fs/promises": path.resolve(shimsDir, "fs.js"),
825
+ "node:fs/promises": path.resolve(shimsDir, "fs.js"),
826
+ child_process: path.resolve(shimsDir, "child_process.js"),
827
+ "node:child_process": path.resolve(shimsDir, "child_process.js"),
828
+ http: path.resolve(shimsDir, "empty.js"),
829
+ "node:http": path.resolve(shimsDir, "empty.js"),
830
+ https: path.resolve(shimsDir, "empty.js"),
831
+ "node:https": path.resolve(shimsDir, "empty.js"),
832
+ net: path.resolve(shimsDir, "empty.js"),
833
+ "node:net": path.resolve(shimsDir, "empty.js"),
834
+ tls: path.resolve(shimsDir, "empty.js"),
835
+ "node:tls": path.resolve(shimsDir, "empty.js"),
836
+ os: path.resolve(shimsDir, "os.js"),
837
+ "node:os": path.resolve(shimsDir, "os.js"),
838
+ cluster: path.resolve(shimsDir, "empty.js"),
839
+ "node:cluster": path.resolve(shimsDir, "empty.js"),
840
+ dgram: path.resolve(shimsDir, "empty.js"),
841
+ "node:dgram": path.resolve(shimsDir, "empty.js"),
842
+ dns: path.resolve(shimsDir, "empty.js"),
843
+ "node:dns": path.resolve(shimsDir, "empty.js"),
844
+ };
845
+
846
+ const commonLoader = {
847
+ ".js": "jsx",
848
+ ".jsx": "jsx",
849
+ ".ts": "ts",
850
+ ".tsx": "tsx",
851
+ ".json": "json",
852
+ ".css": "empty",
853
+ ".svg": "dataurl",
854
+ ".png": "dataurl",
855
+ ".jpg": "dataurl",
856
+ ".jpeg": "dataurl",
857
+ ".webp": "dataurl",
858
+ ".ico": "dataurl",
859
+ };
860
+
861
+ const banner = {
862
+ js: `import { createRequire as ___createRequire } from 'node:module';
863
+ import { AsyncLocalStorage as ___AsyncLocalStorage } from 'node:async_hooks';
864
+ const require = ___createRequire(import.meta.url || 'file:///worker.js');
865
+ const __dirname = '';
866
+ const __filename = '';
867
+ globalThis.__dinou_require__ = require;
868
+ if (typeof globalThis.AsyncLocalStorage === 'undefined' && typeof ___AsyncLocalStorage !== 'undefined') {
869
+ globalThis.AsyncLocalStorage = ___AsyncLocalStorage;
870
+ }
871
+ if (typeof globalThis.__webpack_require__ === 'undefined') {
872
+ globalThis.__webpack_require__ = function(id) {
873
+ if (globalThis.__webpack_modules__ && globalThis.__webpack_modules__[id]) {
874
+ return globalThis.__webpack_modules__[id];
875
+ }
876
+ return {};
877
+ };
878
+ }
879
+ if (typeof globalThis.__webpack_require__.u === 'undefined') {
880
+ globalThis.__webpack_require__.u = function(chunkId) { return '' + chunkId + '.js'; };
881
+ }
882
+ if (typeof globalThis.__webpack_chunk_load__ === 'undefined') {
883
+ globalThis.__webpack_chunk_load__ = () => Promise.resolve();
884
+ }
885
+ var __webpack_require__ = function(id) {
886
+ return globalThis.__webpack_require__ ? globalThis.__webpack_require__(id) : {};
887
+ };
888
+ __webpack_require__.u = function(chunkId) {
889
+ return (globalThis.__webpack_require__ && globalThis.__webpack_require__.u)
890
+ ? globalThis.__webpack_require__.u(chunkId)
891
+ : '' + chunkId + '.js';
892
+ };
893
+ var __webpack_chunk_load__ = function(chunkId) {
894
+ return globalThis.__webpack_chunk_load__ ? globalThis.__webpack_chunk_load__(chunkId) : Promise.resolve();
895
+ };
896
+ `,
897
+ };
898
+
899
+ // Plugins for RSC Engine
900
+ const clientReferencesPlugin = {
901
+ name: "dinou-client-references",
902
+ setup(build) {
903
+ build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
904
+ if (args.path.includes("node_modules")) {
905
+ if (
906
+ args.path.includes("react-server-dom") ||
907
+ args.path.includes("@roggc/react-server-dom-esm") ||
908
+ args.path.includes("node_modules/react/") ||
909
+ args.path.includes("node_modules\\react\\") ||
910
+ args.path.includes("node_modules/react-dom/") ||
911
+ args.path.includes("node_modules\\react-dom\\")
912
+ ) {
913
+ return null;
914
+ }
915
+ }
916
+ const normalizedPath = args.path.replace(/\\/g, "/");
917
+ if (normalizedPath.includes("dinou/core/navigation")) return null;
918
+
919
+ let code;
920
+ try {
921
+ code = fs.readFileSync(args.path, "utf8");
922
+ } catch (e) {
923
+ return null;
924
+ }
925
+
926
+ if (!isSupportedClientModule(args.path, code)) return null;
927
+ if (!useClientRegex.test(code.trim())) return null;
928
+
929
+ const exports = parseExports(code);
930
+ const absPath = path.resolve(args.path);
931
+ const fileUrl = pathToFileURL(absPath).href;
932
+
933
+ let proxyCode = `import { createClientModuleProxy } from "react-server-dom-webpack/server.edge";\n`;
934
+ proxyCode += `const proxy = createClientModuleProxy(${JSON.stringify(fileUrl)});\n`;
935
+
936
+ for (const name of exports) {
937
+ if (name === "default") {
938
+ proxyCode += `export default proxy.default;\n`;
939
+ } else {
940
+ proxyCode += `export const ${name} = proxy[${JSON.stringify(name)}];\n`;
941
+ }
942
+ }
943
+
944
+ if (!exports.includes("default")) {
945
+ proxyCode += `export default proxy.default;\n`;
946
+ }
947
+
948
+ return {
949
+ contents: proxyCode,
950
+ loader: "js",
951
+ };
952
+ });
953
+ },
954
+ };
955
+
956
+ const serverReferencesPlugin = {
957
+ name: "dinou-server-references",
958
+ setup(build) {
959
+ build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
960
+ if (args.path.includes("node_modules")) return null;
961
+
962
+ let code;
963
+ try {
964
+ code = fs.readFileSync(args.path, "utf8");
965
+ } catch (e) {
966
+ return null;
967
+ }
968
+
969
+ if (!useServerRegex.test(code.trim())) return null;
970
+
971
+ const exports = parseExports(code);
972
+ const absPath = path.resolve(args.path);
973
+ const relPath = path.relative(projectRoot, absPath).replace(/\\/g, "/");
974
+ const relativeFileUrl = "file:///" + relPath;
975
+
976
+ let transformed = code + "\n\n";
977
+ transformed += `import { registerServerReference } from "react-server-dom-webpack/server.edge";\n`;
978
+
979
+ for (const name of exports) {
980
+ if (name !== "default") {
981
+ transformed += `registerServerReference(${name}, ${JSON.stringify(relativeFileUrl)}, ${JSON.stringify(name)});\n`;
982
+ }
983
+ }
984
+
985
+ const ext = path.extname(args.path);
986
+ const loader = ext === ".ts" ? "ts" : ext === ".tsx" ? "tsx" : ext === ".jsx" ? "jsx" : "js";
987
+
988
+ return {
989
+ contents: transformed,
990
+ loader,
991
+ };
992
+ });
993
+ },
994
+ };
995
+
996
+ // Plugin for SSR Engine (Register server functions with client.edge)
997
+ const serverReferencesPluginSsr = {
998
+ name: "dinou-server-references-ssr",
999
+ setup(build) {
1000
+ build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
1001
+ if (args.path.includes("node_modules")) return null;
1002
+
1003
+ let code;
1004
+ try {
1005
+ code = fs.readFileSync(args.path, "utf8");
1006
+ } catch (e) {
1007
+ return null;
1008
+ }
1009
+
1010
+ if (!useServerRegex.test(code.trim())) return null;
1011
+
1012
+ const exports = parseExports(code);
1013
+ const absPath = path.resolve(args.path);
1014
+ const relPath = path.relative(projectRoot, absPath).replace(/\\/g, "/");
1015
+ const relativeFileUrl = "file:///" + relPath;
1016
+
1017
+ let transformed = code + "\n\n";
1018
+ transformed += `import { registerServerReference } from "react-server-dom-webpack/client.edge";\n`;
1019
+
1020
+ for (const name of exports) {
1021
+ if (name !== "default") {
1022
+ transformed += `registerServerReference(${name}, ${JSON.stringify(relativeFileUrl + "#" + name)});\n`;
1023
+ transformed += `registerServerReference(${name}, ${JSON.stringify(pathToFileURL(absPath).href + "#" + name)});\n`;
1024
+ }
1025
+ }
1026
+
1027
+ const ext = path.extname(args.path);
1028
+ const loader = ext === ".ts" ? "ts" : ext === ".tsx" ? "tsx" : ext === ".jsx" ? "jsx" : "js";
1029
+
1030
+ return {
1031
+ contents: transformed,
1032
+ loader,
1033
+ };
1034
+ });
1035
+ },
1036
+ };
1037
+
1038
+ const rscOutfile = path.join(cloudflareDir, "rsc-engine.js");
1039
+ const ssrOutfile = path.join(cloudflareDir, "ssr-engine.js");
1040
+ const finalOutfile = path.join(cloudflareDir, "worker.js");
1041
+
1042
+ try {
1043
+ // Pass A: RSC Engine
1044
+ console.log(" ⚔ Bundling Pass A (RSC workerd) & Pass B (SSR workerd)...");
1045
+ await esbuild.build({
1046
+ entryPoints: [rscEntryPath],
1047
+ outfile: rscOutfile,
1048
+ bundle: true,
1049
+ format: "esm",
1050
+ target: "es2022",
1051
+ platform: "neutral",
1052
+ mainFields: ["module", "main"],
1053
+ conditions: ["workerd", "worker", "react-server"],
1054
+ external: externalList,
1055
+ plugins: [clientReferencesPlugin, serverReferencesPlugin],
1056
+ alias: commonAlias,
1057
+ loader: commonLoader,
1058
+ jsx: "automatic",
1059
+ define: {
1060
+ "process.env.NODE_ENV": '"production"',
1061
+ "process.env.DINOU_RUNTIME": '"edge"',
1062
+ "process.env.DINOU_BUILD_TOOL": JSON.stringify(isWebpackBuild ? "webpack" : (process.env.DINOU_BUILD_TOOL || "esbuild")),
1063
+ },
1064
+ logLevel: "warning",
1065
+ });
1066
+
1067
+ // Pass B: SSR Engine
1068
+ await esbuild.build({
1069
+ entryPoints: [ssrEntryPath],
1070
+ outfile: ssrOutfile,
1071
+ bundle: true,
1072
+ format: "esm",
1073
+ target: "es2022",
1074
+ platform: "neutral",
1075
+ mainFields: ["module", "main"],
1076
+ conditions: ["workerd", "worker", "browser"],
1077
+ external: externalList,
1078
+ plugins: [serverReferencesPluginSsr],
1079
+ alias: commonAlias,
1080
+ loader: commonLoader,
1081
+ jsx: "automatic",
1082
+ define: {
1083
+ "process.env.NODE_ENV": '"production"',
1084
+ "process.env.DINOU_RUNTIME": '"edge"',
1085
+ "process.env.DINOU_BUILD_TOOL": JSON.stringify(isWebpackBuild ? "webpack" : (process.env.DINOU_BUILD_TOOL || "esbuild")),
1086
+ },
1087
+ logLevel: "warning",
1088
+ });
1089
+
1090
+ // Pass C: Final Worker Orchestrator
1091
+ console.log(" šŸš€ Bundling Pass C: Cloudflare Worker Orchestrator (.dinou/cloudflare/worker.js)...");
1092
+ await esbuild.build({
1093
+ entryPoints: [workerEntryPath],
1094
+ outfile: finalOutfile,
1095
+ bundle: true,
1096
+ format: "esm",
1097
+ target: "es2022",
1098
+ platform: "neutral",
1099
+ mainFields: ["module", "main"],
1100
+ conditions: ["workerd", "worker", "browser"],
1101
+ external: externalList,
1102
+ banner,
1103
+ alias: commonAlias,
1104
+ loader: commonLoader,
1105
+ define: {
1106
+ "process.env.NODE_ENV": '"production"',
1107
+ "process.env.DINOU_RUNTIME": '"edge"',
1108
+ "process.env.DINOU_BUILD_TOOL": JSON.stringify(isWebpackBuild ? "webpack" : (process.env.DINOU_BUILD_TOOL || "esbuild")),
1109
+ },
1110
+ logLevel: "warning",
1111
+ });
1112
+
1113
+ const relOutfile = path.relative(projectRoot, finalOutfile).replace(/\\/g, "/");
1114
+ console.log(`\nāœ“ Cloudflare Workers build complete!`);
1115
+ console.log(` Output: ${relOutfile}`);
1116
+ console.log(" šŸ‘‰ Preview locally: npx wrangler dev");
1117
+ console.log(" šŸ‘‰ Deploy to edge: npx wrangler deploy\n");
1118
+ } catch (err) {
1119
+ console.error("āŒ [Dinou Cloudflare] Worker bundling failed:", err);
1120
+ process.exit(1);
1121
+ }