- Page URL paths are now relative to src/pages. The old greedy
`.*/pages/` cut mapped src/pages/admin/pages/index.tsx to /index, so
every page under a nested `pages` directory collided with the home page
and was never bundled. SSR also tells API routes by URL path now.
- CommonJS `require("react…")` in client bundles (for example
use-sync-external-store/shim, pulled in by MUI) threw "Dynamic require
of "react" is not supported" in the browser. Those requires now go
through a small bundled ESM module that imports the external.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
100 lines
3.3 KiB
JavaScript
100 lines
3.3 KiB
JavaScript
import { existsSync, readdirSync, statSync } from "fs";
|
|
import grabDirNames from "./grab-dir-names";
|
|
import path from "path";
|
|
import AppNames from "./grab-app-names";
|
|
import checkExcludedPatterns from "./check-excluded-patterns";
|
|
export default function grabAllPages(params) {
|
|
const { PAGES_DIR } = grabDirNames();
|
|
const pages = grabPageDirRecursively({
|
|
page_dir: PAGES_DIR,
|
|
include_server: params?.include_server,
|
|
});
|
|
if (params?.exclude_api) {
|
|
return pages.filter((p) => !Boolean(p.url_path.startsWith("/api/")));
|
|
}
|
|
if (params?.api_only) {
|
|
return pages.filter((p) => Boolean(p.url_path.startsWith("/api/")));
|
|
}
|
|
return pages;
|
|
}
|
|
function grabPageDirRecursively({ page_dir, pages_root = page_dir, include_server, }) {
|
|
const pages = readdirSync(page_dir);
|
|
const pages_files = [];
|
|
for (let i = 0; i < pages.length; i++) {
|
|
const page = pages[i];
|
|
const page_name = page.split("/").pop();
|
|
const full_page_path = path.join(page_dir, page);
|
|
if (!existsSync(full_page_path) || !page_name) {
|
|
continue;
|
|
}
|
|
if (page.match(new RegExp(`${AppNames["RootPagesComponentName"]}`)) &&
|
|
!page_name.match(/\.server\.tsx?/)) {
|
|
continue;
|
|
}
|
|
const is_page_excluded = checkExcludedPatterns({
|
|
path: full_page_path,
|
|
});
|
|
if (is_page_excluded) {
|
|
continue;
|
|
}
|
|
if (full_page_path.match(/__tests__/)) {
|
|
continue;
|
|
}
|
|
if (page_name.match(/\.test\.(t|j)sx?/)) {
|
|
continue;
|
|
}
|
|
if (page_name.match(/\.server\.tsx?/) && !include_server) {
|
|
continue;
|
|
}
|
|
const page_stat = statSync(full_page_path);
|
|
if (page_stat.isDirectory()) {
|
|
if (checkExcludedPatterns({ path: full_page_path }))
|
|
continue;
|
|
const new_page_files = grabPageDirRecursively({
|
|
page_dir: full_page_path,
|
|
pages_root,
|
|
include_server,
|
|
});
|
|
pages_files.push(...new_page_files);
|
|
}
|
|
else if (page.match(/\.(ts|js)x?$/)) {
|
|
const pages_file = grabPageFileObject({
|
|
file_path: full_page_path,
|
|
pages_root,
|
|
});
|
|
if (pages_file) {
|
|
pages_files.push(pages_file);
|
|
}
|
|
}
|
|
}
|
|
return pages_files.sort((a, b) => {
|
|
if (a.url_path === "/index")
|
|
return -1;
|
|
if (b.url_path === "/index")
|
|
return 1;
|
|
return 0;
|
|
});
|
|
}
|
|
/**
|
|
* The URL path is the file's path relative to the pages root, so a nested
|
|
* directory that happens to be called `pages` (e.g. `src/pages/admin/pages/
|
|
* index.tsx` -> `/admin/pages/index`) is kept, not treated as the root.
|
|
*/
|
|
export function grabPageFileObject({ file_path, pages_root, }) {
|
|
const relative_path = path
|
|
.relative(pages_root, file_path)
|
|
.split(path.sep)
|
|
.join("/");
|
|
if (!relative_path || relative_path.startsWith("../"))
|
|
return;
|
|
const url_path = "/" + relative_path.replace(/\.(ts|js)x?$/, "");
|
|
const file_name = url_path.split("/").pop();
|
|
if (!file_name)
|
|
return;
|
|
return {
|
|
local_path: file_path,
|
|
url_path,
|
|
file_name,
|
|
};
|
|
}
|