Skip to content

StaticRouter skips middleware #13307

@jrmyio

Description

@jrmyio

I'm using React Router as a...

library

Reproduction

I am trying the unstable middleware with a StaticRouter. Middleware is not called as can be seen with the following example:

import ReactDOMServer from 'react-dom/server';
import { createStaticHandler } from 'react-router';

import { createStaticRouter, StaticRouterProvider, type RouteObject } from 'react-router';

declare module 'react-router' {
    interface Future {
        unstable_middleware: true;
    }
}

const routes: RouteObject[] = [
    {
        path: '*',
        element: <div>abc</div>,
        unstable_middleware: [
            async () => {
                // NOT called succesfully
                console.log('inside middleware');
            },
        ],
        loader: async () => {
            // called succesfully
            console.log('inside loader');
            return {};
        },
    },
];

let { query } = createStaticHandler(routes);

const context = await query(new Request('https://localhost'));

if (context instanceof Response) {
    console.log('Response', context);
    throw context;
}

const router = createStaticRouter(routes, context, {
    future: {
        unstable_middleware: true,
    },
});
const app = <StaticRouterProvider context={context} router={router} />;

const html = ReactDOMServer.renderToString(app);

console.log({
    html,
});

Here is the sandbox where you can see the Middleware isnt called for StaticRouter:
https://codesandbox.io/p/sandbox/static-router-middleware-cvj4qh

System Info

n/a

Used Package Manager

npm

Expected Behavior

Middleware should be applied even when using the StaticRouter.

Actual Behavior

Middleware is NOT called when using StaticRouter.

The runMiddlewarePipeline is skipped because unstable_respond does not apply middleware when it is undefined:

if (respond && matches.some((m) => m.route.unstable_middleware)) {

I tried passing ctx => ctx to unstable_respond but this will throw an error because the result has to be a Response:

invariant(isResponse(response), "Expected a response in query()");

Temporary work around
Eventually I was able to hack around this issue by:

let { query } = createStaticHandler(routes);

let context = await query(new Request("https://localhost"), {
  requestContext: new Map([
    [ContainerContext, { testMessage: "123" }],
  ]),
  unstable_respond: async (ctx) => {
    const response = new Response();
    (response as any).staticHandlerContext = ctx;

    return response;
  },
});

if (context instanceof Response && "staticHandlerContext" in context) {
  context = context.staticHandlerContext as StaticHandlerContext;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions