dinou 2.1.1 → 2.3.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.
- package/CHANGELOG.md +17 -0
- package/cli.js +7 -8
- package/dinou/asset-extensions.js +31 -0
- package/dinou/babel-esm-loader.js +190 -0
- package/dinou/build-static-pages.js +37 -31
- package/dinou/generate-static-page.js +1 -1
- package/dinou/generate-static-pages.js +1 -1
- package/dinou/get-error-jsx.js +4 -3
- package/dinou/get-file-path-and-dynamic-params.js +14 -12
- package/dinou/get-jsx.js +10 -10
- package/dinou/get-ssg-jsx-or-jsx.js +9 -4
- package/dinou/import-module.js +24 -0
- package/dinou/register-loader.mjs +12 -0
- package/dinou/render-app-to-html.js +34 -31
- package/dinou/render-html.js +52 -72
- package/dinou/server.js +20 -50
- package/eject.js +3 -2
- package/package.json +2 -1
- package/rollup-plugins/dinou-asset-plugin.js +2 -3
- package/rollup.config.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [2.3.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Support for ES modules (ESM). Dinou can now import and use ESM-only packages inside React components.
|
|
13
|
+
|
|
14
|
+
## [2.2.0]
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- buildStaticPages - collectPages.
|
|
19
|
+
- getFilePathAndDynamicParams.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Cookies support. Now getProps receive params, query, and cookies as parameters (function getProps(params, query, cookies)).
|
|
24
|
+
|
|
8
25
|
## [2.1.1]
|
|
9
26
|
|
|
10
27
|
### Fixed
|
package/cli.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { program } = require("commander");
|
|
4
4
|
const { execSync } = require("child_process");
|
|
5
5
|
const path = require("path");
|
|
6
|
+
const { pathToFileURL } = require("url");
|
|
6
7
|
|
|
7
8
|
const dinouPath = path.resolve(__dirname, "dinou");
|
|
8
9
|
const projectRoot = process.cwd();
|
|
@@ -21,10 +22,9 @@ program
|
|
|
21
22
|
.description("Starts")
|
|
22
23
|
.action(() => {
|
|
23
24
|
console.log("Starting...");
|
|
24
|
-
const startExpress = `node --conditions react-server ${
|
|
25
|
-
dinouPath,
|
|
26
|
-
|
|
27
|
-
)}`;
|
|
25
|
+
const startExpress = `node --conditions react-server --import ${
|
|
26
|
+
pathToFileURL(path.join(dinouPath, "register-loader.mjs")).href
|
|
27
|
+
} ${path.join(dinouPath, "server.js")}`;
|
|
28
28
|
const startDevServer = `cross-env NODE_ENV=development rollup -c ${path.join(
|
|
29
29
|
__dirname,
|
|
30
30
|
"rollup.config.js"
|
|
@@ -47,10 +47,9 @@ program
|
|
|
47
47
|
.action(() => {
|
|
48
48
|
console.log("Starting the app...");
|
|
49
49
|
runCommand(
|
|
50
|
-
`cross-env NODE_ENV=production node --conditions react-server ${
|
|
51
|
-
dinouPath,
|
|
52
|
-
|
|
53
|
-
)}`
|
|
50
|
+
`cross-env NODE_ENV=production node --conditions react-server --import ${
|
|
51
|
+
pathToFileURL(path.join(dinouPath, "register-loader.mjs")).href
|
|
52
|
+
} ${path.join(dinouPath, "server.js")}`
|
|
54
53
|
);
|
|
55
54
|
});
|
|
56
55
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const extensions = [
|
|
2
|
+
"png",
|
|
3
|
+
"jpg",
|
|
4
|
+
"jpeg",
|
|
5
|
+
"gif",
|
|
6
|
+
"svg",
|
|
7
|
+
"webp",
|
|
8
|
+
"avif",
|
|
9
|
+
"ico",
|
|
10
|
+
"mp4",
|
|
11
|
+
"webm",
|
|
12
|
+
"ogg",
|
|
13
|
+
"mov",
|
|
14
|
+
"avi",
|
|
15
|
+
"mkv",
|
|
16
|
+
"mp3",
|
|
17
|
+
"wav",
|
|
18
|
+
"flac",
|
|
19
|
+
"m4a",
|
|
20
|
+
"aac",
|
|
21
|
+
"mjpeg",
|
|
22
|
+
"mjpg",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// 🔹 regex útil para plugins tipo Rollup/PostCSS
|
|
26
|
+
const regex = new RegExp(`\\.(${extensions.join("|")})$`, "i");
|
|
27
|
+
|
|
28
|
+
// 🔹 versión con punto para comparaciones directas
|
|
29
|
+
const extensionsWithDot = extensions.map((ext) => `.${ext}`);
|
|
30
|
+
|
|
31
|
+
module.exports = { extensions, extensionsWithDot, regex };
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { transformAsync } = require("@babel/core");
|
|
4
|
+
const { fileURLToPath, pathToFileURL } = require("url");
|
|
5
|
+
const createScopedName = require("./createScopedName");
|
|
6
|
+
const { extensionsWithDot } = require("./asset-extensions.js");
|
|
7
|
+
|
|
8
|
+
require("css-modules-require-hook")({
|
|
9
|
+
generateScopedName: createScopedName,
|
|
10
|
+
extensions: [".css"],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Lee tsconfig/jsconfig y construye un map de alias -> targetBase
|
|
14
|
+
function loadTsconfigAliases() {
|
|
15
|
+
const cwd = process.cwd();
|
|
16
|
+
const tsconfigPath = path.resolve(cwd, "tsconfig.json");
|
|
17
|
+
const jsconfigPath = path.resolve(cwd, "jsconfig.json");
|
|
18
|
+
const configFile = fs.existsSync(tsconfigPath)
|
|
19
|
+
? tsconfigPath
|
|
20
|
+
: fs.existsSync(jsconfigPath)
|
|
21
|
+
? jsconfigPath
|
|
22
|
+
: null;
|
|
23
|
+
if (!configFile) return new Map();
|
|
24
|
+
|
|
25
|
+
let config;
|
|
26
|
+
try {
|
|
27
|
+
config = JSON.parse(fs.readFileSync(configFile, "utf8"));
|
|
28
|
+
} catch (err) {
|
|
29
|
+
// Malformed json
|
|
30
|
+
return new Map();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const paths = (config.compilerOptions && config.compilerOptions.paths) || {};
|
|
34
|
+
const baseUrl =
|
|
35
|
+
(config.compilerOptions && config.compilerOptions.baseUrl) || ".";
|
|
36
|
+
const absoluteBase = path.resolve(cwd, baseUrl);
|
|
37
|
+
|
|
38
|
+
const map = new Map();
|
|
39
|
+
|
|
40
|
+
for (const key of Object.keys(paths)) {
|
|
41
|
+
const targets = paths[key];
|
|
42
|
+
if (!targets || !targets.length) continue;
|
|
43
|
+
|
|
44
|
+
// Normaliza: el primer target es el que usaremos
|
|
45
|
+
let target = Array.isArray(targets) ? targets[0] : targets;
|
|
46
|
+
|
|
47
|
+
// Soportar patterns con /* al final: "@/*" -> "src/*"
|
|
48
|
+
const keyIsWildcard = key.endsWith("/*");
|
|
49
|
+
const targetIsWildcard = target.endsWith("/*");
|
|
50
|
+
|
|
51
|
+
const alias = keyIsWildcard ? key.slice(0, -1) : key; // "@/"
|
|
52
|
+
const targetBase = targetIsWildcard ? target.slice(0, -1) : target; // "src" o "../lib"
|
|
53
|
+
|
|
54
|
+
// resolvemos el targetBase relativo a baseUrl si no es absoluto
|
|
55
|
+
const resolvedTargetBase = path.resolve(absoluteBase, targetBase);
|
|
56
|
+
|
|
57
|
+
map.set(alias, {
|
|
58
|
+
resolvedTargetBase,
|
|
59
|
+
keyIsWildcard,
|
|
60
|
+
targetIsWildcard,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return map;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const aliasMap = loadTsconfigAliases();
|
|
68
|
+
|
|
69
|
+
// Añadir extensiones si no existen
|
|
70
|
+
function tryExtensions(filePath) {
|
|
71
|
+
if (fs.existsSync(filePath)) return filePath;
|
|
72
|
+
const exts = [".js", ".ts", ".jsx", ".tsx"];
|
|
73
|
+
for (const ext of exts) {
|
|
74
|
+
const f = filePath + ext;
|
|
75
|
+
if (fs.existsSync(f)) return f;
|
|
76
|
+
}
|
|
77
|
+
// Si es carpeta, probar index.*
|
|
78
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
|
|
79
|
+
for (const ext of exts) {
|
|
80
|
+
const f = path.join(filePath, "index" + ext);
|
|
81
|
+
if (fs.existsSync(f)) return f;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
exports.resolve = async function resolve(specifier, context, defaultResolve) {
|
|
88
|
+
if (aliasMap.size > 0) {
|
|
89
|
+
for (const [alias, info] of aliasMap.entries()) {
|
|
90
|
+
if (specifier.startsWith(alias)) {
|
|
91
|
+
const absPath = path.resolve(
|
|
92
|
+
info.resolvedTargetBase,
|
|
93
|
+
specifier.slice(alias.length)
|
|
94
|
+
);
|
|
95
|
+
const found = tryExtensions(absPath);
|
|
96
|
+
if (found) {
|
|
97
|
+
const url = pathToFileURL(found).href;
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
url,
|
|
101
|
+
shortCircuit: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
109
|
+
const parentURL = context.parentURL || pathToFileURL(process.cwd()).href;
|
|
110
|
+
const parentDir = path.dirname(fileURLToPath(parentURL));
|
|
111
|
+
const absPath = path.resolve(parentDir, specifier);
|
|
112
|
+
const found = tryExtensions(absPath);
|
|
113
|
+
if (found) return { url: pathToFileURL(found).href, shortCircuit: true };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Fallback to default resolver
|
|
117
|
+
return defaultResolve(specifier, context, defaultResolve);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
exports.load = async function load(url, context, defaultLoad) {
|
|
121
|
+
// --- 🟢 Handle non-JS assets (png, jpg, etc.)
|
|
122
|
+
const assetExts = extensionsWithDot;
|
|
123
|
+
const ext = path.extname(url.split("?")[0]); // remove query params if any
|
|
124
|
+
|
|
125
|
+
if (assetExts.includes(ext)) {
|
|
126
|
+
// Return a tiny stub that mimics what asset-require-hook would do
|
|
127
|
+
const filepath = fileURLToPath(url);
|
|
128
|
+
const localName = path.basename(filepath, ext);
|
|
129
|
+
const hashedName = createScopedName(localName, filepath);
|
|
130
|
+
const virtualExport = `export default "/assets/${hashedName}${ext}";`;
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
format: "module",
|
|
134
|
+
source: virtualExport,
|
|
135
|
+
shortCircuit: true,
|
|
136
|
+
url,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (ext === ".css") {
|
|
141
|
+
const mod = require(fileURLToPath(url));
|
|
142
|
+
const source = `export default ${JSON.stringify(mod)};`;
|
|
143
|
+
return { format: "module", source, shortCircuit: true, url };
|
|
144
|
+
}
|
|
145
|
+
if (/\.(jsx|tsx|ts|js)$/.test(url)) {
|
|
146
|
+
let filename;
|
|
147
|
+
try {
|
|
148
|
+
filename = fileURLToPath(
|
|
149
|
+
url.startsWith("file://") ? url : pathToFileURL(url).href
|
|
150
|
+
);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
throw e;
|
|
153
|
+
}
|
|
154
|
+
const rel = path.relative(process.cwd(), filename);
|
|
155
|
+
if (ext === ".js" && !rel.startsWith("src" + path.sep))
|
|
156
|
+
return defaultLoad(url, context, defaultLoad);
|
|
157
|
+
const source = fs.readFileSync(filename, "utf-8");
|
|
158
|
+
if (ext === ".js") {
|
|
159
|
+
return {
|
|
160
|
+
format: "module",
|
|
161
|
+
source,
|
|
162
|
+
shortCircuit: true,
|
|
163
|
+
url,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const { code } = await transformAsync(source, {
|
|
168
|
+
filename,
|
|
169
|
+
presets: [
|
|
170
|
+
["@babel/preset-react", { runtime: "automatic" }],
|
|
171
|
+
"@babel/preset-typescript",
|
|
172
|
+
],
|
|
173
|
+
sourceMaps: "inline",
|
|
174
|
+
ast: false,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const urlToReturn = pathToFileURL(filename).href;
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
format: "module",
|
|
181
|
+
source: code,
|
|
182
|
+
shortCircuit: true,
|
|
183
|
+
url: urlToReturn,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (url) {
|
|
188
|
+
return defaultLoad(url, context, defaultLoad);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
@@ -26,7 +26,7 @@ async function buildStaticPages() {
|
|
|
26
26
|
mkdirSync(distFolder, { recursive: true });
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function collectPages(currentPath, segments = []) {
|
|
29
|
+
function collectPages(currentPath, segments = [], params = {}) {
|
|
30
30
|
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
31
31
|
const pages = [];
|
|
32
32
|
|
|
@@ -74,17 +74,18 @@ async function buildStaticPages() {
|
|
|
74
74
|
console.log(
|
|
75
75
|
`Found optional catch-all route: ${
|
|
76
76
|
segments.join("/") ?? ""
|
|
77
|
-
}/[
|
|
77
|
+
}/[[...${paramName}]]`
|
|
78
78
|
);
|
|
79
79
|
try {
|
|
80
80
|
if (getStaticPaths) {
|
|
81
81
|
const paths = getStaticPaths();
|
|
82
82
|
for (const path of paths) {
|
|
83
|
-
pages.push(
|
|
84
|
-
path
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
pages.push(
|
|
84
|
+
...collectPages(dynamicPath, [...segments, ...path], {
|
|
85
|
+
...params,
|
|
86
|
+
[paramName]: path,
|
|
87
|
+
})
|
|
88
|
+
);
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
} catch (err) {
|
|
@@ -125,17 +126,18 @@ async function buildStaticPages() {
|
|
|
125
126
|
console.log(
|
|
126
127
|
`Found catch-all route: ${
|
|
127
128
|
segments.join("/") ?? ""
|
|
128
|
-
}/[
|
|
129
|
+
}/[...${paramName}]`
|
|
129
130
|
);
|
|
130
131
|
try {
|
|
131
132
|
if (getStaticPaths) {
|
|
132
133
|
const paths = getStaticPaths();
|
|
133
134
|
for (const path of paths) {
|
|
134
|
-
pages.push(
|
|
135
|
-
path
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
pages.push(
|
|
136
|
+
...collectPages(dynamicPath, [...segments, ...path], {
|
|
137
|
+
...params,
|
|
138
|
+
[paramName]: path,
|
|
139
|
+
})
|
|
140
|
+
);
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
143
|
} catch (err) {
|
|
@@ -177,17 +179,18 @@ async function buildStaticPages() {
|
|
|
177
179
|
console.log(
|
|
178
180
|
`Found optional dynamic route: ${
|
|
179
181
|
segments.join("/") ?? ""
|
|
180
|
-
}/[${paramName}]`
|
|
182
|
+
}/[[${paramName}]]`
|
|
181
183
|
);
|
|
182
184
|
try {
|
|
183
185
|
if (getStaticPaths) {
|
|
184
186
|
const paths = getStaticPaths();
|
|
185
187
|
for (const path of paths) {
|
|
186
|
-
pages.push(
|
|
187
|
-
path
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
pages.push(
|
|
189
|
+
...collectPages(dynamicPath, [...segments, path], {
|
|
190
|
+
...params,
|
|
191
|
+
[paramName]: path,
|
|
192
|
+
})
|
|
193
|
+
);
|
|
191
194
|
}
|
|
192
195
|
}
|
|
193
196
|
} catch (err) {
|
|
@@ -232,11 +235,12 @@ async function buildStaticPages() {
|
|
|
232
235
|
if (getStaticPaths) {
|
|
233
236
|
const paths = getStaticPaths();
|
|
234
237
|
for (const path of paths) {
|
|
235
|
-
pages.push(
|
|
236
|
-
path
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
238
|
+
pages.push(
|
|
239
|
+
...collectPages(dynamicPath, [...segments, path], {
|
|
240
|
+
...params,
|
|
241
|
+
[paramName]: path,
|
|
242
|
+
})
|
|
243
|
+
);
|
|
240
244
|
}
|
|
241
245
|
}
|
|
242
246
|
} catch (err) {
|
|
@@ -245,10 +249,11 @@ async function buildStaticPages() {
|
|
|
245
249
|
}
|
|
246
250
|
} else if (!entry.name.startsWith("@")) {
|
|
247
251
|
pages.push(
|
|
248
|
-
...collectPages(
|
|
249
|
-
|
|
250
|
-
entry.name,
|
|
251
|
-
|
|
252
|
+
...collectPages(
|
|
253
|
+
path.join(currentPath, entry.name),
|
|
254
|
+
[...segments, entry.name],
|
|
255
|
+
params
|
|
256
|
+
)
|
|
252
257
|
);
|
|
253
258
|
}
|
|
254
259
|
}
|
|
@@ -262,7 +267,8 @@ async function buildStaticPages() {
|
|
|
262
267
|
true,
|
|
263
268
|
true,
|
|
264
269
|
undefined,
|
|
265
|
-
segments.length
|
|
270
|
+
segments.length,
|
|
271
|
+
params
|
|
266
272
|
);
|
|
267
273
|
const [pageFunctionsPath] = getFilePathAndDynamicParams(
|
|
268
274
|
segments,
|
|
@@ -326,7 +332,7 @@ async function buildStaticPages() {
|
|
|
326
332
|
const pageFunctionsModule = require(pageFunctionsPath);
|
|
327
333
|
const getProps = pageFunctionsModule.getProps;
|
|
328
334
|
revalidate = pageFunctionsModule.revalidate;
|
|
329
|
-
pageFunctionsProps = await getProps?.(params);
|
|
335
|
+
pageFunctionsProps = await getProps?.(params, {}, {});
|
|
330
336
|
props = { ...props, ...(pageFunctionsProps?.page ?? {}) };
|
|
331
337
|
}
|
|
332
338
|
|
|
@@ -504,7 +510,7 @@ async function buildStaticPage(reqPath) {
|
|
|
504
510
|
const pageFunctionsModule = require(pageFunctionsPath);
|
|
505
511
|
const getProps = pageFunctionsModule.getProps;
|
|
506
512
|
revalidate = pageFunctionsModule.revalidate;
|
|
507
|
-
pageFunctionsProps = await getProps?.(dParams);
|
|
513
|
+
pageFunctionsProps = await getProps?.(dParams, {}, {});
|
|
508
514
|
props = { ...props, ...(pageFunctionsProps?.page ?? {}) };
|
|
509
515
|
}
|
|
510
516
|
|
|
@@ -12,7 +12,7 @@ async function generateStaticPage(reqPath) {
|
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
14
|
// console.log("🔄 Rendering HTML for:", finalReqPath);
|
|
15
|
-
const htmlStream =
|
|
15
|
+
const htmlStream = renderAppToHtml(finalReqPath, paramsString);
|
|
16
16
|
|
|
17
17
|
mkdirSync(path.dirname(htmlPath), { recursive: true });
|
|
18
18
|
const fileStream = createWriteStream(htmlPath);
|
|
@@ -13,7 +13,7 @@ async function generateStaticPages(routes) {
|
|
|
13
13
|
|
|
14
14
|
try {
|
|
15
15
|
// console.log("🔄 Rendering HTML for:", reqPath);
|
|
16
|
-
const htmlStream =
|
|
16
|
+
const htmlStream = renderAppToHtml(reqPath, paramsString);
|
|
17
17
|
|
|
18
18
|
mkdirSync(path.dirname(htmlPath), { recursive: true });
|
|
19
19
|
const fileStream = createWriteStream(htmlPath);
|
package/dinou/get-error-jsx.js
CHANGED
|
@@ -4,8 +4,9 @@ const React = require("react");
|
|
|
4
4
|
const {
|
|
5
5
|
getFilePathAndDynamicParams,
|
|
6
6
|
} = require("./get-file-path-and-dynamic-params");
|
|
7
|
+
const importModule = require("./import-module");
|
|
7
8
|
|
|
8
|
-
function getErrorJSX(reqPath, query, error) {
|
|
9
|
+
async function getErrorJSX(reqPath, query, error) {
|
|
9
10
|
const srcFolder = path.resolve(process.cwd(), "src");
|
|
10
11
|
const reqSegments = reqPath.split("/").filter(Boolean);
|
|
11
12
|
const folderPath = path.join(srcFolder, ...reqSegments);
|
|
@@ -49,7 +50,7 @@ function getErrorJSX(reqPath, query, error) {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
if (pagePath) {
|
|
52
|
-
const pageModule =
|
|
53
|
+
const pageModule = await importModule(pagePath);
|
|
53
54
|
const Page = pageModule.default ?? pageModule;
|
|
54
55
|
jsx = React.createElement(Page, {
|
|
55
56
|
params: dynamicParams ?? {},
|
|
@@ -93,7 +94,7 @@ function getErrorJSX(reqPath, query, error) {
|
|
|
93
94
|
if (layouts && Array.isArray(layouts)) {
|
|
94
95
|
let index = 0;
|
|
95
96
|
for (const [layoutPath, dParams, slots] of layouts.reverse()) {
|
|
96
|
-
const layoutModule =
|
|
97
|
+
const layoutModule = await importModule(layoutPath);
|
|
97
98
|
const Layout = layoutModule.default ?? layoutModule;
|
|
98
99
|
let props = { params: dParams, query, ...slots };
|
|
99
100
|
jsx = React.createElement(Layout, props, jsx);
|
|
@@ -58,13 +58,14 @@ function getFilePathAndDynamicParams(
|
|
|
58
58
|
if (!accumulative) return [candidatePath, dParams];
|
|
59
59
|
const slots = getSlots(currentPath, reqSegments, query);
|
|
60
60
|
accumulate.push([candidatePath, dParams, slots]);
|
|
61
|
-
return accumulate;
|
|
62
|
-
}
|
|
63
|
-
if (accumulative) {
|
|
64
|
-
const slots = getSlots(currentPath, reqSegments, query);
|
|
65
|
-
accumulate.push([candidatePath, dParams, slots]);
|
|
61
|
+
if (finalDestination) return accumulate;
|
|
66
62
|
} else {
|
|
67
|
-
|
|
63
|
+
if (accumulative) {
|
|
64
|
+
const slots = getSlots(currentPath, reqSegments, query);
|
|
65
|
+
accumulate.push([candidatePath, dParams, slots]);
|
|
66
|
+
} else {
|
|
67
|
+
foundInCurrentPath = candidatePath;
|
|
68
|
+
}
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -76,13 +77,14 @@ function getFilePathAndDynamicParams(
|
|
|
76
77
|
if (!accumulative) return [candidatePath, dParams];
|
|
77
78
|
const slots = getSlots(currentPath, reqSegments, query);
|
|
78
79
|
accumulate.push([candidatePath, dParams, slots]);
|
|
79
|
-
return accumulate;
|
|
80
|
-
}
|
|
81
|
-
if (accumulative) {
|
|
82
|
-
const slots = getSlots(currentPath, reqSegments, query);
|
|
83
|
-
accumulate.push([candidatePath, dParams, slots]);
|
|
80
|
+
if (finalDestination) return accumulate;
|
|
84
81
|
} else {
|
|
85
|
-
|
|
82
|
+
if (accumulative) {
|
|
83
|
+
const slots = getSlots(currentPath, reqSegments, query);
|
|
84
|
+
accumulate.push([candidatePath, dParams, slots]);
|
|
85
|
+
} else {
|
|
86
|
+
foundInCurrentPath = candidatePath;
|
|
87
|
+
}
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
}
|
package/dinou/get-jsx.js
CHANGED
|
@@ -4,8 +4,9 @@ const React = require("react");
|
|
|
4
4
|
const {
|
|
5
5
|
getFilePathAndDynamicParams,
|
|
6
6
|
} = require("./get-file-path-and-dynamic-params");
|
|
7
|
+
const importModule = require("./import-module");
|
|
7
8
|
|
|
8
|
-
async function getJSX(reqPath, query) {
|
|
9
|
+
async function getJSX(reqPath, query, cookies) {
|
|
9
10
|
const srcFolder = path.resolve(process.cwd(), "src");
|
|
10
11
|
const reqSegments = reqPath.split("/").filter(Boolean);
|
|
11
12
|
const folderPath = path.join(srcFolder, ...reqSegments);
|
|
@@ -49,31 +50,31 @@ async function getJSX(reqPath, query) {
|
|
|
49
50
|
`Page not found: no "page" file found for "${reqPath}"`
|
|
50
51
|
);
|
|
51
52
|
} else {
|
|
52
|
-
const pageModule =
|
|
53
|
+
const pageModule = await importModule(notFoundPath);
|
|
53
54
|
const Page = pageModule.default ?? pageModule;
|
|
54
55
|
jsx = React.createElement(Page, {
|
|
55
56
|
params: dParams ?? {},
|
|
56
57
|
query,
|
|
57
58
|
});
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
const notFoundDir = path.dirname(notFoundPath);
|
|
60
61
|
const noLayoutNotFoundPath = path.join(
|
|
61
62
|
notFoundDir,
|
|
62
63
|
`no_layout_not_found`
|
|
63
64
|
);
|
|
64
|
-
if (existsSync(noLayoutNotFoundPath)) {
|
|
65
|
+
if (existsSync(noLayoutNotFoundPath)) {
|
|
65
66
|
return jsx;
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
} else {
|
|
69
|
-
const pageModule =
|
|
70
|
+
const pageModule = await importModule(pagePath);
|
|
70
71
|
const Page = pageModule.default ?? pageModule;
|
|
71
72
|
|
|
72
73
|
let props = {
|
|
73
74
|
params: dynamicParams,
|
|
74
75
|
query,
|
|
75
76
|
};
|
|
76
|
-
|
|
77
|
+
|
|
77
78
|
const pageFolder = path.dirname(pagePath);
|
|
78
79
|
const [pageFunctionsPath] = getFilePathAndDynamicParams(
|
|
79
80
|
reqSegments,
|
|
@@ -85,11 +86,10 @@ async function getJSX(reqPath, query) {
|
|
|
85
86
|
undefined,
|
|
86
87
|
reqSegments.length
|
|
87
88
|
);
|
|
88
|
-
|
|
89
89
|
if (pageFunctionsPath) {
|
|
90
|
-
const pageFunctionsModule =
|
|
90
|
+
const pageFunctionsModule = await importModule(pageFunctionsPath);
|
|
91
91
|
const getProps = pageFunctionsModule.getProps;
|
|
92
|
-
pageFunctionsProps = await getProps?.(dynamicParams);
|
|
92
|
+
pageFunctionsProps = await getProps?.(dynamicParams, query, cookies);
|
|
93
93
|
props = { ...props, ...(pageFunctionsProps?.page ?? {}) };
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -124,7 +124,7 @@ async function getJSX(reqPath, query) {
|
|
|
124
124
|
if (layouts && Array.isArray(layouts)) {
|
|
125
125
|
let index = 0;
|
|
126
126
|
for (const [layoutPath, dParams, slots] of layouts.reverse()) {
|
|
127
|
-
const layoutModule =
|
|
127
|
+
const layoutModule = await importModule(layoutPath);
|
|
128
128
|
const layoutFolderPath = path.dirname(layoutPath);
|
|
129
129
|
const resetLayoutPath = getFilePathAndDynamicParams(
|
|
130
130
|
[],
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
const getJSX = require("./get-jsx.js");
|
|
2
2
|
const getSSGJSX = require("./get-ssg-jsx.js");
|
|
3
3
|
|
|
4
|
-
async function getSSGJSXOrJSX(
|
|
4
|
+
async function getSSGJSXOrJSX(
|
|
5
|
+
reqPath,
|
|
6
|
+
query,
|
|
7
|
+
cookies = {},
|
|
8
|
+
isDevelopment = false
|
|
9
|
+
) {
|
|
5
10
|
const result =
|
|
6
|
-
Object.keys(query).length || isDevelopment
|
|
7
|
-
? await getJSX(reqPath, query)
|
|
8
|
-
: getSSGJSX(reqPath) ?? (await getJSX(reqPath, query));
|
|
11
|
+
Object.keys(query).length || isDevelopment || Object.keys(cookies).length
|
|
12
|
+
? await getJSX(reqPath, query, cookies)
|
|
13
|
+
: getSSGJSX(reqPath) ?? (await getJSX(reqPath, query, cookies));
|
|
9
14
|
return result;
|
|
10
15
|
}
|
|
11
16
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { pathToFileURL } = require("url");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
async function importModule(modulePath) {
|
|
5
|
+
try {
|
|
6
|
+
return require(modulePath);
|
|
7
|
+
} catch (err) {
|
|
8
|
+
if (
|
|
9
|
+
err.code === "ERR_REQUIRE_ESM" ||
|
|
10
|
+
/require\(\) of ES Module/.test(err.message)
|
|
11
|
+
) {
|
|
12
|
+
const absPath = path.isAbsolute(modulePath)
|
|
13
|
+
? modulePath
|
|
14
|
+
: path.resolve(process.cwd(), modulePath);
|
|
15
|
+
|
|
16
|
+
const fileUrl = pathToFileURL(absPath).href;
|
|
17
|
+
const mod = await import(fileUrl);
|
|
18
|
+
return mod;
|
|
19
|
+
}
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = importModule;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// dinou/register-loader.mjs
|
|
2
|
+
import { register } from "node:module";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
|
|
8
|
+
// Resuelve el loader dentro del propio paquete dinou
|
|
9
|
+
const loaderPath = require.resolve("./babel-esm-loader.js");
|
|
10
|
+
|
|
11
|
+
// Registra el loader ESM
|
|
12
|
+
register(pathToFileURL(loaderPath).href, pathToFileURL("./"));
|
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const { spawn } = require("child_process");
|
|
3
|
+
const url = require("url");
|
|
3
4
|
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
[path.resolve(__dirname, "render-html.js"), reqPath, paramsString],
|
|
9
|
-
{
|
|
10
|
-
env: {
|
|
11
|
-
...process.env,
|
|
12
|
-
},
|
|
13
|
-
}
|
|
14
|
-
);
|
|
5
|
+
function toFileUrl(p) {
|
|
6
|
+
// Convierte a file://, cross-platform
|
|
7
|
+
return url.pathToFileURL(p).href;
|
|
8
|
+
}
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
const registerLoaderPath = toFileUrl(
|
|
11
|
+
path.join(__dirname, "register-loader.mjs")
|
|
12
|
+
);
|
|
13
|
+
const renderHtmlPath = path.resolve(__dirname, "render-html.js");
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
function renderAppToHtml(reqPath, paramsString, cookiesString = "{}") {
|
|
16
|
+
const child = spawn(
|
|
17
|
+
"node",
|
|
18
|
+
[
|
|
19
|
+
"--import",
|
|
20
|
+
registerLoaderPath,
|
|
21
|
+
renderHtmlPath,
|
|
22
|
+
reqPath,
|
|
23
|
+
paramsString,
|
|
24
|
+
cookiesString,
|
|
25
|
+
],
|
|
26
|
+
{
|
|
27
|
+
env: { ...process.env },
|
|
28
|
+
stdio: ["ignore", "pipe", "pipe"], // stdin, stdout, stderr
|
|
29
|
+
}
|
|
30
|
+
);
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
// Capturamos errores del child
|
|
33
|
+
child.on("error", (err) => {
|
|
34
|
+
console.error("Failed to start child process:", err);
|
|
35
|
+
});
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const errorResult = JSON.parse(errorOutput);
|
|
33
|
-
reject(new Error(errorResult.error || errorOutput));
|
|
34
|
-
} catch {
|
|
35
|
-
reject(new Error(`Child process failed: ${errorOutput}`));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
});
|
|
37
|
+
// Opcional: puedes escuchar stderr y loguear
|
|
38
|
+
child.stderr.on("data", (chunk) => {
|
|
39
|
+
console.error(chunk.toString());
|
|
39
40
|
});
|
|
41
|
+
|
|
42
|
+
return child.stdout; // <-- aquí devuelves un stream legible
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
module.exports = renderAppToHtml;
|
package/dinou/render-html.js
CHANGED
|
@@ -10,34 +10,13 @@ babelRegister({
|
|
|
10
10
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
11
11
|
});
|
|
12
12
|
const addHook = require("./asset-require-hook.js");
|
|
13
|
+
const { extensions } = require("./asset-extensions.js");
|
|
13
14
|
const createScopedName = require("./createScopedName");
|
|
14
15
|
require("css-modules-require-hook")({
|
|
15
16
|
generateScopedName: createScopedName,
|
|
16
17
|
});
|
|
17
18
|
addHook({
|
|
18
|
-
extensions
|
|
19
|
-
"png",
|
|
20
|
-
"jpg",
|
|
21
|
-
"jpeg",
|
|
22
|
-
"gif",
|
|
23
|
-
"svg",
|
|
24
|
-
"webp",
|
|
25
|
-
"avif",
|
|
26
|
-
"ico",
|
|
27
|
-
"mp4",
|
|
28
|
-
"webm",
|
|
29
|
-
"ogg",
|
|
30
|
-
"mov",
|
|
31
|
-
"avi",
|
|
32
|
-
"mkv",
|
|
33
|
-
"mp3",
|
|
34
|
-
"wav",
|
|
35
|
-
"flac",
|
|
36
|
-
"m4a",
|
|
37
|
-
"aac",
|
|
38
|
-
"mjpeg",
|
|
39
|
-
"mjpg",
|
|
40
|
-
],
|
|
19
|
+
extensions,
|
|
41
20
|
name: function (localName, filepath) {
|
|
42
21
|
const result = createScopedName(localName, filepath);
|
|
43
22
|
return result + ".[ext]";
|
|
@@ -133,64 +112,64 @@ function formatErrorHtmlProduction(error) {
|
|
|
133
112
|
`;
|
|
134
113
|
}
|
|
135
114
|
|
|
136
|
-
|
|
115
|
+
function writeErrorOutput(error, isProd) {
|
|
116
|
+
process.stdout.write(
|
|
117
|
+
isProd ? formatErrorHtmlProduction(error) : formatErrorHtml(error)
|
|
118
|
+
);
|
|
119
|
+
process.stderr.write(
|
|
120
|
+
JSON.stringify({ error: error.message, stack: error.stack })
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function renderToStream(reqPath, query, cookies = {}) {
|
|
137
125
|
try {
|
|
138
126
|
const jsx =
|
|
139
|
-
Object.keys(query).length || isDevelopment
|
|
140
|
-
? renderJSXToClientJSX(await getJSX(reqPath, query))
|
|
127
|
+
Object.keys(query).length || isDevelopment || Object.keys(cookies).length
|
|
128
|
+
? renderJSXToClientJSX(await getJSX(reqPath, query, cookies))
|
|
141
129
|
: getSSGJSX(reqPath) ??
|
|
142
|
-
renderJSXToClientJSX(await getJSX(reqPath, query));
|
|
130
|
+
renderJSXToClientJSX(await getJSX(reqPath, query, cookies));
|
|
143
131
|
|
|
144
132
|
const stream = renderToPipeableStream(jsx, {
|
|
145
133
|
onError(error) {
|
|
146
|
-
|
|
134
|
+
process.nextTick(async () => {
|
|
135
|
+
if (stream && !stream.destroyed) {
|
|
136
|
+
try {
|
|
137
|
+
stream.unpipe(process.stdout);
|
|
138
|
+
stream.destroy();
|
|
139
|
+
} catch {}
|
|
140
|
+
}
|
|
141
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const errorJSX = await getErrorJSX(reqPath, query, error);
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
if (errorJSX === undefined) {
|
|
147
|
+
writeErrorOutput(error, isProd);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
const errorStream = renderToPipeableStream(errorJSX, {
|
|
152
|
+
onShellReady() {
|
|
153
|
+
errorStream.pipe(process.stdout);
|
|
154
|
+
},
|
|
155
|
+
onError(err) {
|
|
156
|
+
console.error("Error rendering error JSX:", err);
|
|
157
|
+
writeErrorOutput(error, isProd);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
},
|
|
160
|
+
bootstrapModules: ["/error.js"],
|
|
161
|
+
bootstrapScriptContent: `window.__DINOU_ERROR_MESSAGE__=${JSON.stringify(
|
|
162
|
+
error.message || "Unknown error"
|
|
163
|
+
)};window.__DINOU_ERROR_STACK__=${JSON.stringify(
|
|
164
|
+
error.stack || "No stack trace available"
|
|
165
|
+
)};`,
|
|
166
|
+
});
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.error("Render error (no error.tsx?):", err);
|
|
169
|
+
writeErrorOutput(error, isProd);
|
|
158
170
|
process.exit(1);
|
|
159
171
|
}
|
|
160
|
-
|
|
161
|
-
const errorStream = renderToPipeableStream(errorJSX, {
|
|
162
|
-
onShellReady() {
|
|
163
|
-
errorStream.pipe(process.stdout);
|
|
164
|
-
},
|
|
165
|
-
onError(err) {
|
|
166
|
-
console.error("Error rendering error JSX:", err);
|
|
167
|
-
process.stdout.write(
|
|
168
|
-
isProd
|
|
169
|
-
? formatErrorHtmlProduction(error)
|
|
170
|
-
: formatErrorHtml(error)
|
|
171
|
-
);
|
|
172
|
-
process.stderr.write(
|
|
173
|
-
JSON.stringify({ error: error.message, stack: error.stack })
|
|
174
|
-
);
|
|
175
|
-
process.exit(1);
|
|
176
|
-
},
|
|
177
|
-
bootstrapScripts: ["/error.js"],
|
|
178
|
-
bootstrapScriptContent: `window.__DINOU_ERROR_MESSAGE__=${JSON.stringify(
|
|
179
|
-
error.message || "Unknown error"
|
|
180
|
-
)};window.__DINOU_ERROR_STACK__=${JSON.stringify(
|
|
181
|
-
error.stack || "No stack trace available"
|
|
182
|
-
)};`,
|
|
183
|
-
});
|
|
184
|
-
} catch (err) {
|
|
185
|
-
console.error("Render error (no error.tsx?):", err);
|
|
186
|
-
process.stdout.write(
|
|
187
|
-
isProd ? formatErrorHtmlProduction(error) : formatErrorHtml(error)
|
|
188
|
-
);
|
|
189
|
-
process.stderr.write(
|
|
190
|
-
JSON.stringify({ error: error.message, stack: error.stack })
|
|
191
|
-
);
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
172
|
+
});
|
|
194
173
|
},
|
|
195
174
|
onShellReady() {
|
|
196
175
|
stream.pipe(process.stdout);
|
|
@@ -218,6 +197,7 @@ async function renderToStream(reqPath, query) {
|
|
|
218
197
|
|
|
219
198
|
const reqPath = process.argv[2];
|
|
220
199
|
const query = JSON.parse(process.argv[3]);
|
|
200
|
+
const cookies = JSON.parse(process.argv[4] || "{}");
|
|
221
201
|
|
|
222
202
|
process.on("uncaughtException", (error) => {
|
|
223
203
|
process.stdout.write(formatErrorHtml(error));
|
|
@@ -242,4 +222,4 @@ process.on("unhandledRejection", (reason) => {
|
|
|
242
222
|
process.exit(1);
|
|
243
223
|
});
|
|
244
224
|
|
|
245
|
-
renderToStream(reqPath, query);
|
|
225
|
+
renderToStream(reqPath, query, cookies);
|
package/dinou/server.js
CHANGED
|
@@ -8,6 +8,7 @@ const express = require("express");
|
|
|
8
8
|
const getSSGJSXOrJSX = require("./get-ssg-jsx-or-jsx.js");
|
|
9
9
|
const { getErrorJSX } = require("./get-error-jsx.js");
|
|
10
10
|
const addHook = require("./asset-require-hook.js");
|
|
11
|
+
const { extensions } = require("./asset-extensions.js");
|
|
11
12
|
webpackRegister();
|
|
12
13
|
const babelRegister = require("@babel/register");
|
|
13
14
|
babelRegister({
|
|
@@ -24,35 +25,14 @@ require("css-modules-require-hook")({
|
|
|
24
25
|
generateScopedName: createScopedName,
|
|
25
26
|
});
|
|
26
27
|
addHook({
|
|
27
|
-
extensions
|
|
28
|
-
"png",
|
|
29
|
-
"jpg",
|
|
30
|
-
"jpeg",
|
|
31
|
-
"gif",
|
|
32
|
-
"svg",
|
|
33
|
-
"webp",
|
|
34
|
-
"avif",
|
|
35
|
-
"ico",
|
|
36
|
-
"mp4",
|
|
37
|
-
"webm",
|
|
38
|
-
"ogg",
|
|
39
|
-
"mov",
|
|
40
|
-
"avi",
|
|
41
|
-
"mkv",
|
|
42
|
-
"mp3",
|
|
43
|
-
"wav",
|
|
44
|
-
"flac",
|
|
45
|
-
"m4a",
|
|
46
|
-
"aac",
|
|
47
|
-
"mjpeg",
|
|
48
|
-
"mjpg",
|
|
49
|
-
],
|
|
28
|
+
extensions,
|
|
50
29
|
name: function (localName, filepath) {
|
|
51
30
|
const result = createScopedName(localName, filepath);
|
|
52
31
|
return result + ".[ext]";
|
|
53
32
|
},
|
|
54
33
|
publicPath: "/assets/",
|
|
55
34
|
});
|
|
35
|
+
const importModule = require("./import-module");
|
|
56
36
|
const generateStatic = require("./generate-static.js");
|
|
57
37
|
const renderAppToHtml = require("./render-app-to-html.js");
|
|
58
38
|
const revalidating = require("./revalidating.js");
|
|
@@ -117,18 +97,6 @@ if (isDevelopment) {
|
|
|
117
97
|
}
|
|
118
98
|
}
|
|
119
99
|
|
|
120
|
-
// function clearAllUserCache() {
|
|
121
|
-
// const srcDir = path.resolve(process.cwd(), "src");
|
|
122
|
-
// Object.keys(require.cache).forEach((file) => {
|
|
123
|
-
// if (file.startsWith(srcDir)) {
|
|
124
|
-
// delete require.cache[file];
|
|
125
|
-
// }
|
|
126
|
-
// });
|
|
127
|
-
// console.log(
|
|
128
|
-
// "[Server HMR] Cleared all src/ require caches due to directive change."
|
|
129
|
-
// );
|
|
130
|
-
// }
|
|
131
|
-
|
|
132
100
|
watcher.on("change", () => {
|
|
133
101
|
try {
|
|
134
102
|
const newManifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
@@ -150,12 +118,7 @@ if (isDevelopment) {
|
|
|
150
118
|
// console.log(`Cleared cache for ${absPath} (server -> client)`);
|
|
151
119
|
}
|
|
152
120
|
}
|
|
153
|
-
|
|
154
|
-
// Object.keys(currentManifest).length !== Object.keys(newManifest).length
|
|
155
|
-
// ) {
|
|
156
|
-
// // Only clear if there was a change (add/remove)
|
|
157
|
-
// clearAllUserCache();
|
|
158
|
-
// }
|
|
121
|
+
|
|
159
122
|
currentManifest = newManifest;
|
|
160
123
|
} catch (err) {
|
|
161
124
|
console.error("Error handling manifest change:", err);
|
|
@@ -182,9 +145,10 @@ if (isDevelopment) {
|
|
|
182
145
|
}
|
|
183
146
|
});
|
|
184
147
|
}
|
|
185
|
-
|
|
148
|
+
const cookieParser = require("cookie-parser");
|
|
149
|
+
const appUseCookieParser = cookieParser();
|
|
186
150
|
const app = express();
|
|
187
|
-
|
|
151
|
+
app.use(appUseCookieParser);
|
|
188
152
|
app.use(express.json());
|
|
189
153
|
|
|
190
154
|
app.use(express.static(path.resolve(process.cwd(), webpackFolder)));
|
|
@@ -217,9 +181,12 @@ app.get(/^\/____rsc_payload____\/.*\/?$/, async (req, res) => {
|
|
|
217
181
|
return readStream.pipe(res);
|
|
218
182
|
}
|
|
219
183
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
184
|
+
const jsx = await getSSGJSXOrJSX(
|
|
185
|
+
reqPath,
|
|
186
|
+
{ ...req.query },
|
|
187
|
+
{ ...req.cookies },
|
|
188
|
+
isDevelopment
|
|
189
|
+
);
|
|
223
190
|
const manifest = JSON.parse(
|
|
224
191
|
readFileSync(
|
|
225
192
|
path.resolve(`${webpackFolder}/react-client-manifest.json`),
|
|
@@ -257,7 +224,7 @@ app.post(/^\/____rsc_payload_error____\/.*\/?$/, async (req, res) => {
|
|
|
257
224
|
}
|
|
258
225
|
});
|
|
259
226
|
|
|
260
|
-
app.get(/^\/.*\/?$/,
|
|
227
|
+
app.get(/^\/.*\/?$/, (req, res) => {
|
|
261
228
|
try {
|
|
262
229
|
const reqPath = req.path.endsWith("/") ? req.path : req.path + "/";
|
|
263
230
|
|
|
@@ -271,9 +238,10 @@ app.get(/^\/.*\/?$/, async (req, res) => {
|
|
|
271
238
|
}
|
|
272
239
|
}
|
|
273
240
|
|
|
274
|
-
const appHtmlStream =
|
|
241
|
+
const appHtmlStream = renderAppToHtml(
|
|
275
242
|
reqPath,
|
|
276
|
-
JSON.stringify({ ...req.query })
|
|
243
|
+
JSON.stringify({ ...req.query }),
|
|
244
|
+
JSON.stringify({ ...req.cookies })
|
|
277
245
|
);
|
|
278
246
|
|
|
279
247
|
res.setHeader("Content-Type", "text/html");
|
|
@@ -297,7 +265,7 @@ app.post("/____server_function____", async (req, res) => {
|
|
|
297
265
|
let relativePath = fileUrl.replace(/^file:\/\/\/?/, "");
|
|
298
266
|
const absolutePath = path.resolve(process.cwd(), relativePath);
|
|
299
267
|
|
|
300
|
-
const mod =
|
|
268
|
+
const mod = await importModule(absolutePath);
|
|
301
269
|
|
|
302
270
|
const fn = exportName === "default" ? mod.default : mod[exportName];
|
|
303
271
|
|
|
@@ -305,6 +273,8 @@ app.post("/____server_function____", async (req, res) => {
|
|
|
305
273
|
return res.status(400).json({ error: "Export is not a function" });
|
|
306
274
|
}
|
|
307
275
|
|
|
276
|
+
const context = { req, res };
|
|
277
|
+
args.push(context);
|
|
308
278
|
const result = await fn(...args);
|
|
309
279
|
|
|
310
280
|
if (
|
package/eject.js
CHANGED
|
@@ -34,13 +34,14 @@ if (fs.existsSync(path.join(modulePath, "postcss.config.js"))) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const pkg = require(path.join(projectRoot, "package.json"));
|
|
37
|
-
pkg.scripts["start:express"] =
|
|
37
|
+
pkg.scripts["start:express"] =
|
|
38
|
+
"node --conditions react-server --import ./dinou/register-loader.mjs ./dinou/server.js";
|
|
38
39
|
pkg.scripts["start:dev-server"] = "cross-env NODE_ENV=development rollup -c -w";
|
|
39
40
|
pkg.scripts.dev =
|
|
40
41
|
'concurrently "npm run start:express" "npm run start:dev-server"';
|
|
41
42
|
pkg.scripts.build = "cross-env NODE_ENV=production rollup -c";
|
|
42
43
|
pkg.scripts.start =
|
|
43
|
-
"cross-env NODE_ENV=production node --conditions react-server dinou/server.js";
|
|
44
|
+
"cross-env NODE_ENV=production node --conditions react-server --import ./dinou/register-loader.mjs ./dinou/server.js";
|
|
44
45
|
delete pkg.scripts.eject;
|
|
45
46
|
fs.writeFileSync(
|
|
46
47
|
path.join(projectRoot, "package.json"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dinou",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Minimal React 19 Framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"chokidar": "^4.0.3",
|
|
39
39
|
"commander": "^14.0.0",
|
|
40
40
|
"concurrently": "^9.2.0",
|
|
41
|
+
"cookie-parser": "^1.4.7",
|
|
41
42
|
"cross-env": "^7.0.3",
|
|
42
43
|
"css-modules-require-hook": "^4.2.3",
|
|
43
44
|
"dotenv": "^16.5.0",
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const createScopedName = require("../dinou/createScopedName.js");
|
|
4
|
+
const { regex } = require("../dinou/asset-extensions.js");
|
|
4
5
|
|
|
5
|
-
function dinouAssetPlugin({
|
|
6
|
-
include = /\.(png|jpe?g|gif|svg|webp|avif|ico|mp4|webm|ogg|mov|avi|mkv|mp3|wav|flac|m4a|aac|mjpeg|mjpg)$/i,
|
|
7
|
-
} = {}) {
|
|
6
|
+
function dinouAssetPlugin({ include = regex } = {}) {
|
|
8
7
|
return {
|
|
9
8
|
name: "dinou-asset-plugin",
|
|
10
9
|
async load(id) {
|
package/rollup.config.js
CHANGED
|
@@ -13,6 +13,7 @@ const { esmHmrPlugin } = require("./react-refresh/rollup-plugin-esm-hmr.js");
|
|
|
13
13
|
const dinouAssetPlugin = require("./rollup-plugins/dinou-asset-plugin.js");
|
|
14
14
|
const tsconfigPaths = require("rollup-plugin-tsconfig-paths");
|
|
15
15
|
const serverFunctionsPlugin = require("./rollup-plugins/rollup-plugin-server-functions");
|
|
16
|
+
const { regex } = require("./dinou/asset-extensions.js");
|
|
16
17
|
|
|
17
18
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
18
19
|
const outputDirectory = isDevelopment ? "public" : "dist3";
|
|
@@ -76,8 +77,7 @@ module.exports = async function () {
|
|
|
76
77
|
transformMixedEsModules: true,
|
|
77
78
|
}),
|
|
78
79
|
dinouAssetPlugin({
|
|
79
|
-
include:
|
|
80
|
-
/\.(png|jpe?g|gif|svg|webp|avif|ico|mp4|webm|ogg|mov|avi|mkv|mp3|wav|flac|m4a|aac|mjpeg|mjpg)$/i,
|
|
80
|
+
include: regex,
|
|
81
81
|
}),
|
|
82
82
|
babel({
|
|
83
83
|
babelHelpers: "bundled",
|