Skip to content

Commit 67bc5f1

Browse files
committed
Merge branch 'v8' into brophdawg11/v8-deps
2 parents 7391b91 + ddca616 commit 67bc5f1

9 files changed

Lines changed: 2344 additions & 3855 deletions

File tree

packages/react-router-dev/config/config.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -706,12 +706,10 @@ async function resolveConfig({
706706
"The `future.v8_viteEnvironmentApi` flag has been removed because Vite Environment API usage is now always enabled",
707707
);
708708
}
709-
if ("unstable_trailingSlashAwareDataRequests" in futureConfig) {
710-
return err(
711-
"The `future.unstable_trailingSlashAwareDataRequests` flag has been removed because trailing slash-aware data requests are now the default behavior",
712-
);
713-
}
714-
if ("v8_trailingSlashAwareDataRequests" in futureConfig) {
709+
if (
710+
"unstable_trailingSlashAwareDataRequests" in futureConfig ||
711+
"v8_trailingSlashAwareDataRequests" in futureConfig
712+
) {
715713
return err(
716714
"The `future.v8_trailingSlashAwareDataRequests` flag has been removed because trailing slash-aware data requests are now the default behavior",
717715
);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Upgrade `express` from `4.21.2` to `5.2.1`

packages/react-router-serve/cli.ts

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { createRequestHandler } from "@react-router/express";
88
import { createRequestListener } from "@remix-run/node-fetch-server";
99
import compression from "compression";
1010
import express from "express";
11+
import type { RequestHandler as ExpressRequestHandler } from "express";
1112
import morgan from "morgan";
1213
import sourceMapSupport from "source-map-support";
1314
import getPort from "get-port";
@@ -52,12 +53,12 @@ type NormalizedBuild = {
5253
function isRSCServerBuild(build: unknown): build is RSCServerBuildModule {
5354
return Boolean(
5455
typeof build === "object" &&
55-
build &&
56-
"default" in build &&
57-
typeof build.default === "object" &&
58-
build.default &&
59-
"fetch" in build.default &&
60-
typeof build.default.fetch === "function",
56+
build &&
57+
"default" in build &&
58+
typeof build.default === "object" &&
59+
build.default &&
60+
"fetch" in build.default &&
61+
typeof build.default.fetch === "function",
6162
);
6263
}
6364

@@ -68,6 +69,20 @@ function parseNumber(raw?: string) {
6869
return maybe;
6970
}
7071

72+
function getExpressPath(publicPath: string) {
73+
// Vite allows `base` to be an absolute URL, but Express route paths must be
74+
// pathnames. Strip any origin before mounting static asset middleware.
75+
let pathname: string;
76+
77+
try {
78+
pathname = new URL(publicPath).pathname;
79+
} catch {
80+
pathname = publicPath;
81+
}
82+
83+
return pathname.startsWith("/") ? pathname : `/${pathname}`;
84+
}
85+
7186
async function run() {
7287
let port = parseNumber(process.env.PORT) ?? (await getPort({ port: 3000 }));
7388

@@ -103,7 +118,10 @@ async function run() {
103118
build = buildModule as ServerBuild;
104119
}
105120

106-
let onListen = () => {
121+
let onListen = (error: unknown) => {
122+
if (error) {
123+
throw error;
124+
}
107125
let address =
108126
process.env.HOST ||
109127
Object.values(os.networkInterfaces())
@@ -124,29 +142,34 @@ async function run() {
124142
app.disable("x-powered-by");
125143

126144
if (!isRSCBuild) {
127-
app.use(compression());
145+
// `compression` may resolve to Express 4 types from transitive deps while
146+
// `react-router-serve` uses Express 5, but the runtime middleware signature
147+
// is compatible.
148+
app.use(compression() as unknown as ExpressRequestHandler);
128149
}
129150

151+
let expressPublicPath = getExpressPath(build.publicPath);
152+
130153
app.use(
131-
path.posix.join(build.publicPath, "assets"),
154+
path.posix.join(expressPublicPath, "assets"),
132155
express.static(path.join(build.assetsBuildDirectory, "assets"), {
133156
immutable: true,
134157
maxAge: "1y",
135158
}),
136159
);
137-
app.use(build.publicPath, express.static(build.assetsBuildDirectory));
160+
app.use(expressPublicPath, express.static(build.assetsBuildDirectory));
138161
app.use(express.static("public", { maxAge: "1h" }));
139162
app.use(morgan("tiny"));
140163

141164
if (build.fetch) {
142-
app.all("*", createRequestListener(build.fetch));
165+
app.all("/{*splat}", createRequestListener(build.fetch));
143166
} else {
144167
app.all(
145-
"*",
168+
"/{*splat}",
146169
createRequestHandler({
147170
build: buildModule,
148171
mode: process.env.NODE_ENV,
149-
}),
172+
}) as unknown as ExpressRequestHandler,
150173
);
151174
}
152175

packages/react-router-serve/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"@react-router/node": "workspace:*",
4343
"@remix-run/node-fetch-server": "^0.13.3",
4444
"compression": "^1.8.1",
45-
"express": "^4.19.2",
45+
"express": "^5.2.1",
4646
"get-port": "7.2.0",
4747
"morgan": "^1.10.1",
4848
"source-map-support": "^0.5.21"
@@ -52,7 +52,7 @@
5252
},
5353
"devDependencies": {
5454
"@types/compression": "^1.8.1",
55-
"@types/express": "^4.17.9",
55+
"@types/express": "^5.0.6",
5656
"@types/morgan": "^1.9.10",
5757
"@types/node": "^22.19.19",
5858
"@types/source-map-support": "^0.5.6",

packages/react-router/lib/rsc/server.rsc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ async function generateResourceResponse(
747747
return generateErrorResponse(error);
748748
}
749749
},
750-
normalizePath: (r) => getNormalizedPath(r),
750+
normalizePath: (r) => getNormalizedPath(r, basename),
751751
});
752752
return response;
753753
} catch (error) {
@@ -837,7 +837,7 @@ async function generateRenderResponse(
837837
...(routeIdsToLoad
838838
? { filterMatchesToLoad: (m) => routeIdsToLoad!.includes(m.route.id) }
839839
: {}),
840-
normalizePath: (r) => getNormalizedPath(r),
840+
normalizePath: (r) => getNormalizedPath(r, basename),
841841
async generateMiddlewareResponse(query) {
842842
// If this is an RSC server action, process that and then call query as a
843843
// revalidation. If this is a RR Form/Fetcher submission,

packages/react-router/lib/server-runtime/server.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ function derive(build: ServerBuild, mode?: string) {
104104
loadContext = initialContext || new RouterContextProvider();
105105

106106
let requestUrl = new URL(request.url);
107-
let normalizedPathname = getNormalizedPath(request).pathname;
107+
let normalizedPathname = getNormalizedPath(
108+
request,
109+
build.basename,
110+
).pathname;
108111

109112
let isSpaMode =
110113
getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
@@ -491,7 +494,7 @@ async function handleDocumentRequest(
491494
return new Response(null, { status: 500 });
492495
}
493496
},
494-
normalizePath: (r) => getNormalizedPath(r),
497+
normalizePath: (r) => getNormalizedPath(r, build.basename),
495498
});
496499

497500
if (!isResponse(result)) {
@@ -667,7 +670,7 @@ async function handleResourceRequest(
667670
return handleQueryRouteError(error);
668671
}
669672
},
670-
normalizePath: (r) => getNormalizedPath(r),
673+
normalizePath: (r) => getNormalizedPath(r, build.basename),
671674
});
672675

