Skip to content

Instantly share code, notes, and snippets.

@whs
Created November 14, 2018 01:46
Show Gist options
  • Select an option

  • Save whs/32cca87838ab5071bb9e0c01672ce95f to your computer and use it in GitHub Desktop.

Select an option

Save whs/32cca87838ab5071bb9e0c01672ce95f to your computer and use it in GitHub Desktop.
import {caches as defaultCaches} from 'emotion';
import parse5 from 'parse5';
import {
insertBefore,
createElement,
insertText,
createDocumentFragment,
appendChild,
} from 'parse5/lib/tree-adapters/default';
function generateStyleTag(cssKey, ids, styles) {
let out = createElement('style', '', [
{
name: `data-emotion-${cssKey}`,
value: ids.join(' '),
},
]);
insertText(out, styles);
return out;
}
function findAttr(attrs, key) {
for (let item of attrs) {
if (item.name === key) {
return item;
}
}
return null;
}
function renderStyleToString(caches, html) {
// generate global style
let globalStyle = '';
let globalIds = [];
let seen = {};
for (let id of Object.keys(caches.inserted)) {
let style = caches.inserted[id];
if (
style !== true &&
caches.registered[`${caches.key}-${id}`] === undefined
) {
globalStyle += style;
globalIds.push(id);
seen[id] = true;
}
}
// parse html and find used stylesheet
let document = parse5.parseFragment(html);
const walk = node => {
if (node.attrs) {
let clsAttr = findAttr(node.attrs, 'class');
if (clsAttr) {
let classes = clsAttr.value.split(' ');
let localIds = [];
let localStyle = '';
for (let cls of classes) {
let rawId = cls.substring(caches.key.length + 1);
if (!seen[rawId] && caches.registered[cls] !== undefined) {
seen[rawId] = true;
localIds.push(rawId);
let style = caches.inserted[rawId];
if (style !== true) {
localStyle += style;
}
}
}
if (localStyle) {
let styleNode = generateStyleTag(caches.key, localIds, localStyle);
insertBefore(node.parentNode, styleNode, node);
}
}
}
if (node.childNodes) {
for (let child of node.childNodes) {
walk(child);
}
}
};
walk(document);
html = parse5.serialize(document);
// prepend global styles
if (globalStyle) {
let fragment = createDocumentFragment();
appendChild(fragment, generateStyleTag(caches.key, globalIds, globalStyle));
html = parse5.serialize(fragment) + html;
}
return html;
}
export default html => renderStyleToString(defaultCaches, html);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment