Skip to content

Commit fc90407

Browse files
committed
Add instrumentRoute APIs for server side
1 parent fa563be commit fc90407

File tree

5 files changed

+239
-65
lines changed

5 files changed

+239
-65
lines changed

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { DataRouteMatch, RouteObject } from "../context";
1+
import type { DataRouteMatch, DataRouteObject, RouteObject } from "../context";
22
import type { History, Location, Path, To } from "./history";
33
import {
44
Action as NavigationType,
@@ -3538,6 +3538,9 @@ export function createRouter(init: RouterInit): Router {
35383538
export interface CreateStaticHandlerOptions {
35393539
basename?: string;
35403540
mapRouteProperties?: MapRoutePropertiesFunction;
3541+
unstable_instrumentRoute?: (
3542+
r: AgnosticDataRouteObject,
3543+
) => AgnosticDataRouteObject;
35413544
future?: {};
35423545
}
35433546

@@ -3552,8 +3555,24 @@ export function createStaticHandler(
35523555

35533556
let manifest: RouteManifest = {};
35543557
let basename = (opts ? opts.basename : null) || "/";
3555-
let mapRouteProperties =
3558+
let _mapRouteProperties =
35563559
opts?.mapRouteProperties || defaultMapRouteProperties;
3560+
let mapRouteProperties = _mapRouteProperties;
3561+
3562+
// Leverage the existing mapRouteProperties logic to execute instrumentRoute
3563+
// (if it exists) on all routes in the application
3564+
if (opts?.unstable_instrumentRoute) {
3565+
let instrument = opts?.unstable_instrumentRoute;
3566+
// TODO: Clean up these types
3567+
mapRouteProperties = (r: AgnosticRouteObject) => {
3568+
return instrument({
3569+
...r,
3570+
..._mapRouteProperties(r),
3571+
} as AgnosticDataRouteObject) as AgnosticDataRouteObject & {
3572+
hasErrorBoundary: boolean;
3573+
};
3574+
};
3575+
}
35573576

35583577
let dataRoutes = convertRoutesToDataRoutes(
35593578
routes,

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {
22
ActionFunctionArgs,
3+
AgnosticDataRouteObject,
34
LoaderFunctionArgs,
45
RouterContextProvider,
56
} from "../router/utils";
@@ -12,6 +13,7 @@ import type {
1213
import type { ServerRouteManifest } from "./routes";
1314
import type { AppLoadContext } from "./data";
1415
import type { MiddlewareEnabled } from "../types/future";
16+
import type { RequestHandler } from "./server";
1517

1618
type OptionalCriticalCss = CriticalCss | undefined;
1719

@@ -59,9 +61,9 @@ export interface HandleDataRequestFunction {
5961
(
6062
response: Response,
6163
args: {
62-
request: LoaderFunctionArgs["request"];
63-
context: LoaderFunctionArgs["context"];
64-
params: LoaderFunctionArgs["params"];
64+
request: LoaderFunctionArgs["request"] | ActionFunctionArgs["request"];
65+
context: LoaderFunctionArgs["context"] | ActionFunctionArgs["context"];
66+
params: LoaderFunctionArgs["params"] | ActionFunctionArgs["params"];
6567
},
6668
): Promise<Response> | Response;
6769
}
@@ -70,9 +72,9 @@ export interface HandleErrorFunction {
7072
(
7173
error: unknown,
7274
args: {
73-
request: LoaderFunctionArgs["request"];
74-
context: LoaderFunctionArgs["context"];
75-
params: LoaderFunctionArgs["params"];
75+
request: LoaderFunctionArgs["request"] | ActionFunctionArgs["request"];
76+
context: LoaderFunctionArgs["context"] | ActionFunctionArgs["context"];
77+
params: LoaderFunctionArgs["params"] | ActionFunctionArgs["params"];
7678
},
7779
): void;
7880
}
@@ -85,5 +87,9 @@ export interface ServerEntryModule {
8587
default: HandleDocumentRequestFunction;
8688
handleDataRequest?: HandleDataRequestFunction;
8789
handleError?: HandleErrorFunction;
90+
unstable_instrumentHandler?: (handler: RequestHandler) => RequestHandler;
91+
unstable_instrumentRoute?: (
92+
route: AgnosticDataRouteObject,
93+
) => AgnosticDataRouteObject;
8894
streamTimeout?: number;
8995
}

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

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ function derive(build: ServerBuild, mode?: string) {
5555
let serverMode = isServerMode(mode) ? mode : ServerMode.Production;
5656
let staticHandler = createStaticHandler(dataRoutes, {
5757
basename: build.basename,
58+
unstable_instrumentRoute: build.entry.module.unstable_instrumentRoute,
5859
});
5960

6061
let errorHandler =
@@ -67,42 +68,8 @@ function derive(build: ServerBuild, mode?: string) {
6768
);
6869
}
6970
});
70-
return {
71-
routes,
72-
dataRoutes,
73-
serverMode,
74-
staticHandler,
75-
errorHandler,
76-
};
77-
}
78-
79-
export const createRequestHandler: CreateRequestHandlerFunction = (
80-
build,
81-
mode,
82-
) => {
83-
let _build: ServerBuild;
84-
let routes: ServerRoute[];
85-
let serverMode: ServerMode;
86-
let staticHandler: StaticHandler;
87-
let errorHandler: HandleErrorFunction;
88-
89-
return async function requestHandler(request, initialContext) {
90-
_build = typeof build === "function" ? await build() : build;
91-
92-
if (typeof build === "function") {
93-
let derived = derive(_build, mode);
94-
routes = derived.routes;
95-
serverMode = derived.serverMode;
96-
staticHandler = derived.staticHandler;
97-
errorHandler = derived.errorHandler;
98-
} else if (!routes || !serverMode || !staticHandler || !errorHandler) {
99-
let derived = derive(_build, mode);
100-
routes = derived.routes;
101-
serverMode = derived.serverMode;
102-
staticHandler = derived.staticHandler;
103-
errorHandler = derived.errorHandler;
104-
}
10571

72+
let requestHandler: RequestHandler = async (request, initialContext) => {
10673
let params: RouteMatch<ServerRoute>["params"] = {};
10774
let loadContext: AppLoadContext | RouterContextProvider;
10875

@@ -118,7 +85,7 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
11885
});
11986
};
12087

121-
if (_build.future.v8_middleware) {
88+
if (build.future.v8_middleware) {
12289
if (
12390
initialContext &&
12491
!(initialContext instanceof RouterContextProvider)
@@ -138,7 +105,7 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
138105

139106
let url = new URL(request.url);
140107

141-
let normalizedBasename = _build.basename || "/";
108+
let normalizedBasename = build.basename || "/";
142109
let normalizedPath = url.pathname;
143110
if (stripBasename(normalizedPath, normalizedBasename) === "/_root.data") {
144111
normalizedPath = normalizedBasename;
@@ -158,7 +125,7 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
158125

159126
// When runtime SSR is disabled, make our dev server behave like the deployed
160127
// pre-rendered site would
161-
if (!_build.ssr) {
128+
if (!build.ssr) {
162129
// Decode the URL path before checking against the prerender config
163130
let decodedPath = decodeURI(normalizedPath);
164131

@@ -188,12 +155,12 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
188155

189156
// When SSR is disabled this, file can only ever run during dev because we
190157
// delete the server build at the end of the build
191-
if (_build.prerender.length === 0) {
158+
if (build.prerender.length === 0) {
192159
// ssr:false and no prerender config indicates "SPA Mode"
193160
isSpaMode = true;
194161
} else if (
195-
!_build.prerender.includes(decodedPath) &&
196-
!_build.prerender.includes(decodedPath + "/")
162+
!build.prerender.includes(decodedPath) &&
163+
!build.prerender.includes(decodedPath + "/")
197164
) {
198165
if (url.pathname.endsWith(".data")) {
199166
// 404 on non-pre-rendered `.data` requests
@@ -222,20 +189,20 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
222189

223190
// Manifest request for fog of war
224191
let manifestUrl = getManifestPath(
225-
_build.routeDiscovery.manifestPath,
192+
build.routeDiscovery.manifestPath,
226193
normalizedBasename,
227194
);
228195
if (url.pathname === manifestUrl) {
229196
try {
230-
let res = await handleManifestRequest(_build, routes, url);
197+
let res = await handleManifestRequest(build, routes, url);
231198
return res;
232199
} catch (e) {
233200
handleError(e);
234201
return new Response("Unknown Server Error", { status: 500 });
235202
}
236203
}
237204

238-
let matches = matchServerRoutes(routes, normalizedPath, _build.basename);
205+
let matches = matchServerRoutes(routes, normalizedPath, build.basename);
239206
if (matches && matches.length > 0) {
240207
Object.assign(params, matches[0].params);
241208
}
@@ -248,12 +215,12 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
248215
let singleFetchMatches = matchServerRoutes(
249216
routes,
250217
handlerUrl.pathname,
251-
_build.basename,
218+
build.basename,
252219
);
253220

254221
response = await handleSingleFetchRequest(
255222
serverMode,
256-
_build,
223+
build,
257224
staticHandler,
258225
request,
259226
handlerUrl,
@@ -265,13 +232,13 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
265232
response = generateSingleFetchRedirectResponse(
266233
response,
267234
request,
268-
_build,
235+
build,
269236
serverMode,
270237
);
271238
}
272239

273-
if (_build.entry.module.handleDataRequest) {
274-
response = await _build.entry.module.handleDataRequest(response, {
240+
if (build.entry.module.handleDataRequest) {
241+
response = await build.entry.module.handleDataRequest(response, {
275242
context: loadContext,
276243
params: singleFetchMatches ? singleFetchMatches[0].params : {},
277244
request,
@@ -281,7 +248,7 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
281248
response = generateSingleFetchRedirectResponse(
282249
response,
283250
request,
284-
_build,
251+
build,
285252
serverMode,
286253
);
287254
}
@@ -294,7 +261,7 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
294261
) {
295262
response = await handleResourceRequest(
296263
serverMode,
297-
_build,
264+
build,
298265
staticHandler,
299266
matches.slice(-1)[0].route.id,
300267
request,
@@ -305,8 +272,8 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
305272
let { pathname } = url;
306273

307274
let criticalCss: CriticalCss | undefined = undefined;
308-
if (_build.unstable_getCriticalCss) {
309-
criticalCss = await _build.unstable_getCriticalCss({ pathname });
275+
if (build.unstable_getCriticalCss) {
276+
criticalCss = await build.unstable_getCriticalCss({ pathname });
310277
} else if (
311278
mode === ServerMode.Development &&
312279
getDevServerHooks()?.getCriticalCss
@@ -316,7 +283,7 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
316283

317284
response = await handleDocumentRequest(
318285
serverMode,
319-
_build,
286+
build,
320287
staticHandler,
321288
request,
322289
loadContext,
@@ -336,6 +303,60 @@ export const createRequestHandler: CreateRequestHandlerFunction = (
336303

337304
return response;
338305
};
306+
307+
if (build.entry.module.unstable_instrumentHandler) {
308+
requestHandler =
309+
build.entry.module.unstable_instrumentHandler(requestHandler);
310+
}
311+
312+
return {
313+
routes,
314+
dataRoutes,
315+
serverMode,
316+
staticHandler,
317+
errorHandler,
318+
requestHandler,
319+
};
320+
}
321+
322+
export const createRequestHandler: CreateRequestHandlerFunction = (
323+
build,
324+
mode,
325+
) => {
326+
let _build: ServerBuild;
327+
let routes: ServerRoute[];
328+
let serverMode: ServerMode;
329+
let staticHandler: StaticHandler;
330+
let errorHandler: HandleErrorFunction;
331+
let _requestHandler: RequestHandler;
332+
333+
return async function requestHandler(request, initialContext) {
334+
_build = typeof build === "function" ? await build() : build;
335+
336+
if (typeof build === "function") {
337+
let derived = derive(_build, mode);
338+
routes = derived.routes;
339+
serverMode = derived.serverMode;
340+
staticHandler = derived.staticHandler;
341+
errorHandler = derived.errorHandler;
342+
_requestHandler = derived.requestHandler;
343+
} else if (
344+
!routes ||
345+
!serverMode ||
346+
!staticHandler ||
347+
!errorHandler ||
348+
!_requestHandler
349+
) {
350+
let derived = derive(_build, mode);
351+
routes = derived.routes;
352+
serverMode = derived.serverMode;
353+
staticHandler = derived.staticHandler;
354+
errorHandler = derived.errorHandler;
355+
_requestHandler = derived.requestHandler;
356+
}
357+
358+
return _requestHandler(request, initialContext);
359+
};
339360
};
340361

341362
async function handleManifestRequest(

0 commit comments

Comments
 (0)