dinou 4.0.8 → 4.0.9

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 (33) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dinou/core/build-static-pages.js +37 -40
  3. package/dinou/core/css-require-hook.js +64 -64
  4. package/dinou/core/generating-isg.js +2 -3
  5. package/dinou/core/get-error-jsx.js +1 -3
  6. package/dinou/core/get-file-path-and-dynamic-params.js +0 -1
  7. package/dinou/core/get-jsx.js +1 -3
  8. package/dinou/core/get-ssg-jsx-or-jsx.js +2 -2
  9. package/dinou/core/render-app-to-html.js +1 -5
  10. package/dinou/core/render-html.js +23 -26
  11. package/dinou/core/server-function-proxy-webpack.js +2 -3
  12. package/dinou/core/server.js +20 -65
  13. package/dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs +0 -1
  14. package/dinou/esbuild/helpers-esbuild/get-config-esbuild.mjs +0 -1
  15. package/dinou/esbuild/helpers-esbuild/get-esbuild-entries.mjs +8 -8
  16. package/dinou/esbuild/helpers-esbuild/write.mjs +6 -6
  17. package/dinou/esbuild/plugins-esbuild/assets-plugin.mjs +17 -17
  18. package/dinou/esbuild/plugins-esbuild/babel-react-compiler-plugin.mjs +11 -11
  19. package/dinou/esbuild/plugins-esbuild/server-functions-plugin.mjs +5 -5
  20. package/dinou/esbuild/plugins-esbuild/stable-chunk-names-and-maps-plugin.mjs +12 -12
  21. package/dinou/esbuild/plugins-postcss/postcss-extract-plugin.js +3 -3
  22. package/dinou/esbuild/react-refresh/esm-hmr-plugin.mjs +12 -39
  23. package/dinou/esbuild/react-refresh/react-refresh-runtime.mjs +1 -2
  24. package/dinou/package.json +1 -2
  25. package/dinou/rollup/rollup-plugins/rollup-plugin-react-client-manifest.js +4 -4
  26. package/dinou/rollup/rollup-plugins/rollup-plugin-server-functions.js +5 -5
  27. package/dinou/rollup/rollup.config.js +30 -58
  28. package/dinou/webpack/helpers/get-webpack-entries.js +7 -31
  29. package/dinou/webpack/loaders/server-functions-loader.js +4 -5
  30. package/dinou/webpack/plugins/manifest-generator-plugin.js +6 -6
  31. package/dinou/webpack/plugins/server-functions-plugin.js +7 -12
  32. package/dinou/webpack/webpack.config.js +21 -36
  33. package/package.json +1 -2
@@ -218,13 +218,11 @@ if (isDevelopment) {
218
218
  isInitial = true;
219
219
  currentManifest = {};
220
220
  });
221
- // manifestWatcher.on("all", (event) => console.log("event", event));
222
221
  manifestWatcher.on("change", onManifestChange);
223
222
  }
224
223
  startManifestWatcher();
225
224
  }
226
225
  let serverFunctionsManifest = null;
227
- // const devCache = new Map(); // For dev: Map<absolutePath, Set<exports>>
228
226
 
229
227
  if (!isDevelopment) {
230
228
  // In prod/build: load generated manifest
@@ -326,14 +324,6 @@ function getContext(req, res) {
326
324
 
327
325
  // 4. REDIRECT (Your existing smart wrapper)
328
326
  redirect: (...args) => safeResCall("redirect", ...args),
329
- // redirect: (...args) => {
330
- // if (res.headersSent) {
331
- // // Do nothing on res object.
332
- // // We trust that your Server Function will return <ClientRedirect />
333
- // return;
334
- // }
335
- // res.redirect.apply(res, args);
336
- // },
337
327
  },
338
328
  };
339
329
  return context;
@@ -513,12 +503,7 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
513
503
  // isStatic,
514
504
  // reqPath
515
505
  // );
516
- if (
517
- (!isDevelopment &&
518
- /*Object.keys({ ...req.query }).length === 0 &&*/
519
- !dynamicState.value) ||
520
- isStatic
521
- ) {
506
+ if ((!isDevelopment && !dynamicState.value) || isStatic) {
522
507
  const payloadPath = path.resolve(
523
508
  "dist2",
524
509
  reqPath.replace(/^\//, ""),
@@ -536,16 +521,6 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
536
521
  console.error("Error reading RSC file:", err);
537
522
  res.status(500).end();
538
523
  });
539
- // readStream.on("end", () => {
540
- // if (!regenerating.has(reqPath)) {
541
- // // Regeneration has finished, delete the old one
542
- // try {
543
- // unlinkSync(payloadPathOld);
544
- // } catch (err) {
545
- // console.error("Error deleting old RSC file:", err);
546
- // }
547
- // }
548
- // });
549
524
  return readStream.pipe(res);
550
525
  }
551
526
  }
@@ -560,16 +535,16 @@ async function serveRSCPayload(req, res, isOld = false, isStatic = false) {
560
535
  );
561
536
  const manifest = isDevelopment
562
537
  ? JSON.parse(
563
- readFileSync(
564
- path.resolve(
565
- process.cwd(),
566
- isWebpack
567
- ? `${outputFolder}/react-client-manifest.json`
568
- : `react_client_manifest/react-client-manifest.json`,
569
- ),
570
- "utf8",
538
+ readFileSync(
539
+ path.resolve(
540
+ process.cwd(),
541
+ isWebpack
542
+ ? `${outputFolder}/react-client-manifest.json`
543
+ : `react_client_manifest/react-client-manifest.json`,
571
544
  ),
572
- )
545
+ "utf8",
546
+ ),
547
+ )
573
548
  : cachedClientManifest;
574
549
 
575
550
  const { pipe } = renderToPipeableStream(jsx, manifest);
