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

Dynamic page loading failed Error: Trying to replace an element that wasn't mounted! #987

Closed
DeividasK opened this issue Jul 12, 2017 · 19 comments
Assignees
Labels

Comments

@DeividasK
Copy link

DeividasK commented Jul 12, 2017

Version

styled-components: 2.1.1
babel-plugin-styled-components: 1.1.7

  • SSR is configured with code-splitting using react-boilerplate.
  • Some components are imported from an npm package which exports components styled with styled-components.

Error stack trace

Dynamic page loading failed Error: Trying to replace an element that wasn't mounted!
    at BrowserTag.replaceElement (eval at ./node_modules/styled-components/lib/models/BrowserStyleSheet.js (main.js:4034), <anonymous>:122:36)
    at BrowserTag.addComponent (eval at ./node_modules/styled-components/lib/models/BrowserStyleSheet.js (main.js:4034), <anonymous>:63:27)
    at StyleSheet.getOrCreateTag (eval at ./node_modules/styled-components/lib/models/StyleSheet.js (main.js:4058), <anonymous>:141:18)
    at StyleSheet.deferredInject (eval at ./node_modules/styled-components/lib/models/StyleSheet.js (main.js:4058), <anonymous>:94:10)
    at new ComponentStyle (eval at ./node_modules/styled-components/lib/models/ComponentStyle.js (main.js:4042), <anonymous>:38:39)
    at createStyledComponent (eval at ./node_modules/styled-components/lib/models/StyledComponent.js (main.js:4074), <anonymous>:238:26)
    at templateFunction (eval at ./node_modules/styled-components/lib/constructors/constructWithOptions.js (main.js:3986), <anonymous>:26:14)
    at eval (eval at ./app/pages/CustomerStory/Quote.js (main.js:1815), <anonymous>:8:3)
    at Object../app/pages/CustomerStory/Quote.js (main.js:1815)
    at __webpack_require__ (main.js:660)

Reproduction

I cannot reliably reproduce the error on webpackbin. Things I can reproduce:

  • If I remove CSS injection on the server the error goes away (initially page is loaded without styles).
  • Error happens only in some of the pages, but not in every page. However, when it happens, it usually happens consistently.
  • Error always points to the same component. If I change / rename the component, the error starts pointing to another component, but the stacktrace is the same.
  • Error sometimes points to the component, that is not even present on the page.
  • We've never encountered this error when using styled-components v1. It started occurring once we switched to v2 (without any other changes to the setup).

What I've tried

  • Fiddling with babel-plugin-styled-components options
    • ssr on/off
    • preprocess on/off

Any suggestion that could point to the possible culprit / solution would be greatly appreciated.

@kitten
Copy link
Member

kitten commented Jul 12, 2017

Since this seems to be an SSR related issue, can you post some code on how you integrated our SSR API with the boilerplate? Cheers

cc @geelen

@DeividasK
Copy link
Author

DeividasK commented Jul 12, 2017

Hi Phil, thanks for a quick response. About 3 months ago this PR was forked to bootstrap the project. I've followed instructions from the docs. The relevant code part (capturing of styles) below:

// 1st render phase - triggers the sagas
renderToString(
  <AppRoot store={store}>
    <RouterContext {...renderProps} />
  </AppRoot>
);

// send signal to sagas that we're done
store.dispatch(END);

// wait for all tasks to finish
await sagasDone();

// capture the state after the first render
const state = store.getState().toJS();

const sheet = new ServerStyleSheet();

// 2nd render phase - the sagas triggered in the first phase are resolved by now
const appMarkup = renderToString(
  sheet.collectStyles(
    <AppRoot store={store}>
      <RouterContext {...renderProps} />
    </AppRoot>
  )
);

// capture the generated css
const css = sheet.getStyleElement();

const doc = renderToStaticMarkup(
  <HtmlDocument
    appMarkup={appMarkup}
    state={state}
    head={Helmet.rewind()}
    assets={assets}
    css={css}
    webpackDllNames={webpackDllNames}
  />
);
return `<!DOCTYPE html>\n${doc}`;

@kitten
Copy link
Member

kitten commented Jul 12, 2017

hm, I suspect that the two render phases are responsible for this trouble. Can you try this:

import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

// 1st render phase - triggers the sagas
renderToString(
  <StyleSheetManager sheet={new ServerStyleSheet().instance}>
);

// ...
// 2nd render phase

const sheet = new ServerStyleSheet();

const appMarkup = renderToString(
  sheet.collectStyles(
    <AppRoot store={store}>
      <RouterContext {...renderProps} />
    </AppRoot>
  )
);

