ryanseddon / react-frame-component

Render your React app to an iFrame
http://ryanseddon.github.io/react-frame-component/
MIT License
1.75k stars 156 forks source link

CSS from npm packages not getting inserted into iframe head #208

Closed 318097 closed 2 years ago

318097 commented 2 years ago

I am developing a chrome extension that injects a react app into the webpage using a content script. To avoid style conflicts with the main page, I am trying to load the react app (chrome extension) through an iframe.

The JSX & all the local styles (through mini-css-extract-plugin) are getting loaded using iframe but I have used 2 external libraries for UI

  1. mantine
  2. One of my custom library (used styled-components)

The CSS from these 2 libraries is not getting injected into the iframe's head. Please help.

vittorio commented 2 years ago

Same problem here with styled-components

export const StyledFrame = ({ children, ...rest }) => (
  <Frame {...rest}>
    <FrameContextConsumer>
      {
          (frameContext) => (
            <StyleSheetManager target={frameContext.document.head}>
              <>{children}</>
            </StyleSheetManager>
          )
        }
    </FrameContextConsumer>
  </Frame>
);

iframe's head remains empty :(

ryanseddon commented 2 years ago

@vittorio can you create a codesandbox.io showing the problem please

vittorio commented 2 years ago

@ryanseddon nevermind, it was a problem with children not with Frame. Sorry, example above is working just fine.

318097 commented 2 years ago

@ryanseddon - Hey, I have a sandbox that I forked from one of the solutions provided on StackOverflow. It's by the creators of Emotion I guess.

Here is the sandbox link

Note: Test component has 2 buttons rendered -

  1. mantine library - latest version uses emotion
  2. codedrops/react-ui - my custom library. uses styled-components

When Test is rendered outside Frame it works fine but inside the frame, it loses the CSS.

Please help.

318097 commented 2 years ago

@ryanseddon nevermind, it was a problem with children not with Frame. Sorry, example above is working just fine.

Can you please show me how you did it? Can you share codesandbox?

318097 commented 2 years ago

@ryanseddon I have created a new sandbox that shows how the component is rendered:

  1. normally
  2. using Frame
  3. using Frame along with StyleSheetManager

Here is the link

The component should look the same in an iframe and outside the iframe.

vittorio commented 2 years ago

@ryanseddon nevermind, it was a problem with children not with Frame. Sorry, example above is working just fine.

Can you please show me how you did it? Can you share codesandbox?

Exactly like here https://github.com/ryanseddon/react-frame-component/issues/208#issuecomment-1012324213

318097 commented 2 years ago

@ryanseddon nevermind, it was a problem with children not with Frame. Sorry, example above is working just fine.

Can you please show me how you did it? Can you share codesandbox?

Exactly like here #208 (comment)

I have implemented it here - https://codesandbox.io/s/load-styled-components-emotion-into-iframe-forked-v4kgc?file=/src/index.js

It's not working for external libraries. Can you suggest what can be done?

vittorio commented 2 years ago

@318097 are your external libraries styles build with styled-components or just injected via <link>?

318097 commented 2 years ago

@vittorio - It's build with styled-components and one is built with emotion

vittorio commented 2 years ago

@318097 try to add

<Frame initialContent={`<!DOCTYPE html><html><head>${document.head.innerHTML.toString()}</head><body><div></div></body></html>`} {...rest}>

to copy everything from parent's head into iframe

318097 commented 2 years ago

@vittorio will try it out

318097 commented 2 years ago

@vittorio - It's not working. Thanks anyways :)

ryanseddon commented 2 years ago

@318097 I responded to the discussion in the mantine repo. Essentially mantine needs to expose some apis within the emotion library which supports injecting styles into another container. Closing this as it's an issue with mantine.

318097 commented 2 years ago

@ryanseddon Thanks. But then all the external libraries which make use of CSS-in-JS need to expose that API? Because I can really understand if updates are needed from CSS-in-JS libraries (styled-components, emotion), UI libraries making use of CSS-in-JS packages (mantine), or the iframe/shadow DOM libraries (react-frame-components)

Lol..Just stuck in a loop

But Thank you @ryanseddon for helping out with whatever you could :)

ryanseddon commented 2 years ago

I think there is a way around it without having to rely on mantine to expose the apis, you'd have to install @emotion/cache and @emotion/core as direct dependencies which should dedupe for mantine. With that you then createCache and use the provider to pass down the configuration and in theory mantine will pick up that.

I'll try and have a play around with it when I get some free time.

318097 commented 2 years ago

Sure will try that. I would have to rewrite my app & library if I don't get a solution.

Please share codesandbox if you find a solution. I am trying variations of Vittorio's solution.

paulm17 commented 1 year ago

@318097 Did you ever get this working? I tried the solution over at the mantine thread but I didn't get any styles.

In the end, this is what worked for me. Hopefully it works well when there are a lot of components in the iframe. 🤔

const emotionStyles =
    typeof document === "object"
      ? Array.from(
          (document as any).head.querySelectorAll(`style[data-emotion]`),
        )
      : []

<FrameContextConsumer>
  {({ document }) => {
    setTimeout(() => {
      if (document.head.querySelector("#emotion")) {
        // remove the old styles
        document.head.querySelector("#emotion").innerHTML = ""

        // inject the new styles
        ;(stylesRef.current as Element[]).forEach(s =>
          document.head
            .querySelector("#emotion")
            .appendChild(s.cloneNode(true)),
        )
      }
    }, 100)

    return <Editor />              
  }}
</FrameContextConsumer>
hilmanauz commented 1 year ago

Hi @paulm17 , it's kinda interesting because i also use mantine on iframe but can you please share the code on codesandbox? i want to see the output itself. Thanks

paulm17 commented 1 year ago

@hilmanauz unfortunately not. All I can suggest is to try mantine v7, as v6 did not work. Also I am not really using mantine now, more of a fork to support tailwind.