Skip to content
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

hydration error when there is a chrome extension that modifies DOM #4822

Open
jin2255 opened this issue Dec 10, 2022 · 68 comments
Open

hydration error when there is a chrome extension that modifies DOM #4822

jin2255 opened this issue Dec 10, 2022 · 68 comments

Comments

@jin2255
Copy link

jin2255 commented Dec 10, 2022

What version of Remix are you using?

latest

Steps to Reproduce

I installed an extension that modifies DOM such as Grammar Checker into my browser and tried to develop a web app with Remix.
I get the following errors and the styles of the app were messed up.

Hydration failed because the initial UI does not match what was rendered on the server.
There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

Expected Behavior

I have errors when I install any extension that modifies DOM into my browser

Actual Behavior

The favicon and styles are messed up
The important thing is that this error has already been mentioned many times and there is no exact solution
What's even more interesting is that the https://remix.run site doesn't have this error occur even if it was developed with Remix

@trevordebard
Copy link

This is a known gotcha, however, I agree it would be helpful if Remix could do something to prevent this from happening. For me the error only occurs in development. Has anyone found a workaround other than incognito or uninstalling the extensions?

@machour
Copy link
Collaborator

machour commented Dec 12, 2022

We talked about this with @mjackson

The root of the problem is that remix hydrates the whole document, instead of a div on the body.

Not sure if the team is willing to reconsider this choice, and the consequences it would have on handling things like meta & so on. Maybe a good topic for today's live roadmap stream.

@jin2255
Copy link
Author

jin2255 commented Dec 13, 2022

Thank you all for the answers.
It's a pity that there is no exact solution yet.
A few months ago, I started developing sites with Remix instead of Next and now I can't deploy to production because of this problem.
Hopefully, the team at Remix will fix this soon.
And I wonder how this error doesn't happen in the https://remix.run site.
Doesn't this mean that we already have the possibility to solve this problem?
If anyone knows, please... 🙏

@trevordebard
Copy link

@jin2255 Are you experiencing this error when running in production? I only experience it in development.

@jin2255
Copy link
Author

jin2255 commented Dec 13, 2022

This happens in both production and development.
The problem is not an error in the dev tools console.
The problem is that favicon and styles are disappeared.

@jin2255
Copy link
Author

jin2255 commented Dec 14, 2022

We talked about this with @mjackson

The root of the problem is that remix hydrates the whole document, instead of a div on the body.

Not sure if the team is willing to reconsider this choice, and the consequences it would have on handling things like meta & so on. Maybe a good topic for today's live roadmap stream.

thank you, @machour
So, do we have to wait for the team to fix this?
😥

@machour
Copy link
Collaborator

machour commented Dec 14, 2022

@jin2255 someone needs to post a proposal for change and a discussion needs to happen, in order to get this on the team radar:
https://remix.run/docs/en/v1/pages/contributing#feature-development

@alexhoo
Copy link

alexhoo commented Dec 15, 2022

This happens in both production and development. The problem is not an error in the dev tools console. The problem is that favicon and styles are disappeared.

for me its only happening in production :'(

@jin2255
Copy link
Author

jin2255 commented Dec 17, 2022

thank you @machour
I posted a discussion to #4902
I hope I can get a exact solution...

@bidbanRG
Copy link

I am not getting any error in Firefox and incognito of chrome. Do anyone getting any error in production???

@lmachens
Copy link

lmachens commented Jan 6, 2023

I face the same issue with https://chrome.google.com/webstore/detail/autoscroll/occjjkgifpmdgodlplnacmkejpdionan/related extension on development and production.

@OnurGvnc
Copy link

OnurGvnc commented Jan 13, 2023

I was able to resolve my issue by invoking clearBrowserExtensionInjectionsBeforeHydration() prior to executing hydrateRoot().
https://gist.github.com/OnurGvnc/31f03f0d5237b78224aa083493fda645

@jin2255
Copy link
Author

jin2255 commented Jan 13, 2023

mhmm, so it seems there is not exact solution yet
I will not use remix till the remix team solve the problem correctly or till I can sure it's possible to prevent this error correctly
my next project will be developed by next js or any other frameworks, no remix

Really I loved remix
but the remix community is not big yet and it seems remix has some potential errors
😪 😭
I hope I can use remix for my future projects later

thank you @machour , @OnurGvnc

@alexhoo
Copy link

alexhoo commented Jan 14, 2023

Well @jin2255 I just needed to downgrade react version ( from 18.x.x to 17.x.x ) and every it is fine by now in our production environment.

@machour
Copy link
Collaborator

machour commented Jan 14, 2023

@jin2255 Ryan and Michael discussed this in the Roadmap live stream last week.
I recommend to view these two parts:

So basically my understanding is:

  • Remix sees this as a React issue
  • That issue doesn't affect your website. It just means that React swaps your UI at some point, and user still don't notice it.
  • If you are able to show that this is actually a problem, and your website is breaking because of this, please set up a repository reproducing the issue, and the team will give this a deeper look.

@jin2255
Copy link
Author

jin2255 commented Jan 14, 2023

Well @jin2255 I just needed to downgrade react version ( from 18.x.x to 17.x.x ) and every it is fine by now in our production environment.

@jin2255 jin2255 closed this as completed Jan 14, 2023
@jin2255 jin2255 reopened this Jan 14, 2023
@sergiocarneiro
Copy link
Contributor

When using CSS-in-JS, the styles fail to render, so as you can imagine it feels like the entire site breaks.

In summary, it's a React 18 problem and it can be seen at entry.client.tsx.

FAILS

hydrateRoot(document, <RemixBrowser />)

WORKS

hydrate(<RemixBrowser />, document)
// Warning: ReactDOM.hydrate is no longer supported in React 18. Use hydrateRoot instead.
// Until you switch to the new API, your app will behave as if it's running React 17

Reproduction

https://stackblitz.com/edit/node-czrvzk?file=app/entry.client.tsx

I used styled-components and I have a large project using styletron that also has this same issue and workaround.

@sergiocarneiro
Copy link
Contributor

This is not just a Chrome Extension problem.

If you share your website on social media, it opens in an in-app browser. Meta, at least, injects fancy stuff in the DOM (weird, right?), which leads to the same issue.

This one is more concerning to me, as the brand's reputation is at stake (they are linking the customers to an apparently broken site), and affects 100% of the users.

@kzsa
Copy link

kzsa commented Jan 21, 2023

On remix.run
If you scroll down to "Remix has a cheat code: Nested Routes." when viewing the home page with google chrome's built-in translator, the page runs into an error.

Képernyőkép – 2023-01-21 07-57-59

@kzsa
Copy link

kzsa commented Jan 21, 2023

This is not just a Chrome Extension problem.

If you share your website on social media, it opens in an in-app browser. Meta, at least, injects fancy stuff in the DOM (weird, right?), which leads to the same issue.

This one is more concerning to me, as the brand's reputation is at stake (they are linking the customers to an apparently broken site), and affects 100% of the users.

For the time being, I think it's better to avoid R18.
If you can't use the built-in Chrome translator on your site, there is a hidden accessibility problem. Content translation can be expensive and time-consuming process. Not all startups can finance content translation at the beginning.

@Xiphe
Copy link

Xiphe commented Jan 23, 2023

Still with react@17 additional injected elements (such as the <style /> from styled-components) are wiped when hydrating - even when there are no hydration errors displayed

...unless they're placed as the last child of an element, which is not controllable in every case...

@kzsa
Copy link

kzsa commented Jan 23, 2023

Still with react@17 additional injected elements (such as the <style /> from styled-components) are wiped when hydrating - even when there are no hydration errors displayed

...unless they're placed as the last child of an element, which is not controllable in every case...

