Skip to content

Commit

Permalink
create-emotion-server: refactor inline for performance (#725)
Browse files Browse the repository at this point in the history
The current version of renderStylesToString is highly inefficient as
it allocates new arrays over and over, which isn't necessary.
Instead just do a single pass hydrate which improves performance
roughly 30x in most scenarios.
  • Loading branch information
apapirovski authored and emmatown committed Jun 14, 2018
1 parent 6057202 commit 0847bd2
Showing 1 changed file with 48 additions and 51 deletions.
99 changes: 48 additions & 51 deletions packages/create-emotion-server/src/inline.js
Original file line number Diff line number Diff line change
@@ -1,77 +1,74 @@
// @flow
import type { Emotion } from 'create-emotion'

function toTag(
emotion: Emotion,
ids: Array<string>,
thing: { keys: Array<string> },
function generateStyleTag(
cssKey: string,
ids: string,
styles: string,
nonceString: string
) {
let idhash = ids.reduce((o, x) => {
o[x] = true
return o
}, {})
let styles = ''
let idHydration = ''
thing.keys = thing.keys.filter(id => {
if (idhash[id] !== undefined && emotion.caches.inserted[id] !== true) {
styles += emotion.caches.inserted[id]
idHydration += ` ${id}`
}
return true
})
return `<style data-emotion-${emotion.caches.key}="${idHydration.substring(
return `<style data-emotion-${cssKey}="${ids.substring(
1
)}"${nonceString}>${styles}</style>`
}

const createRenderStylesToString = (emotion: Emotion, nonceString: string) => (
html: string
): string => {
let regex = new RegExp(`<|${emotion.caches.key}-([a-zA-Z0-9-]+)`, 'gm')
const { inserted, key: cssKey, registered } = emotion.caches
const regex = new RegExp(`<|${cssKey}-([a-zA-Z0-9-]+)`, 'gm')

const seen = {}

let match
let lastBackIndex = 0
let idBuffer = []
let result = ''
let insed = {}
let keys = Object.keys(emotion.caches.inserted)
let globalStyles = ''
let globalIds = ''
keys = keys.filter(id => {
if (
emotion.caches.registered[`${emotion.caches.key}-${id}`] === undefined &&
emotion.caches.inserted[id] !== true
) {
globalStyles += emotion.caches.inserted[id]
globalIds += ` ${id}`
return false
let globalStyles = ''

for (const id in inserted) {
if (inserted.hasOwnProperty(id)) {
const style = inserted[id]
const key = `${cssKey}-${id}`
if (style !== true && registered[key] === undefined) {
globalStyles += style
globalIds += ` ${id}`
}
}
return true
})
}

if (globalStyles !== '') {
result += `<style data-emotion-${emotion.caches.key}="${globalIds.substring(
1
)}"${nonceString}>${globalStyles}</style>`
result = generateStyleTag(cssKey, globalIds, globalStyles, nonceString)
}
const thing = { keys }

let ids = ''
let styles = ''
let lastInsertionPoint = 0
let match

while ((match = regex.exec(html)) !== null) {
if (match[0] === '<') {
idBuffer = idBuffer.filter(x => !insed[x])
if (idBuffer.length > 0) {
result += toTag(emotion, idBuffer, thing, nonceString)
if (ids !== '') {
result += generateStyleTag(cssKey, ids, styles, nonceString)
ids = ''
styles = ''
}
result += html.substring(lastBackIndex, match.index)
lastBackIndex = match.index
idBuffer.forEach(x => {
insed[x] = true
})
idBuffer = []
} else {
idBuffer.push(match[1])
result += html.substring(lastInsertionPoint, match.index)
lastInsertionPoint = match.index
continue
}

const id = match[1]
const style = inserted[id]
if (style === true || seen[id]) {
continue
}

seen[id] = true
styles += style
ids += ` ${id}`
}
result += html.substring(lastBackIndex, html.length)

result += html.substring(lastInsertionPoint)

return result
}

Expand Down

0 comments on commit 0847bd2

Please sign in to comment.