Preventing React Router Server Code Bundling in Vite

Written by on .

remix
react-router
fastify

  1. vite.config.ts
    1. react-router.config.ts

      Glama is built entirely on top of React Router v7. I love it, but debugging certain issues has been a pain.

      Namely, whenever there is an error and the stack trace points to the server bundle, it usually points to a line with thousands of characters of code on a single line. This is because React Router uses Vite/Rollup to bundle the client and server code.

      So I spent several hours trying to figure out how to stop the Vite from bundling the React Routers server code.

      Here is how I did it.

      vite.config.ts

      You will need to update vite.config.ts such that you can modify the configuration depending on whether it is a client or server build.

      export default defineConfig(({ isSsrBuild }) => {});

      If isSsrBuild is true, then the configuration will be for a server build. Otherwise, it will be for a client build.

      Here is how you adjust the rollupOptions to stop bundling the server code from being bundled.

      rollupOptions: { output: isSsrBuild ? { // Preserve the original scripts without bundling them. preserveModules: true, } : {}, },

      After this, you are already going to get a server build that retains the original scripts.

      However, every script will have a name like indexX.js where X is a number.

      This is because React Router also overrides entryFileNames to be index.js. Luckily, it also provides an easy way to override it.

      react-router.config.ts

      The last piece is to add serverBuildFile to the react-router.config.ts file.

      import { type Config } from '@react-router/dev/config'; export default { serverBuildFile: '[name].js', serverModuleFormat: 'esm', ssr: true, } satisfies Config;

      When set to [name].js, Vite will retain the original name of the script.

      ... and that's it! You should now be able to have a production build that does not bundle the server code.

      Written by Frank Fiegel (@punkpeye)