311eea4c6a
### What & Why emotion-js has its own [jsx transform](https://emotion.sh/docs/typescript#emotionreact) which is being applied when `compiler.emotion` is enabled in `next.config.js`. Thanks to emotion-js team that provided an emotion-js example setup with app router [here](https://github.com/emotion-js/emotion/issues/2928#issuecomment-1319792703), so that we can use it as test example with app router. Based on the setup, we create a test case working with emotion js but failed with error mentioned in #41994 that some client hooks appearing in server components. That is because the emotion-js jsx factory includes some client hooks. ### How For server components, css-in-js is not recommended to apply so we disabled the transform before, the emotion jsx factory is a separate config that should also not be applied in server components. So in this case we still use react jsx factory instead of the emotion-js one for server components then it won't error. The test case can also be used as an example for basic emotion-js use case with app router. Fixes #41994 Closes NEXT-1368
47 lines
1.2 KiB
JavaScript
47 lines
1.2 KiB
JavaScript
'use client'
|
|
|
|
import { CacheProvider } from '@emotion/react'
|
|
import createCache from '@emotion/cache'
|
|
import { useServerInsertedHTML } from 'next/navigation'
|
|
import { useState } from 'react'
|
|
|
|
export default function RootStyleRegistry({ children }) {
|
|
const [{ cache, flush }] = useState(() => {
|
|
const cache = createCache({ key: 'emotion-cache' })
|
|
cache.compat = true
|
|
const prevInsert = cache.insert
|
|
let inserted = []
|
|
cache.insert = (...args) => {
|
|
const serialized = args[1]
|
|
if (cache.inserted[serialized.name] === undefined) {
|
|
inserted.push(serialized.name)
|
|
}
|
|
return prevInsert(...args)
|
|
}
|
|
const flush = () => {
|
|
const prevInserted = inserted
|
|
inserted = []
|
|
return prevInserted
|
|
}
|
|
return { cache, flush }
|
|
})
|
|
|
|
useServerInsertedHTML(() => {
|
|
const names = flush()
|
|
if (names.length === 0) return null
|
|
let styles = ''
|
|
for (const name of names) {
|
|
styles += cache.inserted[name]
|
|
}
|
|
return (
|
|
<style
|
|
data-emotion={`${cache.key} ${names.join(' ')}`}
|
|
dangerouslySetInnerHTML={{
|
|
__html: styles,
|
|
}}
|
|
/>
|
|
)
|
|
})
|
|
|
|
return <CacheProvider value={cache}>{children}</CacheProvider>
|
|
}
|