Right, I just checked that it is also 17.
image

@jin2255
Copy link
Author

jin2255 commented Feb 1, 2023

thank you, all
I know this error doesn't happen in React 17.
I've seen many articles and advertisements saying that remix is much better than next.
So, I recently tried to use remix to businesses and found an unexpected bug, and the remix team just said it isn't a remix problem...
Disappointment!
I will go with React 18, Next JS

@owlyowl
Copy link

owlyowl commented Dec 18, 2023

Upgrade react AND react-dom to latest canary version

Not sure we can do this in the guise of shopify-remix-app-template and the dependency tree

@replygirl
Copy link

Upgrade react AND react-dom to latest canary version

Not sure we can do this in the guise of shopify-remix-app-template and the dependency tree

@Ikdemm
Copy link

Ikdemm commented Jan 16, 2024

I'm on React 18.2.0 and face up with the same issue. Any updates?

Go for canary that's the only way

Is it safe to do this for a Remix project on PROD? 🤔

@brophdawg11
Copy link
Contributor

Per the React team, yes. Next.js (at least the app router) only uses canaries so any production Next.js app using the App Router is using a canary.

It's really up to you and your team though if you feel comfortable shipping a canary release to production.

@Loschcode
Copy link

I'm facing the same problem as described. When having Grammarly on, the favicon jumps in production and development, and a bunch of hydration errors appear in the console.

It's been over a year and is quite critical. We are talking about people developing entire websites and then seeing it all broken because HTML is injected dynamically, which is a common occurrence.

Is there a hack other than using the React canary version?

@YannBirba
Copy link

I'm facing the same problem as described. When having Grammarly on, the favicon jumps in production and development, and a bunch of hydration errors appear in the console.

It's been over a year and is quite critical. We are talking about people developing entire websites and then seeing it all broken because HTML is injected dynamically, which is a common occurrence.

Is there a hack other than using the React canary version?

Nah I don't think so ... https://twitter.com/BrooksLybrand/status/1763678388806394127?t=pxowwBKSwYI-VP4yADlDvw&s=19

@MariMax
Copy link

MariMax commented Mar 22, 2024

my workaround to prevent any DOM modifications until after hydration happens
root:

        <script
          dangerouslySetInnerHTML={{
            __html: `
              const observerConfig = {
                childList: true,
                subtree: true,
                attributes: true,
                attributeOldValue: true,
                characterData: true,
                characterDataOldValue: true,
              };
              window.hydration_observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                  switch (mutation.type) {
                    case 'childList': {
                      window.hydration_observer.disconnect();
                      mutation.addedNodes.forEach((node) => {
                        try {
                        mutation.target.removeChild(node);
                        } catch (e) {
                          console.error(e);
                        }
                      });
                      window.hydration_observer.observe(document, observerConfig);
                      break;
                    }
                    case 'attributes': {
                      mutation.target.removeAttribute(mutation.attributeName);
                      break;
                    }
                  }
                });
                
              });
              window.addEventListener('DOMContentLoaded', () => {
                window.hydration_observer.observe(document, observerConfig);
              });
            `,
          }}
        />

client entry

  hydrateRoot(
    document,
    <Provider>
      </StrictMode>
    </Provider>,
  );
  window.hydration_observer.disconnect();

@MaeThird
Copy link

I just wanted to smoothly deploy to the production environment, I didn't expect so many pitfalls. If I had known it would be like this, I wouldn't have used this tool. This is my temporary solution, I just comment out this line, and the world becomes quiet.

/node_modules/react-dom/cjs/react-dom.development.js:

function throwOnHydrationMismatch(fiber) {
  //throw new Error('Hydration failed because the initial UI does not match what was ' + 'rendered on the server.');
}

@kiliman
Copy link
Collaborator

kiliman commented Mar 26, 2024

@MaeThird, update to the React canary version to resolve the hydration issues. This is a React issue because Remix hydrates the entire document instead of a single div.