@@ -610,16 +585,16 @@ app.post(/^\/____rsc_payload_error____\/.*\/?$/, async (req, res) => {
610
585
  );
611
586
  const manifest = isDevelopment
612
587
  ? JSON.parse(
613
- readFileSync(
614
- path.resolve(
615
- process.cwd(),
616
- isWebpack
617
- ? `${outputFolder}/react-client-manifest.json`
618
- : `react_client_manifest/react-client-manifest.json`,
619
- ),
620
- "utf8",
588
+ readFileSync(
589
+ path.resolve(
590
+ process.cwd(),
591
+ isWebpack
592
+ ? `${outputFolder}/react-client-manifest.json`
593
+ : `react_client_manifest/react-client-manifest.json`,
621
594
  ),
622
- )
595
+ "utf8",
596
+ ),
597
+ )
623
598
  : cachedClientManifest;
624
599
  const { pipe } = renderToPipeableStream(jsx, manifest);
625
600
  pipe(res);
@@ -642,11 +617,7 @@ app.get(/^\/.*\/?$/, (req, res) => {
642
617
  // Get reference to the mutable object
643
618
  const dynamicState = isDynamic.get(reqPath);
644
619
  // console.log("dynamicState.value", dynamicState.value);
645
- if (
646
- !isDevelopment &&
647
- /*Object.keys({ ...req.query }).length === 0 &&*/
648
- !dynamicState.value
649
- ) {
620
+ if (!isDevelopment && !dynamicState.value) {
650
621
  revalidating(reqPath, dynamicState);
651
622
  let htmlPathOld;
652
623
  if (regenerating.has(reqPath)) {
@@ -686,16 +657,6 @@ app.get(/^\/.*\/?$/, (req, res) => {
686
657
 
687
658
  // 4. Manually close the response (now we do)
688
659
  res.end();
689
-
690
- // // 5. Optional cleanup logic (async to avoid blocking)
691
- // if (htmlPathOld && !regenerating.has(reqPath)) {
692
- // // It is better to use fs.promises to avoid blocking the event loop
693
- // require("fs")
694
- // .promises.unlink(htmlPathOld)
695
- // .catch((err) => {
696
- // console.error("Error deleting old HTML file:", err);
697
- // });
698
- // }
699
660
  });
700
661
 
701
662
  return; // The stream is already flowing
@@ -761,7 +722,6 @@ app.get(/^\/.*\/?$/, (req, res) => {
761
722
  appHtmlStream.on("end", resolve);
762
723
  appHtmlStream.on("error", (error) => {
763
724
  console.error("Stream error:", error);
764
- // resolve(); // ⚠️ WATCH OUT: If you resolve here and then try to send status 500, it might fail if headers sent
765
725
  if (!res.headersSent) res.status(500).send("Internal Server Error");
766
726
  resolve(); // Better resolve at the end
767
727
  });
@@ -921,9 +881,6 @@ app.post("/____server_function____", async (req, res) => {
921
881
  // Prod: use manifest (relativePath is already normalized)
922
882
  allowedExports = serverFunctionsManifest[relativePath];
923
883
  } else {
924
- // Dev: use cache or verify file
925
- // allowedExports = devCache.get(absolutePath);
926
- // if (!allowedExports) {
927
884
  const fileContent = readFileSync(absolutePath, "utf8"); // Reads only once
928
885
  if (!useServerRegex.test(fileContent)) {
929
886
  return res
@@ -933,8 +890,6 @@ app.post("/____server_function____", async (req, res) => {
933
890
  // Parse exports (you need to implement parseExports on server if not present)
934
891
  const exports = parseExports(fileContent); // Assume you move parseExports to a shared util
935
892
  allowedExports = new Set(exports);
936
- // devCache.set(absolutePath, allowedExports);
937
- // }
938
893
  }
939
894
 
940
895
  // Validate exportName against allowedExports
@@ -61,7 +61,6 @@ export default function getConfigEsbuildProd({
61
61
  "/serverFunctionProxy.js",
62
62
  "/__hmr_client__.js",
63
63
  "/react-refresh-entry.js",
64
- // "dinou",
65
64
  ],
66
65
  plugins,
67
66
  };
@@ -58,7 +58,6 @@ export default function getConfigEsbuild({
58
58
  "/serverFunctionProxy.js",
59
59
  "/__hmr_client__.js",
60
60
  "/react-refresh-entry.js",
61
- // "dinou",
62
61
  ],
63
62
  plugins,
64
63
  };
@@ -68,7 +68,7 @@ export default async function getEsbuildEntries({
68
68
  continue;
69
69
  }
70
70
 
71
- // Leer el archivo UNA sola vez
71
+ // Read the file ONLY once
72
72
  let importedCode;
73
73
  try {
74
74
  importedCode = readFileSync(absImportPathWithExt, "utf8");
@@ -81,12 +81,12 @@ export default async function getEsbuildEntries({
81
81
  }
82
82
 
83
83
  if (!isTopLevelClientComponent) {
84
- // Verificar si es un client component
84
+ // Verify if it is a client component
85
85
  const isImportedFileClient = useClientRegex.test(importedCode.trim());
86
86
 
87
- // Si es client component, NO procesar recursivamente
87
+ // If it is a client component, DO NOT process recursively
88
88
  if (isImportedFileClient) {
89
- continue; // No procesar recursivamente client components
89
+ continue; // Do not recursively process client components
90
90
  }
91
91
  } else {
92
92
  const isImportedFileServer = useServerRegex.test(importedCode.trim());
@@ -96,7 +96,7 @@ export default async function getEsbuildEntries({
96
96
  }
97
97
  }
98
98
 
99
- // Para módulos no-client, procesar normalmente
99
+ // For non-client modules, process normally
100
100
  if (
101
101
  absImportPathWithExt.endsWith(".css") ||
102
102
  absImportPathWithExt.endsWith(".scss") ||
@@ -111,15 +111,15 @@ export default async function getEsbuildEntries({
111
111
  continue;
112
112
  }
113
113
 
114
- // 🚨 LA SOLUCIÓN: Si es un JSON, lo añadimos pero NO lo parseamos con Babel
114
+ // 🚨 THE SOLUTION: If it is a JSON file, add it but DO NOT parse it with Babel
115
115
  if (absImportPathWithExt.endsWith(".json")) {
116
116
  imports.add(absImportPathWithExt);
117
- continue; // Esto evita que pase a la recursividad de Babel
117
+ continue; // This prevents it from entering Babel recursion
118
118
  }
119
119
 
120
120
  imports.add(absImportPathWithExt);
121
121
 
122
- // Procesar imports recursivamente para módulos no-client
122
+ // Process imports recursively for non-client modules
123
123
  try {
124
124
  const nested = await getImportsAndAssetsAndCsss(
125
125
  importedCode,
@@ -16,31 +16,31 @@ export default async function write(result) {
16
16
  entryPointNormalized = entryPointNormalized.replace("dinou-asset:", "");
17
17
  }
18
18
  const inputKeys = Object.keys(info.inputs);
19
- // Lógica para assets
19
+ // Logic for assets
20
20
  if (
21
21
  regex.test(entryPointNormalized) &&
22
22
  inputKeys.length === 1 &&
23
23
  inputKeys[0] === info.entryPoint
24
24
  ) {
25
- // Saltar el .js inútil
25
+ // Skip the useless .js file
26
26
  const normalizedPath = normalizeRel(relPath);
27
27
  skipSet.add(normalizedPath);
28
- // Saltar el .map correspondiente si existe
28
+ // Skip the corresponding .map file if it exists
29
29
  const mapRelPath = relPath.replace(/\.js$/, ".js.map");
30
30
  if (result.metafile.outputs[mapRelPath]) {
31
31
  skipSet.add(normalizeRel(mapRelPath));
32
32
  }
33
33
  }
34
- // Lógica para CSS
34
+ // Logic for CSS
35
35
  if (
36
36
  cssRegex.test(info.entryPoint) &&
37
37
  ((inputKeys.length === 1 && inputKeys[0] === info.entryPoint) ||
38
38
  inputKeys.length === 0)
39
39
  ) {
40
- // Saltar el .js inútil
40
+ // Skip the useless .js file
41
41
  const normalizedPath = normalizeRel(relPath);
42
42
  skipSet.add(normalizedPath);
43
- // Saltar el .map correspondiente si existe
43
+ // Skip the corresponding .map file if it exists
44
44
  const mapRelPath = relPath + ".map";
45
45
  if (result.metafile.outputs[mapRelPath]) {
46
46
  skipSet.add(normalizeRel(mapRelPath));
@@ -18,7 +18,7 @@ export default function assetsPlugin({ include = regex } = {}) {
18
18
 
19
19
  build.initialOptions.assetNames = "assets/[name]-[hash]";
20
20
 
21
- // Manejar la carga de assets con namespaces diferentes
21
+ // Handle asset loading with different namespaces
22
22
  build.onResolve({ filter: include }, (args) => {
23
23
  // console.log("[assets-plugin] onResolve", args);
24
24
  const resolvedAlias =
@@ -28,7 +28,7 @@ export default function assetsPlugin({ include = regex } = {}) {
28
28
  parentURL: pathToFileURL(args.importer).href,
29
29
  });
30
30
 
31
- // CRUCIAL: Namespace diferente para entry points
31
+ // CRUCIAL: Different namespace for entry points
32
32
  if (args.kind === "entry-point") {
33
33
  return {
34
34
  path: resolvedAlias,
@@ -42,13 +42,13 @@ export default function assetsPlugin({ include = regex } = {}) {
42
42
  };
43
43
  });
44
44
 
45
- // Loader para assets normales
45
+ // Loader for normal assets
46
46
  build.onLoad({ filter: /.*/, namespace: "dinou-asset" }, async (args) => {
47
47
  const contents = await fs.readFile(args.path);
48
48
  return { contents, loader: "file" };
49
49
  });
50
50
 
51
- // Loader para assets entry points
51
+ // Loader for asset entry points
52
52
  build.onLoad(
53
53
  { filter: /.*/, namespace: "dinou-asset-entry" },
54
54
  async (args) => {
@@ -64,7 +64,7 @@ export default function assetsPlugin({ include = regex } = {}) {
64
64
  const normalizeRel = (p) => p.replace(/\\/g, "/");
65
65
  const processedSourceFiles = new Set();
66
66
 
67
- // Primera pasada: assets normales (archivos individuales)
67
+ // First pass: normal assets (individual files)
68
68
  for (const [oldRelPath, info] of Object.entries(
69
69
  result.metafile.outputs
70
70
  )) {
@@ -88,11 +88,11 @@ export default function assetsPlugin({ include = regex } = {}) {
88
88
  processedSourceFiles.add(sourceFile);
89
89
  }
90
90
 
91
- // Segunda pasada: buscar assets que están dentro de chunks
91
+ // Second pass: find assets that are inside chunks
92
92
  for (const [outputPath, info] of Object.entries(
93
93
  result.metafile.outputs
94
94
  )) {
95
- // Solo buscar en chunks JavaScript
95
+ // Only search in JavaScript chunks
96
96
  if (!outputPath.endsWith(".js") || info.entryPoint) continue;
97
97
 
98
98
  for (const inputPath of Object.keys(info.inputs)) {
@@ -111,10 +111,10 @@ export default function assetsPlugin({ include = regex } = {}) {
111
111
  const scoped = createScopedName(base, sourceFile);
112
112
  const newLocal = `assets/${scoped}${ext}`;
113
113
 
114
- // Leer el asset original
114
+ // Read the original asset
115
115
  const assetContent = await fs.readFile(sourceFile);
116
116
 
117
- // Crear un nuevo output file para este asset
117
+ // Create a new output file for this asset
118
118
  const newOutputFile = {
119
119
  path: path.join(outdir, newLocal),
120
120
  contents: assetContent,
@@ -130,7 +130,7 @@ export default function assetsPlugin({ include = regex } = {}) {
130
130
  // `Extracted asset from chunk: ${sourceFile} → ${newLocal}`
131
131
  // );
132
132
 
133
- // Buscar el chunk que contiene este asset
133
+ // Find the chunk that contains this asset
134
134
  const chunkFile = result.outputFiles.find(
135
135
  (f) =>
136
136
  normalizeRel(path.relative(process.cwd(), f.path)) ===
@@ -140,12 +140,12 @@ export default function assetsPlugin({ include = regex } = {}) {
140
140
  if (chunkFile) {
141
141
  let chunkContent = new TextDecoder().decode(chunkFile.contents);
142
142
 
143
- // ENFOQUE MÁS PRECISO: Buscar el comentario específico de este asset
143
+ // MORE PRECISE APPROACH: Find the specific comment for this asset
144
144
  const assetComment = `// ${inputPath}`;
145
145
  const commentIndex = chunkContent.indexOf(assetComment);
146
146
 
147
147
  if (commentIndex !== -1) {
148
- // Encontrar la línea siguiente que contiene la asignación de variable
148
+ // Find the next line containing the variable assignment
149
149
  const nextLineStart =
150
150
  chunkContent.indexOf("\n", commentIndex) + 1;
151
151
  const nextLineEnd = chunkContent.indexOf("\n", nextLineStart);
@@ -154,7 +154,7 @@ export default function assetsPlugin({ include = regex } = {}) {
154
154
  nextLineEnd
155
155
  );
156
156
 
157
- // Extraer el nombre de la variable (ej: "dinou_default")
157
+ // Extract the variable name (e.g., "dinou_default")
158
158
  const varMatch = assignmentLine.match(
159
159
  /var (\w+)_default = "([^"]+)"/
160
160
  );
@@ -163,7 +163,7 @@ export default function assetsPlugin({ include = regex } = {}) {
163
163
  const varName = varMatch[1];
164
164
  const oldPath = varMatch[2];
165
165
 
166
- // Reemplazar SOLO esta asignación específica
166
+ // Replace ONLY this specific assignment
167
167
  const newAssignmentLine = `var ${varName}_default = "/${newLocal}";`;
168
168
  chunkContent =
169
169
  chunkContent.substring(0, nextLineStart) +
@@ -175,7 +175,7 @@ export default function assetsPlugin({ include = regex } = {}) {
175
175
  // );
176
176
  }
177
177
  } else {
178
- // Fallback: buscar por el nombre de archivo en la ruta
178
+ // Fallback: search by filename in the path
179
179
  const assetName = path.basename(sourceFile);
180
180
  const escapedAssetName = escapeRegExp(assetName);
181
181
  const pattern = new RegExp(
@@ -202,7 +202,7 @@ export default function assetsPlugin({ include = regex } = {}) {
202
202
  }
203
203
  }
204
204
 
205
- // Actualizar referencias en archivos JS/CSS (código existente)
205
+ // Update references in JS/CSS files (existing code)
206
206
  for (const file of result.outputFiles) {
207
207
  const relPath = normalizeRel(path.relative(process.cwd(), file.path));
208
208
  if (!relPath.endsWith(".js") && !relPath.endsWith(".css")) continue;
@@ -226,7 +226,7 @@ export default function assetsPlugin({ include = regex } = {}) {
226
226
  file.contents = new TextEncoder().encode(content);
227
227
  }
228
228
 
229
- // Actualizar paths (código existente)
229
+ // Update paths (existing code)
230
230
  for (const file of result.outputFiles) {
231
231
  const relPath = normalizeRel(path.relative(process.cwd(), file.path));
232
232
  const oldLocal = normalizeRel(path.relative(outdir, relPath));
@@ -7,10 +7,10 @@ export default function babelReactCompilerPlugin() {
7
7
  name: "babel-react-compiler-bridge",
8
8
  setup(build) {
9
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
10
+ // Intercept JS/TS/JSX/TSX files
11
+ // NOTE: Filter node_modules to avoid slowing down by processing external libraries
12
12
  build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
13
- // Doble chequeo de seguridad para evitar node_modules
13
+ // Double check security to avoid node_modules
14
14
  if (args.path.includes("node_modules")) return;
15
15
  const abs = path.resolve(args.path);
16
16
 
@@ -25,30 +25,30 @@ export default function babelReactCompilerPlugin() {
25
25
  const source = await fs.readFile(args.path, "utf8");
26
26
  const filename = args.path;
27
27
 
28
- // Transformamos el código con Babel + React Compiler
28
+ // Transform the code with Babel + React Compiler
29
29
  const result = await babel.transformAsync(source, {
30
30
  filename,
31
31
  presets: [
32
- // Necesitamos decirle a Babel que entienda React y TS antes de compilar
32
+ // We need to tell Babel to understand React and TS before compiling
33
33
  ["@babel/preset-react", { runtime: "automatic" }],
34
34
  "@babel/preset-typescript",
35
35
  ],
36
36
  plugins: [
37
- "babel-plugin-react-compiler", // 👈 LA JOYA DE LA CORONA
37
+ "babel-plugin-react-compiler", // 👈 The jewel in the crown
38
38
  ],
39
- sourceMaps: true, // Vital para que los sourcemaps de esbuild funcionen
40
- configFile: false, // Ignoramos babel.config.js globales para ir al grano
39
+ sourceMaps: true, // Vital for esbuild sourcemaps to work
40
+ configFile: false, // Ignore global babel.config.js to get straight to the point
41
41
  });
42
42
 
43
- // Si por alguna razón Babel no devuelve código, dejamos a esbuild actuar
43
+ // If for some reason Babel does not return code, let esbuild handle it
44
44
  if (!result || !result.code) return;
45
45
 
46
46
  return {
47
47
  contents: result.code,
48
- loader: "js", // Babel devuelve JS estándar
48
+ loader: "js", // Babel returns standard JS
49
49
  };
50
50
  } catch (error) {
51
- // Si falla Babel, mostramos error bonito para no romper el build silenciosamente
51
+ // If Babel fails, show a clean error to not break the build silently
52
52
  return {
53
53
  errors: [
54
54
  {
@@ -8,7 +8,7 @@ export default function serverFunctionsPlugin(manifestData = {}) {
8
8
  name: "server-functions-proxy",
9
9
  setup(build) {
10
10
  const root = process.cwd();
11
- const serverFunctions = new Map(); // Recolectar aquí: Map<relativePath, Set<exports>>
11
+ const serverFunctions = new Map(); // Collect server functions here: Map<relativePath, Set<exports>>
12
12
 
13
13
  // 1. TRANSFORM FILES DURING BUILD
14
14
  build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
@@ -20,11 +20,11 @@ export default function serverFunctionsPlugin(manifestData = {}) {
20
20
  if (exports.length === 0) return null;
21
21
 
22
22
  const relativePath = path.relative(root, args.path);
23
- serverFunctions.set(relativePath, new Set(exports)); // Guardar exports como Set para uniqueness
23
+ serverFunctions.set(relativePath, new Set(exports)); // Save exports as a Set to guarantee uniqueness
24
24
 
25
25
  const fileUrl = `file:///${relativePath}`;
26
26
 
27
- // Proxy code (igual que antes)
27
+ // Generate proxy code that forwards calls to the server instead of executing the actual code
28
28
  let proxyCode = `
29
29
  import { createServerFunctionProxy } from "/__SERVER_FUNCTION_PROXY__";
30
30
  `;
@@ -69,13 +69,13 @@ export default function serverFunctionsPlugin(manifestData = {}) {
69
69
  }
70
70
  }
71
71
 
72
- // Generar manifest: convertir Map a objeto simple
72
+ // Generate the final manifest by converting the Map to a plain object
73
73
  const manifestObj = {};
74
74
  for (const [path, exportsSet] of serverFunctions.entries()) {
75
75
  manifestObj[path] = Array.from(exportsSet);
76
76
  }
77
77
 
78
- // Escribir el manifest en el output dir (ej. mismo lugar que otros assets)
78
+ // Write the server functions manifest JSON file to the output directory
79
79
  const manifestPath = path.join(
80
80
  "server_functions_manifest",
81
81
  "server-functions-manifest.json"
@@ -11,7 +11,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
11
11
 
12
12
  const renames = new Map(); // oldFilename → newFilename (e.g., 'chunk-ABC.js' → 'chunk-stable.js')
13
13
  const normalizeRel = (p) => p.replace(/\\/g, "/");
14
- // Primero, renombrar chunks
14
+ // First, rename chunks
15
15
  for (const [oldRelPath, info] of Object.entries(
16
16
  result.metafile.outputs
17
17
  )) {
@@ -21,7 +21,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
21
21
  (f) => f.startsWith("src/") && /\.(js|jsx|ts|tsx)$/.test(f)
22
22
  );
23
23
  if (!sourceFile) continue;
24
- // Nombre estable basado en el archivo fuente (siempre igual)
24
+ // Stable name based on the source file (always the same)
25
25
  const rel = path.relative("src", sourceFile);
26
26
  const normalizedRel = rel.replace(/\\/g, "/");
27
27
  const dir = path.dirname(normalizedRel);
@@ -33,7 +33,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
33
33
  dir === "." ? base : `${dir.replace(/\//g, "-")}-${base}`;
34
34
  let finalName;
35
35
  if (dev) {
36
- finalName = `${stableName}.js`; // 100% estable en dev
36
+ finalName = `${stableName}.js`; // 100% stable in dev
37
37
  } else {
38
38
  const hash = oldRelPath.match(/-([A-Z0-9]+)\./)?.[1] || "";
39
39
  finalName = `${stableName}-${hash}.js`;
@@ -42,7 +42,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
42
42
  const oldLocal = path.basename(oldRelPath);
43
43
  renames.set(oldLocal, finalRelPath);
44
44
  }
45
- // Segundo, renombrar maps correspondientes a los chunks
45
+ // Second, rename maps corresponding to the chunks
46
46
  for (const [oldRelPath, info] of Object.entries(
47
47
  result.metafile.outputs
48
48
  )) {
@@ -56,7 +56,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
56
56
  renames.set(oldMapLocal, newMapLocal);
57
57
  }
58
58
  }
59
- // Paso 3: Actualizar referencias en importers (imports en .js)
59
+ // Step 3: Update references in importers (imports in .js)
60
60
  const outputs = result.metafile.outputs;
61
61
  const escapeRegExp = (string) =>
62
62
  string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -74,22 +74,22 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
74
74
  const oldImportedLocal = path.basename(importedRelPath);
75
75
  const newImportedLocal = renames.get(oldImportedLocal);
76
76
  if (!newImportedLocal) continue;
77
- // Reemplazar para double quotes con ./
77
+ // Replace for double quotes with ./
78
78
  const oldDouble = `"./${escapeRegExp(oldImportedLocal)}"`;
79
79
  const newDouble = `"./${newImportedLocal}"`;
80
80
  content = content.replace(new RegExp(oldDouble, "g"), newDouble);
81
- // Reemplazar para double quotes sin ./
81
+ // Replace for double quotes without ./
82
82
  const oldDoubleNoDot = `"${escapeRegExp(oldImportedLocal)}"`;
83
83
  const newDoubleNoDot = `"${newImportedLocal}"`;
84
84
  content = content.replace(
85
85
  new RegExp(oldDoubleNoDot, "g"),
86
86
  newDoubleNoDot
87
87
  );
88
- // Reemplazar para single quotes con ./
88
+ // Replace for single quotes with ./
89
89
  const oldSingle = `'./${escapeRegExp(oldImportedLocal)}'`;
90
90
  const newSingle = `'./${newImportedLocal}'`;
91
91
  content = content.replace(new RegExp(oldSingle, "g"), newSingle);
92
- // Reemplazar para single quotes sin ./
92
+ // Replace for single quotes without ./
93
93
  const oldSingleNoDot = `'${escapeRegExp(oldImportedLocal)}'`;
94
94
  const newSingleNoDot = `'${newImportedLocal}'`;
95
95
  content = content.replace(
@@ -99,7 +99,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
99
99
  }
100
100
  importerFile.contents = new TextEncoder().encode(content);
101
101
  }
102
- // Nuevo: Actualizar sourceMappingURL en los .js que se renombran
102
+ // New: Update sourceMappingURL in the .js files being renamed
103
103
  for (const file of result.outputFiles) {
104
104
  if (!file.path.endsWith(".js")) continue;
105
105
  const oldRelPath = normalizeRel(
@@ -123,7 +123,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
123
123
  );
124
124
  file.contents = new TextEncoder().encode(content);
125
125
  }
126
- // Actualizar paths en outputFiles para chunks y maps
126
+ // Update paths in outputFiles for chunks and maps
127
127
  for (const file of result.outputFiles) {
128
128
  const relPath = normalizeRel(path.relative(process.cwd(), file.path));
129
129
  const oldLocal = path.basename(relPath);
@@ -132,7 +132,7 @@ export default function stableChunkNamesAndMapsPlugin({ dev = true } = {}) {
132
132
  file.path = path.join(path.dirname(file.path), newLocal);
133
133
  }
134
134
  }
135
- // Actualizar metafile para consistencia
135
+ // Update metafile for consistency
136
136
  const newOutputs = {};
137
137
  for (const oldRelPath in outputs) {
138
138
  const oldLocal = path.basename(oldRelPath);
@@ -7,7 +7,7 @@ const createPostCSSExtractPlugin = (options = {}) => {
7
7
 
8
8
  let extractedCSS = "";
9
9
 
10
- // El plugin de PostCSS propiamente dicho
10
+ // Define the PostCSS plugin to intercept and extract CSS rules
11
11
  const postcssPlugin = {
12
12
  postcssPlugin: "postcss-extract",
13
13
 
@@ -18,13 +18,13 @@ const createPostCSSExtractPlugin = (options = {}) => {
18
18
  extractedCSS += root.toString();
19
19
  extractedCSS += "\n";
20
20
 
21
- // Limpia el CSS original
21
+ // Remove all CSS rules from the original file to prevent duplicate injection
22
22
  root.removeAll();
23
23
  }
24
24
  },
25
25
  };
26
26
 
27
- // Función para finalizar
27
+ // Write the collected CSS contents to the final output file on disk
28
28
  const finalize = () => {
29
29
  if (!extractedCSS) return;
30
30
  const outputDir = path.dirname(outputFile);