@skatejs/ssr
Version:
Server-side render your web components.
62 lines (51 loc) • 2.12 kB
HTML
<script src="./index.js"></script>
<script>
function __ssr () {
const script = document.currentScript;
const host = script.previousElementSibling;
const fakeShadowRoot = host.firstElementChild;
const slots = host.getElementsByTagName('slot');
const move = (from, to) => { while (from.firstChild) to.appendChild(from.firstChild) };
// At each Shadow Root, we only care about its slots, not composed slots,
// therefore we need to move the children of top level slots, but no others
// Also can't 'move' in loop as that will mutate the DOM and ruin the
// 'contains' checks for subsequent slots.
const topLevelSlots = (() => {
let top = [],
ref;
for (let i = 0, k = slots.length; i < k; i++) {
const slot = slots[i];
// Ref is last known top level slot, if current slot is contained by it,
// then that slot is nested and can be ignored
if (!(ref && ref.contains(slot))) {
top.push(slot);
ref = slot;
}
}
return top;
})();
topLevelSlots.forEach(slot => move(slot, host));
// // Removing the script speeds up rendering by a few hundred ms when
// // not optimised and only a few when optimised.
script.parentNode.removeChild(script);
// The fastest overall method is to simply use innerHTML. This seems to be
// faster when not optimised (by about 50%) but is slightly slower when
// optimised compared to traversing the fake shadow root and appending each
// element to the real one:
const realShadowRoot = host.attachShadow({ mode: 'open' });
move(fakeShadowRoot, realShadowRoot);
host.removeChild(fakeShadowRoot);
}
</script>
<script>
test(a => {
const frag = document.createDocumentFragment();
const div = document.createElement('div');
const script = document.createElement('script');
div.innerHTML = `<shadow-root><strong><slot>${a}</slot></strong></shadow-root>`;
script.innerHTML = `__ssr();`;
frag.appendChild(div);
frag.appendChild(script);
return frag;
});
</script>