Open brandonmp opened 7 years ago
i've worked up a solution but not sure it's solid. basically: i start a MutationObserver
that listens for data-aphrodite
style to be injected in the head
, then I take the textContent
of data-aphrodite
and inject it into my ShadowDOM
Does Aphrodite change the content of the style tag during run time? i.e., shoudl I also add a mutation observer for changes to the data-aphrodite
tag?
// observer listens for nodes added to <head>
// (this code isn't tested but it works at first blush)
const findAphrodite = new MutationObserver((mutations, obs) => {
mutations.forEach(mutation => {
Array.from(mutation.addedNodes).forEach(n => {
if (n.attributes.getNamedItem('data-aphrodite')) {
// find shadow DOM style tag and inject
document.querySelector('#extension')
.shadowRoot.querySelector('#aphroditeStyle').textContent = n.textContent
obs.disconnect()
}
})
})
})
then modified the original injection script to:
window.addEventListener('load', () => {
let injectDiv = document.createElement('div')
injectDiv.id = 'extension'
const shadowRoot = injectDiv.attachShadow({ mode: 'open' })
shadowRoot.innerHTML =
`<style>${require('raw-loader!app/styles/extension-material')}</style>
<div id='shadowReactRoot' />`
document.body.appendChild(injectDiv)
findAphrodite.observe(document.head, { childList: true })
ReactDOM.render(
<App />,
shadowRoot.querySelector('#shadowReactRoot')
)
})
})
The original error you were seeing,
Target container is not a DOM element.
(…)invariant @ invariant.js:44
_renderNewRootComponent @ ReactMount.js:311
_renderSubtreeIntoContainer @ ReactMount.js:401
render @ ReactMount.js:422
(anonymous function) @ index.js:88
is because you forgot to close your <style>
tag, so your <div id='shadowReactRoot' />
wasn't being added, and so React was complaining that you were trying to render to undefined. Closing your <style>
tag at least makes the error go away, but doesn't fix your overall problem.
There's another issue that's sorta similar to this one, #130. I wonder if the suggested StyleSheet.renderInFrame(frame, () => { ... })
suggestion might work here as well? Then your code would turn out like...
StyleSheet.renderInDocument(shadowRoot, () => {
ReactDOM.render(
<App />,
shadowRoot.querySelector('#shadowReactRoot')
)
});
Maybe we could do something fancy to detect if we're in a shadow DOM or an iframe, so that we don't try to use the <head>
tag.
@xymostech ah, i've spent too much time in jsx
i think. i didn't forget to close, i just thought style
could be self-closing (ie, <style data-aphrodite/>
)
the mutation observer is doing the trick for now, but i'll give a look @ the renderInDocument
approach if it starts to give me trouble.
Okay! That API doesn't exist yet, it was just something I was thinking about a while back and never got to implementing. :P If I get around to it I'll mention it here, maybe you could try it out.
I have a chrome extension that injects a content script into a shadow DOM node:
The first
style
tag is forreact-mdl
components. This nicely containerizes all the requisite style in the Extension content script w/o leaking style into the parent page.Aphrodite doesn't seem to like this, though. I followed the readme & tagged a
style
tag withdata-aphrodite
, but got this error:I assume the problem is this snippet from https://github.com/Khan/aphrodite/blob/master/src/inject.js
Is there a way using the existing Aphrodite API to inject into the correct style tag, nested within the shadow DOM node?
ETA: things I've tried:
When I remove the
<style data-aphrodite />
tag, the content script renders fine, and theaphrodite
styles are injected into the parent page'shead
Adding my own
<head />
to my shadow DOM node doesn't work--the shadow's<head />
doesn't even render^^ same is true when i try to structure shadow DOM more (
head
,html
,body
, etc.)