Skip to content

Commit

Permalink
Fixed issue with cache created in render crashing SSRed site
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Mar 14, 2020
1 parent 994402e commit 3199270
Show file tree
Hide file tree
Showing 29 changed files with 777 additions and 731 deletions.
2 changes: 1 addition & 1 deletion packages/cache/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Allows changing Stylis's vendor prefixing settings. It can be a boolean or a fun

### `key`

`string`, defaults to `"css"`
`string`,

The prefix before class names. It will also be set as the value of the `data-emotion` attribute on the style tags that emotion inserts and it's used in the attribute name that marks style elements in `renderStylesToString` and `renderStylesToNodeStream`. This is **required if using multiple emotion caches in the same app**.

Expand Down
4 changes: 2 additions & 2 deletions packages/cache/__tests__/__snapshots__/hydration.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`it works 1`] = `
<html>
<head>
<style
data-emotion-css="1lrxbo5"
data-emotion="css 1lrxbo5"
>
.css-1lrxbo5{color:hotpink;}
</style>
Expand All @@ -17,7 +17,7 @@ exports[`rehydrated styles to head can be flushed 1`] = `
<html>
<head>
<style
data-emotion-emo="1lrxbo5"
data-emotion="emo 1lrxbo5"
>
.emo-1lrxbo5{color:hotpink;}
</style>
Expand Down
6 changes: 3 additions & 3 deletions packages/cache/__tests__/hydration.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ test('it works', () => {
let hash = hashString(css)
safeQuerySelector(
'body'
).innerHTML = `<style data-emotion-css="${hash}">.css-${hash}{${css}}</style>`
let cache = createCache()
).innerHTML = `<style data-emotion="css ${hash}">.css-${hash}{${css}}</style>`
let cache = createCache({ key: 'css' })
expect(cache.inserted).toEqual({ [hash]: true })
expect(document.documentElement).toMatchSnapshot()
})
Expand All @@ -24,7 +24,7 @@ test('rehydrated styles to head can be flushed', () => {
let hash = hashString(css)
safeQuerySelector(
'head'
).innerHTML = `<style data-emotion-emo="${hash}">.emo-${hash}{${css}}</style>`
).innerHTML = `<style data-emotion="emo ${hash}">.emo-${hash}{${css}}</style>`

// this moves emotion style tags at initialization time
jest.resetModules()
Expand Down
50 changes: 38 additions & 12 deletions packages/cache/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type Options = {
nonce?: string,
stylisPlugins?: StylisPlugins,
prefix?: PrefixOption,
key?: string,
key: string,
container?: HTMLElement,
speedy?: boolean,
prepend?: boolean
Expand All @@ -42,11 +42,31 @@ let getServerStylisCache = isBrowser
}
})

let movedStyles = false

let createCache = (options?: Options): EmotionCache => {
if (options === undefined) options = {}
let key = options.key || 'css'
let key = options.key
let stylisOptions

if (!key) {
throw new Error(
"You have to configure `key` for your cache. Please make sure it's unique (and not equal to 'css') as it's used for linking styles to your cache.\n" +
'If multiple caches share the same key they might "fight" for each other\'s style elements.'
)
}

if (isBrowser && !movedStyles && key === 'css') {
movedStyles = true

const ssrStyles = document.querySelectorAll(`style[data-emotion]`)
// get SSRed styles out of the way of React's hydration
// document.head is a safe place to move them to
Array.prototype.forEach.call(ssrStyles, (node: HTMLStyleElement) => {
;((document.head: any): HTMLHeadElement).appendChild(node)
})
}

if (options.prefix !== undefined) {
stylisOptions = {
prefix: options.prefix
Expand All @@ -70,16 +90,22 @@ let createCache = (options?: Options): EmotionCache => {
if (isBrowser) {
container = options.container || document.head

const nodes = document.querySelectorAll(`style[data-emotion-${key}]`)

Array.prototype.forEach.call(nodes, (node: HTMLStyleElement) => {
const attrib = node.getAttribute(`data-emotion-${key}`)
// $FlowFixMe
attrib.split(' ').forEach(id => {
inserted[id] = true
})
nodesToRehydrate.push(node)
})
Array.prototype.forEach.call(
document.querySelectorAll(`style[data-emotion]`),
(node: HTMLStyleElement) => {
const attrib = ((node.getAttribute(`data-emotion`): any): string).split(
' '
)
if (attrib[0] !== key) {
return
}
// $FlowFixMe
for (let i = 1; i < attrib.length; i++) {
inserted[attrib[i]] = true
}
nodesToRehydrate.push(node)
}
)
}

let insert: (
Expand Down
2 changes: 1 addition & 1 deletion packages/cache/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface Options {
nonce?: string
stylisPlugins?: StylisPlugin | Array<StylisPlugin>
prefix?: Prefix
key?: string
key: string
container?: HTMLElement
speedy?: boolean
prepend?: boolean
Expand Down
2 changes: 1 addition & 1 deletion packages/cache/types/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import createCache, { Options } from '@emotion/cache'
declare const testOptions: Options

// $ExpectType EmotionCache
createCache()
createCache({ key: 'test-key' })
// $ExpectType EmotionCache
createCache(testOptions)
2 changes: 1 addition & 1 deletion packages/css/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export const {
css,
sheet,
cache
} = createEmotion()
} = createEmotion({ key: 'css' })
Loading

0 comments on commit 3199270

Please sign in to comment.