Skip to content

Commit

Permalink
Stylis v4 tryout
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Mar 20, 2020
1 parent ff9746b commit 9145eaa
Show file tree
Hide file tree
Showing 39 changed files with 2,038 additions and 3,530 deletions.
158 changes: 71 additions & 87 deletions packages/cache/src/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
// @flow
import { StyleSheet } from '@emotion/sheet'
import { type EmotionCache, type SerializedStyles } from '@emotion/utils'
import Stylis from '@emotion/stylis'
import {
serialize,
compile,
middleware,
rulesheet,
stringify,
compat,
prefixer
} from '@emotion/stylis'
import weakMemoize from '@emotion/weak-memoize'
import { Sheet, removeLabel, ruleSheet } from './stylis-plugins'
import { removeLabel } from './stylis-plugins'
import type { StylisPlugin } from './types'

let isBrowser = typeof document !== 'undefined'
Expand All @@ -23,8 +31,6 @@ export type Options = {
prepend?: boolean
}

let rootServerStylisCache = {}

let getServerStylisCache = isBrowser
? undefined
: weakMemoize(() => {
Expand All @@ -42,11 +48,11 @@ let getServerStylisCache = isBrowser
}
})

const defaultStylisPlugins = [compat, prefixer]
let movedStyles = false

let createCache = (options: Options): EmotionCache => {
let key = options.key
let stylisOptions

if (!key) {
throw new Error(
Expand All @@ -66,13 +72,7 @@ let createCache = (options: Options): EmotionCache => {
})
}

if (options.prefix !== undefined) {
stylisOptions = {
prefix: options.prefix
}
}

let stylis = new Stylis(stylisOptions)
const stylisPlugins = options.stylisPlugins || defaultStylisPlugins

if (process.env.NODE_ENV !== 'production') {
// $FlowFixMe
Expand Down Expand Up @@ -115,46 +115,59 @@ let createCache = (options: Options): EmotionCache => {
) => string | void

if (isBrowser) {
stylis.use(options.stylisPlugins)(ruleSheet)
let currentSheet
const finalizer = middleware(
stylisPlugins.concat([
removeLabel,
stringify,
rulesheet(rule => {
currentSheet.insert(rule)
})
])
)
const stylis = styles => serialize(compile(styles), finalizer)

insert = (
selector: string,
serialized: SerializedStyles,
sheet: StyleSheet,
shouldCache: boolean
): void => {
let name = serialized.name
Sheet.current = sheet
currentSheet = sheet
if (
process.env.NODE_ENV !== 'production' &&
serialized.map !== undefined
) {
let map = serialized.map
Sheet.current = {
insert: (rule: string) => {
sheet.insert(rule + map)
currentSheet = {
insert: rule => {
sheet.insert(rule + serialized.map)
}
}
}
stylis(selector, serialized.styles)

if (selector === '') {
stylis(serialized.styles)
} else {
stylis(`${selector}{${serialized.styles}}`)
}

if (shouldCache) {
cache.inserted[name] = true
cache.inserted[serialized.name] = true
}
}
} else {
stylis.use(removeLabel)
let serverStylisCache = rootServerStylisCache
if (options.stylisPlugins || options.prefix !== undefined) {
stylis.use(options.stylisPlugins)
// $FlowFixMe
serverStylisCache = getServerStylisCache(
options.stylisPlugins || rootServerStylisCache
)(options.prefix)
}
const finalizer = middleware(stylisPlugins.concat([removeLabel, stringify]))
const stylis = styles => serialize(compile(styles), finalizer)

let serverStylisCache = getServerStylisCache(stylisPlugins)
let getRules = (selector: string, serialized: SerializedStyles): string => {
let name = serialized.name
if (serverStylisCache[name] === undefined) {
serverStylisCache[name] = stylis(selector, serialized.styles)
if (selector === '') {
serverStylisCache[name] = stylis(serialized.styles)
} else {
serverStylisCache[name] = stylis(`${selector}{${serialized.styles}}`)
}
}
return serverStylisCache[name]
}
Expand Down Expand Up @@ -201,62 +214,33 @@ let createCache = (options: Options): EmotionCache => {
}

if (process.env.NODE_ENV !== 'production') {
// https://esbench.com/bench/5bf7371a4cd7e6009ef61d0a
const commentStart = /\/\*/g
const commentEnd = /\*\//g

stylis.use((context, content) => {
switch (context) {
case -1: {
while (commentStart.test(content)) {
commentEnd.lastIndex = commentStart.lastIndex

if (commentEnd.test(content)) {
commentStart.lastIndex = commentEnd.lastIndex
continue
}

throw new Error(
'Your styles have an unterminated comment ("/*" without corresponding "*/").'
)
}

commentStart.lastIndex = 0
break
}
}
})

stylis.use((context, content, selectors) => {
switch (context) {
case -1: {
const flag =
'emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason'
const unsafePseudoClasses = content.match(
/(:first|:nth|:nth-last)-child/g
)

if (unsafePseudoClasses && cache.compat !== true) {
unsafePseudoClasses.forEach(unsafePseudoClass => {
const ignoreRegExp = new RegExp(
`${unsafePseudoClass}.*\\/\\* ${flag} \\*\\/`
)
const ignore = ignoreRegExp.test(content)

if (unsafePseudoClass && !ignore) {
console.error(
`The pseudo class "${unsafePseudoClass}" is potentially unsafe when doing server-side rendering. Try changing it to "${
unsafePseudoClass.split('-child')[0]
}-of-type".`
)
}
})
}

break
}
}
})
// stylis.use((context, content, selectors) => {
// switch (context) {
// case -1: {
// const flag =
// 'emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason'
// const unsafePseudoClasses = content.match(
// /(:first|:nth|:nth-last)-child/g
// )
// if (unsafePseudoClasses && cache.compat !== true) {
// unsafePseudoClasses.forEach(unsafePseudoClass => {
// const ignoreRegExp = new RegExp(
// `${unsafePseudoClass}.*\\/\\* ${flag} \\*\\/`
// )
// const ignore = ignoreRegExp.test(content)
// if (unsafePseudoClass && !ignore) {
// console.error(
// `The pseudo class "${unsafePseudoClass}" is potentially unsafe when doing server-side rendering. Try changing it to "${
// unsafePseudoClass.split('-child')[0]
// }-of-type".`
// )
// }
// })
// }
// break
// }
// }
// })
}

const cache: EmotionCache = {
Expand Down
97 changes: 12 additions & 85 deletions packages/cache/src/stylis-plugins.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,16 @@
// @flow
// https://github.com/thysultan/stylis.js/tree/master/plugins/rule-sheet
// inlined to avoid umd wrapper and peerDep warnings/installing stylis
// since we use stylis after closure compiler
import { DECLARATION, charat } from '@emotion/stylis'

import type { StylisPlugin } from './types'

const delimiter = '/*|*/'
const needle = delimiter + '}'

function toSheet(block) {
if (block) {
Sheet.current.insert(block + '}')
}
}

export let Sheet: { current: { +insert: string => void } } = {
current: (null: any)
}

export let ruleSheet: StylisPlugin = (
context,
content,
selectors,
parents,
line,
column,
length,
ns,
depth,
at
) => {
switch (context) {
// property
case 1: {
switch (content.charCodeAt(0)) {
case 64: {
// @import
Sheet.current.insert(content + ';')
return ''
}
// charcode for l
case 108: {
// charcode for b
// this ignores label
if (content.charCodeAt(2) === 98) {
return ''
}
}
}
break
export let removeLabel = element => {
if (element.type === DECLARATION) {
var value = element.value
if (
// charcode for l
charat(value, 0) === 108 &&
// charcode for b
charat(value, 2) === 98
) {
// this ignores label
element.value = ''
}
// selector
case 2: {
if (ns === 0) return content + delimiter
break
}
// at-rule
case 3: {
switch (ns) {
// @font-face, @page
case 102:
case 112: {
Sheet.current.insert(selectors[0] + content)
return ''
}
default: {
return content + (at === 0 ? delimiter : '')
}
}
}
case -2: {
content.split(needle).forEach(toSheet)
}
}
}

export let removeLabel: StylisPlugin = (context, content) => {
if (
context === 1 &&
// charcode for l
content.charCodeAt(0) === 108 &&
// charcode for b
content.charCodeAt(2) === 98
// this ignores label
) {
return ''
}
}
6 changes: 2 additions & 4 deletions packages/cache/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// Definitions by: Junyoung Clare Jang <https://github.com/Ailrun>
// TypeScript Version: 2.2
import { Plugin as StylisPlugin, Prefix } from '@emotion/stylis'
import { EmotionCache } from '@emotion/utils'

export { StylisPlugin, Prefix, EmotionCache }
export { EmotionCache }

export interface Options {
nonce?: string
stylisPlugins?: StylisPlugin | Array<StylisPlugin>
prefix?: Prefix
stylisPlugins?: any
key: string
container?: HTMLElement
speedy?: boolean
Expand Down
Loading

0 comments on commit 9145eaa

Please sign in to comment.