[]previous and next page

What the compiler emits

Read the compiler's output for a component once; it explains most of the numbers.

For agentsUpdated

Read the compiler's output for a component once; it explains most of the numbers. compile() from @shadow-js/compiler is the same function the Vite plugin calls.

peek.tstsx
import { compile } from "@shadow-js/compiler";

const source = `
import { useStore } from "@shadow-js/core";
export function Row(props) {
  const [count, setCount] = useStore(0);
  const double = count() * 2;
  return (
    <li class="row" data-id={props.id}>
      <b>static</b> {props.label} {count()} {double}
      <button onClick={() => setCount(count() + 1)}>go</button>
    </li>
  );
}`;
const { code } = compile(source, { filename: "row.tsx", generate: "dom", dev: false, hmr: false });

const count = (pattern: RegExp): number => code.match(pattern)?.length ?? 0;
console.log(count(/_\$template\("/g)); // static markup, parsed once
console.log(count(/_\$effect\(/g)); // the data-id attribute
console.log(count(/_\$insert\(/g)); // three dynamic text slots
console.log(count(/_\$derived\(/g)); // `double`
console.log(JSON.stringify(["template", "effect", "insert", "derived"]));
Expected output
1
1
3
1
[

What the output shows for that component:

  • Static markup is hoisted into one template("<li class=\"row\">..."). The string is parsed once, on first use, and every row is a cloneNode of it. class="row" and <b>static</b> cost nothing per update.
  • Each dynamic child is its own insert against its own anchor, so {props.label}, {count()} and {double} update independently. A signal accessor passed as a child (count) is handed over as the accessor itself; an expression (props.label) is wrapped in an arrow function.
  • Each dynamic attribute is its own effect. Static attributes are in the template.
  • Event handlers are delegated for the common events (click, input, keydown, ...): the handler is stored on the element as $$click, and one listener per event name lives on document. A list of 10 000 buttons has one click listener.
  • const double = count() * 2 becomes a memo (derived), so it recomputes only when count changes and is shared by every place that reads it.

Pass /*@static*/ before an expression to tell the compiler it never changes, and autoReactive: false to the Vite plugin to turn the derived-value rewrite off for a file (the forgiving reactivity contract lists the rules).