node.jsvitekongremix.run

Remix Vite base not reading asset or public path correctly in deep subpaths url with Kong Gateway


Hello brothers and sisters,

I'm currently exploring how to deploy Remix Vite to my server and just found out that Vite "base" config have 1 major problem (in my case). So I've been reading that base option can be a relative ("", "./") or specific like /remix/.

So in production server, my Remix app is deployed to docker, let's say its IP is 10.20.30.40:3000, and have it mapped to Kong Gateway with domain mydomain.com/myapp

Here are the two cases:

  1. Using /remix/ as base:
    Local: all my routes in localhost have /remix/<routes> and /remix/<assets> working perfectly even when I visit deep subpath like localhost:4000/remix/dashboard/users/internal, all assets and routes have no problem.
    Server: the routes work fine like mydomain.com/myapp/dashboard, or mydomain.com/myapp/dashboard/users/internal, but the assets paths is not read correctly, the correct assets path for this gateway becomes mydomain.com/myapp/myapp/assets/<assetfile> (doubles the basepath). Because path from Kong Gateway and base from Vite are combined.
  2. Using "" or "./" as base:
    Both Local and Server: visiting index page like localhost:3000/dashboard or mydomain.com/myapp/dashboard work fine, route and assets (like tailwind) are read correctly, url was normal localhost:3000/assets/<assetfile> or mydomain.com/myapp/assets/<assetfile>. But when I visit deep subpath like localhost:3000/dashboard/users or mydomain.com/myapp/dashboard/users the asset and other url don't work as they become localhost:3000/dashboard/assets/<assetfile> or mydomain.com/myapp/dashboard/assets/<assetfile> which is not found.

Is there anything I'm missing? Here's the config I'm using:

export default defineConfig({
  base: "/remix/", // or base: "",
  ...
  other configs
});

Remix version : 2.8.1
Vite version : 5.0.1


I've tried using domain as base, edit the build.assetsDir but nothing work.

There's a temporary working solution like setting the path for Kong as / so when I visit mydomain.com it points to Remix deployed at 10.20.30.40:3000, with base as /remix/ everything works fine visiting myadomain.com/remix/* but that means mydomain.com is explicitly used by my Remix app even with no index page at its root / (got 404 when visiting mydomain.com), which also interferes with other apps mapped to mydomain.com.

Target I want to achieve is like below,
mydomain.com -> empty map or other app
mydomain.com/app1 -> 10.20.30.40:3000
mydomain.com/app2 -> 10.20.30.50:3000

If I use current temporary solution, it will be like:
mydomain.com/ -> 10.20.30.40:3000 -> base /remix/
mydomain.com/ -> 10.20.30.50:3000 -> base /others/

Visiting mydomain.com/remix/ points me to app1, visiting mydomain.com/others points me to app2. But when I visit mydomain.com only, Kong Gateway confused which of index / root to serve (app1 or app2).


Solution

  • Remix allows you to mount your app on a different path than /. You specify this in the remix() plugin.

    https://remix.run/docs/en/main/file-conventions/vite-config#basename

    However, it still assumes the server still serves files from the root, so the default assets are served from /assets.

    You change this via the base Vite config. This should only apply to production, not the Vite dev server.

    https://vitejs.dev/config/shared-options.html#base

    Here's the updated config that should serve your app correctly.

    import { vitePlugin as remix } from "@remix-run/dev";
    import { installGlobals } from "@remix-run/node";
    import { defineConfig } from "vite";
    import tsconfigPaths from "vite-tsconfig-paths";
    
    installGlobals();
    
    export default defineConfig({
      server: {
        port: 3000,
      },
      // set the base for assets to /remix/ in production
      base: process.env.NODE_ENV === "production" ? "/remix/" : undefined,
      plugins: [
        remix({
          basename: "/remix",
        }),
        tsconfigPaths(),
      ],
    });
    

    Here is the nginx.conf file I used:

    server {
      listen 8000;
    
      location /remix {
        proxy_pass http://host.docker.internal:3000/remix;
      }
      location / {
        proxy_pass http://host.docker.internal:3001/;
      }
    
      error_page 500 502 503 504 /50x.html;
      location = /50x.html {
        root /usr/share/nginx/html;
      }
    }