remix-run / remix

Build Better Websites. Create modern, resilient user experiences with web fundamentals.
https://remix.run
MIT License
29.93k stars 2.52k forks source link

[Bug]: Style tags disappear from Head during Error/Catch Boundary #1136

Closed hgeldenhuys closed 1 year ago

hgeldenhuys commented 2 years ago

Which Remix packages are impacted?

What version of Remix are you using?

1.1.1

What version of Node are you using? Minimum supported version is 14.

16.13.0

Steps to Reproduce

Inject style tags into header in entry.server.tsx during markup generation. Example:

let markup = renderToString(
    <RemixServer context={remixContext} url={request.url} />
  );

  const html = markup.replace(
    "<head>",
    `<head>${getSSRStyles(markup, server)}`
  );

  responseHeaders.set("Content-Type", "text/html");

  return new Response("<!DOCTYPE html>" + html, {
    status: responseStatusCode,
    headers: responseHeaders,
  });

Expected Behavior

The style tags should stay intact during 404, or at least after 404, refetch the HTML from server.entry.

I'm guessing because Remix only generates links an meta tags in head dynamically, things like style and base will get overridden when Error boundary generates a new document. This is unfortunate, as initial load will contain Style tags that prevent the page from loading janky and will be lost during errors.

This prevents us from using major UI libraries like Material UI and Mantine, which generate dynamic styles based on frameworks like emotion. The CatchBoundary/Error should re-render from server-side, not client-side (rehydrate head tag from server.entry)

Actual Behavior

Error/Catch boundaries removes everything in Head tag, not just the dynamically generated head-elements provided by the route, meaning style tags get removed, that are "global" styles.

kevinbailey25 commented 1 year ago

@kevinbailey25 have you tried solutions like Vanilla Extract? would you recommend it if it's a project that is in the early stage where migrating to it would not hurt?

I have not personally used Vanilla Extract. Based off of everything I've seen and read, I'd recommend it. Just about any css framework/tool that gives you a standard css file that you can link to is recommended by me. As @machour mentioned above, there is an example for remix as well.

JAD3N commented 1 year ago

This issue is probably related to #4175

muco-rolle commented 1 year ago

@kevinbailey25 can this https://github.com/Xiphe/remix-island fix this issue?

kevinbailey25 commented 1 year ago

@muco-rolle

I saw this the other day, in theory it could. Although the library even mentions at the end of their readme that it may have unexpected results with libraries that inject things into the head like styled-components and such.

At my work, we've decided to move away from CSS-in-JS libraries and move towards solutions that give us css files to link on the page and not have the extra overhead of runtime css.

muco-rolle commented 1 year ago

Thanks for your feedback @kevinbailey25.

What tools are you using now?

kevinbailey25 commented 1 year ago

Thanks for your feedback @kevinbailey25.

What tools are you using now?

We have a component/design library that we've fully removed styled-components from in favor of plain css. Our library ships with a single css file for the whole thing. (We may split that up into smaller css files the future if we find necessary).

All of our products that consume that component library, are configured to use Tailwind to help with layout and any other styling needs that our design system doesn't cover.

danramos-evoiq commented 1 year ago

This still seems to be an issue, any update?

markdalgleish commented 1 year ago

Thanks for raising this issue, and thanks everyone for helping out with all the different fixes and workarounds.

Since this affects multiple libraries and the workaround for each one is going to be different, I'm going to close this overarching issue just so it's not open indefinitely. If there are more specific issues related to a single CSS-in-JS library, UI framework etc., please feel free to open a separate issue.

Transparently supporting any library that injects global side-effects into the document would require a bigger change to Remix's architecture. This is something we'll keep in mind moving forwards but we don't have any concrete plans to address this at the moment.

In the meantime I'd encourage everyone to help contribute to the Remix examples repo with any fixes or workarounds for specific libraries. Note that we already have a working Emotion example and I've just opened a PR that fixes the Mantine example based on the comments in this issue (thanks @correiarmjoao!).

thebeyondr commented 9 months ago

My styles were disappearing when my error boundary got triggered. I'm using the Vite version with TailwindCSS.

I fixed my issue here in case this helps anyone: https://github.com/remix-run/remix/discussions/6356?sort=top#discussioncomment-8128826

NTag commented 7 months ago

This still happens with a very simple setup: Remix with Vite (which is now the recommended way) and just CSS modules. Click on a 404 link, press back and boom all CSS has disappeared. I don't believe the fix should be done at each styling library, I think there is a problem with how Remix handle errors and back navigation. Remix shouldn't make any assumption about the tools we use, and pressing back after navigating to a 404 page should bring us in the exact previous state. This problem is so annoying as it has been here for years and still happens on a new simple projet after minutes of development… Thanks 🙏

kiliman commented 7 months ago

@NTag do you have a simple repo?

NTag commented 7 months ago

Now I do, just here: https://github.com/NTag/remix-demo-vite-errors-css

