dinou 4.0.3 → 4.0.5

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.
@@ -38,7 +38,8 @@ const isHashChangeOnly = (finalPath) => {
38
38
  );
39
39
  };
40
40
 
41
- const getRSCPayload = (url) => {
41
+ const getRSCPayload = (rscKey) => {
42
+ const url = rscKey.split("::")[0];
42
43
  // Important: url must already be normalized here
43
44
  if (cache.has(url)) return cache.get(url);
44
45
 
@@ -55,7 +56,7 @@ const getRSCPayload = (url) => {
55
56
  name: window.__DINOU_ERROR_NAME__,
56
57
  },
57
58
  }),
58
- })
59
+ }),
59
60
  );
60
61
  cache.set(url, content);
61
62
  return content;
@@ -113,7 +114,7 @@ function Router() {
113
114
  // Normal RSC Navigation
114
115
  scrollCache.set(
115
116
  window.location.pathname + window.location.search,
116
- window.scrollY
117
+ window.scrollY,
117
118
  );
118
119
  // cache.delete(finalPath);
119
120
  if (options.replace) {
@@ -231,7 +232,8 @@ function Router() {
231
232
  }, [route]);
232
233
 
233
234
  // RSC Logic
234
- const content = getRSCPayload(route);
235
+ const rscKey = route + "::" + version;
236
+ const content = getRSCPayload(rscKey);
235
237
 
236
238
  const contextValue = useMemo(
237
239
  () => ({
@@ -242,7 +244,7 @@ function Router() {
242
244
  refresh,
243
245
  isPending,
244
246
  }),
245
- [route, isPending]
247
+ [route, isPending],
246
248
  );
247
249
 
248
250
  return (
@@ -38,7 +38,8 @@ const isHashChangeOnly = (finalPath) => {
38
38
  );
39
39
  };
40
40
 
41
- const getRSCPayload = (url) => {
41
+ const getRSCPayload = (rscKey) => {
42
+ const url = rscKey.split("::")[0];
42
43
  // Important: url must already be normalized here
43
44
  if (cache.has(url)) return cache.get(url);
44
45
 
@@ -55,7 +56,7 @@ const getRSCPayload = (url) => {
55
56
  name: window.__DINOU_ERROR_NAME__,
56
57
  },
57
58
  }),
58
- })
59
+ }),
59
60
  );
60
61
  cache.set(url, content);
61
62
  return content;
