[]previous and next page

What runs on the server

The server render builds the tree once, then disposes it.

For agentsUpdated

The server render builds the tree once, then disposes it. Nothing is reactive there.

  • Effects do not run: useEffect, useRenderEffect and onMount are no-ops. Do browser work in onMount (it is skipped on the server by design) instead of guarding with typeof window.
  • Memos and component bodies run, once. A signal read gives its current value; writes to signals do not re-render anything.
  • isServer from @shadow-js/core is true, isDev follows the build.
  • Resources start their fetch. renderToString does not wait for them; their Suspense boundaries render the fallback. renderToStringAsync and renderToStream wait (below).
  • Event handlers are dropped. ref, use: and on: directives are dropped.
  • The root is disposed before renderToString returns, so onCleanup callbacks run.
  • innerHTML is written as raw markup; everything else is escaped. Attribute names are validated and URL attributes are sanitized exactly as on the client (Security).
  • Writes to signals created outside the render (module-level state) are allowed and are shared by every request in the process. Do not keep per-request data in module-level signals.
server-semantics.tsxtsx
import { isServer, onCleanup, onMount, useEffect, useMemo, useStore } from "@shadow-js/core";
import { renderToString } from "@shadow-js/web/server";

const record = { effects: 0, setup: 0, cleanups: 0 };

function Probe() {
  const [n] = useStore(2);
  const doubled = useMemo(() => n() * 2);
  record.setup += 1;
  useEffect(() => {
    record.effects += 1;
  });
  onMount(() => {
    record.effects += 1;
  });
  onCleanup(() => {
    record.cleanups += 1;
  });
  return (
    <strong>
      {doubled()} {isServer ? "server" : "browser"}
      {isServer ? null : <i>client only</i>}
    </strong>
  );
}

console.log(renderToString(() => <Probe />));
console.log(`effects: ${record.effects} setup: ${record.setup} cleanups: ${record.cleanups}`);
Expected output
<strong data-hk=