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.
- package/CHANGELOG.md +19 -0
- package/README.md +112 -2
- package/dinou/core/build-static-pages.js +257 -261
- package/dinou/core/client-error-webpack.jsx +7 -5
- package/dinou/core/client-error.jsx +7 -5
- package/dinou/core/client-webpack.jsx +8 -6
- package/dinou/core/client.jsx +8 -6
- package/dinou/core/server-function-proxy-webpack.js +23 -7
- package/dinou/core/server-function-proxy.js +22 -6
- package/dinou/core/server.js +51 -1
- package/dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs +2 -0
- package/dinou/esbuild/plugins-esbuild/babel-react-compiler-plugin.mjs +64 -0
- package/dinou/esbuild/react-refresh/esm-hmr-plugin.mjs +42 -48
- package/dinou/package.json +5 -2
- package/dinou/rollup/rollup.config.js +6 -1
- package/dinou/webpack/helpers/get-webpack-entries.js +37 -8
- package/dinou/webpack/loaders/server-functions-loader.js +5 -10
- package/dinou/webpack/webpack.config.js +45 -36
- package/package.json +5 -2
|
@@ -38,7 +38,8 @@ const isHashChangeOnly = (finalPath) => {
|
|
|
38
38
|
);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const getRSCPayload = (
|
|
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
|
|
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 = (
|
|
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
|
|
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 = (
|
|
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
|
-
|
|
56
|
-
|
|
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
|
|
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 (
|
package/dinou/core/client.jsx
CHANGED
|
@@ -39,7 +39,8 @@ const isHashChangeOnly = (finalPath) => {
|
|
|
39
39
|
);
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
const getRSCPayload = (
|
|
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
|
-
|
|
57
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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 {
|
package/dinou/core/server.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
128
|
-
...babelConfig,
|
|
107
|
+
const { code } = transformSync(source, {
|
|
129
108
|
filename: abs,
|
|
130
|
-
|
|
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:
|
|
134
|
-
loader:
|
|
127
|
+
contents: code,
|
|
128
|
+
loader: "js",
|
|
135
129
|
};
|
|
136
130
|
} catch (e) {
|
|
137
|
-
|
|
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);
|
package/dinou/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "dinou",
|
|
3
|
-
"version": "4.0.
|
|
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: [
|
|
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
|