673676
return handleQueryRouteResult(result);

packages/react-router/lib/server-runtime/single-fetch.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function singleFetchAction(
6868
return handleQueryError(error);
6969
}
7070
},
71-
normalizePath: (r) => getNormalizedPath(r),
71+
normalizePath: (r) => getNormalizedPath(r, build.basename),
7272
});
7373

7474
return handleQueryResult(result);
@@ -151,7 +151,7 @@ export async function singleFetchLoaders(
151151
return handleQueryError(error);
152152
}
153153
},
154-
normalizePath: (r) => getNormalizedPath(r),
154+
normalizePath: (r) => getNormalizedPath(r, build.basename),
155155
});
156156

157157
return handleQueryResult(result);

packages/react-router/lib/server-runtime/urls.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import type { Path } from "../router/history";
2+
import { stripBasename } from "../router/utils";
23

3-
export function getNormalizedPath(request: Request): Path {
4+
export function getNormalizedPath(
5+
request: Request,
6+
basename: string | undefined,
7+
): Path {
8+
basename = basename || "/";
49
let url = new URL(request.url);
510
let pathname = url.pathname;
611

@@ -12,6 +17,10 @@ export function getNormalizedPath(request: Request): Path {
1217
pathname = pathname.replace(/\.data$/, "");
1318
}
1419

20+
if (stripBasename(pathname, basename) !== "/" && pathname.endsWith("/")) {
21+
pathname = pathname.slice(0, -1);
22+
}
23+
1524
// Strip _routes param
1625
let searchParams = new URLSearchParams(url.search);
1726
searchParams.delete("_routes");

0 commit comments

Comments
 (0)