-
-
Notifications
You must be signed in to change notification settings - Fork 23
feat: render devtools in a shadow node #181
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
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 4b3b456 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
More templates
@tanstack/devtools
@tanstack/devtools-ui
@tanstack/devtools-utils
@tanstack/devtools-vite
@tanstack/devtools-event-bus
@tanstack/devtools-event-client
@tanstack/react-devtools
@tanstack/solid-devtools
commit: |
observer.disconnect() | ||
}) | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So "syncing" the styles from the parent page to the shadow DOM node is not what I initially set out to do. In fact, there were two approaches I made prior to this, but both failed.
-
Approach 1: Leverage goobers
css.bind({ target: <element> })
feature.- This basically involves creating a context provider that binds the CSS target and passes that down to child components to use.
- This looked like a
useGoober
hook in the UI library, that provides the CSS bound target for the shadow node - Just did not work. Even when binding the target manually, goober always appended the styles to the head of the owner document and not the shadow root. Both UI and devtool packages were implementing the context packages correctly.
- Reference material, Goober Docs
- Perhaps this is worth a revisit
-
Approach 2: Just do Goobers
extractCSS
- Only works on the server 🤷
})) | ||
} | ||
|
||
setPluginContainers((prev) => ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we are rendering the component in a shadow DOM node, e.ownerDocument.getElementById(id)
always returns null
and the plugins are never mounted.
I'm not certain I understand what this if
statement guards against since I thought the elements were defined by the devtools plugin itself. Shouldn't they always exist?
0300fc1
to
cc4f0c6
Compare
e3dbc48
to
47ba6ce
Compare
3649303
to
4b3b456
Compare
Thank you for the PR, I'll review it in more details as soon as I can, before then, what exactly would be the benefit of rendering it in a shadow dom besides escaping global styling? |
Of course, @AlemTuzlak! I honestly haven't really thought about any other benefits but I guess this is what I found after a little research:
Beyond that, I'm not sure what additional benefits we receive. In all honesty, I would hope style isolation would be an absolute requirement for this package if its intended to be used across any application. I've tried to introduce this into our organization, but our CSS reset is getting in the way of the styles in the devtools and things are quite visually broken. |
As an FYI, I was able to end up binding the goober All this to say, the current solution (in this PR) syncs styles from all goober usage on the page, to within the shadow root and it works perfectly fine. The code for the pip styling was inspiration for this. This was the proof-of-concept for the context stuff if you cared to see, but it seems like it would be a pain to continue down this route. // packages/devtools-ui/src/components/shadow-root.tsx
import { createContext, onCleanup, onMount, useContext } from 'solid-js'
import { render } from 'solid-js/web'
import { css as gooberCss } from 'goober'
import type { ParentComponent } from 'solid-js'
export type CssFn = typeof gooberCss
type GooberCtx = { css: CssFn }
const GooberContext = createContext<GooberCtx>()
export const useCss = () => {
const ctx = useContext(GooberContext)
if (!ctx) throw new Error('useCss must be used inside <ShadowRoot>')
return ctx
}
export const ShadowRoot: ParentComponent = (props) => {
let host!: HTMLDivElement
onMount(() => {
const shadow = host.attachShadow({ mode: 'open' })
const ctx: GooberCtx = { css: gooberCss.bind({ target: shadow }) }
const dispose = render(
() => (
<GooberContext.Provider value={ctx}>
{props.children}
</GooberContext.Provider>
),
shadow,
)
onCleanup(dispose)
})
return <div ref={host} />
} |
I had a question @jakiestfu - I already started using the DevTools to be a frame for some existing UI pieces I'm using in my app. Does this affect that use case? I'd rather not have to muck around with css injection or something to get around the shadow dom. |
Do you mean this frame, @colelawrence? If so, I have no idea. I could explore your use-cases for you if you wanted to share a little more or high-level it for me. MDN does note And if by chance you mean
We already do that for the PIP window though because we're using Goober 🥺 |
I apologize in advance for my eagerness to have this shipped or explored by the maintainers. The lack of style sandboxing is fully preventing us at Turo from adopting devtools internally as the styles are well... broken Stronger CSS styling could help this problem, but that pushes the work and effort unto the end-users of the devtools package as opposed to the package itself handling this. What can I do for ya'll to help support your efforts? |
Sorry I had some deadlines I needed to hit so I had no time to look at this, will get to it this week definitely |
@AlemTuzlak Hello again! I have built a feature to render the devtools in a shadow dom node. This ensures that styles are not inherited from the parent page. However, there are some caveats and/or things I'm not 100% certain I understand, and wanted to pose this PR to perhaps start those discussions.
As you can see, I've added some styles to the basic example that aggressively target the styles of the devtools UI. After the change, there is no interference.