Also make sure you pin the version and add to overrides
https://twitter.com/kiliman/status/1769730243772780825

@MaeThird
Copy link

@kiliman works now! Thank you.

@wong2
Copy link

wong2 commented May 24, 2024

I'm facing this issue with react 18.3.1

@kiliman
Copy link
Collaborator

kiliman commented May 24, 2024

v18.3 used to be the canary version that fixed this. It's now React 19. So install the latest RC react@rc react-dom@rc.

@hamez0r
Copy link

hamez0r commented Jun 14, 2024

I was able to resolve my issue by invoking clearBrowserExtensionInjectionsBeforeHydration() prior to executing hydrateRoot(). https://gist.github.com/OnurGvnc/31f03f0d5237b78224aa083493fda645

This definitely helped, but Grammarly was still acting up and messing up the entire page. Until a stable version of React 19 is out, I found this workaround.

startTransition(() => {
  clearBrowserExtensionInjectionsBeforeHydration();

  const root = hydrateRoot(
    document,
    <StrictMode>
      <MuiProvider>
        <RemixBrowser />
      </MuiProvider>
    </StrictMode>,
    {
      onRecoverableError: () => {
        console.log("Hydration failed! Attempting recovery...");
        root.render(
          <StrictMode>
            <MuiProvider>
              <RemixBrowser />
            </MuiProvider>
          </StrictMode>,
        );
        console.info("Recovery successful!");
      },
    },
  );
});

Thanks @OnurGvnc for clearBrowserExtensionInjectionsBeforeHydration

@blaiseludvig
Copy link

For anyone else still struggling with this, the only thing that worked for me with both browser extensions and browsers that inject into the DOM

This is not just a Chrome Extension problem.

If you share your website on social media, it opens in an in-app browser. Meta, at least, injects fancy stuff in the DOM (weird, right?), which leads to the same issue.

This one is more concerning to me, as the brand's reputation is at stake (they are linking the customers to an apparently broken site), and affects 100% of the users.

Is using the canary version mentioned here:

MaeThird, update to the React canary version to resolve the hydration issues. This is a React issue because Remix hydrates the entire document instead of a single div.

Also make sure you pin the version and add to overrides twitter.com/kiliman/status/1769730243772780825

Just set the React version in package.json to this:

"dependencies": {
  "react": "18.3.0-canary-a870b2d54-20240314",
  "react-dom": "18.3.0-canary-a870b2d54-20240314",
}

and add this to avoid issues with dependencies:

"dependencies": {
  "react": "18.3.0-canary-a870b2d54-20240314",
  "react-dom": "18.3.0-canary-a870b2d54-20240314",
},
"overrides": {
  "react": "18.3.0-canary-a870b2d54-20240314",
  "react-dom": "18.3.0-canary-a870b2d54-20240314"
},

The permanent solution to this is to upgrade to React 19 once it becomes stable. You can keep this canary version until your dependencies start supporting React 19.
Hope this saves someone a lot of time!

Skn0tt added a commit to microsoft/playwright that referenced this issue Sep 17, 2024
…ation (#32637)

Closes #32632. A side
effect of Remix's hydration implementation is that it throws away the
entire DOM. This is broadly discussed in
remix-run/remix#4822 - there might be a fix in
coming React versions, but who knows.
Besides breaking browser extensions, this also deletes our toolbar!
This PR fixes it by periodically checking in on `x-pw-glass`, and
remounting it if it was unmounted. Hacky but effective!
Dbuggerx added a commit to Dbuggerx/remix-webrtc-chat that referenced this issue Nov 5, 2024
…ix-ui/react-slot to align with https://react.dev/blog/2024/04/25/react-19-upgrade-guide#deprecated-element-ref

Script injections (by browser extensions or test runners like Cypress or TestCafe) cause hydration errors. React19 improves that situation (remix-run/remix#4822).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests