-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
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
CSS-in-JS Rendering Hooks #3236
Comments
Hi, This is definitively something we should have, but is not so easy. It's already been mentioned somewhere that we may need to do something similar to how Gatsby works (docusaurus-browser/docusaurus-ssr files...). I don't have much more infos to provide, this needs exploration :) Maybe a good start would be to study all the css-in-js gatsby plugins, and maybe create some kind of doc/spreadsheet, to see what are the useful lifecycles / api surface to provide to make it possible to support a wide range of CSS-in-JS libraries. |
Yes, off the top of my head the necessary operations for CSS-in-JS libs tend to be:
The latter 3 are all supported in Docusaurus in one way or another AFAICT; what's really missing is wrapping the In Gatsby as I'm sure you know, this is done through the It seems to me, that these correspond to the |
Examples from Gatsbyβnote: many only require a babel plugin for the client side, and only modify rendering for the SSR part |
@slorber on closer examination, after trying to hack this today: I'm guessing when you said "it's not so easy" you might have been thinking about |
Thanks for the details @lunelson I don't have time to investigate these things right now but we'll likely come back to it once i18n is there |
Note, we might introduce a way to wrap root element in this PR: #3153 |
@slorber yes functions for wrapping root and/or page element would also solve #2891. I see that you've indicated it as low-priority, but IMO it's rather important, e.g. for components or context-providers that may be maintaining global state and doing async operations, such as an analytics consent-manager which is causing me trouble at the moment |
@lunelson in the meantime alpha66 declare a new component "LayoutProviders" that you can swizzle and wrap with custom providers. For minimum maintenance burden, you can also check this doc to "enhance" an existing theme comp without duplicating its code: https://v2.docusaurus.io/docs/using-themes/#wrapping-theme-components But I understand the issue about stateful providers resetting their states. We'll try to solve this soon after I finish i18n. |
Thanks for the tips @slorber, good to know about those new components, but indeed yes the remounting-on-route-change problem remains open |
@slorber @lunelson Could you suggest any workaround to avoid a flash of unstyled content using docusaurus and |
@sawasawasawa yes I believe this is the essential problem with CSS-in-JS in docusaurus, that is the lack of server-side-rendering support. Normally in the SSR phase, CSS-in-JS rules should be collected and written in to the |
So the fouc has something to do with docusaurus and not with styled components? |
It has something to do with both. |
ok.. so the issue can only be fixed in docusaurus itself? |
ok.. I investigated some time in fixing this issue.. so is there a plan in creating a styled-component integration for docusaurus in the near future |
@bennodev19 the solution requires an API to be made available from docusaurus, similar to Gatsby's |
yeah sure.. I tried to create such interface/api.. but I wasn't able to bring it to life.. |
@bennodev19 that's something we want to work on but is not so simple. You'd rather convert to css modules if you cannot wait because I don't think we should rush on implementation without a careful design. |
Hey guys, I found a super hacky way to collect styles for I'm voting for public API, which will allow returning your element before passing it to Hacky way
import React from 'react'
import { renderToString } from 'react-dom/server'
import { ServerStyleSheet } from 'styled-components'
import { StaticRouter, useLocation } from 'react-router-dom'
import { HelmetProvider } from 'react-helmet-async'
import { Context as DocusaurusContext } from '@docusaurus/core/lib/client/docusaurusContext'
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
function ServerStyle({ from: children }) {
let style = null
const location = useLocation()
const context = useDocusaurusContext()
const sheet = new ServerStyleSheet()
try {
renderToString(
sheet.collectStyles(
<HelmetProvider>
<StaticRouter location={location}>
<DocusaurusContext.Provider value={context}>
{children}
</DocusaurusContext.Provider>
</StaticRouter>
</HelmetProvider>,
),
)
style = sheet.getStyleElement()
} catch (error) {
console.error(error)
} finally {
sheet.seal()
}
return style
}
function ClientStyle() {
return null
}
export default typeof window === 'undefined' ? ServerStyle : ClientStyle
// /src/theme/Root.js
import React from 'react'
import ServerStyle from './ServerStyle'
function Root({ children }) {
return (
<>
<ServerStyle from={children} />
{children}
</>
)
}
export default Root UPD: Fixed |
I think that we can add a plugin point here: plugin.serverSideRender = (renderToString, element /*wholeTreeWithLoadableHelmetProviderStaticRouterEtc*/)=>{
const sheet = new ServerStyleSheet();
const html = renderToString(sheet.collectStyles(element))
const headTags = sheet.getStyleTags()
return {headTags, html}
} |
Yes, that seems like a reasonable thing to do. I'd be interested if someone could help design an API that works for most CSS-in-JS libs, and also allow composition (ie one plugin provides its CSS-in-JS integration, and you can use 2 CSS-in-JS libs by combining 2 plugins) This requires studying the ecosystem a bit. I'd like to have a table with expected CSS-in-JS libs compatibility before merging a PR. This is the Gatsby API: https://www.gatsbyjs.com/docs/reference/config-files/gatsby-ssr/#replaceRenderer |
en... |
I would recommend considering https://github.com/callstack/linaria as it is much better for performance than others. |
hello Docusaurus friends π I wanted to report having the same issue here w/ rendering any styled-components in my extended/swizzled Docusaurus templates. This caused a good deal of flicker and in some cases the CSS did not load initially at all. As of now, the workaround @exah describes above is working well for me when I render these components separately during the Layout rendering when the window is not yet available. Some Docusuarus components are SSR safe, but others which rely on Scroll Context or Announcement Context etc do not seem to be at the moment. Just sharing for anyone else facing this challenge. (swizzled theme-common Layout):
|
I'm commenting on this without thinking - we can use https://stitches.dev |
The usage of React Server Components is growing, and we plan to adopt them in Docusaurus. And we see that the past generation of runtime-based CSS-in-JS libs does not play with React Server Components (more explanations here: #8959). At this point I'm not even sure we need to have these hooks anymore, it goes against the industry trend to adopt no-runtime solutions. Many existing libs are in the process of figuring out how to benefit most from Server Components, so I think we should wait and decide later what is best for Docusaurus. For the moment, I'm leaning towards not implementing these hooks because I believe it wouldn't encourage the usage of performant code by default in the long term, and the only good reason to implement those is to be compatible with legacy UI libs. |
π₯ Proposal: Hooks for CSS-in-JS Client and Server Rendering
So, the [v2] βοΈ Umbrella issue for v2 docs has the above open TODO (although the issue has been closed); and this is also currently mentioned in the docs as "welcoming PRs".
I have some experience with the setup patterns for
emotion
(incl. v11) andstyled-components
here, and would like to help with this. As far as I can tell from the source, this would require additions to the Lifecycle APIs so that theserverEntry.js
andclientEntry.ts
files' rendering functions could be modified. I would need some guidance on creating these hooks.Anyone want to help me get started?
The text was updated successfully, but these errors were encountered: