dinou 6.1.1 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/README.md +9461 -1080
- package/cli.js +392 -169
- package/dinou/adapters/bun.js +62 -0
- package/dinou/adapters/cloudflare.js +65 -0
- package/dinou/adapters/deno.js +48 -0
- package/dinou/adapters/netlify.js +85 -0
- package/dinou/adapters/node.mjs +31 -0
- package/dinou/bun/build.mjs +1077 -0
- package/dinou/cloudflare/build.mjs +1121 -0
- package/dinou/cloudflare/shims/child_process.js +14 -0
- package/dinou/cloudflare/shims/empty.js +2 -0
- package/dinou/cloudflare/shims/fs.js +99 -0
- package/dinou/cloudflare/shims/os.js +29 -0
- package/dinou/config.js +1 -0
- package/dinou/config.mjs +2 -0
- package/dinou/constants.js +29 -4
- package/dinou/core/babel-esm-loader.js +66 -37
- package/dinou/core/bailout-proxy.js +61 -0
- package/dinou/core/build-static-pages.js +309 -157
- package/dinou/core/cache-revalidate.js +471 -144
- package/dinou/core/cache-slot.js +387 -0
- package/dinou/core/client-redirect.jsx +12 -7
- package/dinou/core/client-webpack.jsx +457 -82
- package/dinou/core/client.jsx +452 -82
- package/dinou/core/config.js +11 -0
- package/dinou/core/dinou-paths.js +52 -0
- package/dinou/core/edge-ssr.js +122 -0
- package/dinou/core/export-static.mjs +64 -0
- package/dinou/core/generate-route-types.js +252 -0
- package/dinou/core/generate-static-page.js +55 -94
- package/dinou/core/generate-static-rsc.js +47 -15
- package/dinou/core/generate-static.js +212 -10
- package/dinou/core/generating-isg.js +5 -0
- package/dinou/core/get-asset-from-manifest.js +9 -3
- package/dinou/core/get-error-jsx.js +221 -41
- package/dinou/core/get-file-path-and-dynamic-params.js +9 -13
- package/dinou/core/get-jsx.js +172 -95
- package/dinou/core/handler.js +2296 -0
- package/dinou/core/http-adapter.js +115 -0
- package/dinou/core/import-module.js +83 -53
- package/dinou/core/layout-functions.js +181 -0
- package/dinou/core/link.jsx +18 -6
- package/dinou/core/load-dinou-config.js +60 -0
- package/dinou/core/manifest-provider.js +261 -0
- package/dinou/core/navigation-utils.js +4 -0
- package/dinou/core/navigation.js +50 -39
- package/dinou/core/parse-exports.js +207 -2
- package/dinou/core/ppr-context.js +105 -0
- package/dinou/core/ppr-runtime.js +263 -0
- package/dinou/core/redirect.jsx +20 -19
- package/dinou/core/render-jsx-to-client-jsx.js +133 -15
- package/dinou/core/request-context.js +47 -13
- package/dinou/core/resolve-module-ppr.js +32 -0
- package/dinou/core/revalidating.js +28 -9
- package/dinou/core/route-generator.js +107 -0
- package/dinou/core/rsc-renderer.js +90 -0
- package/dinou/core/run-ssg.js +19 -0
- package/dinou/core/scan-dependency-components.js +218 -0
- package/dinou/core/server-function-proxy-webpack.js +3 -0
- package/dinou/core/server-function-proxy.js +3 -0
- package/dinou/core/slot.js +302 -0
- package/dinou/core/status-manifest.js +41 -1
- package/dinou/core/storage-adapter.js +522 -0
- package/dinou/core/url-resolver.js +16 -16
- package/dinou/core/vfs.js +139 -68
- package/dinou/deno/build.mjs +1112 -0
- package/dinou/deno/seed-kv.js +115 -0
- package/dinou/esbuild/build.mjs +51 -1
- package/dinou/esbuild/dev.mjs +290 -224
- package/dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs +3 -2
- package/dinou/esbuild/helpers-esbuild/get-config-esbuild.mjs +104 -16
- package/dinou/esbuild/helpers-esbuild/get-esbuild-entries.mjs +31 -19
- package/dinou/esbuild/helpers-esbuild/strip-namespace.mjs +9 -0
- package/dinou/esbuild/helpers-esbuild/swc-disk-cache.mjs +225 -0
- package/dinou/esbuild/helpers-esbuild/update-manifest-for-module.mjs +7 -0
- package/dinou/esbuild/helpers-esbuild/write.mjs +111 -2
- package/dinou/esbuild/plugins-esbuild/assets-plugin.mjs +236 -161
- package/dinou/esbuild/plugins-esbuild/css-processor-plugin.mjs +101 -5
- package/dinou/esbuild/plugins-esbuild/react-client-manifest-plugin.mjs +63 -24
- package/dinou/esbuild/plugins-esbuild/server-functions-plugin.mjs +177 -56
- package/dinou/esbuild/plugins-esbuild/skip-missing-entry-points-plugin.mjs +3 -0
- package/dinou/esbuild/plugins-esbuild/stable-chunk-names-and-maps-plugin.mjs +182 -137
- package/dinou/esbuild/plugins-postcss/postcss-extract-plugin.js +38 -11
- package/dinou/esbuild/react-refresh/esm-hmr/client.mjs +55 -8
- package/dinou/esbuild/react-refresh/esm-hmr/server.js +1 -1
- package/dinou/esbuild/react-refresh/esm-hmr-plugin.mjs +238 -101
- package/dinou/esbuild/react-refresh/is-react-refresh-boundary.mjs +18 -4
- package/dinou/index.d.ts +315 -11
- package/dinou/index.js +12 -6
- package/dinou/index.mjs +9 -0
- package/dinou/node/build.mjs +195 -0
- package/dinou/node/bundle-dual-engine.mjs +1012 -0
- package/dinou/node/dev.mjs +2589 -0
- package/dinou/node/port-selector.mjs +164 -0
- package/dinou/node/terminal-status.mjs +345 -0
- package/dinou/package.json +16 -14
- package/dinou/rollup/react-refresh/esm-hmr/client.js +66 -10
- package/dinou/rollup/react-refresh/esm-hmr/server.js +1 -1
- package/dinou/rollup/react-refresh/is-react-refresh-boundary.js +24 -5
- package/dinou/rollup/react-refresh/react-refresh-runtime.js +13 -6
- package/dinou/rollup/react-refresh/react-refresh-wrap-modules.js +56 -11
- package/dinou/rollup/react-refresh/rollup-plugin-esm-hmr.js +176 -48
- package/dinou/rollup/rollup-plugins/dinou-asset-plugin.js +9 -5
- package/dinou/rollup/rollup-plugins/rollup-plugin-memory.js +66 -0
- package/dinou/rollup/rollup-plugins/rollup-plugin-react-client-manifest.js +468 -123
- package/dinou/rollup/rollup-plugins/rollup-plugin-server-functions.js +44 -12
- package/dinou/rollup/rollup-plugins/rollup-plugin-swc.js +100 -0
- package/dinou/rollup/rollup.config.js +155 -43
- package/dinou/server.d.ts +114 -12
- package/dinou/server.js +35 -10
- package/dinou/server.mjs +30 -9
- package/dinou/webpack/helpers/get-webpack-entries.js +14 -19
- package/dinou/webpack/loaders/server-functions-loader.js +22 -1
- package/dinou/webpack/loaders/swc-loader.js +76 -0
- package/dinou/webpack/plugins/manifest-generator-plugin.js +1 -0
- package/dinou/webpack/plugins/server-functions-plugin.js +75 -19
- package/dinou/webpack/plugins/webpack-memory-plugin.js +66 -0
- package/dinou/webpack/webpack.config.js +227 -29
- package/eject.js +173 -94
- package/package.json +110 -108
- package/dinou/core/asset-require-hook.js +0 -58
- package/dinou/core/client-error-webpack.jsx +0 -432
- package/dinou/core/client-error.jsx +0 -432
- package/dinou/core/concurrency-manager.js +0 -48
- package/dinou/core/context-proxy.js +0 -68
- package/dinou/core/generate-static-pages.js +0 -130
- package/dinou/core/generate-static-rscs.js +0 -151
- package/dinou/core/get-ssg-metadata.js +0 -31
- package/dinou/core/register-loader.mjs +0 -11
- package/dinou/core/register-paths.js +0 -27
- package/dinou/core/render-app-to-html.js +0 -430
- package/dinou/core/render-html.js +0 -407
- package/dinou/core/server.js +0 -1542
- package/dinou/esbuild/plugins-esbuild/write-metafile-plugin.mjs +0 -16
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// dinou/core/http-adapter.js
|
|
2
|
+
// Bidirectional adapter between Node.js HTTP (IncomingMessage/ServerResponse)
|
|
3
|
+
// and WHATWG Web Standards (Request/Response/ReadableStream).
|
|
4
|
+
|
|
5
|
+
const { Readable } = require("node:stream");
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Converts a Node.js IncomingMessage / Express Request into a standard Web Request.
|
|
9
|
+
* @param {import('express').Request | import('http').IncomingMessage} req
|
|
10
|
+
* @returns {Request}
|
|
11
|
+
*/
|
|
12
|
+
function nodeToWebRequest(req) {
|
|
13
|
+
const protocol = req.headers["x-forwarded-proto"] || (req.socket?.encrypted ? "https" : "http");
|
|
14
|
+
const host = req.headers["x-forwarded-host"] || req.headers.host || "localhost";
|
|
15
|
+
const url = new URL(req.originalUrl || req.url || "/", `${protocol}://${host}`).href;
|
|
16
|
+
|
|
17
|
+
const headers = new Headers();
|
|
18
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
19
|
+
if (value === undefined) continue;
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
for (const v of value) headers.append(key, v);
|
|
22
|
+
} else {
|
|
23
|
+
headers.set(key, value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const method = req.method || "GET";
|
|
28
|
+
const isBodyAllowed = method !== "GET" && method !== "HEAD";
|
|
29
|
+
|
|
30
|
+
let body = null;
|
|
31
|
+
if (isBodyAllowed) {
|
|
32
|
+
if (req.body && typeof req.body === "object" && !(req.body instanceof Buffer)) {
|
|
33
|
+
const contentType = req.headers["content-type"] || "";
|
|
34
|
+
if (contentType.includes("application/json")) {
|
|
35
|
+
body = JSON.stringify(req.body);
|
|
36
|
+
} else {
|
|
37
|
+
body = JSON.stringify(req.body);
|
|
38
|
+
}
|
|
39
|
+
} else if (Buffer.isBuffer(req.body) || typeof req.body === "string") {
|
|
40
|
+
body = req.body;
|
|
41
|
+
} else if (typeof req.on === "function") {
|
|
42
|
+
// If body hasn't been consumed yet, wrap Node stream into Web ReadableStream
|
|
43
|
+
body = Readable.toWeb(req);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const init = {
|
|
48
|
+
method,
|
|
49
|
+
headers,
|
|
50
|
+
body: isBodyAllowed ? body : null,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Node.js fetch / undici requires duplex: 'half' when streaming request bodies
|
|
54
|
+
if (body && typeof body.getReader === "function") {
|
|
55
|
+
init.duplex = "half";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return new Request(url, init);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Sends a standard Web Response into a Node.js ServerResponse / Express Response.
|
|
63
|
+
* @param {Response} webResponse
|
|
64
|
+
* @param {import('express').Response | import('http').ServerResponse} res
|
|
65
|
+
*/
|
|
66
|
+
async function sendWebResponseToNode(webResponse, res) {
|
|
67
|
+
res.statusCode = webResponse.status;
|
|
68
|
+
if (webResponse.statusText) {
|
|
69
|
+
res.statusMessage = webResponse.statusText;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Handle cookies (multiple Set-Cookie headers)
|
|
73
|
+
if (typeof webResponse.headers.getSetCookie === "function") {
|
|
74
|
+
const cookies = webResponse.headers.getSetCookie();
|
|
75
|
+
if (cookies && cookies.length > 0) {
|
|
76
|
+
res.setHeader("Set-Cookie", cookies);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const [key, value] of webResponse.headers.entries()) {
|
|
81
|
+
if (key.toLowerCase() === "set-cookie") {
|
|
82
|
+
if (typeof webResponse.headers.getSetCookie !== "function") {
|
|
83
|
+
res.setHeader("Set-Cookie", value);
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
res.setHeader(key, value);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!webResponse.body) {
|
|
91
|
+
return res.end();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (typeof webResponse.body.getReader === "function") {
|
|
95
|
+
const nodeStream = Readable.fromWeb(webResponse.body);
|
|
96
|
+
nodeStream.on("error", (err) => {
|
|
97
|
+
console.error("[http-adapter] Error in response stream:", err);
|
|
98
|
+
if (!res.headersSent) {
|
|
99
|
+
res.statusCode = 500;
|
|
100
|
+
res.end("Internal Server Error");
|
|
101
|
+
} else {
|
|
102
|
+
res.destroy(err);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
nodeStream.pipe(res);
|
|
106
|
+
} else {
|
|
107
|
+
const arrayBuffer = await webResponse.arrayBuffer();
|
|
108
|
+
res.end(Buffer.from(arrayBuffer));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
nodeToWebRequest,
|
|
114
|
+
sendWebResponseToNode,
|
|
115
|
+
};
|
|
@@ -1,53 +1,83 @@
|
|
|
1
|
-
const { pathToFileURL } = require("url");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
1
|
+
const { pathToFileURL } = require("url");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
|
|
5
|
+
function getMtimeParam(absPath) {
|
|
6
|
+
try {
|
|
7
|
+
const stats = fs.statSync(absPath);
|
|
8
|
+
return Math.round(stats.mtimeMs);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
return Date.now();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalizeKey(p) {
|
|
15
|
+
if (!p) return "";
|
|
16
|
+
let s = String(p).replace(/\\/g, "/");
|
|
17
|
+
s = s.replace(/^file:\/\/\/?/, "");
|
|
18
|
+
if (s.length > 2 && s[1] === ":") s = s.slice(2);
|
|
19
|
+
const srcIdx = s.indexOf("/src/");
|
|
20
|
+
if (srcIdx !== -1) {
|
|
21
|
+
s = s.slice(srcIdx + 1);
|
|
22
|
+
} else if (s.startsWith("/src/")) {
|
|
23
|
+
s = s.slice(1);
|
|
24
|
+
}
|
|
25
|
+
const cwd = typeof process !== "undefined" && typeof process.cwd === "function"
|
|
26
|
+
? process.cwd().replace(/\\/g, "/")
|
|
27
|
+
: "";
|
|
28
|
+
if (cwd && s.startsWith(cwd)) {
|
|
29
|
+
s = s.slice(cwd.length);
|
|
30
|
+
}
|
|
31
|
+
s = s.replace(/^\/+/, "").replace(/^\.\//, "");
|
|
32
|
+
return s;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function importModule(modulePath) {
|
|
36
|
+
const registry = typeof globalThis !== "undefined" ? globalThis.__DINOU_ROUTE_MODULES__ : null;
|
|
37
|
+
if (registry) {
|
|
38
|
+
const key = normalizeKey(modulePath);
|
|
39
|
+
if (registry[key]) {
|
|
40
|
+
const loader = registry[key];
|
|
41
|
+
return typeof loader === "function" ? await loader() : loader;
|
|
42
|
+
}
|
|
43
|
+
// Also try with or without extensions / leading src/
|
|
44
|
+
const alternateKeys = [
|
|
45
|
+
key,
|
|
46
|
+
key.startsWith("src/") ? key.slice(4) : "src/" + key,
|
|
47
|
+
key.replace(/\.[jt]sx?$/, ""),
|
|
48
|
+
key.startsWith("src/") ? key : "src/" + key,
|
|
49
|
+
key.startsWith("/") ? key : "/" + key,
|
|
50
|
+
];
|
|
51
|
+
for (const alt of alternateKeys) {
|
|
52
|
+
if (registry[alt]) {
|
|
53
|
+
const loader = registry[alt];
|
|
54
|
+
return typeof loader === "function" ? await loader() : loader;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const absPath = path.isAbsolute(modulePath)
|
|
60
|
+
? modulePath
|
|
61
|
+
: path.resolve(process.cwd(), modulePath);
|
|
62
|
+
|
|
63
|
+
let fileUrl = pathToFileURL(absPath).href;
|
|
64
|
+
if (process.env.NODE_ENV !== "production") {
|
|
65
|
+
fileUrl += `?mtime=${getMtimeParam(absPath)}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const mod = await import(/* webpackIgnore: true */ fileUrl);
|
|
69
|
+
return mod;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function registerRouteModules(modulesMap) {
|
|
73
|
+
if (typeof globalThis !== "undefined") {
|
|
74
|
+
globalThis.__DINOU_ROUTE_MODULES__ = {
|
|
75
|
+
...(globalThis.__DINOU_ROUTE_MODULES__ || {}),
|
|
76
|
+
...modulesMap,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
importModule.register = registerRouteModules;
|
|
82
|
+
|
|
83
|
+
module.exports = importModule;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { existsSync } = require("./vfs");
|
|
3
|
+
const importModule = require("./import-module");
|
|
4
|
+
const { resolveModulePpr } = require("./resolve-module-ppr");
|
|
5
|
+
|
|
6
|
+
const LAYOUT_FUNCTIONS_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
7
|
+
const LAYOUT_FUNCTIONS_NAMES = ["layout_functions", "layout.functions"];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Finds the layout_functions file in the given layout directory, if it exists.
|
|
11
|
+
* @param {string} layoutFolderPath
|
|
12
|
+
* @returns {string | null}
|
|
13
|
+
*/
|
|
14
|
+
function getLayoutFunctionsPath(layoutFolderPath) {
|
|
15
|
+
if (!layoutFolderPath) return null;
|
|
16
|
+
for (const name of LAYOUT_FUNCTIONS_NAMES) {
|
|
17
|
+
for (const ext of LAYOUT_FUNCTIONS_EXTENSIONS) {
|
|
18
|
+
const candidate = path.join(layoutFolderPath, `${name}${ext}`);
|
|
19
|
+
if (existsSync(candidate)) {
|
|
20
|
+
return candidate;
|
|
21
|
+
}
|
|
22
|
+
const slashCandidate = candidate.replace(/\\/g, "/");
|
|
23
|
+
if (existsSync(slashCandidate)) {
|
|
24
|
+
return slashCandidate;
|
|
25
|
+
}
|
|
26
|
+
if (typeof globalThis !== "undefined" && globalThis.__DINOU_ROUTE_MODULES__) {
|
|
27
|
+
const norm = slashCandidate.replace(/^file:\/\/\/?/, "").replace(/^\/+/, "");
|
|
28
|
+
const clean = norm.startsWith("src/") ? norm : "src/" + norm.replace(/^.*\/src\//, "");
|
|
29
|
+
if (globalThis.__DINOU_ROUTE_MODULES__[clean] || globalThis.__DINOU_ROUTE_MODULES__[norm]) {
|
|
30
|
+
return clean;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Executes getProps from layout_functions for a given layout, returning the props directly.
|
|
40
|
+
* @param {string} layoutPath
|
|
41
|
+
* @param {object} dParams
|
|
42
|
+
* @returns {Promise<object>}
|
|
43
|
+
*/
|
|
44
|
+
async function getLayoutProps(layoutPath, dParams = {}) {
|
|
45
|
+
if (!layoutPath) return {};
|
|
46
|
+
const layoutFolder = /\.[a-zA-Z0-9]+$/.test(layoutPath)
|
|
47
|
+
? path.dirname(layoutPath)
|
|
48
|
+
: layoutPath;
|
|
49
|
+
const layoutFunctionsPath = getLayoutFunctionsPath(layoutFolder);
|
|
50
|
+
if (!layoutFunctionsPath) return {};
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const mod = await importModule(layoutFunctionsPath);
|
|
54
|
+
const getPropsFn =
|
|
55
|
+
mod.getProps ||
|
|
56
|
+
mod.default?.getProps ||
|
|
57
|
+
(typeof mod.default === "function" ? mod.default : null);
|
|
58
|
+
if (typeof getPropsFn === "function") {
|
|
59
|
+
const res = await getPropsFn(dParams);
|
|
60
|
+
return res && typeof res === "object" ? res : {};
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error(`[Dinou] Error executing getProps in ${layoutFunctionsPath}:`, err);
|
|
64
|
+
}
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolves layout_functions configuration (revalidate, tags, dynamic, allowISG, validateParams).
|
|
70
|
+
* @param {string} layoutPath
|
|
71
|
+
* @param {object} dParams
|
|
72
|
+
* @returns {Promise<object>}
|
|
73
|
+
*/
|
|
74
|
+
async function resolveLayoutFunctionsConfig(layoutPath, dParams = {}) {
|
|
75
|
+
const defaultConfig = {
|
|
76
|
+
allowISG: true,
|
|
77
|
+
staticPathsSet: null,
|
|
78
|
+
validateParams: null,
|
|
79
|
+
isDynamic: false,
|
|
80
|
+
revalidate: undefined,
|
|
81
|
+
tags: [],
|
|
82
|
+
getProps: null,
|
|
83
|
+
ppr: null,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
if (!layoutPath) return defaultConfig;
|
|
87
|
+
|
|
88
|
+
const layoutFolder = /\.[a-zA-Z0-9]+$/.test(layoutPath)
|
|
89
|
+
? path.dirname(layoutPath)
|
|
90
|
+
: layoutPath;
|
|
91
|
+
const layoutFunctionsPath = getLayoutFunctionsPath(layoutFolder);
|
|
92
|
+
if (!layoutFunctionsPath) return defaultConfig;
|
|
93
|
+
|
|
94
|
+
let layoutPpr = null;
|
|
95
|
+
try {
|
|
96
|
+
const mod = await importModule(layoutFunctionsPath);
|
|
97
|
+
if (mod) {
|
|
98
|
+
layoutPpr = await resolveModulePpr(mod);
|
|
99
|
+
}
|
|
100
|
+
if (layoutPpr === null && typeof globalThis !== "undefined" && globalThis.__DINOU_ROUTE_METADATA__) {
|
|
101
|
+
const normKey = layoutFunctionsPath ? layoutFunctionsPath.replace(/\\/g, "/") : "";
|
|
102
|
+
for (const [k, meta] of Object.entries(globalThis.__DINOU_ROUTE_METADATA__)) {
|
|
103
|
+
if (meta.ppr !== undefined && (normKey === k || normKey.endsWith("/" + k) || normKey.endsWith(k))) {
|
|
104
|
+
layoutPpr = Boolean(meta.ppr);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const resolvedAllowISG =
|
|
110
|
+
typeof mod.allowISG === "function"
|
|
111
|
+
? await mod.allowISG()
|
|
112
|
+
: typeof mod.default?.allowISG === "function"
|
|
113
|
+
? await mod.default.allowISG()
|
|
114
|
+
: (mod.allowISG ?? mod.default?.allowISG ?? true);
|
|
115
|
+
|
|
116
|
+
const getStaticPathsFn = mod.getStaticPaths || mod.default?.getStaticPaths;
|
|
117
|
+
let staticPathsSet = null;
|
|
118
|
+
if (getStaticPathsFn) {
|
|
119
|
+
const paths = await (typeof getStaticPathsFn === "function" ? getStaticPathsFn() : getStaticPathsFn);
|
|
120
|
+
if (Array.isArray(paths)) {
|
|
121
|
+
staticPathsSet = new Set(
|
|
122
|
+
paths.map((p) => {
|
|
123
|
+
if (typeof p === "object" && p !== null && !Array.isArray(p)) {
|
|
124
|
+
const sorted = Object.entries(p).sort((a, b) => a[0].localeCompare(b[0]));
|
|
125
|
+
return JSON.stringify(sorted);
|
|
126
|
+
}
|
|
127
|
+
return String(p);
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const revalidateVal =
|
|
134
|
+
typeof mod.revalidate === "function"
|
|
135
|
+
? await mod.revalidate()
|
|
136
|
+
: typeof mod.default?.revalidate === "function"
|
|
137
|
+
? await mod.default.revalidate()
|
|
138
|
+
: (mod.revalidate ?? mod.default?.revalidate);
|
|
139
|
+
|
|
140
|
+
const isDynamic = typeof revalidateVal === "number" && revalidateVal < 1;
|
|
141
|
+
|
|
142
|
+
const rawTags = mod.getCacheTags ?? mod.default?.getCacheTags;
|
|
143
|
+
let tagsVal = [];
|
|
144
|
+
if (typeof rawTags === "function") {
|
|
145
|
+
try {
|
|
146
|
+
tagsVal = await rawTags(dParams);
|
|
147
|
+
} catch (e) {
|
|
148
|
+
console.error("Error running getCacheTags in layout-functions:", e);
|
|
149
|
+
}
|
|
150
|
+
} else if (Array.isArray(rawTags)) {
|
|
151
|
+
tagsVal = rawTags;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const validateParamsFn = mod.validateParams || mod.default?.validateParams;
|
|
155
|
+
const getPropsFn =
|
|
156
|
+
mod.getProps ||
|
|
157
|
+
mod.default?.getProps ||
|
|
158
|
+
(typeof mod.default === "function" ? mod.default : null);
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
allowISG: resolvedAllowISG,
|
|
162
|
+
staticPathsSet,
|
|
163
|
+
validateParams: typeof validateParamsFn === "function" ? validateParamsFn : null,
|
|
164
|
+
isDynamic,
|
|
165
|
+
revalidate: revalidateVal,
|
|
166
|
+
tags: Array.isArray(tagsVal) ? tagsVal : [],
|
|
167
|
+
getProps: typeof getPropsFn === "function" ? getPropsFn : null,
|
|
168
|
+
ppr: layoutPpr,
|
|
169
|
+
};
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.error(`[Dinou] Error resolving layout_functions config from ${layoutFunctionsPath}:`, err);
|
|
172
|
+
return { ...defaultConfig, ppr: layoutPpr };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
getLayoutFunctionsPath,
|
|
178
|
+
getLayoutProps,
|
|
179
|
+
resolveLayoutFunctionsConfig,
|
|
180
|
+
};
|
|
181
|
+
|
package/dinou/core/link.jsx
CHANGED
|
@@ -5,37 +5,49 @@ import { resolveUrl, isExternalUrl } from "./navigation-utils.js";
|
|
|
5
5
|
|
|
6
6
|
export function Link({
|
|
7
7
|
href,
|
|
8
|
+
to,
|
|
8
9
|
children,
|
|
9
10
|
prefetch = true,
|
|
10
11
|
fresh = false,
|
|
12
|
+
onClick,
|
|
11
13
|
...props
|
|
12
14
|
}) {
|
|
15
|
+
const targetHref = href || to || "";
|
|
13
16
|
const { push } = useRouter();
|
|
14
17
|
const pathname = usePathname();
|
|
15
|
-
const resolvedHref = resolveUrl(
|
|
18
|
+
const resolvedHref = resolveUrl(targetHref, pathname);
|
|
16
19
|
|
|
17
20
|
const handlePrefetch = () => {
|
|
18
|
-
if (!prefetch || !
|
|
21
|
+
if (!prefetch || !targetHref || fresh || isExternalUrl(targetHref)) return;
|
|
19
22
|
if (window.__DINOU_PREFETCH__) {
|
|
20
23
|
window.__DINOU_PREFETCH__(resolvedHref);
|
|
21
24
|
}
|
|
22
25
|
};
|
|
23
26
|
|
|
24
27
|
const handleClick = (e) => {
|
|
25
|
-
if (
|
|
28
|
+
if (onClick) {
|
|
29
|
+
onClick(e);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (e.defaultPrevented) return;
|
|
33
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || isExternalUrl(targetHref)) return;
|
|
26
34
|
|
|
27
35
|
e.preventDefault();
|
|
28
|
-
|
|
36
|
+
if (targetHref) {
|
|
37
|
+
push(targetHref, { fresh });
|
|
38
|
+
}
|
|
29
39
|
};
|
|
30
40
|
|
|
31
41
|
return (
|
|
32
42
|
<a
|
|
33
|
-
|
|
43
|
+
{...props}
|
|
44
|
+
href={resolvedHref || undefined}
|
|
34
45
|
onClick={handleClick}
|
|
35
46
|
onMouseEnter={handlePrefetch}
|
|
36
|
-
{...props}
|
|
37
47
|
>
|
|
38
48
|
{children}
|
|
39
49
|
</a>
|
|
40
50
|
);
|
|
41
51
|
}
|
|
52
|
+
|
|
53
|
+
export default Link;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { existsSync } = require("fs");
|
|
3
|
+
const { pathToFileURL } = require("url");
|
|
4
|
+
|
|
5
|
+
let dinouConfig = { plugins: [] };
|
|
6
|
+
let dinouConfigPromise = null;
|
|
7
|
+
|
|
8
|
+
async function getDinouConfig() {
|
|
9
|
+
if (typeof globalThis !== "undefined" && globalThis.__DINOU_CONFIG__) {
|
|
10
|
+
return globalThis.__DINOU_CONFIG__;
|
|
11
|
+
}
|
|
12
|
+
if (dinouConfigPromise) return dinouConfigPromise;
|
|
13
|
+
dinouConfigPromise = (async () => {
|
|
14
|
+
const cwd = typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd() : ".";
|
|
15
|
+
for (const filename of ["dinou.config.js", "dinou.config.mjs", "dinou.config.cjs", "dinou.config.ts"]) {
|
|
16
|
+
const p = path.resolve(cwd, filename);
|
|
17
|
+
if (existsSync(p)) {
|
|
18
|
+
try {
|
|
19
|
+
let loaded;
|
|
20
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
21
|
+
if (p.endsWith(".mjs")) {
|
|
22
|
+
loaded = await import(pathToFileURL(p).href + (isDev ? `?t=${Date.now()}` : ""));
|
|
23
|
+
} else {
|
|
24
|
+
const nodeReq =
|
|
25
|
+
typeof globalThis !== "undefined" && typeof globalThis.__dinou_require__ === "function"
|
|
26
|
+
? globalThis.__dinou_require__
|
|
27
|
+
: typeof require === "function"
|
|
28
|
+
? require
|
|
29
|
+
: null;
|
|
30
|
+
if (nodeReq) {
|
|
31
|
+
try {
|
|
32
|
+
loaded = nodeReq(p);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
loaded = await import(pathToFileURL(p).href + (isDev ? `?t=${Date.now()}` : ""));
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
loaded = await import(pathToFileURL(p).href + (isDev ? `?t=${Date.now()}` : ""));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const cfg = loaded && loaded.default ? loaded.default : loaded || { plugins: [] };
|
|
41
|
+
dinouConfig = cfg;
|
|
42
|
+
return cfg;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
console.error(`[Dinou] Error loading ${filename}:`, err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return dinouConfig;
|
|
49
|
+
})();
|
|
50
|
+
return dinouConfigPromise;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Initial sync attempt if already set on globalThis
|
|
54
|
+
if (typeof globalThis !== "undefined" && globalThis.__DINOU_CONFIG__) {
|
|
55
|
+
dinouConfig = globalThis.__DINOU_CONFIG__;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = {
|
|
59
|
+
getDinouConfig,
|
|
60
|
+
};
|