See the demo: CleanShot 2024-03-19 at 14 52 58

Also, when creating the repo, I noted that the issue only appears after a first navigation. If you directly go (in my repo) to the /about page, refresh, click the broken link, and press back, everything is fine, the style stays.

However if you first start with the home page (like in the viceo), then navigate to the /about page and then click on the broken link, and back, this is when the styles completely disappears.

Hope it helps!

seanmcquaid commented 6 months ago

@NTag Did you ever find a solution to this problem?? I have been seeing the same thing even after implementing a Layout component exported in root.tsx. Which in theory should allow the Meta/Links to persist in a root ErrorBoundary.

NTag commented 6 months ago

No solution yet no…

mosino commented 3 months ago

I found a (bit of a hacky) workaround:

root.tsx

const error = useRouteError();
const navigate = useNavigate()

useEffect(() => {
    if(isRouteErrorResponse(error)) {
       window.location.href = "./errorPage"
    }
}, [error, navigate]);

And of course, put an ErrorPage.tsx in the routes.

I agree that this is a major bug

mhmdjaw commented 3 months ago

This is still happening and things really get messed up when I'm using animation and UI libraries like framer-motion and react-konva.

lifeiscontent commented 3 months ago

@mhmdjaw @mosino @NTag this is how you fix the issue: https://github.com/NTag/remix-demo-vite-errors-css/pull/1

mhmdjaw commented 3 months ago

@mhmdjaw @mosino @NTag this is how you fix the issue: NTag/remix-demo-vite-errors-css#1

I'm already doing that. It still happens.

mosino commented 3 months ago

@mhmdjaw @mosino @NTag this is how you fix the issue: NTag/remix-demo-vite-errors-css#1

I'm already doing that. It still happens.

same here

lifeiscontent commented 3 months ago

Hmm, the repro that @NTag put together seems to be fixed, is there something I missed? or is what you're talking about not outlined in the repro @mhmdjaw @mosino ?

mhmdjaw commented 3 months ago

@lifeiscontent I believe it still happens although in my case (I'm using CSS modules) not all styles are affected. Whenever I navigate to the 404 ErrorBoundary component and navigate back, some styles get messed up. It seems to be happening to the same styles when I test again, so although it seems random it's probably not. I don't know why it happens to certain styles only, but I can try to reproduce with a simple setup if you wish.

Edit: okay, so I'm not sure if this has something to do with it but I'm using SPA mode, with the default SPA mode setup. Not sure if it happens with the basic default startup. I was able to reproduce it with CSS modules. If this was solved in the default installation then maybe it's just a problem with SPA mode template.

https://github.com/user-attachments/assets/2f335b87-5b0c-492f-8efe-544c0b6dbcf3

lifeiscontent commented 3 months ago

@mhmdjaw yeah, I'd love to try and help figure it out, if you can put a repro together, I'll see what I can come up with.

mhmdjaw commented 3 months ago

@mhmdjaw yeah, I'd love to try and help figure it out, if you can put a repro together, I'll see what I can come up with.

I actually did include a very simple repro, and an edit to my comment a few hours ago. Tell me if you need anything else.

lifeiscontent commented 2 months ago

@mhmdjaw here's how you fix it with ssr: false

additional commit: https://github.com/NTag/remix-demo-vite-errors-css/pull/1/commits/6d268086a3c456eb1ae038ad5648cca6a93f2c32 pr: https://github.com/NTag/remix-demo-vite-errors-css/pull/1

mhmdjaw commented 2 months ago

@lifeiscontent Unfortunately it still didn't solve the problem. If you're still curious about solving it, here's the repo. My bad I forgot to push last time.

lifeiscontent commented 2 months ago

@mhmdjaw fixed with splat routes: https://github.com/mhmdjaw/remix-spa-styles-bug/pull/1

lifeiscontent commented 2 months ago

@mhmdjaw did that work for you?

mhmdjaw commented 2 months ago

@lifeiscontent Yup. That's the right workaround but it still doesn't solve the issue of losing the styles when navigating back from the ErrorBoundary, since this solution avoids it altogether.

lifeiscontent commented 2 months ago

@mhmdjaw yeah, another idea would be to add reloadDocument on the link, but that seems heavy handed.

mhmdjaw commented 2 months ago

@lifeiscontent yeah, what I ended up doing in my actual project was using a normal anchor instead of the remix Link which reloads the app at the home page. Switching to browser navigation is definitely not ideal, but it's just an error page so it's not a big deal. Otherwise your workaround with splat route is totally fine when the error is 404 not found.

rhyek commented 1 month ago

@lifeiscontent yeah, what I ended up doing in my actual project was using a normal anchor instead of the remix Link which reloads the app at the home page. Switching to browser navigation is definitely not ideal, but it's just an error page so it's not a big deal. Otherwise your workaround with splat route is totally fine when the error is 404 not found.

This is a good enough solution for me.