Search code examples
javascriptreactjsexpressreact-router-domvite

React/Vite using createBrowserRouter hosted in a subdirectory does not work without a trailing slash


I'm using React/Vite/Express to build an app that is hosted in a subdirectory. As an example, let's say it's hosted at: https://example.com/my/app/

In my Vite config, I've set base to ./

export default defineConfig({
    base: './',
    build: {
        outDir: './public/build',
    },
    plugins: [react()],
    css: {
        preprocessorOptions: {
            scss: {
                implementation: sass,
            },
        },
    }
});

I am also using react-router-dom. Here is my config for createBrowserRouter:

export const router = createBrowserRouter(
    [
        {
            path: '/',
            element: <App />,
            errorElement: <Error />,
            children: [
                {
                    path: '/',
                    element: <Home />,
                },
                {
                    path: '/test1',
                    element: <Test1 />,
                },
                {
                    path: '/test2',
                    element: <Test2 />,
                },
            ],
        },
    ],
    {
        basename: '/my/app',
    },
);

When I visit the page with the /, it works just fine, e.g. https://example.com/my/app/

However, if I remove the trailing app using https://example.com/my/app, Vite thinks that the base is the parent directory /my/ and uses that as the root. The React JS and CSS then throw 404s.

Is there a way in Vite to fix this without hard-coding the full path as base, or is this something I need to fix on the server to redirect to the URL with the trailing slash?

I'd rather not hard code the base because it will change depending on environments. If that's the best-practice approach, though, I'll go with that solution.

I expected that the application would assume that my/app was a directory. Instead, it seem to be using my/ as the directory. I've tried changing base to . and to an empty string, with no luck.


Solution

  • The issue not only related to vite configuration, but with the react-router configuration. Try this:

    export const router = createBrowserRouter(
        [
            {
                element: <App />,
                errorElement: <Error />,
                children: [
                    {
                        index: true,
                        element: <Home />,
                    },
                    {
                        path: '/test1',
                        element: <Test1 />,
                    },
                    {
                        path: '/test2',
                        element: <Test2 />,
                    },
                ],
            },
        ],
        {
            basename: '/my/app',
        },
    );
    
    1. basename value should have leading slash and no trailing slash: '/my/app' - you have already corrected this in your code snippet
    2. for index routes (<Home />in our case) set index: true instead of path: '/'
    3. get rid of path for <App> route

    vite config:

    export default defineConfig({
        base: '/my/app/',
        ...
    });