UNPKG

@skatejs/ssr

Version:

Server-side render your web components.

62 lines (51 loc) 2.12 kB
<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>