// ...
const css = sheet.getStyleElement();

The problem seems to be that in the 1st phase you're rendering loads of Styled Components without them being captured with the server stylesheet. We can't reuse the same one for two rendering cycles, but we can try to use two separate ones, I believe

@DeividasK
Copy link
Author

DeividasK commented Jul 12, 2017

Tried this:

import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

// ...

// 1st render phase - triggers the sagas
renderToString(
  <StyleSheetManager sheet={new ServerStyleSheet().instance}>
    <AppRoot store={store}>
      <RouterContext {...renderProps} />
    </AppRoot>
  </StyleSheetManager>
);

// ...

// 2nd render phase - the sagas triggered in the first phase are resolved by now
const sheet = new ServerStyleSheet();

const appMarkup = renderToString(
  sheet.collectStyles(
    <AppRoot store={store}>
      <RouterContext {...renderProps} />
    </AppRoot>
  )
);

// capture the generated css
const css = sheet.getStyleElement();

and this

import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

// ...

const sheet = new ServerStyleSheet();

// 1st render phase - triggers the sagas
renderToString(
  <StyleSheetManager sheet={sheet.instance}>
    <AppRoot store={store}>
      <RouterContext {...renderProps} />
    </AppRoot>
  </StyleSheetManager>
);
// ...

// 2nd render phase - the sagas triggered in the first phase are resolved by now

const appMarkup = renderToString(
  sheet.collectStyles(
    <AppRoot store={store}>
      <RouterContext {...renderProps} />
    </AppRoot>
  )
);

// capture the generated css
const css = sheet.getStyleElement();

Both result in the same error.

As for loading a lot of components during the first render cycle - I think we are loading the same (or lower) amount of components, because when sagas are done we have additional components to display with new data.

@kitten
Copy link
Member

kitten commented Jul 12, 2017

Error happens only in some of the pages, but not in every page. However, when it happens, it usually happens consistently.
Error always points to the same component. If I change / rename the component, the error starts pointing to another component, but the stacktrace is the same.
Error sometimes points to the component, that is not even present on the page.

Is there anything special about these components in the way they're used together with the state?

@kitten
Copy link
Member

kitten commented Jul 12, 2017

After reading through the code, I noticed that the error occurs when a style tag is not mounted in the head anymore. Which sounds weird. I'm not familiar with the rehydration yet, so @geelen might have to jump in.

Are you sure that the style tags are injected into the head statically and stay there?

https://github.com/styled-components/styled-components/blob/master/src/models/BrowserStyleSheet.js

@DeividasK
Copy link
Author

DeividasK commented Jul 12, 2017

There's nothing special about those components (except from the fact that they are not used in the page that gets this error). An example of a particular component above:

import styled from 'styled-components';

const Quote = styled.p`
  font-weight: 700;
  font-family: Abhaya Libre,serif;
  font-size: 30px;
  line-height: 1.6;


  border-left: 5px solid #9df6df;
  text-align: left;
  padding-left: 10px;

  &::after {
    content: ' ”';
  }

  &::before {
    content: '“ ';
  }
`;

export default Quote;

This particular component is created when we map through an array of data received from our headless CMS. However, maping occurs in another component, which is not loaded in this page.

I'm 100% sure that the styles are injected into the head. Here's how they look:

<style type="text/css" data-styled-components="rPGQc kGbJUQ bQHhuX eEjGQg gCQUri euQgqQ jsGwgt czKzNZ fXGJEd esYmnI lgKJiB dawqLu gUBkcu bgATzB ddpDRo daFMBo iEzPRN jPjSWh cMdELy gIcplz dHFWjw MUOSJ hXQcQI cIVxBE bGQeLV jSyOU jVdDWo TaYKd dsYfnr hTeuSa jQwvVs" data-styled-components-is-local="true">/* sc-component-id: StyledHero__StyledHero-oeql2j-0 */
.StyledHero__StyledHero-oeql2j-0 {}
.czKzNZ{display: -webkit-box;display: -webkit-flex;display: -ms-flexbox;display: flex;-webkit-box-pack: center;-webkit-justify-content: center;-ms-flex-pack: center;justify-content: center;-webkit-align-items: center;-webkit-box-align: center;-ms-flex-align: center;align-items: center;-webkit-flex-direction: column;-ms-flex-direction: column;flex-direction: column;padding: 160px 20px 0;width: 100%;  ;}
/* sc-component-id: HeroSubtitle__HeroSubtitle-urumro-0 */
.HeroSubtitle__HeroSubtitle-urumro-0 {}
...

