Skip to content

Commit 65fac47

Browse files
authored
Fix SSR with multiple createEmotion calls with the same context (#605)
1 parent 9e2184c commit 65fac47

3 files changed

Lines changed: 82 additions & 30 deletions

File tree

packages/create-emotion/src/index.js

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ type StylisPlugins = Function[] | null | Function
1515
type EmotionCaches = {|
1616
registered: { [key: string]: string },
1717
inserted: { [key: string]: string | true },
18-
stylis: (scope: string, styles: string) => string,
19-
sheet: StyleSheet,
2018
nonce?: string,
2119
key: string
2220
|}
@@ -62,9 +60,12 @@ type EmotionOptions = {
6260
}
6361

6462
function createEmotion(
65-
context: { __SECRET_EMOTION__?: EmotionCaches },
63+
context: { __SECRET_EMOTION__?: Emotion },
6664
options?: EmotionOptions
6765
): Emotion {
66+
if (context.__SECRET_EMOTION__ !== undefined) {
67+
return context.__SECRET_EMOTION__
68+
}
6869
if (options === undefined) options = {}
6970
let key = options.key || 'css'
7071
if (process.env.NODE_ENV !== 'production') {
@@ -74,10 +75,7 @@ function createEmotion(
7475
)
7576
}
7677
}
77-
// $FlowFixMe
78-
let caches: EmotionCaches = context.__SECRET_EMOTION__
7978
let current
80-
8179
function insertRule(rule: string) {
8280
current += rule
8381
if (isBrowser) {
@@ -87,35 +85,33 @@ function createEmotion(
8785

8886
const insertionPlugin = stylisRuleSheet(insertRule)
8987

90-
if (caches === undefined) {
91-
const stylisOptions: StylisOptions = {
92-
keyframe: false,
93-
global: false,
94-
prefix: options.prefix === undefined ? true : options.prefix,
95-
semicolon: true
96-
}
88+
const stylisOptions: StylisOptions = {
89+
keyframe: false,
90+
global: false,
91+
prefix: options.prefix === undefined ? true : options.prefix,
92+
semicolon: true
93+
}
9794

98-
if (process.env.NODE_ENV !== 'production') {
99-
stylisOptions.compress = false
100-
}
101-
context.__SECRET_EMOTION__ = caches = {
102-
registered: {},
103-
inserted: {},
104-
sheet: new StyleSheet(options),
105-
stylis: new Stylis(stylisOptions),
106-
nonce: options.nonce,
107-
key
108-
}
95+
if (process.env.NODE_ENV !== 'production') {
96+
stylisOptions.compress = false
97+
}
98+
99+
const caches = {
100+
registered: {},
101+
inserted: {},
102+
nonce: options.nonce,
103+
key
104+
}
105+
106+
const sheet = new StyleSheet(options)
109107

110-
caches.stylis.use(options.stylisPlugins)(insertionPlugin)
108+
if (isBrowser) {
111109
// 🚀
112-
if (isBrowser) {
113-
caches.sheet.inject()
114-
}
110+
sheet.inject()
115111
}
116112

117-
let stylis = caches.stylis
118-
let sheet = caches.sheet
113+
let stylis = new Stylis(stylisOptions)
114+
stylis.use(options.stylisPlugins)(insertionPlugin)
119115

120116
let currentSourceMap = ''
121117

@@ -355,6 +351,7 @@ function createEmotion(
355351
sheet,
356352
caches
357353
}
354+
context.__SECRET_EMOTION__ = emotion
358355
return emotion
359356
}
360357

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`multiple createEmotion calls with the same context are the same 1`] = `
4+
5+
<style data-emotion-css="84kji8 16qlhaj hbhpyh">
6+
@font-face{font-family:'Patrick Hand SC';font-style:normal;font-weight:400;src:local('Patrick Hand SC'),local('PatrickHandSC-Regular'),url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');unicode-range:U+0100-024f,U+1-1eff,U+20a0-20ab,U+20ad-20cf,U+2c60-2c7f,U+A720-A7FF;}@-webkit-keyframes animation-16qlhaj{from,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%,43%{-webkit-animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-30px,0);-ms-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0);}70%{-webkit-animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-15px,0);-ms-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0);}90%{-webkit-transform:translate3d(0,-4px,0);-ms-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}@keyframes animation-16qlhaj{from,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);animation-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%,43%{-webkit-animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-30px,0);-ms-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0);}70%{-webkit-animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);animation-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-15px,0);-ms-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0);}90%{-webkit-transform:translate3d(0,-4px,0);-ms-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}}.no-prefix{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}
7+
</style>
8+
<style data-emotion-css="4xq7ky">
9+
.css-4xq7ky{color:hotpink;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}.css-4xq7ky:hover{color:white;background-color:lightgray;border-color:aqua;box-shadow:-15px -15px 0 0 aqua,-30px -30px 0 0 cornflowerblue;}
10+
</style>
11+
<main class="css-4xq7ky e126fyao0"
12+
data-reactroot
13+
>
14+
<style data-emotion-css="z382ib">
15+
.css-z382ib{-webkit-animation:animation-16qlhaj;animation:animation-16qlhaj;border-radius:50%;height:50px;width:50px;background-color:red;}
16+
</style>
17+
<img size="30"
18+
class="css-z382ib e126fyao1"
19+
>
20+
<img size="100"
21+
class="css-z382ib e126fyao1"
22+
>
23+
<img class="css-z382ib e126fyao1">
24+
</main>
25+
26+
`;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// @flow
2+
/**
3+
* @jest-environment node
4+
*/
5+
import React from 'react'
6+
import createEmotion from 'create-emotion'
7+
import createEmotionServer from 'create-emotion-server'
8+
import createEmotionStyled from 'create-emotion-styled'
9+
import { renderToString } from 'react-dom/server'
10+
import { getComponents } from '../../emotion-server/test/util'
11+
12+
test('multiple createEmotion calls with the same context are the same', () => {
13+
const context = {}
14+
const emotion1 = createEmotion(context)
15+
const emotion2 = createEmotion(context)
16+
const emotionServer1 = createEmotionServer(emotion1)
17+
const emotionServer2 = createEmotionServer(emotion2)
18+
const styled = createEmotionStyled(emotion1, React)
19+
20+
const Components = getComponents(emotion1, { default: styled })
21+
const one = emotionServer1.renderStylesToString(
22+
renderToString(<Components.Page1 />)
23+
)
24+
const two = emotionServer2.renderStylesToString(
25+
renderToString(<Components.Page1 />)
26+
)
27+
expect(one).toEqual(two)
28+
expect(one).toMatchSnapshot()
29+
})

0 commit comments

Comments
 (0)