question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Custom CacheProvider does not pick up styles from bundled components

See original GitHub issue

Current behavior:

A custom CacheProvider does not pick up styles from components imported from bundled JS. Styles for these components are prefixed with the default css key and are injected into the document head, not the location specified in the cache.

To reproduce:

Repo with example: https://github.com/ChrisMccollister-minted/emotion-cache-provider-test

Expected behavior:

For the code shown below, I would expect the styles used by LibraryComponent to be prefixed with bbb and injected into the div holding the t2Ref.

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {css, CacheProvider} from '@emotion/core';
import createCache from '@emotion/cache';
import LibraryComponent from 'emotion-cache-test-lib';

const localStyle = css`
  color: red;
`;

const LocalComponent = ({children}) => (
  <div css={localStyle}>{children}</div>
);

class Main extends Component {
  constructor(props) {
    super(props);
    this.t1Ref = React.createRef();
    this.t2Ref = React.createRef();
    this.state = {
      isReady: false,
    };
  }

  componentDidMount() {
    this.t1Cache = createCache({
      key: 'aaa',
      container: this.t1Ref.current,
    });
    this.t2Cache = createCache({
      key: 'bbb',
      container: this.t2Ref.current,
    });
    this.setState({isReady: true});
  }

  render() {
    const {isReady} = this.state;
    return (
      <div>
        <div ref={this.t1Ref}>
          {isReady &&
            <CacheProvider value={this.t1Cache}>
              <LocalComponent>
                LocalComponent
              </LocalComponent>
            </CacheProvider>
          }
        </div>
        <div ref={this.t2Ref}>
          {isReady &&
            <CacheProvider value={this.t2Cache}>
              <LibraryComponent>
                LibraryComponent
              </LibraryComponent>
            </CacheProvider>
          }
        </div>
      </div>
    );
  }
}

ReactDOM.render(
  <Main />,
  document.getElementById('root')
);

Looking at the resulting document, I see that the styles for LocalComponent are correctly prefixed with aaa and injected into the div holding the t1Ref. The styles used by LibraryComponent however, are prefixed with the default css prefix and injected into the document head, as if no custom CacheProvider was being used.

Screen Shot 2019-06-04 at 3 43 35 PM

If this is the intended behavior, then I would expect the docs to mention that CacheProvider does not work with bundled components.

Environment information:

  • react version: 16.8.6
  • @emotion/core version: 10.0.10
  • @emotion/cache version: 10.0.9

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:10
  • Comments:13 (7 by maintainers)

github_iconTop GitHub Comments

4reactions
zeckdudecommented, Mar 17, 2020

This works for JSS btw, so I’m not convinced this issue is how things work in general. I couldn’t tell you what the solution is but they made it work. Basically I have some code in the shadow dom in which I am using components made in Material UI (which uses JSS behind the scenes) that are from an external package and I am able to specify the location where those styles should be inserted. Not only does it insert all styles that are created within the shadow dom but also the ones that are imported via the package.

Unfortunately the solution that allows me to specify where to add the emotion styles that are created within the shadow dom does not also include the emotion styles that are imported via the package.

import root from 'react-shadow';
import { jssPreset, StylesProvider as MuiStylesProvider, MuiThemeProvider } from '@material-ui/core/styles';
import { ThemeProvider as EmotionThemeProvider } from 'emotion-theming';
import { create } from 'jss';
import React, { useState } from 'react';
import { CacheProvider as EmotionCacheProvider } from '@emotion/core';
import createCache from '@emotion/cache';
import { Theme, Components } from 'design-library';

// Define custom location to insert JSS styles (instead of document head)
// From: https://stackoverflow.com/a/57221293/83916

// Define custom location to insert Emotion styles (instead of document head)
// From: https://emotion.sh/docs/cache-provider

const ShadowDomContainer = ({ children }) => {
  const [jss, setJss] = useState(null);
  const [emotionCache, setEmotionCache] = useState(null);

  function createJssStyles(headRef) {
    if (headRef && !jss) {
      const createdJssWithRef = create({ ...jssPreset(), insertionPoint: headRef });
      setJss(createdJssWithRef);
    }
  }

  function setEmotionStyles(emotionRef) {
    if (emotionRef && !emotionCache) {
      const createdEmotionWithRef = createCache({
        container: emotionRef,
      });
      setEmotionCache(createdEmotionWithRef);
    }
  }

  function setShadowHeadRef(headRef) {
    createJssStyles(headRef);
    setEmotionStyles(headRef);
  }

  return (
    <root.div>
      <head ref={setShadowHeadRef} />
      {jss && emotionCache && (
        <MuiThemeProvider theme={Theme}>
          <EmotionThemeProvider theme={Theme}>
            <EmotionCacheProvider value={emotionCache}>
              <MuiStylesProvider jss={jss}>
                <Components.ScopedCssBaseline>{children}</Components.ScopedCssBaseline>
              </MuiStylesProvider>
            </EmotionCacheProvider>
          </EmotionThemeProvider>
        </MuiThemeProvider>
      )}
    </root.div>
  );
};

export default ShadowDomContainer;
3reactions
zeckdudecommented, Mar 18, 2020

@Andarist If that is the case, how would I solve the multiple packages issue?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Server Side Rendering - Emotion
To use emotion's SSR with Next.js you need a custom Document component in pages/_document.js that renders the styles and inserts them into the...
Read more >
Style library interoperability - Material UI - MUI
Note: If you are using styled-components and have StyleSheetManager with a custom target , make sure that the target is the first element...
Read more >
How to pass 'nonce' option to the @emotion/cache which is a ...
Using storybook for preact demos and webpack bundles ... I can see cache-block is rendered but the header styles are not updated with...
Read more >
Why you shouldn't use @emotion/core - Colin McDonnell
Emotion recommends using their non-standard css prop to style your components, instead of React's built-in className . This causes me ...
Read more >
Next.Js + MUI v5 tutorial - DEV Community ‍ ‍
With the help of MUI theme files you can create custom styles or ... First we import React; Next we import CacheProvider component...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found