@DeividasK
Copy link
Author

DeividasK commented Jul 12, 2017

I know this is far from ideal, but would it be possible to fail silently? Because when this error is thrown, the execution of the code stops and the page "breaks", which is undesired.

@kitten
Copy link
Member

kitten commented Jul 12, 2017

@DeividasK I'm not sure about that either, because it's a critical error in the rehydration. Again, Glen will probably be able to shine a light on this

@DeividasK
Copy link
Author

@geelen Hey Glen, just wanted to bump this up. Any ideas / experiments that I could do to try and fix this would be really helpful.

@DeividasK
Copy link
Author

He guys, any updates on this?

@kitten
Copy link
Member

kitten commented Jul 18, 2017

@DeividasK I can probably take a quick look and try out some things to solve this. Do you have a reproduction repo somewhere?

@DeividasK
Copy link
Author

Hey Phil, not really. The main problem is that it is hard to precisely reproduce. The only way I am able to reproduce it now is in the main project repo. It disappears if I remove server side rendering. Removing code splitting does not help.

@DeividasK
Copy link
Author

@philpl turns out that the issue was with duplicated styled-components modules. One of the dependencies for our npm package was styled-components. Once I removed that from dependencies to devDependencies (also added to peerDependencies for the warnings) AND in webpack config specified it with externals

externals: {
    react: 'react',
    'react-dom': 'react-dom',
    'styled-components': 'styled-components',
  },

the issues have disappeared.

Simply removing it from dependencies did not help as it was necessary to specify it together with other external libraries.

I closed this issue, but I think it's worth having a discussion if styled-components should somehow detect and prevent this from happening.

@xiaolin
Copy link

xiaolin commented Jul 25, 2017

For anyone who googled and found this. I had a similar issue using redux-connect and styled-components on the server.

I was doing something very similar to @DeividasK

const sheet = new ServerStyleSheet();

const appHTML = renderToStaticMarkup(
  <StyleSheetManager sheet={sheet.instance}>
    <Provider store={store} key="provider">
      <ReduxAsyncConnect {...renderProps} />
    </Provider>
  </StyleSheetManager>
);

// capture the generated css
const css = sheet.getStyleElement();

const doc = renderToStaticMarkup(
  <HtmlDocument
    appMarkup={appHTML}
    css={css}
  />
);
res.send('<!DOCTYPE html>' + doc);

But on the client after the JS loads I would get an error Trying to replace an element that wasn't mounted! causing some css to be missing.

I was able to get rid of the error on the client by changing

const css = sheet.getStyleElement();
to
const css = sheet.getStyleTags();

and in my HtmlDocument I changed it from

<head>
  {css}
</head>

to

<head>
  <style dangerouslySetInnerHTML={{ __html: css}} />
</head>

barryph added a commit to callumflack/vjray-strata that referenced this issue Oct 3, 2017
Occured when server side rendering any page other than index
Fix found at: styled-components/styled-components#987
callumflack added a commit to callumflack/vjray-group that referenced this issue Oct 5, 2017
Replicating B’s commit on Strata site:
callumflack/vjray-strata@103f62d70dda3f447fd85
b831556be4b518c4bc9
Occured when server side rendering any page other than index
Fix found at: styled-components/styled-components#987
@ilanus
Copy link

ilanus commented Oct 5, 2017

@xiaolin I get the same error Uncaught Error: Trying to replace an element that wasn't mounted! however, this error is happening on the client-side only. I think const styleTags = sheet.getStyleTags(); Is fine just gets the stylesheet tags from styled-components, have you found any clean solution for this?

@kitten
Copy link
Member

kitten commented Oct 5, 2017

@ilanus This issue is extremely old! Please refrain from commenting in older issues that have been resolved

Check the docs on how to set up SSR: https://www.styled-components.com/docs/advanced#server-side-rendering

  • Using this API on the client is not supported
  • If the error is on the client but the API is set up correctly make sure that the style tags are injected into your HTML's head

@jorilallo
Copy link

@philpl old or not, I also ran into issue with the Next.js example and was able to fix them with @xiaolin's tweak. Not trying to stir up shit but seems like other Next users might face similar issues.

@Coobaha
Copy link

Coobaha commented Dec 25, 2017

This can be caused by multiple styled-components instances used by different modules

with npm use npm dedupe
with yarn add this to package.json with correct version and do yarn install after

"resolutions": {
  "styled-components": "your version"
}

hellais added a commit to hellais/ooni-explorer-next that referenced this issue Jan 19, 2018
hellais added a commit to ooni/explorer that referenced this issue Jun 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants