dinou 6.1.0 → 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 +99 -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 +17 -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 -107
  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
@@ -1,260 +1,326 @@
1
+ process.env.DINOU_DEV = "true";
2
+ if (!process.env.NODE_ENV) {
3
+ process.env.NODE_ENV = "development";
4
+ }
5
+
1
6
  import esbuild from "esbuild";
2
7
  import fs from "node:fs/promises";
3
8
  import getConfigEsbuild from "./helpers-esbuild/get-config-esbuild.mjs";
4
9
  import getEsbuildEntries from "./helpers-esbuild/get-esbuild-entries.mjs";
5
- import chokidar from "chokidar";
6
10
  import path from "node:path";
7
- import { regex as assetRegex } from "../core/asset-extensions.js";
8
11
  import normalizePath from "./helpers-esbuild/normalize-path.mjs";
9
- import { fileURLToPath, pathToFileURL } from "url";
12
+ import { fileURLToPath } from "url";
10
13
  import { updateManifestForModule } from "./helpers-esbuild/update-manifest-for-module.mjs";
11
- import { useServerRegex } from "../constants.js";
14
+ import {
15
+ syncAllSwcFiles,
16
+ transformToDisk,
17
+ getMirrorPath,
18
+ } from "./helpers-esbuild/swc-disk-cache.mjs";
12
19
 
13
20
  const __filename = fileURLToPath(import.meta.url);
14
21
  const __dirname = path.dirname(__filename);
15
22
 
