Skip to content

Commit 61cbefd

Browse files
authored
fix: use static params in file-system based router for ssg (#83)
Implements static parameters support in the file-system based router and validates input parameters for static routes at static-site generation phase of an application build. Converts static parameters defined in a `.static.{ts,mjs,json}` to SSG compatible format. Static parameters exported as default: ```ts // /posts/[id].static.ts export default [{ id: 1 }, { id: 2 }, { id: 3 }] ``` Converted to the default format used in `exports` of configuration in a `react-server.config.mjs`: ```js [{ path: "/posts/1" }, { path: "/posts/2" }, { path: "/posts/3" }] ``` #81
1 parent 3955213 commit 61cbefd

File tree

4 files changed

+440
-329
lines changed

4 files changed

+440
-329
lines changed

packages/react-server/lib/build/static.mjs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,16 @@ export default async function staticSiteGenerator(root, options) {
107107
paths =
108108
typeof configRoot.export === "function"
109109
? await configRoot.export(paths)
110-
: [...configRoot.export, ...paths];
110+
: [...(configRoot.export ?? []), ...paths];
111+
const validPaths = paths.filter(({ path, filename }) => filename || path);
112+
if (validPaths.length < paths.length) {
113+
throw new Error(
114+
`${colors.bold("path")} property is not defined for ${colors.bold(
115+
paths.length - validPaths.length
116+
)} path${paths.length - validPaths.length > 1 ? "s" : ""}`
117+
);
118+
}
119+
paths = validPaths;
111120

112121
if (paths.length === 0) {
113122
console.log(colors.yellow("warning: no paths to export, skipping..."));

packages/react-server/lib/plugins/file-router/plugin.mjs

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { forChild, forRoot } from "@lazarv/react-server/config/context.mjs";
99
import * as sys from "@lazarv/react-server/lib/sys.mjs";
1010
import merge from "@lazarv/react-server/lib/utils/merge.mjs";
1111
import { getContext } from "@lazarv/react-server/server/context.mjs";
12+
import { applyParamsToPath } from "@lazarv/react-server/server/route-match.mjs";
1213
import { BUILD_OPTIONS } from "@lazarv/react-server/server/symbols.mjs";
1314
import { watch } from "chokidar";
1415
import glob from "fast-glob";
@@ -749,46 +750,62 @@ export default function viteReactServerRouter(options = {}) {
749750
for (const [, path] of manifest.pages.filter(
750751
([, , outlet, type]) => !outlet && type === "page"
751752
)) {
752-
if (/\[[^/]+\]/.test(path)) {
753-
try {
754-
const staticSrc = manifest.pages.find(
755-
([, staticPath, , staticType]) =>
756-
staticType === "static" && staticPath === path
757-
)?.[0];
758-
759-
if (staticSrc) {
760-
const key = relative(cwd, dirname(staticSrc));
761-
const filename = basename(staticSrc);
762-
const src = join(cwd, key, filename);
763-
const hash = createHash("shake256", {
764-
outputLength: 4,
765-
})
766-
.update(await readFile(src, "utf8"))
767-
.digest("hex");
768-
const exportEntry = pathToFileURL(
769-
join(cwd, outDir, "static", `${hash}.mjs`)
770-
);
771-
config.build.rollupOptions.input[join("static", hash)] =
772-
staticSrc;
773-
paths.push(async () => {
774-
const staticPaths = (await import(exportEntry)).default;
775-
if (typeof staticPaths === "boolean" && staticPaths) {
776-
if (/\[[^\]]+\]/.test(path)) {
777-
throw new Error(
778-
`Static path ${colors.green(path)} contains dynamic segments`
779-
);
780-
}
781-
return path;
782-
}
783-
if (typeof staticPaths === "function") {
784-
return await staticPaths();
753+
try {
754+
const staticSrc = manifest.pages.find(
755+
([, staticPath, , staticType]) =>
756+
staticType === "static" && staticPath === path
757+
)?.[0];
758+
759+
if (staticSrc) {
760+
const key = relative(cwd, dirname(staticSrc));
761+
const filename = basename(staticSrc);
762+
const src = join(cwd, key, filename);
763+
const hash = createHash("shake256", {
764+
outputLength: 4,
765+
})
766+
.update(await readFile(src, "utf8"))
767+
.digest("hex");
768+
const exportEntry = pathToFileURL(
769+
join(cwd, outDir, "static", `${hash}.mjs`)
770+
);
771+
config.build.rollupOptions.input[join("static", hash)] =
772+
staticSrc;
773+
paths.push(async () => {
774+
const staticPaths = (await import(exportEntry)).default;
775+
if (typeof staticPaths === "boolean" && staticPaths) {
776+
if (/\[[^\]]+\]/.test(path)) {
777+
throw new Error(
778+
`missing values on static site generation of ${colors.bold(
779+
path
780+
)}, add missing values for all dynamic segments`
781+
);
785782
}
786-
return staticPaths;
787-
});
788-
}
789-
} catch (e) {
790-
console.error(e);
783+
return { path };
784+
}
785+
if (typeof staticPaths === "function") {
786+
return await staticPaths();
787+
}
788+
const validPaths = await Promise.all(
789+
staticPaths.map(async (def) => {
790+
let obj = def;
791+
if (typeof def === "function") {
792+
obj = await def();
793+
}
794+
try {
795+
return { path: applyParamsToPath(path, obj) };
796+
} catch (e) {
797+
if (typeof obj.path === "string") {
798+
return { path: obj.path };
799+
}
800+
throw e;
801+
}
802+
})
803+
);
804+
return validPaths;
805+
});
791806
}
807+
} catch (e) {
808+
console.error(e);
792809
}
793810
}
794811
if (paths.length > 0) {

0 commit comments

Comments
 (0)