@@ -113,7 +114,7 @@ function Router() {
113
114
  // Normal RSC Navigation
114
115
  scrollCache.set(
115
116
  window.location.pathname + window.location.search,
116
- window.scrollY
117
+ window.scrollY,
117
118
  );
118
119
  // cache.delete(finalPath);
119
120
  if (options.replace) {
@@ -231,7 +232,8 @@ function Router() {
231
232
  }, [route]);
232
233
 
233
234
  // RSC Logic
234
- const content = getRSCPayload(route);
235
+ const rscKey = route + "::" + version;
236
+ const content = getRSCPayload(rscKey);
235
237
 
236
238
  const contextValue = useMemo(
237
239
  () => ({
@@ -242,7 +244,7 @@ function Router() {
242
244
  refresh,
243
245
  isPending,
244
246
  }),
245
- [route, isPending]
247
+ [route, isPending],
246
248
  );
247
249
 
248
250
  return (
@@ -38,7 +38,8 @@ const isHashChangeOnly = (finalPath) => {
38
38
  );
39
39
  };
40
40
 
41
- const getRSCPayload = (url) => {
41
+ const getRSCPayload = (rscKey) => {
42
+ const url = rscKey.split("::")[0];
42
43
  // 1. Check Idempotence (Avoids the infinite loop of React)
43
44
  if (cache.has(url)) {
44
45
  return cache.get(url);
@@ -52,8 +53,8 @@ const getRSCPayload = (url) => {
52
53
  ? "/____rsc_payload_old_static____" + url
53
54
  : "/____rsc_payload_old____" + url
54
55
  : window.__DINOU_USE_STATIC__
55
- ? "/____rsc_payload_static____" + url
56
- : "/____rsc_payload____" + url;
56
+ ? "/____rsc_payload_static____" + url
57
+ : "/____rsc_payload____" + url;
57
58
 
58
59
  // Clean flags immediately
59
60
  window.__DINOU_USE_OLD_RSC__ = false;
@@ -120,7 +121,7 @@ function Router() {
120
121
  // Normal RSC Navigation
121
122
  scrollCache.set(
122
123
  window.location.pathname + window.location.search,
123
- window.scrollY
124
+ window.scrollY,
124
125
  );
125
126
  // cache.delete(finalPath);
126
127
  if (options.replace) {
@@ -238,7 +239,8 @@ function Router() {
238
239
  }, [route]);
239
240
 
240
241
  // RSC Logic
241
- const content = getRSCPayload(route);
242
+ const rscKey = route + "::" + version;
243
+ const content = getRSCPayload(rscKey);
242
244
 
243
245
  const contextValue = useMemo(
244
246
  () => ({
@@ -249,7 +251,7 @@ function Router() {
249
251
  refresh,
250
252
  isPending,
251
253
  }),
252
- [route, isPending]
254
+ [route, isPending],
253
255
  );
254
256
 
255
257
  return (
@@ -39,7 +39,8 @@ const isHashChangeOnly = (finalPath) => {
39
39
  );
40
40
  };
41
41
 
42
- const getRSCPayload = (url) => {
42
+ const getRSCPayload = (rscKey) => {
43
+ const url = rscKey.split("::")[0];
43
44
  // 1. Check Idempotence (Avoids the infinite loop of React)
44
45
  if (cache.has(url)) {
45
46
  return cache.get(url);
@@ -53,8 +54,8 @@ const getRSCPayload = (url) => {
53
54
  ? "/____rsc_payload_old_static____" + url
54
55
  : "/____rsc_payload_old____" + url
55
56
  : window.__DINOU_USE_STATIC__
56
- ? "/____rsc_payload_static____" + url
57
- : "/____rsc_payload____" + url;
57
+ ? "/____rsc_payload_static____" + url
58
+ : "/____rsc_payload____" + url;
58
59
 
59
60
  // Clean flags immediately
60
61
  window.__DINOU_USE_OLD_RSC__ = false;
@@ -121,7 +122,7 @@ function Router() {
121
122
  // Normal RSC Navigation
122
123
  scrollCache.set(
123
124
  window.location.pathname + window.location.search,
124
- window.scrollY
125
+ window.scrollY,
125
126
  );
126
127
  // cache.delete(finalPath);
127
128
  if (options.replace) {
@@ -239,7 +240,8 @@ function Router() {
239
240
  }, [route]);
240
241
 
241
242
  // RSC Logic
242
- const content = getRSCPayload(route);
243
+ const rscKey = route + "::" + version;
244
+ const content = getRSCPayload(rscKey);
243
245
 
244
246
  const contextValue = useMemo(
245
247
  () => ({
@@ -250,7 +252,7 @@ function Router() {
250
252
  refresh,
251
253
  isPending,
252
254
  }),
253
- [route, isPending]
255
+ [route, isPending],
254
256
  );
255
257
 
256
258
  return (
@@ -4,13 +4,29 @@ import { createFromFetch } from "react-server-dom-webpack/client";
4
4
  function createServerFunctionProxy(id) {
5
5
  return new Proxy(() => {}, {
6
6
  apply: async (_target, _thisArg, args) => {
7
+ let body;
8
+ const headers = {
9
+ "x-server-function-call": "1",
10
+ };
11
+
12
+ if (args[0] instanceof FormData) {
13
+ const formData = args[0];
14
+
15
+ formData.append("__dinou_func_id", id);
16
+
17
+ if (args.length > 1) {
18
+ formData.append("__dinou_args", JSON.stringify(args.slice(1)));
19
+ }
20
+
21
+ body = formData;
22
+ } else {
23
+ headers["Content-Type"] = "application/json";
24
+ body = JSON.stringify({ id, args });
25
+ }
7
26
  const res = await fetch("/____server_function____", {
8
27
  method: "POST",
9
- headers: {
10
- "Content-Type": "application/json",
11
- "x-server-function-call": "1",
12
- },
13
- body: JSON.stringify({ id, args }),
28
+ headers,
29
+ body,
14
30
  });
15
31
 
16
32
  if (!res.ok) throw new Error("Server function failed");
@@ -48,7 +64,7 @@ function createServerFunctionProxy(id) {
48
64
  // CHECK: We search for the tag start, whether it has the closing > or not
49
65
  if (buffer.includes("<script")) {
50
66
  console.warn(
51
- "[Dinou] Stream ended with incomplete script. Discarding tail."
67
+ "[Dinou] Stream ended with incomplete script. Discarding tail.",
52
68
  );
53
69
  // We do not enqueue.
54
70
  } else {
@@ -86,7 +102,7 @@ function createServerFunctionProxy(id) {
86
102
  // Once executed, we remove them so they don't go to React
87
103
  buffer = buffer.replace(scriptRegex, "");
88
104
 
89
- // 4. CALCULATE WHAT IS SAFE TO SEND (Anti-cut logic)
105
+ // 4. CALCULATE WHAT IS SAFE TO SEND (The anti-cut logic)
90
106
  // We need to know if the buffer ends with something that LOOKS like the start of a script
91
107
  // Dangerous patterns at the end: <, <s, <sc, <scr, <scri, <scrip, <script
92
108
 
@@ -4,13 +4,29 @@ import { createFromFetch } from "@roggc/react-server-dom-esm/client";
4
4
  export function createServerFunctionProxy(id) {
5
5
  return new Proxy(() => {}, {
6
6
  apply: async (_target, _thisArg, args) => {
7
+ let body;
8
+ const headers = {
9
+ "x-server-function-call": "1",
10
+ };
11
+
12
+ if (args[0] instanceof FormData) {
13
+ const formData = args[0];
14
+
15
+ formData.append("__dinou_func_id", id);
16
+
17
+ if (args.length > 1) {
18
+ formData.append("__dinou_args", JSON.stringify(args.slice(1)));
19
+ }
20
+
21
+ body = formData;
22
+ } else {
23
+ headers["Content-Type"] = "application/json";
24
+ body = JSON.stringify({ id, args });
25
+ }
7
26
  const res = await fetch("/____server_function____", {
8
27
  method: "POST",
9
- headers: {
10
- "Content-Type": "application/json",
11
- "x-server-function-call": "1",
12
- },
13
- body: JSON.stringify({ id, args }),
28
+ headers,
29
+ body,
14
30
  });
15
31
 
16
32
  if (!res.ok) throw new Error("Server function failed");
@@ -48,7 +64,7 @@ export function createServerFunctionProxy(id) {
48
64
  // CHECK: We search for the tag start, whether it has the closing > or not
49
65
  if (buffer.includes("<script")) {
50
66
  console.warn(
51
- "[Dinou] Stream ended with incomplete script. Discarding tail."
67
+ "[Dinou] Stream ended with incomplete script. Discarding tail.",
52
68
  );
53
69
  // We do not enqueue.
54
70
  } else {
@@ -803,8 +803,25 @@ function isOriginAllowed(req) {
803
803
  }
804
804
  }
805
805
 
806
+ const multer = require("multer");
807
+
808
+ const upload = multer().any();
809
+
810
+ const runMiddleware = (req, res, fn) => {
811
+ return new Promise((resolve, reject) => {
812
+ fn(req, res, (result) => {
813
+ if (result instanceof Error) return reject(result);
814
+ return resolve(result);
815
+ });
816
+ });
817
+ };
818
+
806
819
  app.post("/____server_function____", async (req, res) => {
807
820
  try {
821
+ if (req.headers["content-type"]?.includes("multipart/form-data")) {
822
+ await runMiddleware(req, res, upload);
823
+ }
824
+
808
825
  // 1. Check Origin (Prevent calls from other domains)
809
826
  const origin = req.headers.origin;
810
827
  const host = req.headers.host;
@@ -827,7 +844,40 @@ app.post("/____server_function____", async (req, res) => {
827
844
  );
828
845
  return res.status(403).json({ error: "Origin not allowed" });
829
846
  }
830
- const { id, args } = req.body;
847
+
848
+ let id, args;
849
+
850
+ if (req.headers["content-type"]?.includes("multipart/form-data")) {
851
+ id = req.body.__dinou_func_id;
852
+
853
+ const formData = new FormData();
854
+
855
+ for (const key in req.body) {
856
+ if (key === "__dinou_func_id" || key === "__dinou_args") continue;
857
+ formData.append(key, req.body[key]);
858
+ }
859
+
860
+ if (req.files && Array.isArray(req.files)) {
861
+ for (const file of req.files) {
862
+ const blob = new Blob([file.buffer], { type: file.mimetype });
863
+ formData.append(file.fieldname, blob, file.originalname);
864
+ }
865
+ }
866
+
867
+ args = [formData];
868
+
869
+ if (req.body.__dinou_args) {
870
+ try {
871
+ const extraArgs = JSON.parse(req.body.__dinou_args);
872
+ args.push(...extraArgs);
873
+ } catch (e) {
874
+ console.error("Error parsing extra args in multipart request");
875
+ }
876
+ }
877
+ } else {
878
+ id = req.body.id;
879
+ args = req.body.args;
880
+ }
831
881
 
832
882
  // Basic input validation: id must be string, args an array
833
883
  if (typeof id !== "string" || !Array.isArray(args)) {
@@ -6,6 +6,7 @@ import assetsPlugin from "../plugins-esbuild/assets-plugin.mjs";
6
6
  import copyStaticFiles from "esbuild-copy-static-files";
7
7
  import manifestGeneratorPlugin from "../plugins-esbuild/manifest-generator-plugin.mjs";
8
8
  import writePlugin from "../plugins-esbuild/write-plugin.mjs";
9
+ import babelReactCompilerPlugin from "../plugins-esbuild/babel-react-compiler-plugin.mjs";
9
10
  import { existsSync } from "node:fs";
10
11
 
11
12
  const manifestData = {};
@@ -16,6 +17,7 @@ export default function getConfigEsbuildProd({
16
17
  manifest = {},
17
18
  }) {
18
19
  let plugins = [
20
+ babelReactCompilerPlugin(),
19
21
  TsconfigPathsPlugin({}),
20
22
  cssProcessorPlugin({ outdir }),
21
23
  reactClientManifestPlugin({
@@ -0,0 +1,64 @@
1
+ import babel from "@babel/core";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ const norm = (p) => path.resolve(p).replace(/\\/g, "/");
5
+ export default function babelReactCompilerPlugin() {
6
+ return {
7
+ name: "babel-react-compiler-bridge",
8
+ setup(build) {
9
+ const entryPoints = build.initialOptions.entryPoints;
10
+ // Interceptamos archivos JS/TS/JSX/TSX
11
+ // OJO: Filtramos node_modules para no ralentizar procesando librerías externas
12
+ build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
13
+ // Doble chequeo de seguridad para evitar node_modules
14
+ if (args.path.includes("node_modules")) return;
15
+ const abs = path.resolve(args.path);
16
+
17
+ const absNorm = norm(abs);
18
+ const isAnEntryPoint = Object.values(entryPoints).some(
19
+ (val) => norm(path.resolve(val)) === absNorm,
20
+ );
21
+ if (!isAnEntryPoint) {
22
+ return;
23
+ }
24
+ try {
25
+ const source = await fs.readFile(args.path, "utf8");
26
+ const filename = args.path;
27
+
28
+ // Transformamos el código con Babel + React Compiler
29
+ const result = await babel.transformAsync(source, {
30
+ filename,
31
+ presets: [
32
+ // Necesitamos decirle a Babel que entienda React y TS antes de compilar
33
+ ["@babel/preset-react", { runtime: "automatic" }],
34
+ "@babel/preset-typescript",
35
+ ],
36
+ plugins: [
37
+ "babel-plugin-react-compiler", // 👈 LA JOYA DE LA CORONA
38
+ ],
39
+ sourceMaps: true, // Vital para que los sourcemaps de esbuild funcionen
40
+ configFile: false, // Ignoramos babel.config.js globales para ir al grano
41
+ });
42
+
43
+ // Si por alguna razón Babel no devuelve código, dejamos a esbuild actuar
44
+ if (!result || !result.code) return;
45
+
46
+ return {
47
+ contents: result.code,
48
+ loader: "js", // Babel devuelve JS estándar
49
+ };
50
+ } catch (error) {
51
+ // Si falla Babel, mostramos error bonito para no romper el build silenciosamente
52
+ return {
53
+ errors: [
54
+ {
55
+ text: error.message,
56
+ detail: error,
57
+ },
58
+ ],
59
+ };
60
+ }
61
+ });
62
+ },
63
+ };
64
+ }
@@ -1,8 +1,9 @@
1
1
  // plugins-esbuild/esm-hmr-plugin.mjs
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
- import * as babelCore from "@babel/core";
5
- import { babelConfig } from "./babel-config.js";
4
+ // import * as babelCore from "@babel/core";
5
+ // import { babelConfig } from "./babel-config.js";
6
+ import { transformSync } from "@swc/core";
6
7
  import { createServer } from "node:http";
7
8
  import { EsmHmrEngine } from "./esm-hmr/server.js";
8
9
  import { fileURLToPath } from "node:url";
@@ -49,41 +50,6 @@ export default function esmHmrPlugin({
49
50
  }
50
51
  });
51
52
 
52
- // build.onLoad({ filter: /.*/ }, async (args) => {
53
- // const abs = path.resolve(args.path);
54
-
55
- // const outfileName = Object.entries(entryPoints).find(
56
- // ([, value]) => norm(value) === norm(abs)
57
- // )?.[0];
58
-
59
- // if (!outfileName) {
60
- // return null;
61
- // }
62
-
63
- // for (let i = 0; i < entryAbsPaths.length; i++) {
64
- // if (abs === entryAbsPaths[i] && entrySources[i]) {
65
- // let injectCode = `import { createHotContext } from "/__hmr_client__.js";\n`;
66
- // injectCode += `window.__hotContext = createHotContext;\n`;
67
-
68
- // return {
69
- // contents: injectCode + entrySources[i],
70
- // loader: "jsx",
71
- // };
72
- // }
73
- // }
74
-
75
- // const source = await fs.readFile(args.path, "utf8");
76
- // const transformed = babelCore.transformSync(source, {
77
- // ...babelConfig,
78
- // filename: abs,
79
- // }).code;
80
-
81
- // return {
82
- // contents: transformed,
83
- // loader: args.path.endsWith(".tsx") ? "tsx" : "jsx",
84
- // };
85
- // });
86
-
87
53
  build.onLoad({ filter: /.*/ }, async (args) => {
88
54
  const abs = path.resolve(args.path);
89
55
 
@@ -92,7 +58,7 @@ export default function esmHmrPlugin({
92
58
  // 1. Comprobamos si es un ROOT Entry (client.jsx o error.tsx)
93
59
  // Estos son los que tienes guardados en 'entryAbsPaths'
94
60
  const rootIndex = entryAbsPaths.findIndex(
95
- (entryPath) => norm(entryPath) === absNorm
61
+ (entryPath) => norm(entryPath) === absNorm,
96
62
  );
97
63
 
98
64
  // CASO A: Es Main o Error (Roots)
@@ -115,7 +81,7 @@ export default function esmHmrPlugin({
115
81
  // 2. Comprobamos si es cualquier OTRO Entry Point de la configuración de esbuild
116
82
  // (Aquí están tus páginas, layouts, componentes...)
117
83
  const isAnEntryPoint = Object.values(entryPoints).some(
118
- (val) => norm(path.resolve(val)) === absNorm
84
+ (val) => norm(path.resolve(val)) === absNorm,
119
85
  );
120
86
 
121
87
  // CASO B: Es una página o componente de usuario
@@ -123,18 +89,46 @@ export default function esmHmrPlugin({
123
89
  // AQUÍ SÍ aplicamos Babel para tener React Fast Refresh
124
90
  const source = await fs.readFile(args.path, "utf8");
125
91
 
92
+ // try {
93
+ // const transformed = babelCore.transformSync(source, {
94
+ // ...babelConfig,
95
+ // filename: abs,
96
+ // }).code;
97
+
98
+ // return {
99
+ // contents: transformed,
100
+ // loader: args.path.endsWith(".tsx") ? "tsx" : "jsx",
101
+ // };
102
+ // } catch (e) {
103
+ // // Si babel falla, fallback al original
104
+ // return null;
105
+ // }
126
106
  try {
127
- const transformed = babelCore.transformSync(source, {
128
- ...babelConfig,
107
+ const { code } = transformSync(source, {
129
108
  filename: abs,
130
- }).code;
109
+ jsc: {
110
+ parser: {
111
+ syntax: "typescript",
112
+ tsx: true,
113
+ dynamicImport: true,
114
+ },
115
+ target: "es2022",
116
+ transform: {
117
+ react: {
118
+ refresh: true,
119
+ development: true,
120
+ runtime: "automatic",
121
+ },
122
+ },
123
+ },
124
+ });
131
125
 
132
126
  return {
133
- contents: transformed,
134
- loader: args.path.endsWith(".tsx") ? "tsx" : "jsx",
127
+ contents: code,
128
+ loader: "js",
135
129
  };
136
130
  } catch (e) {
137
- // Si babel falla, fallback al original
131
+ console.error("SWC Error:", e);
138
132
  return null;
139
133
  }
140
134
  }
@@ -147,7 +141,7 @@ export default function esmHmrPlugin({
147
141
  if (!result || !result.outputFiles) return;
148
142
  const clientPath = path.resolve(
149
143
  path.dirname(fileURLToPath(import.meta.url)),
150
- "./esm-hmr/client.mjs"
144
+ "./esm-hmr/client.mjs",
151
145
  );
152
146
  const clientCode = await fs.readFile(clientPath, "utf8");
153
147
  const assetPath = path.join(outdir, "__hmr_client__.js");
@@ -174,7 +168,7 @@ export default function esmHmrPlugin({
174
168
  const relPath = normalizeRel(bF);
175
169
  const outputFile = result.outputFiles.find(
176
170
  (f) =>
177
- normalizeRel(path.relative(process.cwd(), f.path)) === relPath
171
+ normalizeRel(path.relative(process.cwd(), f.path)) === relPath,
178
172
  );
179
173
  if (!outputFile) continue;
180
174
  const baseName = path.basename(bF, ".js");
@@ -194,7 +188,7 @@ export default function esmHmrPlugin({
194
188
  const source = new TextDecoder().decode(outputFile.contents);
195
189
 
196
190
  const imports = Array.from(
197
- source.matchAll(/import\s+["'](.+?)["']/g)
191
+ source.matchAll(/import\s+["'](.+?)["']/g),
198
192
  ).map((m) => m[1]);
199
193
 
200
194
  hmrEngine.value.setEntry(urlId, imports, true);
@@ -1,6 +1,6 @@
1
1
  {
2
- "name": "dinou",
3
- "version": "4.0.3",
2
+ "name": "dinou-ejected",
3
+ "version": "4.0.5",
4
4
  "main": "index.js",
5
5
  "private": true,
6
6
  "exports": {
@@ -30,9 +30,11 @@
30
30
  "@rollup/plugin-json": "^6.1.0",
31
31
  "@rollup/plugin-node-resolve": "^16.0.1",
32
32
  "@rollup/plugin-replace": "^6.0.2",
33
+ "@swc/core": "^1.15.10",
33
34
  "@tailwindcss/postcss": "^4.1.10",
34
35
  "autoprefixer": "^10.4.21",
35
36
  "babel-loader": "^10.0.0",
37
+ "babel-plugin-react-compiler": "^1.0.0",
36
38
  "chokidar": "^4.0.3",
37
39
  "commander": "^14.0.0",
38
40
  "concurrently": "^9.2.0",
@@ -48,6 +50,7 @@
48
50
  "generic-names": "^4.0.0",
49
51
  "loader-utils": "^3.3.1",
50
52
  "mini-css-extract-plugin": "^2.9.4",
53
+ "multer": "^2.0.2",
51
54
  "postcss": "^8.5.5",
52
55
  "postcss-import": "^16.1.1",
53
56
  "postcss-loader": "^8.2.0",
@@ -148,6 +148,7 @@ module.exports = async function () {
148
148
  "@babel/preset-typescript",
149
149
  ],
150
150
  plugins: [
151
+ "babel-plugin-react-compiler",
151
152
  isDevelopment && require.resolve("react-refresh/babel"),
152
153
  "@babel/plugin-syntax-import-meta",
153
154
  ].filter(Boolean),
@@ -185,7 +186,11 @@ module.exports = async function () {
185
186
  serverFunctionsPlugin(),
186
187
  ].filter(Boolean),
187
188
  watch: {
188
- exclude: ["public/**", "react_client_manifest/**"],
189
+ exclude: [
190
+ "public/**",
191
+ "react_client_manifest/**",
192
+ "server_functions_manifest/**",
193
+ ],
189
194
  },
190
195
  onwarn(warning, warn) {
191
196
  // Ignore eval warning if it comes from our request-context file