16
- const outdir = ".dinou/public";
17
- await fs.rm(outdir, { recursive: true, force: true });
18
- await fs.rm(".dinou/react_client_manifest", { recursive: true, force: true });
19
- await fs.rm(".dinou/server_functions_manifest", { recursive: true, force: true });
20
-
21
- let currentCtx = null; // Track the active esbuild context
22
- let debounceTimer = null; // For debouncing recreations
23
- let clientComponentsPaths = [];
24
- let currentServerFiles = new Set();
25
- const absPathToClientRedirect = path.resolve(
26
- __dirname,
27
- "../core/client-redirect.jsx"
28
- );
29
- const absPathToLink = path.resolve(
30
- __dirname,
31
- "../core/link.jsx"
32
- );
33
-
34
- const frameworkEntryPoints = {
35
- main: path.resolve(__dirname, "../core/client.jsx"),
36
- error: path.resolve(__dirname, "../core/client-error.jsx"),
37
- serverFunctionProxy: path.resolve(
38
- __dirname,
39
- "../core/server-function-proxy.js"
40
- ),
41
- runtime: path.resolve(__dirname, "react-refresh/react-refresh-runtime.mjs"),
42
- "react-refresh-entry": path.resolve(
23
+ export async function startEsbuildDev(options = {}) {
24
+ const onRebuilt = options.onRebuilt || (() => {});
25
+ const onBuildStart = options.onBuildStart || (() => {});
26
+ const onBuildEnd = options.onBuildEnd || (() => {});
27
+ const outdir = ".dinou/public";
28
+ if (typeof globalThis !== "undefined") {
29
+ if (globalThis.__DINOU_MEM_FILES__) {
30
+ globalThis.__DINOU_MEM_FILES__.clear();
31
+ }
32
+ delete globalThis.__DINOU_RAW_CLIENT_MANIFEST__;
33
+ delete globalThis.__DINOU_RAW_SERVER_FUNCTIONS_MANIFEST__;
34
+ }
35
+ await fs.rm(outdir, { recursive: true, force: true });
36
+ await fs.rm(".dinou/react_client_manifest", { recursive: true, force: true });
37
+ await fs.rm(".dinou/server_functions_manifest", { recursive: true, force: true });
38
+
39
+ let currentCtx = null; // Track the active esbuild context
40
+ let activeBuildResolve = null;
41
+ let clientComponentsPaths = [];
42
+ let currentServerFiles = new Set();
43
+ const absPathToClientRedirect = path.resolve(
43
44
  __dirname,
44
- "react-refresh/react-refresh-entry.js"
45
- ),
46
- dinouClientRedirect: absPathToClientRedirect,
47
- dinouLink: absPathToLink,
48
- };
49
-
50
- const changedIds = new Set();
51
- const hmrEngine = { value: null };
52
-
53
- const watcher = chokidar.watch("src", {
54
- ignoreInitial: true,
55
- ignored: /node_modules|dist/,
56
- });
57
-
58
- const codeCssRegex = /.(js|jsx|ts|tsx|css|scss|less)$/i;
59
-
60
- let manifest = {};
61
- let entryPoints = {};
62
-
63
- async function updateEntriesAndComponents() {
64
- manifest = {};
65
- const [
66
- esbuildEntries,
67
- detectedCSSEntries,
68
- detectedAssetEntries,
69
- serverFiles,
70
- ] = await getEsbuildEntries({ manifest });
71
-
72
- updateManifestForModule(
73
- absPathToClientRedirect,
74
- await fs.readFile(absPathToClientRedirect, "utf8"),
75
- true,
76
- manifest
77
- );
78
- updateManifestForModule(
79
- absPathToLink,
80
- await fs.readFile(absPathToLink, "utf8"),
81
- true,
82
- manifest
45
+ "../core/client-redirect.jsx"
83
46
  );
84
-
85
- currentServerFiles = new Set(
86
- serverFiles.map((f) => normalizePath(path.resolve(f)))
87
- );
88
-
89
- const componentEntryPoints = [...esbuildEntries].reduce(
90
- (acc, dCE) => ({ ...acc, [dCE.outfileName]: dCE.absPath }),
91
- {}
92
- );
93
-
94
- clientComponentsPaths = Object.values(componentEntryPoints);
95
-
96
- const cssEntryPoints = [...detectedCSSEntries].reduce(
97
- (acc, dCSSE) => ({ ...acc, [dCSSE.outfileName]: dCSSE.absPath }),
98
- {}
47
+ const absPathToLink = path.resolve(
48
+ __dirname,
49
+ "../core/link.jsx"
99
50
  );
100
-
101
- const assetEntryPoints = [...detectedAssetEntries].reduce(
102
- (acc, dAE) => ({ ...acc, [dAE.outfileName]: dAE.absPath }),
103
- {}
51
+ const absPathToSlot = path.resolve(
52
+ __dirname,
53
+ "../core/slot.js"
104
54
  );
105
55
 
106
- entryPoints = {
107
- ...frameworkEntryPoints,
108
- ...componentEntryPoints,
109
- ...cssEntryPoints,
110
- ...assetEntryPoints,
56
+ const frameworkEntryPoints = {
57
+ main: path.resolve(__dirname, "../core/client.jsx"),
58
+ serverFunctionProxy: path.resolve(
59
+ __dirname,
60
+ "../core/server-function-proxy.js"
61
+ ),
62
+ runtime: path.resolve(__dirname, "react-refresh/react-refresh-runtime.mjs"),
63
+ "react-refresh-entry": path.resolve(
64
+ __dirname,
65
+ "react-refresh/react-refresh-entry.js"
66
+ ),
67
+ dinouClientRedirect: absPathToClientRedirect,
68
+ dinouLink: absPathToLink,
69
+ dinouSlot: absPathToSlot,
111
70
  };
112
- }
113
71
 
114
- // Function to (re)create esbuild context with current entries
115
- async function createEsbuildContext() {
116
- try {
117
- if (currentCtx) {
118
- await currentCtx.dispose(); // Clean up old context
119
- // console.log("Disposed old esbuild context");
120
- }
121
-
122
- await fs.rm(outdir, { recursive: true, force: true });
123
- // console.log("manifest before creating context:", manifest);
124
- currentCtx = await esbuild.context(
125
- getConfigEsbuild({
126
- entryPoints,
127
- manifest,
128
- changedIds,
129
- hmrEngine,
130
- })
72
+ const changedIds = new Set();
73
+ const hmrEngine = { value: null };
74
+
75
+ let manifest = {};
76
+ let entryPoints = {};
77
+ let cssEntryPoints = {};
78
+ let allComponentEntries = {};
79
+ let activeComponentEntries = new Map();
80
+ let pathToOutfile = new Map();
81
+ let outfileNameToPath = new Map();
82
+
83
+ async function updateEntriesAndComponents() {
84
+ manifest = {};
85
+ const [
86
+ esbuildEntries,
87
+ detectedCSSEntries,
88
+ detectedAssetEntries,
89
+ serverFiles,
90
+ ] = await getEsbuildEntries({ manifest });
91
+
92
+ updateManifestForModule(
93
+ absPathToClientRedirect,
94
+ await fs.readFile(absPathToClientRedirect, "utf8"),
95
+ true,
96
+ manifest
97
+ );
98
+ updateManifestForModule(
99
+ absPathToLink,
100
+ await fs.readFile(absPathToLink, "utf8"),
101
+ true,
102
+ manifest
103
+ );
104
+ updateManifestForModule(
105
+ absPathToSlot,
106
+ await fs.readFile(absPathToSlot, "utf8"),
107
+ true,
108
+ manifest
131
109
  );
132
110
 
133
- await currentCtx.watch();
134
- // console.log("✓ Watching (changes will trigger rebuild)");
135
- } catch (err) {
136
- console.error("Error recreating context:", err);
137
- }
138
- }
111
+ currentServerFiles = new Set(
112
+ serverFiles.map((f) => normalizePath(path.resolve(f)))
113
+ );
139
114
 
140
- // Initial setup on ready
141
- watcher.on("ready", async () => {
142
- await updateEntriesAndComponents();
143
- await createEsbuildContext();
144
- });
115
+ await syncAllSwcFiles(path.resolve(process.cwd(), "src"), process.cwd());
145
116
 
146
- const debounceRecreate = () => {
147
- if (debounceTimer) clearTimeout(debounceTimer);
148
- debounceTimer = setTimeout(async () => {
149
- await createEsbuildContext();
150
- }, 300); // 300ms debounce — adjust as needed
151
- };
117
+ const componentEntryPoints = [...esbuildEntries].reduce(
118
+ (acc, dCE) => ({ ...acc, [dCE.outfileName]: getMirrorPath(dCE.absPath, process.cwd()) }),
119
+ {}
120
+ );
152
121
 
153
- const debounceRecreateAndReload = () => {
154
- if (debounceTimer) clearTimeout(debounceTimer);
155
- debounceTimer = setTimeout(async () => {
156
- await createEsbuildContext();
157
- hmrEngine.value.broadcastMessage({ type: "reload" });
158
- }, 300);
159
- };
122
+ clientComponentsPaths = Object.values(componentEntryPoints);
160
123
 
161
- let reloadTimer = null;
162
- const debounceReload = () => {
163
- if (reloadTimer) clearTimeout(reloadTimer);
164
- reloadTimer = setTimeout(() => {
165
- if (hmrEngine.value) {
166
- hmrEngine.value.broadcastMessage({ type: "reload" });
167
- }
168
- }, 100);
169
- };
124
+ cssEntryPoints = [...detectedCSSEntries].reduce(
125
+ (acc, dCSSE) => ({ ...acc, [dCSSE.outfileName]: dCSSE.absPath }),
126
+ {}
127
+ );
170
128
 
171
- watcher.on("add", async (file) => {
172
- const ext = path.extname(file);
173
- if (codeCssRegex.test(ext) || assetRegex.test(ext)) {
174
- // console.log(`New relevant file detected: ${file}. Recreating context...`);
175
- await updateEntriesAndComponents();
176
- debounceRecreateAndReload();
177
- }
178
- });
129
+ const assetEntryPoints = [...detectedAssetEntries].reduce(
130
+ (acc, dAE) => ({ ...acc, [dAE.outfileName]: dAE.absPath }),
131
+ {}
132
+ );
179
133
 
180
- watcher.on("unlink", async (file) => {
181
- const ext = path.extname(file);
182
- if (codeCssRegex.test(ext) || assetRegex.test(ext)) {
183
- // console.log(`File deleted: ${file}. Recreating context...`);
184
- await updateEntriesAndComponents();
185
- if (currentCtx) {
186
- await currentCtx.dispose();
187
- currentCtx = null;
134
+ allComponentEntries = componentEntryPoints;
135
+ for (const [outName, absP] of Object.entries(componentEntryPoints)) {
136
+ const norm = normKey(absP);
137
+ pathToOutfile.set(norm, outName);
138
+ outfileNameToPath.set(outName, absP);
139
+ }
140
+ for (const dCE of esbuildEntries) {
141
+ pathToOutfile.set(normKey(dCE.absPath), dCE.outfileName);
188
142
  }
189
- debounceRecreate();
190
- }
191
- });
192
-
193
- watcher.on("addDir", async () => {
194
- // console.log(`New directory: ${dir}. Recreating context...`);
195
- await updateEntriesAndComponents();
196
- debounceRecreateAndReload();
197
- });
198
143
 
199
- watcher.on("unlinkDir", async () => {
200
- // console.log(`Directory deleted: ${dir}. Recreating context...`);
201
- await updateEntriesAndComponents();
202
- if (currentCtx) {
203
- await currentCtx.dispose();
204
- currentCtx = null;
144
+ entryPoints = {
145
+ ...frameworkEntryPoints,
146
+ ...componentEntryPoints,
147
+ ...cssEntryPoints,
148
+ };
205
149
  }
206
- debounceRecreate();
207
- });
208
150
 
209
- function existsInManifest(resolvedFile, manifest) {
210
- const manifestKey = pathToFileURL(resolvedFile).href;
211
- // console.log("Checking manifest for key:", manifestKey);
212
- for (const key of Object.keys(manifest)) {
213
- if (key === manifestKey) {
214
- return true;
151
+ // Function to (re)create esbuild context with current entries
152
+ async function createEsbuildContext(waitForBuild = false) {
153
+ try {
154
+ if (currentCtx) {
155
+ await currentCtx.dispose();
156
+ currentCtx = null;
157
+ }
158
+
159
+ let buildPromise = null;
160
+ if (waitForBuild) {
161
+ buildPromise = new Promise((res) => {
162
+ activeBuildResolve = res;
163
+ });
164
+ }
165
+
166
+ currentCtx = await esbuild.context(
167
+ getConfigEsbuild({
168
+ entryPoints,
169
+ manifest,
170
+ changedIds,
171
+ hmrEngine,
172
+ serverFiles: currentServerFiles,
173
+ hmrPort: options.hmrPort,
174
+ onManifestUpdated: async () => {
175
+ await onRebuilt();
176
+ },
177
+ onBuildStart: () => {
178
+ onBuildStart();
179
+ },
180
+ onBuildEnd: async (result) => {
181
+ await onBuildEnd(result);
182
+ if (activeBuildResolve) {
183
+ const res = activeBuildResolve;
184
+ activeBuildResolve = null;
185
+ res();
186
+ }
187
+ },
188
+ })
189
+ );
190
+
191
+ const isStandalone =
192
+ process.argv[1] &&
193
+ fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
194
+
195
+ if (isStandalone) {
196
+ await currentCtx.watch();
197
+ } else {
198
+ await currentCtx.rebuild();
199
+ }
200
+ if (buildPromise) {
201
+ await buildPromise;
202
+ }
203
+ } catch (err) {
204
+ console.error("Error recreating context:", err);
205
+ if (activeBuildResolve) {
206
+ const res = activeBuildResolve;
207
+ activeBuildResolve = null;
208
+ res();
209
+ }
215
210
  }
216
211
  }
217
- return false;
218
- }
219
212
 
220
- watcher.on("change", async (file) => {
221
- const resolvedFile = normalizePath(path.resolve(file));
222
- const oldManifest = { ...manifest };
223
- const oldEntryKeys = JSON.stringify(Object.keys(entryPoints).sort());
213
+ const normKey = (p) => {
214
+ if (!p) return "";
215
+ let s = path.resolve(p).replace(/\\/g, "/");
216
+ if (process.platform === "win32") {
217
+ s = s.replace(/^([a-zA-Z]):/, (_, d) => d.toLowerCase() + ":");
218
+ }
219
+ return s;
220
+ };
224
221
 
222
+ // Initial build
223
+ const tBabel0 = Date.now();
225
224
  await updateEntriesAndComponents();
225
+ const clientEntriesBabel = Date.now() - tBabel0;
226
+
227
+ const tClientBuild0 = Date.now();
228
+ await createEsbuildContext(true);
229
+ const clientBuild = Date.now() - tClientBuild0;
230
+
231
+ return {
232
+ broadcast: (msg) => {
233
+ hmrEngine.value?.broadcastMessage?.(msg);
234
+ },
235
+ ensureActiveRoute: async (routeOrChunk) => {
236
+ if (!currentCtx || !routeOrChunk) return false;
237
+ // Ignore route paths (e.g. "/test-dev"). Esbuild compiles entrypoints eagerly.
238
+ if (typeof routeOrChunk === "string" && (routeOrChunk.startsWith("/") || routeOrChunk.startsWith("\\"))) {
239
+ return true;
240
+ }
241
+ const clean = routeOrChunk.replace(/^\//, "").replace(/\.js$/, "");
242
+ const mem = globalThis.__DINOU_MEM_FILES__;
243
+ if (
244
+ mem?.has(clean) ||
245
+ mem?.has(`${clean}.js`) ||
246
+ mem?.has(`/${clean}.js`) ||
247
+ mem?.has(`/${clean}`)
248
+ ) {
249
+ return true;
250
+ }
251
+ try {
252
+ await updateEntriesAndComponents();
253
+ await currentCtx.rebuild();
254
+ return Boolean(
255
+ mem?.has(clean) ||
256
+ mem?.has(`${clean}.js`) ||
257
+ mem?.has(`/${clean}.js`) ||
258
+ mem?.has(`/${clean}`)
259
+ );
260
+ } catch (e) {
261
+ return false;
262
+ }
263
+ },
264
+ notifyFileChanged: async (filePath) => {
265
+ if (filePath) {
266
+ const norm = normKey(filePath);
267
+ changedIds.add(norm);
268
+
269
+ // Fast disk-backed SWC compilation of the modified file
270
+ if (/\.[jt]sx?$/i.test(filePath)) {
271
+ const tSwc0 = Date.now();
272
+ const mirrorPath = await transformToDisk(filePath, process.cwd());
273
+ globalThis.__DINOU_SWC_TIME__ = Date.now() - tSwc0;
274
+ globalThis.__DINOU_SWC_COUNT__ = 1;
275
+ if (mirrorPath) {
276
+ changedIds.add(normKey(mirrorPath));
277
+ }
278
+ }
279
+
280
+ if (currentCtx) {
281
+ const t0 = Date.now();
282
+ return currentCtx.rebuild().then((result) => {
283
+ globalThis.__ESBUILD_CORE_TIME__ = Date.now() - t0;
284
+ return result;
285
+ }).catch((err) => {
286
+ console.error("❌ [Esbuild Dev] Rebuild error:", err);
287
+ });
288
+ }
289
+ }
290
+ return Promise.resolve();
291
+ },
292
+ restart: async () => {
293
+ console.log("⚡ [Esbuild Dev] Recreating client bundle due to directive change...");
294
+ await updateEntriesAndComponents();
295
+ await createEsbuildContext(true);
296
+ },
297
+ close: async () => {
298
+ try {
299
+ if (currentCtx) await currentCtx.dispose();
300
+ if (hmrEngine.value?.server?.close) {
301
+ try { hmrEngine.value.server.close(); } catch (e) {}
302
+ }
303
+ } catch (e) {}
304
+ },
305
+ timings: {
306
+ clientEntriesBabel,
307
+ clientBuild,
308
+ postCss: globalThis.__DINOU_POSTCSS_TIME__ || 0,
309
+ postCssCount: globalThis.__DINOU_POSTCSS_COUNT__ || 0,
310
+ swc: globalThis.__DINOU_SWC_TIME__ || 0,
311
+ swcCount: globalThis.__DINOU_SWC_COUNT__ || 0,
312
+ sf: globalThis.__DINOU_SF_TIME__ || 0,
313
+ sfCount: globalThis.__DINOU_SF_COUNT__ || 0,
314
+ rcm: globalThis.__DINOU_RCM_TIME__ || 0,
315
+ stable: globalThis.__DINOU_STABLE_TIME__ || 0,
316
+ writeDisk: globalThis.__DINOU_WRITE_TIME__ || 0,
317
+ },
318
+ };
319
+ }
226
320
 
227
- const newEntryKeys = JSON.stringify(Object.keys(entryPoints).sort());
228
- const entryPointsChanged = oldEntryKeys !== newEntryKeys;
229
-
230
- // Check if changed file is a client component
231
- const isClientModule = clientComponentsPaths.includes(resolvedFile);
232
- const isServerModule = currentServerFiles.has(resolvedFile);
233
- // console.log(
234
- // `File changed: ${resolvedFile} | Client Module: ${isClientModule} | Server Module: ${isServerModule}`
235
- // );
236
- // console.log("currentServerFiles:", currentServerFiles);
237
-
238
- if (
239
- isClientModule &&
240
- !isServerModule &&
241
- existsInManifest(resolvedFile, oldManifest)
242
- ) {
243
- changedIds.add(resolvedFile);
244
- return;
245
- }
246
-
247
- // If it's a Server Action module ("use server"), do not reload the browser
248
- const fileContent = await fs.readFile(resolvedFile, "utf8").catch(() => "");
249
- const isServerAction = useServerRegex.test(fileContent.trim());
250
- if (isServerAction) {
251
- return;
252
- }
253
-
254
- // Only recreate context and reload if entry points actually changed or it's a CSS file
255
- if (entryPointsChanged || file.endsWith(".css") || file.endsWith(".scss")) {
256
- debounceRecreateAndReload();
257
- } else {
258
- debounceReload();
259
- }
260
- });
321
+ if (
322
+ process.argv[1] &&
323
+ fileURLToPath(import.meta.url) === path.resolve(process.argv[1])
324
+ ) {
325
+ startEsbuildDev();
326
+ }
@@ -30,10 +30,11 @@ export default function getConfigEsbuildProd({
30
30
  writePlugin(),
31
31
  ];
32
32
 
33
- if (existsSync("favicons")) {
33
+ const staticDir = existsSync("public") ? "public" : (existsSync("favicons") ? "favicons" : null);
34
+ if (staticDir) {
34
35
  plugins = [
35
36
  copyStaticFiles({
36
- src: "favicons",
37
+ src: staticDir,
37
38
  dest: outdir,
38
39
  }),
39
40
  ...plugins,