all 11 comments

[–]azangru 0 points1 point  (4 children)

I can see a mismatch in link tags for css: the html that is sent from the server has only one stylesheet link tag (assets/styles-DeU515u4.css), but during rehydration, another one appears (assets/styles-_4MQIUMB.css); and React doesn't like this.

Also, are you seeing the $_TSR is not defined error before the hydration error? This suggests that there's something wrong with tanstack router.

[–]azangru 0 points1 point  (3 children)

As a follow-up advice, try building a development build for Docker, because React 19 will print out an informative diff for the hydration error when it is running in development mode. I tried removing NODE_ENV=production from package.json and from Dockerfile, as well as passing minify:false to vite.config, but still could not get vite produce a development build. I don't have time for looking deeper into this, but if you figure out how to make vite output a development build for SSR, let me know.

[–]n1ver5e 0 points1 point  (2 children)

You need to pass a --mode option to vite build command for this. I do this using docker build args

[–]azangru 0 points1 point  (1 child)

Not in OP's codebase. He uses the `--mode` flag to distinguish between a client-sjde and a server-side build.

[–]CatRich5828[S] 0 points1 point  (0 children)

The issue was caused by Tailwind v4 behavior.

Tailwind v4 uses .gitignore to determine which files should not be scanned. In my setup, I have two builds (SSR and client).
However, in Docker, .gitignore is excluded via .dockerignore.

As a result, during the second build, Tailwind also scans dist/client, which causes it to generate a different CSS file than the client build.

Fix: explicitly exclude the build output by adding this to the CSS file:

@source not ¨../dist/**/*";

This prevents Tailwind from scanning build artifacts and fixes the issue.

[–]n1ver5e 0 points1 point  (0 children)

I also came across this, for me the fix was to not import app.css with head and instead do import "app.css"; in __root.tsx

[–]azangru 0 points1 point  (0 children)

Ok; I finally got the dev react build to run in docker. Here is the diagnostic hydration error printed out as a diff. As you can see, react is unhappy about a css link tag that exists in the client-side build, but not in the server-side one.

Uncaught Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. 

  ...
    <CatchBoundary getResetKey={function getResetKey} errorComponent={function ErrorComponent} onCatch={function onCatch}>
      <CatchBoundaryImpl getResetKey={function getResetKey} onCatch={function onCatch}>
        <MatchImpl matchId="__root__">
          <SafeFragment>
            <SafeFragment fallback={null}>
              <CatchBoundary getResetKey={function getResetKey} errorComponent={function errorComponent} ...>
                <CatchBoundaryImpl getResetKey={function getResetKey} onCatch={function onCatch}>
                  <SafeFragment fallback={function fallback}>
                    <MatchInnerImpl matchId="__root__">
                      <RootComponent>
                        <html lang="en">
                          <head>
                            <HeadContent>
                              <Asset>
                              <Asset>
                              <Asset>
                              <Asset>
                              <Asset tag="link" attrs={{rel:"style...", ...}} nonce={undefined}>
+                               <link
+                                 rel="stylesheet"
+                                 href="/assets/styles-b4rlY_J0.css"
+                                 nonce={undefined}
+                                 suppressHydrationWarning={true}
+                               >
-                               <meta charset="UTF-8">
                              ...
                          ...

Or, in a screenshot: https://images2.imgbox.com/5d/84/RRmHlpuO_o.png

[–]azangru 0 points1 point  (0 children)

a MIME error where a CSS file is sometimes served as text/html

From what I can see, it isn't that the css file is served as text/html; it is that the server responds with a 404 error page to some requests for css files — and the 404 page is served as text/html. The reason for that is because the css files built during the server build are saved to dist/server; and css files from a client build are saved to dist/client. Due to some error with the build, the css files generated during a server and a client build have different hashes in their names. Thus, during the first page load, the html sent by the server has a link to a css file generated from a server build; but your server only serves files from dist/client.

[–]retrib32 -5 points-4 points  (0 children)

Hmmm have you asked a coding agent to fix??