diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2023-07-19 12:04:56 +0100 |
---|---|---|
committer | Hayleigh Thompson <me@hayleigh.dev> | 2023-07-19 12:04:56 +0100 |
commit | 8dab8d94fdae07b9e7de7eb0706c7ebca1f374fd (patch) | |
tree | cf40f9ea00dea8a8194f74fd6601c72af9fc77ed | |
parent | 410b190a13d6e0d5059f1ea719c60a41e69d9825 (diff) | |
download | lustre-8dab8d94fdae07b9e7de7eb0706c7ebca1f374fd.tar.gz lustre-8dab8d94fdae07b9e7de7eb0706c7ebca1f374fd.zip |
:zap: Iterate gleam lists with while loops for that sweet perf.
-rw-r--r-- | src/runtime.ffi.mjs | 112 |
1 files changed, 69 insertions, 43 deletions
diff --git a/src/runtime.ffi.mjs b/src/runtime.ffi.mjs index 355c923..616d15b 100644 --- a/src/runtime.ffi.mjs +++ b/src/runtime.ffi.mjs @@ -1,56 +1,62 @@ import { h, t } from "./lustre/element.mjs"; -import { fold, each } from "../gleam_stdlib/gleam/list.mjs"; +import { fold } from "../gleam_stdlib/gleam/list.mjs"; const Element = h("").constructor; const Text = t("").constructor; export function morph(prev, curr) { if (curr instanceof Element) { - if (prev?.nodeType === 1 && prev.nodeName !== curr[0].toUpperCase()) { - return morphElement(prev, curr); - } else { - const el = document.createElement(curr[0]); + return prev?.nodeType === 1 && prev.nodeName === curr[0].toUpperCase() + ? morphElement(prev, curr) + : createElement(prev, curr); + } - each(curr[1], (attr) => { - const name = attr[0]; - const value = attr[1]; + if (curr instanceof Text) { + return prev?.nodeType === 3 + ? morphText(prev, curr) + : createText(prev, curr); + } - morphAttr(el, name, value); - }); + return document.createComment( + [ + "[internal lustre error] I couldn't work out how to render this element. This", + "function should only be called internally by lustre's runtime: if you think", + "this is an error, please open an issue at", + "https://github.come/hayleigh-dot-dev/lustre/issues/new.", + ].join(" ") + ); +} - each(curr[2], (child) => { - el.appendChild(morph(null, child)); - }); +// ELEMENTS -------------------------------------------------------------------- - if (prev) prev.replaceWith(el); +function createElement(prev, curr) { + const el = document.createElement(curr[0]); - return el; - } + let attr = curr[1]; + while (attr.head) { + morphAttr(el, attr.head[0], attr.head[1]); + attr = attr.tail; } - if (curr instanceof Text) { - if (prev?.nodeType === 3) { - return morphText(prev, curr); - } else { - const el = document.createTextNode(curr[0]); - if (prev) prev.replaceWith(el); - return el; - } + let child = curr[2]; + while (child.head) { + el.appendChild(morph(null, child.head)); + child = child.tail; } - return null; + if (prev) prev.replaceWith(el); + return el; } function morphElement(prev, curr) { const prevAttrs = prev.attributes; - const currAttrs = fold(curr[1], new Map(), (acc, attr) => { - const name = attr[0]; - const value = attr[1]; + const currAttrs = new Map(); - acc.set(name, value); - return acc; - }); - const currChildren = curr[2].toArray(); + let currAttr = curr[1]; + while (currAttr.head) { + currAttrs.set(currAttr.head[0], currAttr.head[1]); + currAttr = currAttr.tail; + } for (const { name, value: prevValue } of prevAttrs) { if (!currAttrs.has(name)) prev.removeAttribute(name); @@ -66,25 +72,27 @@ function morphElement(prev, curr) { morphAttr(prev, name, value); } - for (let child = prev.firstChild; child; child = child.nextSibling) { - if (currChildren.length) { - morph(child, currChildren.shift()); - } else { - prev.removeChild(child); + let prevChild = prev.firstChild; + let currChild = curr[2]; + + while (prevChild) { + if (currChild.head) { + morph(prevChild, currChild.head); + currChild = currChild.tail; } + + prevChild = prevChild.nextSibling; } - for (const child of currChildren) { - prev.appendChild(morph(null, child)); + while (currChild.head) { + prev.appendChild(morph(null, currChild.head)); + currChild = currChild.tail; } return prev; } -function morphText(prev, curr) { - if (prev.nodeValue !== curr[0]) prev.nodeValue = curr[0]; - return prev; -} +// ATTRIBUTES ------------------------------------------------------------------ function morphAttr(el, name, value) { switch (typeof value) { @@ -104,3 +112,21 @@ function morphAttr(el, name, value) { if (el[name] !== value) el[name] = value; } } + +// TEXT ------------------------------------------------------------------------ + +function createText(prev, curr) { + const el = document.createTextNode(curr[0]); + + if (prev) prev.replaceWith(el); + return el; +} + +function morphText(prev, curr) { + const prevValue = prev.nodeValue; + const currValue = curr[0]; + + if (prevValue !== currValue) prev.nodeValue = currValue; + + return prev; +} |