New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug]: Style tags disappear from Head during Error/Catch Boundary #1136
Comments
I would also add in that script tags from the end of the body are removed too so remix context gets lost other among other things. |
So far I have ascertained a few things relating to this issue. IMPORTANTNavigating in browser to a non-existing url does NOT reproduce this issue, INSTEADClicking a link in app to a non-existing url renders As well as losing any user generated style tags from the head the Remix Context does not get loaded in |
Well, the issue is that the top-most (root.tsx) error & catch boundary - if default unchanged - re-renders the whole document, including I think it could be partially worked around using some layout root with error and catch boundaries one level underneath the root.tsx. Still, if there is a problem in this layout route, it will fall back to root.tsx, but at least not for every error and you are not required to unnaturally have boundaries all over the place. Alternative, I did some research, would be to re-inject all the styles in effect. However the material UI style engine at first glance does not seem to give access for the underlying emotion sheet instance (I did only a glance check). Also, re-injecting as effect might cause flickr after initial boundary render |
I'm having a very similar issues (although using styled-components). Any catch/error boundaries that I create in the As @akomm said, it would be great to have some "layout" middle piece that only re-renders a piece in the body and not the whole document. |
Or at least not the Head-tag, since components live in the body only, but the route could at the very least inherit the same head |
The styled-components official example has this error too when adding error/catch boundaries.
In addition to this, I found that navigating to a non-existing url using a normal anchor tag ( |
Any idea of how to resolve this? This is one of the last pieces preventing us from converting our apps at work to Remix. |
Add pathless layout route Add the pathless route directly descending your Now the issue should only appear, if you have an error in your pathless route, but not any route beneath it. |
Thank you @akomm! This should do exactly what I need. I knew about the pathless routes in |
I'm experiencing a similar issue, and I was able to resolve component errors by doing what @akomm mentioned. However, even with using a CatchBoundary in the pathless route, 404s are still being unhandled, I'm assuming since they are not originating inside the pathless route, any way to handle that? |
@jpod32 I just tested manually throwing an 404 response and the catch boundary works in a regular route. I don't have yet the possibility to make a test on a pathless route. If you want me to check into it, you could create a reproduction sandbox. It is possible that catch boundary does not work when the routing fails, hence my manually thrown 404 response is not the same. Or it might be only issue with pathless routes. Or maybe you'v overlooked something? |
My issue is with 404s that aren't thrown manually, which can just be reproduced by entering an invalid url. From my attempts, this doesn't go to the catch boundary inside the pathless route. |
I'm also experiencing this, and can second @jpod32's experience. I tried the pathless route solution and had the same issue for 404s from invalid URLs. Has anyone else found a workaround to this yet? |
TL;DR: talked to Ryan Florence about it... so he at least knows it's a pain point for those of us trying to migrate to Remix, but I have no perfect solution. I lucked out at Remix Conf to have Ryan Florence sit at my table for lunch during the workshop. He asked everyone what's one thing that you wished Remix had and I brought up a lot of the styling pains I've had while trying to migrate. Remix really wants to give you full control of your network tab. Hence why they want you to set the url for your css in the Then if you jumped into styled-components... it was... write your css that goes with that component. Things get more complicated when you've written a component library that's a separate package that expects styled-components to just work. I get why Remix went the way they did, but we can't re-write the whole app to get away from styled-components... I just can't convince the higher ups right now that it's worth it. Hopefully they can help get some happy paths for us using css-in-js libs. :/ |
Any progress on this bug, it is the one thing preventing us to use Remix with Mantine. Please give us feedback so at least we understand why fixing this issue is not easy. Thank you for your awesome work! |
@absamo its not exactly a bug, since it behaves as it should, the whole document is re-rendered and anything injected directly into the DOM, like normally for react, disappears. But I agree this is an important to solve issue. Some statement would be nice, even if its "we can't for this reason" or "it would mean this and that". Maybe someone get an idea based on this how to still make it better, if a 100% perfect solution is not possible. Oh and its clear, one of the options, that the devs probably don't want to use is removing the control over the document itself in the way we have it yet. Currently its kind of first-class, as any other components. |
It‘s the same for me. I have tried Remix, loved it immediately for its data fetching model and then I’ve noticed the bug. It was heartbreaking experience 😉. |
Had the same problem when trying to use Mantine. I was able to work around it by reapplying the styles on the client using emotion cache, it should also work for other libraries that use emotion but will probably need another context for server styles. Made a small repo with an example, let me know if it helps @kwiat1990 @absamo |
Wow, thanks for the repo. I forked it and I will definitely try it after my vacations! |
Yes, basically this as I'v mentioned:
But sometimes you use it via other libraries, which don't expose the instances of cache they'v created. |
Thanks @correiarmjoao I can confirm this works. Simply pay attention to the following files when making changes to your own project: After updating my project accordingly, the problem has been solved. There is though the problem of Flash Of Unstyled Content in Mantine that occurs when navigating to a 404 page. It's not a big deal for me but something you should be aware of. Other supported frameworks(Gatsby, Next) and Chakra UI users are also facing the same issue. |
@brandiqa was the FOUC not because of Next or /and using |
I am currently using yarn. Navigating between existing routes works fine. FOUC only appears when the 404 error page is generated. How did you solve the problem? |
With Remix I didn’t try it yet. But in my Next project I needed to switch to yarn and downgrade Next to version |
Interesting... I just checked the deployed/production version and there's no FOUC. I guess it's a non-issue after all since it only happens when running remix in dev mode. |
Awesome, nice work around. Thanks for sharing it. |
@correiarmjoao, i have forked your repo and built based on it and luckily I didn't experience FOUC anymore. Thanks! |
This is pretty standard to how the web works in general. This is not unique to remix. With how you've set up your |
The cache off suggestion was just to make the issue occur frequently. Does this mean it's probably better to keep the top level CatchBoundary on a pathless layout below |
@jca41 if you want to avoid that, then yes having higher level Catch/Error Boundary will help. Typically I have multiple levels of Catch/Error Boundaries in my apps. I usually want to try to keep as much navigation and other elements on the page so if something does go wrong, the user still can navigate to other sections of the app easily. |
@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? |
@muco-rolle should work fine, we have an example in the examples repo. |
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. |
This issue is probably related to #4175 |
This workaround for this bug remix-run/remix#1136.
* chore(utilities): change order in which languages appear * dev: install swift wasm in project * feat(swift-compiler): add basic swift support * ci(swift-compiler): add deployment config * ci: remove duplicated deployment configs * ci(swift-compiler); install required libraries * ci: set correct executables * ci(deployment): remove prompts during package installations * feat(website/auth): display error notif if invalid passcode used * build: remove versions from all packages * feat(compilers): return time elapsed to execute compilation * feat(executor): return execution time * feat(orchestrator): return compilation and execution times * feat(website): query for elapsed times * build(compilers): include toolchain versions * refactor(compilers): move common func to utils library * ci(compilers): extract common step to template * Revert "build(compilers): include toolchain versions" This reverts commit 71f0794. * feat(compilers): add simple func to get version * fix(compilers): execute correct command to get version * feat(compilers): add resolvers to get toolchain versions * chore(compilers): use correct name for version func * chore(macros): rename variable * feat(executor): add resolver to get version * feat(orchestrator): add endpoint to get toolchain info * fix(website): handle cases with no outputs/inputs * feat(orchestrator): return execution time for each test case * feat(website): display elapsed time for test cases * feat(website): do not reload loader on form submission * dev: install wasi-ruby in dev env * feat: add ruby support * ci: add partial configuration for ruby * fix(executor): get the ruby executor working * ci(executor): manually install wasmtime * feat(examples): add haskell example * feat(website): add root level error page * feat(website): make component more generic * feat(website): add root level 404 page * feat(website): handle 404 errors gracefully * feat(website): add helper to redirect from forbidden routes * fix(website): display terse messages in UI * feat(website): extract title func to utils * feat(website): display output in playground * refactor(website): extract output display to component * feat(website): make solve page responsive * feat(website): add basic UI to render test case outputs * refactor(website): break display output component into success and error * refactor(website): extract to common component * refactor: change service names * refactor: rename project * perf(orchestrator): parallelize fetching version info * feat(website): select failed test case automatically * feat(orchestrator): allow individual cases to error * feat(generated): use new graphql schema * feat(website): allow individual test cases to fail * feat(orchestrator): return diff for executed test cases * feat(generated): fetch diff test cases * feat(website): display diff for test cases * fix(website): move prop to correct component * dev: install latest moon version * dev: append paths using only one file * ci: new action to setup moon in gh actions * ci(mails): add task to generate mails * fix(website/auth): remove needless pin-input * feat(website/playground): add basic drawer to add args * feat(website/question): add page title * feat(website/question): group btns together * refactor(website): move test cases to a separate component * feat(languages): add basic grain support * feat(orchestrator): add config for grain * refactor: rename compilers to languages * feat: add grain support * ci(deployment): add config for grain service * feat(orchestrator): log the language that is being initialized * feat(website): allow adding args in UI * feat: support arguments in playground * feat(website/playground): add btn to save args * feat(orchestrator): log failed language * fix(website): make problem statement required * tests(website-e2e): add basic files * tests(website): add basic tests * chore(website-e2e): set port for server * dev: install dependencies required for cypress * ci(moon): add dependencies to project * ci(website-e2e): remove outputs from cmd * feat(website): display stack trace in dev mode * refactor(website): move common func to utils module * feat(website): allow create question page to update as well * refactor(website): create `notImplemented` func error resp * ci(website): do not disable typescript compiler emit * fix(website): trim problem text before submission * feat(website): wrap test cases with input wrapper * chore(orchestrator): remove useless unwrap for services * feat(orchestrator): support forward pagination in questions list * feat(orchestrator): support backward pagination * feat(orchestrator): add relay connection support * feat(orchestrator): rename method to be more explicit * feat(website): got forward pagination working * build(website): update jsonwebtoken dep to latest * feat: complete cursor pagination * fix(website): use correct number of questions per page * ci: setup some projects * chore(questions/list): remove useless `console.log` * feat(website): add basic pagination * feat(website): add info tab on sidebar * feat(website): add basic toolchain info page * feat(proc_macros): add macro to embed image as base64 * feat(languages): add logos for langs * feat(languages): include logos in binaries * feat(languages): return logo from information handler * feat(orchestrator): return toolchain logo image from resolver * feat(generated): add query for compiler info * feat(website): display toolchain information * feat(languages): remove useless func call * fix(website): change tooltip position * ci: exclude complicated tests from simple ci * feat: upgrade react-email version * ci(mails): disable email generation in CI * fix(orchestrator): change order of diffs * feat: remove `classes` and `authored_by` fields from schema * fix: remove refs to non-existent fields * feat: allow editing questions * ci: setup initial binaries build * fix(ci): do not install nodejs in `build-initial` job * feat(ci): add support for nodejs projects * feat(orchestrator): handle cases with empty outputs * fix9website): display code output as block * ci: add new logic for building and pushing containers * fix: convert array correctly * ci: use correct executable discovery * ci: install correct rust version * fix(ci): rename actions to correct names * fix(ci): quote executable names * fix(ci): set correct dockerfile paths * fix(deployment): remove un-needed env vars * feat: remove target directory from .dockerignore * ci: log all existent docker images * ci: remove caching * ci: use docker builder for building * chore(ci): remove useless command * fix(ci): set correct env vars * ci: select correct dockerfiles for languages * ci: build all images in one script * ci: setup basic caching * ci: set correct nodejs version * ci: script to build for project type * ci(deployment: enable lint and typecheck commands * ci: use buildx to build docker images * ci: allow installing specific dasel version * ci: build and push in one command * ci(dasel): set correct input version * ci(website): set correct nodejs version * ci: correct usage * feat(orchestrator): add cache controls on responses * ci: do not install cypress binary in release * ci: remove node modules from dockerignore * ci: delete dockerignore * ci(deployment): use correct eslint config * ci: install project nodejs version * feat(website): guess data types more accurately * feat(website): display question name on solve page * feat(website): make edit page responsive * feat(website): text input and select box * build: pin tool versions * fix(website): specify language attr in html tag * chore(react-ui): remove useless library * fix(website): remove erroneous `json.stringify` usage * feat(website): handle styles not appearing in root component This workaround for this bug remix-run/remix#1136. * feat(website): add strict mode to root component * feat(orchestrator): add resolver to delete question * feat(website): add action to delete a question * feat: handle edge cases for test cases * fix(website): handle display more effectively * fix(website): use correct component hierarchy * fix(website): display code in block * feat(main-db): normalize test case data in db * feat(website): adapt to new schema * feat(authenticator): remove hardcoded params * feat(website): handle duplicating questions * feat(website): change setup of questions actions * ci(eslint): ignore vite timestamp files While building, vite builds a timestamp file. Sometimes when running the tasks in parallel, eslint ends up reading this file and then later reports it as does not exist (because the vite build has already deleted it). Ignoring this file rids us of those errors. * try(orchestrator, fail): setup cron jobs * Revert "try(orchestrator, fail): setup cron jobs" This reverts commit 390bb50.
@kevinbailey25 can this https://github.com/Xiphe/remix-island fix this issue? |
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 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. |
Thanks for your feedback @kevinbailey25. What tools are you using now? |
We have a component/design library that we've fully removed 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. |
This still seems to be an issue, any update? |
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!). |
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: #6356 |
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 🙏 |
@NTag do you have a simple repo? |
Now I do, just here: https://github.com/NTag/remix-demo-vite-errors-css 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 However if you first start with the home page (like in the viceo), then navigate to the Hope it helps! |
@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. |
No solution yet no… |
Which Remix packages are impacted?
remix
(Remix core)@remix-run/react
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: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.
The text was updated successfully, but these errors were encountered: