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