<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Lin</title>
    <description>The latest articles on DEV Community by Michael Lin (@unadlib).</description>
    <link>https://dev.to/unadlib</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F660642%2Fa5ea89e2-1032-4b46-85ea-310216e75c83.png</url>
      <title>DEV Community: Michael Lin</title>
      <link>https://dev.to/unadlib</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/unadlib"/>
    <language>en</language>
    <item>
      <title>React Compiler and Beyond: Capability Boundaries of Compiler-Driven UI Frameworks</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Wed, 04 Mar 2026 18:01:09 +0000</pubDate>
      <link>https://dev.to/unadlib/react-compiler-and-beyond-capability-boundaries-of-compiler-driven-ui-frameworks-4928</link>
      <guid>https://dev.to/unadlib/react-compiler-and-beyond-capability-boundaries-of-compiler-driven-ui-frameworks-4928</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Bottom line first: React Compiler is a major step forward, but it optimizes React's expression and render costs within React's runtime contract.&lt;br&gt;&lt;br&gt;
Compiler-first fine-grained frameworks like Fict pursue a different objective: move more update routing to compile time, then execute updates through dependency propagation at runtime.&lt;br&gt;&lt;br&gt;
This is not a winner-takes-all debate. It is an engineering trade-off across different objective functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fict Repo: &lt;a href="https://github.com/fictjs/fict" rel="noopener noreferrer"&gt;https://github.com/fictjs/fict&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  0. Scope and Rigor
&lt;/h2&gt;

&lt;p&gt;To avoid slogan-level comparisons, this article uses strict boundaries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It compares two technical routes:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;React + React Compiler&lt;/code&gt; (preserving React semantics)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Compiler-first fine-grained&lt;/code&gt; (using Fict as the concrete example)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It separates three layers:

&lt;ul&gt;
&lt;li&gt;Developer experience (mental overhead and ergonomics)&lt;/li&gt;
&lt;li&gt;Performance model (update path and cost structure)&lt;/li&gt;
&lt;li&gt;Semantic constraints (effects, lifecycle, error handling, consistency)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Claims about Fict are grounded in this repository's implementation and docs, not idealized marketing descriptions.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. What React Compiler Actually Solves
&lt;/h2&gt;

&lt;p&gt;React Compiler does not "replace React." It improves React's default performance posture by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inferring dependency boundaries so developers write less manual &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reusing expressions and JSX subtrees more aggressively.&lt;/li&gt;
&lt;li&gt;Raising performance floor while preserving the React programming model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A conceptual sketch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSelect&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCompilerCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;filtered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handleClick&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onSelect&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;onSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listJSX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key point: this is stronger automatic memoization inside React semantics, not a replacement of Fiber/Hook contracts.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. What React Compiler Does Not Redefine
&lt;/h2&gt;

&lt;p&gt;A precise statement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React Compiler can remove substantial redundant compute and subtree work.&lt;/li&gt;
&lt;li&gt;It does not redefine React into a signal-driven DOM execution engine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React's core abstraction is still component-tree scheduling and commit semantics.&lt;/li&gt;
&lt;li&gt;Compiler optimizations must remain inside React boundaries: hook ordering, effect timing, concurrent scheduling, error boundary behavior.&lt;/li&gt;
&lt;li&gt;Therefore it optimizes "how much work React does," not "what React fundamentally is."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Practical implications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React updates are not always full-tree reruns due to bailouts and memoized outputs.&lt;/li&gt;
&lt;li&gt;But the dominant scheduling unit remains component/subtree semantics, not explicit signal graph nodes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;React.memo&lt;/code&gt; with &lt;code&gt;children&lt;/code&gt; is not inherently useless:

&lt;ul&gt;
&lt;li&gt;It often fails if children are recreated each render.&lt;/li&gt;
&lt;li&gt;It can work when references are stabilized by caller patterns or compiler transforms.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. What Fict Changes (Based on Current Repository)
&lt;/h2&gt;

&lt;p&gt;Fict's route is compiler-first fine-grained reactivity: compile dependency relationships, then propagate updates through runtime graph nodes.&lt;/p&gt;

&lt;p&gt;This is visible in the current codebase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Macro contract:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$state&lt;/code&gt; and &lt;code&gt;$effect&lt;/code&gt; are compile-time macros and throw if executed at runtime (&lt;code&gt;packages/fict/src/index.ts&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Compile-time placement constraints:

&lt;ul&gt;
&lt;li&gt;Macro placement is validated; loops/conditionals/nested contexts are restricted according to compiler rules (&lt;code&gt;packages/compiler/src/index.ts&lt;/code&gt;, &lt;code&gt;docs/compiler-spec.md&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IR and lowering pipeline:

&lt;ul&gt;
&lt;li&gt;HIR build, optimization, and lowering stages exist in &lt;code&gt;packages/compiler/src/ir/*&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Runtime graph model:

&lt;ul&gt;
&lt;li&gt;Signal/computed/effect propagation is implemented in &lt;code&gt;packages/runtime/src/signal.ts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Local list reconciliation still exists:

&lt;ul&gt;
&lt;li&gt;Fict avoids whole-tree VDOM diffing, but keyed local reconciliation is implemented (&lt;code&gt;packages/runtime/src/reconcile.ts&lt;/code&gt;, &lt;code&gt;packages/runtime/src/list-helpers.ts&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fail-closed guarantee mode is explicit:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FICT_STRICT_GUARANTEE=1&lt;/code&gt; enforces strict diagnostics in CI (&lt;code&gt;docs/reactivity-guarantee-matrix.md&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This corrects two frequent misconceptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Fict has no reconciliation at all."
Not true. It avoids whole-tree VDOM diffing; it still reconciles local keyed list paths.&lt;/li&gt;
&lt;li&gt;"Fict is only syntax sugar over existing runtimes."
Not true. It has a dedicated compile-time dataflow and lowering pipeline with a distinct runtime execution model.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Cost Model: Same Interaction, Different Work Units
&lt;/h2&gt;

&lt;p&gt;Use a searchable list as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// React + Compiler (conceptual)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSortBy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSortBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Date&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; results&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Fict (conceptual)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SearchList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sortBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onInput&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Date&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; results&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptual complexity comparison:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React path:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;O(rendered-subtree + diff-subtree + patch)&lt;/code&gt;, reduced by compiler/bailouts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fict path:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;O(changed-sources + affected-computed/effects + affected-bindings + local-list-reconcile)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The correct conclusion is not "always faster/slower":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fine-grained tends to win when changes are local, dependency graph is sparse, and list size is large.&lt;/li&gt;
&lt;li&gt;React Compiler is often sufficient when bottlenecks are I/O dominated or UI compute is moderate.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  5. Semantic Trade-offs (The Part People Skip)
&lt;/h2&gt;

&lt;p&gt;Performance-only comparisons are incomplete. Semantic behavior determines production risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Effects Are Not Mechanical One-to-One Replacements
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;$effect&lt;/code&gt; are not drop-in equivalents:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fict &lt;code&gt;$effect&lt;/code&gt; is compiler-constrained and analyzed in a macro-based model.&lt;/li&gt;
&lt;li&gt;Dependency collection semantics differ from React dependency-array workflows.&lt;/li&gt;
&lt;li&gt;Less manual dependency bookkeeping reduces a class of developer mistakes, but correctness partially shifts toward compiler analyzability and guarantee coverage.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.2 Control Flow and Dynamic Shapes Need Explicit Validation
&lt;/h3&gt;

&lt;p&gt;High-risk migration areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Effect cleanup timing under control-flow branch switching.&lt;/li&gt;
&lt;li&gt;Closure reads in event chains and async callbacks.&lt;/li&gt;
&lt;li&gt;Cancellation/race handling in async flows.&lt;/li&gt;
&lt;li&gt;List identity behavior under unstable key quality.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.3 "No Free Ecosystem Inheritance"
&lt;/h3&gt;

&lt;p&gt;React's long-lived advantages are structural:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ecosystem breadth and battle-tested framework integrations.&lt;/li&gt;
&lt;li&gt;Mature concurrent scheduling and tooling culture.&lt;/li&gt;
&lt;li&gt;Broad operational knowledge in teams.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Compiler-first routes must independently harden:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DevTools observability&lt;/li&gt;
&lt;li&gt;SSR/Hydration/Resume stability&lt;/li&gt;
&lt;li&gt;Error boundary and suspense consistency&lt;/li&gt;
&lt;li&gt;Third-party integration contracts&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6. Side-by-Side Decision Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;React + Compiler&lt;/th&gt;
&lt;th&gt;Fict / Compiler-First Fine-Grained&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary objective&lt;/td&gt;
&lt;td&gt;Reduce React performance tuning overhead&lt;/td&gt;
&lt;td&gt;Lower runtime update upper bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core mechanism&lt;/td&gt;
&lt;td&gt;Automatic memoization + bailouts&lt;/td&gt;
&lt;td&gt;Compile-time dependency graph + runtime propagation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dominant update unit&lt;/td&gt;
&lt;td&gt;Component/subtree scheduling&lt;/td&gt;
&lt;td&gt;Source/computed/binding-level propagation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List behavior&lt;/td&gt;
&lt;td&gt;Reconciliation in React tree semantics&lt;/td&gt;
&lt;td&gt;Local keyed reconciliation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration cost&lt;/td&gt;
&lt;td&gt;Low to medium (keep React mental model)&lt;/td&gt;
&lt;td&gt;Medium to high (compiler constraints + semantic verification)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Main risk&lt;/td&gt;
&lt;td&gt;Performance predictability tied to component structure&lt;/td&gt;
&lt;td&gt;Semantic edge cases and compiler coverage boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Important framing: this is objective-function selection, not a "modernity contest."&lt;/p&gt;




&lt;h2&gt;
  
  
  7. What a Defensible Technical Article Must Include
&lt;/h2&gt;

&lt;p&gt;If the goal is engineering evidence rather than opinion, include at least:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Public benchmark method:

&lt;ul&gt;
&lt;li&gt;Dataset, warm/cold separation, hardware/software baselines.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Metric decomposition:

&lt;ul&gt;
&lt;li&gt;Render/commit timing, DOM mutations, GC, memory peak.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Counterexample sets:

&lt;ul&gt;
&lt;li&gt;Cases where React is better; cases where fine-grained is better.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Semantic equivalence tests:

&lt;ul&gt;
&lt;li&gt;Cleanup, error boundaries, async races, fallback paths.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Migration cost quantification:

&lt;ul&gt;
&lt;li&gt;Changed LOC, defect categories, regression count, fix lead time.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without this, conclusions remain high-quality perspective, not reproducible engineering claims.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Reproducible Evaluation Appendix
&lt;/h2&gt;

&lt;p&gt;Use repository-native commands only.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Environment baseline:

&lt;ul&gt;
&lt;li&gt;Node &lt;code&gt;&amp;gt;=20&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;pnpm &lt;code&gt;&amp;gt;=9&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;OS/CPU/RAM&lt;/li&gt;
&lt;li&gt;Browser version (for benchmark runs)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Repository health:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm build
pnpm &lt;span class="nb"&gt;test
&lt;/span&gt;pnpm typecheck
pnpm lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Strict guarantee gate:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;FICT_STRICT_GUARANTEE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 pnpm build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Framework benchmark flow:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm perf:data
pnpm perf:results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Runtime stress:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm stress:runtime
pnpm stress:runtime:long
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Compiler optimization regression guard:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm bench:optimizer:guard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Reporting minimums:

&lt;ul&gt;
&lt;li&gt;Scenario and data scale (&lt;code&gt;N&lt;/code&gt;, update rate, list size)&lt;/li&gt;
&lt;li&gt;Median + IQR from at least 5 runs&lt;/li&gt;
&lt;li&gt;Error logs and failure sample links&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  9. Migration Readiness Checklist
&lt;/h2&gt;

&lt;p&gt;Before adopting a compiler-first route, verify:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You are solving a front-end CPU update bottleneck, not primarily network/back-end latency.&lt;/li&gt;
&lt;li&gt;You can run strict guarantee mode in CI (&lt;code&gt;FICT_STRICT_GUARANTEE=1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;You have semantic regression coverage for effects, async races, and error boundaries.&lt;/li&gt;
&lt;li&gt;Team conventions can absorb macro constraints and compile-time diagnostics.&lt;/li&gt;
&lt;li&gt;You have a rollback strategy for fallback-path regressions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When to prefer React + Compiler first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Large existing React codebase with narrow migration window.&lt;/li&gt;
&lt;li&gt;Heavy dependency on mainstream React ecosystem/runtime assumptions.&lt;/li&gt;
&lt;li&gt;Performance gains needed are incremental, not architectural.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When Fict-like route is justified:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CPU update path is a top product bottleneck.&lt;/li&gt;
&lt;li&gt;Large/interactive local updates dominate user experience.&lt;/li&gt;
&lt;li&gt;Team is willing to trade some migration complexity for lower runtime update ceiling.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  10. Final Conclusion
&lt;/h2&gt;

&lt;p&gt;React Compiler matters because it turns performance tuning expertise into compiler defaults inside React semantics.&lt;/p&gt;

&lt;p&gt;Fict-like compiler-first systems matter because they can replace rerun-and-compare execution with dependency-driven propagation for many update paths.&lt;/p&gt;

&lt;p&gt;Both are valid. They optimize different costs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React Compiler answers:

&lt;ul&gt;
&lt;li&gt;How far can we push automatic performance within React's existing contract?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Compiler-first fine-grained answers:

&lt;ul&gt;
&lt;li&gt;If dataflow is known at compile time, how much runtime tree-level comparison can we avoid?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A serious engineering decision should not declare a universal winner.&lt;br&gt;&lt;br&gt;
It should define boundaries, publish evidence, and make trade-offs explicit.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>react</category>
    </item>
    <item>
      <title>Renderify: A Runtime Engine for Rendering LLM-Generated UI Instantly in the Browser</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Thu, 26 Feb 2026 18:34:56 +0000</pubDate>
      <link>https://dev.to/unadlib/renderify-a-runtime-engine-for-rendering-llm-generated-ui-instantly-in-the-browser-1amf</link>
      <guid>https://dev.to/unadlib/renderify-a-runtime-engine-for-rendering-llm-generated-ui-instantly-in-the-browser-1amf</guid>
      <description>&lt;p&gt;Repo: &lt;a href="https://github.com/webllm/renderify" rel="noopener noreferrer"&gt;github.com/webllm/renderify&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As large language models (LLMs) advance rapidly, AI can now generate structurally complete and logically sound UI code. Yet a key engineering question remains open: &lt;strong&gt;how do you safely and efficiently render LLM-generated UI directly in the browser — without any backend compilation or deployment pipeline?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Existing approaches each have limitations: v0/Bolt.new rely on a full Next.js compilation backend; Streamlit/Gradio are Python-based and server-rendered; Anthropic Artifacts is closed-source and non-embeddable; JSON Schema renderers can only express a predefined component set; Sandpack/WebContainers are powerful but heavyweight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Renderify&lt;/strong&gt; was built to fill this gap. It is a runtime-first dynamic rendering engine that transpiles, sandboxes, and renders LLM-generated JSX/TSX (or structured JSON plans) directly in the browser as interactive UI — with zero build steps, zero server-side compilation, and zero deployment pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM Output (JSX/TSX or Structured Plan)
  → Code Generator (parse + normalize)
    → Security Policy Check (intercept before execution)
      → Runtime Execution (Babel transpilation + JSPM module resolution)
        → Interactive UI rendered in the browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Industry Landscape (as of 2026-02-16)
&lt;/h2&gt;

&lt;p&gt;Before discussing Renderify's differentiation, it helps to establish a common framework. The diagram below breaks the "LLM → UI" path into six stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Intent
  -&amp;gt; [A] LLM generates code / description
    -&amp;gt; [B] Code parsing / transformation / orchestration
      -&amp;gt; [C] Security checks + sandboxing
        -&amp;gt; [D] Browser module resolution (bare import -&amp;gt; URL)
          -&amp;gt; [E] Runtime execution + DOM rendering
            -&amp;gt; [F] State management + interaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Definitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: Whether the core SDK/runtime has public source code (the platform service itself may be closed-source).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embeddable&lt;/strong&gt;: Whether it can be integrated as a capability into your own application, rather than used only within the vendor's hosted product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stages Covered&lt;/strong&gt;: Represents the typical primary path, not the full capability boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Solution&lt;/th&gt;
&lt;th&gt;Stages Covered (typical)&lt;/th&gt;
&lt;th&gt;Core Path&lt;/th&gt;
&lt;th&gt;Open Source&lt;/th&gt;
&lt;th&gt;Embeddable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;v0 (Vercel)&lt;/td&gt;
&lt;td&gt;A→E (backend build path)&lt;/td&gt;
&lt;td&gt;LLM → Next.js compile/deploy&lt;/td&gt;
&lt;td&gt;Platform closed-source, SDK open-source&lt;/td&gt;
&lt;td&gt;✅ (Platform API/SDK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bolt.new (StackBlitz)&lt;/td&gt;
&lt;td&gt;A→E (WebContainers path)&lt;/td&gt;
&lt;td&gt;LLM → WebContainers → full Node.js&lt;/td&gt;
&lt;td&gt;Partial (frontend open-source, WebContainers engine closed-source)&lt;/td&gt;
&lt;td&gt;Limited (primarily a product)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Artifacts&lt;/td&gt;
&lt;td&gt;A→E (private sandbox)&lt;/td&gt;
&lt;td&gt;LLM → private render sandbox&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel AI SDK&lt;/td&gt;
&lt;td&gt;A + E (+ experimental RSC)&lt;/td&gt;
&lt;td&gt;LLM orchestration → framework UI&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ (multiple frameworks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI.JSX&lt;/td&gt;
&lt;td&gt;A→B&lt;/td&gt;
&lt;td&gt;LLM selects/orchestrates predefined components&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;llm-ui&lt;/td&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;LLM text → Markdown/JSON components&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen-UI-Lang&lt;/td&gt;
&lt;td&gt;A→B&lt;/td&gt;
&lt;td&gt;LLM → DSL → multi-target output&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thesys GenUI&lt;/td&gt;
&lt;td&gt;A→E&lt;/td&gt;
&lt;td&gt;LLM → structured DSL/API → React render layer&lt;/td&gt;
&lt;td&gt;Partial (SDK/examples open-source)&lt;/td&gt;
&lt;td&gt;✅ (primarily React SDK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sandpack&lt;/td&gt;
&lt;td&gt;D→E&lt;/td&gt;
&lt;td&gt;Predefined code → iframe bundler execution&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebContainers&lt;/td&gt;
&lt;td&gt;D→E&lt;/td&gt;
&lt;td&gt;In-browser Node.js/WASM environment&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;✅ (provides embed API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E2B&lt;/td&gt;
&lt;td&gt;C→E&lt;/td&gt;
&lt;td&gt;Code → remote micro VM execution&lt;/td&gt;
&lt;td&gt;Partial (SDK open-source)&lt;/td&gt;
&lt;td&gt;✅ (typically requires server)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Renderify&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;B→F (core) + A (optional)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LLM/external input → IR → security policy → Babel/JSPM → render&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From this perspective, Renderify's positioning is more precisely described as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A browser-runtime-centric, locally embeddable execution chain covering stages &lt;strong&gt;B→F&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage A is optional&lt;/strong&gt; — you can plug in &lt;code&gt;@renderify/llm&lt;/code&gt;, or supply a RuntimePlan from any external system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Monorepo Package Topology
&lt;/h3&gt;

&lt;p&gt;Renderify is organized as a monorepo using pnpm workspaces + Turborepo, consisting of seven packages with clearly separated responsibilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@renderify/ir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Intermediate representation — RuntimePlan/Node/State/Action type contracts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@renderify/security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security policy engine — profile configuration, static analysis, module allowlists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@renderify/runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runtime execution engine — transpilation, module loading, sandboxed execution, UI rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@renderify/core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Orchestration layer — RenderifyApp full pipeline, streaming, plugin system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@renderify/llm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LLM provider abstraction — OpenAI/Anthropic/Google/Ollama/LMStudio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;renderify&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Top-level SDK facade — the recommended application entry point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@renderify/cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI tooling + browser Playground&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Package dependencies form a clean directed acyclic graph (DAG). &lt;code&gt;@renderify/ir&lt;/code&gt; is a leaf node with no internal dependencies; all other packages build upon it layer by layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Five-Stage Pipeline
&lt;/h3&gt;

&lt;p&gt;The rendering pipeline consists of five strictly ordered stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  LLM Interpreter │────▶│  Code Generator  │────▶│   RuntimePlan    │
│  (OpenAI/Claude/ │     │  (JSON or TSX    │     │   (IR)           │
│   Gemini)        │     │   extraction)    │     │                  │
└──────────────────┘     └──────────────────┘     └────────┬─────────┘
                                                           │
                                                           ▼
                                                  ┌──────────────────┐
                                                  │  Security Policy │
                                                  │  Checker         │
                                                  └────────┬─────────┘
                                                           │
                                                           ▼
                                                 ┌───────────────────┐
                                                 │  Runtime Manager  │
                                                 │  (execute plan,   │
                                                 │   resolve modules,│
                                                 │   transpile)      │
                                                 └─────────┬─────────┘
                                                           │
                                                           ▼
                                                 ┌───────────────────┐
                                                 │  UI Renderer      │
                                                 │  (HTML generation,│
                                                 │   DOM reconcile)  │
                                                 └───────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  RuntimePlan: The Unified Intermediate Representation
&lt;/h2&gt;

&lt;p&gt;RuntimePlan is the core contract of the entire system, serving as a stable interface between all pipeline stages. Regardless of the LLM's output format, everything is normalized into a RuntimePlan before flowing through security checks, runtime execution, and UI rendering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Three node types compose the UI tree&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RuntimeNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;RuntimeTextNode&lt;/span&gt; &lt;span class="c1"&gt;// Text node: { type: "text", value: string }&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;RuntimeElementNode&lt;/span&gt; &lt;span class="c1"&gt;// Element node: { type: "element", tag: string, props?, children? }&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;RuntimeComponentNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Component node: { type: "component", module: string, props?, children? }&lt;/span&gt;

&lt;span class="c1"&gt;// Complete RuntimePlan structure&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RuntimePlan&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;specVersion&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;runtime-plan/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RuntimeNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Declarative UI tree (required)&lt;/span&gt;
  &lt;span class="nl"&gt;source&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;RuntimeSourceModule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// JSX/TSX source code module&lt;/span&gt;
  &lt;span class="nl"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// npm dependency declarations&lt;/span&gt;
  &lt;span class="nl"&gt;state&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;RuntimeStateModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// State model&lt;/span&gt;
  &lt;span class="nl"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;RuntimeCapabilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Capability declarations&lt;/span&gt;
  &lt;span class="nl"&gt;moduleManifest&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;RuntimeModuleManifest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Module resolution manifest&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dual Input Paths
&lt;/h3&gt;

&lt;p&gt;Renderify supports two fundamentally different input formats, both of which converge at the same security check and execution pipeline:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Path A: Structured RuntimePlan JSON&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The LLM generates a structured RuntimePlan directly via JSON Schema constraints. This path offers maximum control and deterministic behavior, making it ideal for production systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"specVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runtime-plan/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dashboard-v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"root"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"element"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"div"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"domWrite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Path B: TSX/JSX Source Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The LLM generates free-form text containing code blocks. The code generation stage extracts the source code and wraps it as a RuntimePlan with a &lt;code&gt;source&lt;/code&gt; field; the runtime then transpiles and executes it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preact/hooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LineChart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Line&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recharts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMetric&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;revenue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dual-path design maximizes flexibility — structured JSON suits scenarios that demand precise control, while TSX/JSX code blocks feel more natural for LLMs and can express richer interactive logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security: Defense in Depth
&lt;/h2&gt;

&lt;p&gt;When LLMs generate code, security is paramount. An LLM may produce &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags, &lt;code&gt;eval()&lt;/code&gt; calls, or unsafe network requests. Renderify employs multiple independent defense layers, enforcing strict security policies before any code executes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Security Profiles
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;Strict&lt;/th&gt;
&lt;th&gt;Balanced (default)&lt;/th&gt;
&lt;th&gt;Relaxed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Max tree depth&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max node count&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max source size&lt;/td&gt;
&lt;td&gt;20KB&lt;/td&gt;
&lt;td&gt;80KB&lt;/td&gt;
&lt;td&gt;200KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max imports&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max execution time&lt;/td&gt;
&lt;td&gt;5s&lt;/td&gt;
&lt;td&gt;15s&lt;/td&gt;
&lt;td&gt;60s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manifest required&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Module integrity&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic imports&lt;/td&gt;
&lt;td&gt;Blocked&lt;/td&gt;
&lt;td&gt;Blocked&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Seven Defense Layers
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static pattern analysis&lt;/strong&gt;: Regex-based detection of dangerous source patterns (&lt;code&gt;eval(&lt;/code&gt;, &lt;code&gt;new Function(&lt;/code&gt;, &lt;code&gt;fetch(&lt;/code&gt;, &lt;code&gt;document.cookie&lt;/code&gt;, &lt;code&gt;localStorage&lt;/code&gt;, &lt;code&gt;child_process&lt;/code&gt;, etc.), plus path-traversal detection on module specifiers (including encoded variants).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structural limits&lt;/strong&gt;: Tree depth, node count, source byte size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tag blocklist&lt;/strong&gt;: Blocks &lt;code&gt;script&lt;/code&gt;, &lt;code&gt;iframe&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;embed&lt;/code&gt;, and other dangerous tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Module allowlist&lt;/strong&gt;: Only pre-approved modules may be imported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manifest integrity&lt;/strong&gt;: In strict mode, all imports must have exact URL mappings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution budgets&lt;/strong&gt;: Wall-clock timeouts, import count limits, and component invocation limits, enforced via &lt;code&gt;Promise.race()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sandbox isolation&lt;/strong&gt;: Three sandbox modes — Worker/iframe/ShadowRealm — with automatic fallback chains.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The overall strategy is &lt;strong&gt;fail-closed by default&lt;/strong&gt;: tags, modules, hosts, and execution profiles not explicitly permitted by the policy are rejected. In strict/balanced mode, uncovered bare specifiers are also rejected. The &lt;code&gt;relaxed&lt;/code&gt; profile selectively loosens these constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser ESM Module Graph Materialization
&lt;/h2&gt;

&lt;p&gt;A key engineering capability of Renderify is how it resolves and loads npm packages entirely in the browser — without any server-side bundler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Browsers natively support ES Modules, but with one critical limitation: &lt;strong&gt;bare specifiers are not supported&lt;/strong&gt;. You cannot directly &lt;code&gt;import { format } from "date-fns"&lt;/code&gt; in the browser. Traditional solutions require bundlers like webpack or Vite to resolve these specifiers on the server, which contradicts Renderify's zero-build-step design goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: The fetch → rewrite → blob URL Pipeline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source code
  → es-module-lexer extracts import declarations
    → JSPM CDN resolves bare specifiers
      → Recursively materialize child dependency imports
        → Rewrite import statements to resolved URLs
          → Create blob: URL
            → dynamic import() to load
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The detailed flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lexical extraction&lt;/strong&gt;: Use &lt;code&gt;es-module-lexer&lt;/code&gt; to extract all import declarations from the source code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specifier resolution&lt;/strong&gt;: Resolve bare specifiers (e.g., &lt;code&gt;recharts&lt;/code&gt;) to exact CDN URLs via the JSPM CDN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive materialization&lt;/strong&gt;: Fetch remote module source, parse its child imports, and recursively repeat the same process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rewriting&lt;/strong&gt;: Replace all import specifiers with materialized blob/data URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Packaging&lt;/strong&gt;: Create a blob URL from the rewritten source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loading&lt;/strong&gt;: Load the blob URL via &lt;code&gt;dynamic import()&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Asset Proxy Modules
&lt;/h3&gt;

&lt;p&gt;For non-JavaScript assets, Renderify handles them transparently through proxy modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CSS imports&lt;/strong&gt;: Converted to &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; injection proxy modules (deduplicated by FNV-1a hash — created on first encounter, reused on subsequent ones).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON imports&lt;/strong&gt;: Wrapped as &lt;code&gt;export default &amp;lt;parsed-json&amp;gt;&lt;/code&gt; ESM modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary assets&lt;/strong&gt;: Converted to proxy modules that export the CDN URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Auto-Pin-Latest Strategy
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;renderPlanInBrowser&lt;/code&gt; enables auto-pin-latest mode by default:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developers use bare imports in source code (e.g., &lt;code&gt;import { format } from "date-fns/format"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;On first run, Renderify resolves the bare specifier to an exact versioned URL via JSPM.&lt;/li&gt;
&lt;li&gt;The resolution result is immediately injected into the &lt;code&gt;moduleManifest&lt;/code&gt;; subsequent executions use the pinned version.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For production, use &lt;code&gt;manifest-only&lt;/code&gt; mode (&lt;code&gt;autoPinLatestModuleManifest: false&lt;/code&gt;) to ensure fully pre-pinned, auditable dependency mappings.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Ecosystem Compatibility Bridge
&lt;/h2&gt;

&lt;p&gt;LLM-generated code typically uses the React API — it is the most common frontend framework in model training data.&lt;/p&gt;

&lt;p&gt;Renderify transparently redirects common React imports to the Preact compat layer via built-in compatibility mappings (Preact is approximately 3–4KB gzipped, significantly smaller than the React runtime; exact figures vary by version), reducing runtime overhead and improving cold-start performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_JSPM_SPECIFIER_OVERRIDES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;react&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preact/compat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preact/compat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preact/compat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react/jsx-runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preact/jsx-runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;recharts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recharts@3.3.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means LLMs can freely generate standard React code, and it will execute on the smaller, faster Preact runtime. React ecosystem libraries such as Recharts and MUI work as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming Rendering Architecture
&lt;/h2&gt;

&lt;p&gt;In Chat UI scenarios, users expect real-time feedback. Renderify's streaming pipeline delivers progressive preview updates while the LLM is still generating code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM tokens ──▶ llm-delta chunks ──▶ preview renders ──▶ final render
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;llm-delta&lt;/strong&gt;: Each token from the LLM is emitted as a chunk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;preview&lt;/strong&gt;: At configurable intervals, the accumulated text is parsed and rendered as a preview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;final&lt;/strong&gt;: After LLM completion, the full pipeline executes and emits the final result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;error&lt;/strong&gt;: If any stage fails, an error chunk is emitted before the exception propagates.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Efficient Change Detection
&lt;/h3&gt;

&lt;p&gt;The streaming code generation stage uses FNV-1a 64-bit hashing for efficient change detection. As the LLM continuously outputs tokens, the system computes a hash signature over the accumulated text — only re-parsing and re-rendering when the signature changes. This avoids redundant computation during streaming while maintaining responsive incremental previews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugin System
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;CustomizationEngine&lt;/code&gt; provides 10 hook points covering every pipeline stage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beforeLLM → [LLM] → afterLLM
  → beforeCodeGen → [CodeGen] → afterCodeGen
    → beforePolicyCheck → [Security] → afterPolicyCheck
      → beforeRuntime → [Runtime] → afterRuntime
        → beforeRender → [UI] → afterRender
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each hook receives the current stage's payload and can transform it before passing it to the next stage. Multiple plugins execute in registration order. This design lets developers inject custom logic without forking the core — from modifying the LLM prompt to post-processing render output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandbox Execution Model
&lt;/h2&gt;

&lt;p&gt;For scenarios requiring stronger isolation, Renderify offers three browser sandbox modes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Characteristics&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sandbox-worker&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Web Worker + blob URL + &lt;code&gt;postMessage&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Separate-thread execution with timeout and abort support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sandbox-iframe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sandbox="allow-scripts"&lt;/code&gt; iframe + MessageChannel&lt;/td&gt;
&lt;td&gt;Isolated document context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sandbox-shadowrealm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ShadowRealm API + blob URL bridge&lt;/td&gt;
&lt;td&gt;Same-thread isolated realm&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The three modes support automatic fallback chains — if the preferred mode is unavailable, execution automatically falls back to the next one. Each mode supports configurable timeouts and fail-closed behavior (fail-closed by default; can be disabled via &lt;code&gt;browserSourceSandboxFailClosed&lt;/code&gt; to fall back to non-sandboxed execution on failure).&lt;/p&gt;

&lt;h2&gt;
  
  
  DOM Reconciliation and UI Rendering
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;DefaultUIRenderer&lt;/code&gt; is not a simple &lt;code&gt;innerHTML&lt;/code&gt; replacement — it implements a full DOM reconciliation algorithm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keyed + positional child matching&lt;/strong&gt;: Prioritizes key-based matching, then falls back to positional matching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Differential attribute updates&lt;/strong&gt;: Only updates attributes that have actually changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text node updates&lt;/strong&gt;: Directly modifies &lt;code&gt;textContent&lt;/code&gt; rather than replacing the node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive state preservation&lt;/strong&gt;: Preserves scroll positions during reconciliation and avoids overwriting &lt;code&gt;value&lt;/code&gt;/&lt;code&gt;checked&lt;/code&gt; on focused input elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event delegation&lt;/strong&gt;: Implements event handling via &lt;code&gt;data-renderify-event-*&lt;/code&gt; attributes and &lt;code&gt;CustomEvent&lt;/code&gt; dispatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XSS protection&lt;/strong&gt;: Blocks dangerous tags/attributes and sanitizes inline styles (blocking &lt;code&gt;expression()&lt;/code&gt;, &lt;code&gt;url()&lt;/code&gt;, &lt;code&gt;javascript:&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  One-Line Embed API
&lt;/h2&gt;

&lt;p&gt;Renderify provides a minimal embed API — a single call completes the entire flow from Plan to rendered UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderPlanInBrowser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renderify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderPlanInBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#mount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally, this call automatically creates all required infrastructure — module loader, security checker, runtime manager, UI renderer — and uses a &lt;code&gt;WeakMap&lt;/code&gt;-backed render lock to ensure concurrent renders to the same DOM target are properly serialized.&lt;/p&gt;

&lt;p&gt;A complete 30-second example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderPlanInBrowser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renderify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;renderPlanInBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello_jsx_runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
        import { format } from "date-fns/format";

        export default function App() {
          return &amp;lt;section&amp;gt;Today: {format(new Date(), "yyyy-MM-dd")}&amp;lt;/section&amp;gt;;
        }
      `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#mount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above does three things: (1) executes JSX/TSX directly at browser runtime; (2) auto-resolves the &lt;code&gt;date-fns&lt;/code&gt; bare import via JSPM; (3) pins the resolved URL into &lt;code&gt;moduleManifest&lt;/code&gt; before execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization Strategies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Transpilation Cache
&lt;/h3&gt;

&lt;p&gt;The runtime transpiler uses an LRU cache (256 entries) with cache keys composed from &lt;code&gt;language/runtime/filename/code&lt;/code&gt;, avoiding redundant transpilation of unchanged source code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request Deduplication
&lt;/h3&gt;

&lt;p&gt;Both &lt;code&gt;JspmModuleLoader&lt;/code&gt; and &lt;code&gt;RuntimeSourceModuleLoader&lt;/code&gt; implement request deduplication — when multiple components request the same module concurrently, only a single network request is made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-CDN Fault Tolerance
&lt;/h3&gt;

&lt;p&gt;Module fetching supports multi-CDN fallback using &lt;code&gt;Promise.any&lt;/code&gt; for hedged requests. The default source is the JSPM GA CDN, with fallback to esm.sh and other alternative CDNs on failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Budget Racing
&lt;/h3&gt;

&lt;p&gt;Execution budgets constrain async paths via remaining-time calculation + &lt;code&gt;Promise.race()&lt;/code&gt;. For synchronously blocking code, sandboxed execution (such as browser sandbox or &lt;code&gt;isolated-vm&lt;/code&gt;) is still required to mitigate the risk of main-thread stalls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blob URL Cleanup
&lt;/h3&gt;

&lt;p&gt;The runtime manager tracks all created blob URLs and revokes them in bulk during cleanup to prevent memory leaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuning Parameters
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enableDependencyPreflight&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Better safety and earlier failure signals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remoteFetchTimeoutMs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prevents long hangs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remoteFetchRetries&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Better resilience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;browserSourceSandboxMode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;worker&lt;/code&gt; in browser (&lt;code&gt;none&lt;/code&gt; outside browser)&lt;/td&gt;
&lt;td&gt;Isolation for untrusted source code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;autoPinLatestModuleManifest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Developer experience for bare imports&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;p&gt;Renderify is well-suited for the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LLM Chat / Agent platforms&lt;/strong&gt;: Render dynamic UI from model output — dashboards, forms, cards, data visualizations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Agent toolchains&lt;/strong&gt;: An Agent analyzes user data and dynamically generates interactive dashboards or operation interfaces, rather than just returning text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low-Code / No-Code AI backends&lt;/strong&gt;: Users describe intent in natural language; the LLM generates a runnable UI component on the fly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic forms and approval workflows&lt;/strong&gt;: Generate context-aware forms at runtime, more flexible than JSON Schema renderers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid prototyping&lt;/strong&gt;: Go from prompt to rendered UI in seconds, not minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe rendering of untrusted UI&lt;/strong&gt;: Any application that needs to securely render dynamically generated UI in the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SDK Embedding (Recommended)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add renderify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderPlanInBrowser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renderify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderPlanInBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quickstart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Loading...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`export default () =&amp;gt; &amp;lt;section&amp;gt;Hello from Renderify&amp;lt;/section&amp;gt;;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#mount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CLI Playground
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start the browser Playground&lt;/span&gt;
pnpm playground

&lt;span class="c"&gt;# Render from a prompt&lt;/span&gt;
pnpm cli &lt;span class="nt"&gt;--&lt;/span&gt; run &lt;span class="s2"&gt;"Build a welcome card"&lt;/span&gt;

&lt;span class="c"&gt;# Output RuntimePlan JSON&lt;/span&gt;
pnpm cli &lt;span class="nt"&gt;--&lt;/span&gt; plan &lt;span class="s2"&gt;"Build a welcome card"&lt;/span&gt;

&lt;span class="c"&gt;# Probe plan compatibility (security policy + runtime preflight)&lt;/span&gt;
pnpm cli &lt;span class="nt"&gt;--&lt;/span&gt; probe-plan examples/runtime/recharts-dashboard-plan.json

&lt;span class="c"&gt;# Configure LLM provider&lt;/span&gt;
&lt;span class="nv"&gt;RENDERIFY_LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openai &lt;span class="nv"&gt;RENDERIFY_LLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;key&amp;gt; pnpm playground
&lt;span class="nv"&gt;RENDERIFY_LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;anthropic &lt;span class="nv"&gt;RENDERIFY_LLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;key&amp;gt; pnpm playground
&lt;span class="nv"&gt;RENDERIFY_LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;google &lt;span class="nv"&gt;RENDERIFY_LLM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;key&amp;gt; pnpm playground
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Renderer-Only Mode (No LLM)
&lt;/h3&gt;

&lt;p&gt;From a capability standpoint, Renderify's LLM integration is optional. You can supply a RuntimePlan from any source — your backend API, another SDK, or a different model provider.&lt;/p&gt;

&lt;p&gt;Note that the top-level &lt;code&gt;renderify&lt;/code&gt; package includes &lt;code&gt;@renderify/llm&lt;/code&gt; as a dependency for out-of-the-box convenience. If you want to minimize the runtime entry point, use &lt;code&gt;@renderify/runtime&lt;/code&gt; + &lt;code&gt;@renderify/ir&lt;/code&gt; directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderPlanInBrowser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@renderify/runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RuntimePlan&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@renderify/ir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RuntimePlan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;specVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;runtime-plan/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renderer_only&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from BYO plan&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;domWrite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderPlanInBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#mount&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Design Philosophy and Technical Highlights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. IR as a Stable Contract
&lt;/h3&gt;

&lt;p&gt;The RuntimePlan intermediate representation fully decouples LLM output format from execution and rendering. Even outside of Renderify, this IR design provides a reusable schema for any system that needs to describe "LLM-generated interactive UI."&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Reusable Security Policy Framework
&lt;/h3&gt;

&lt;p&gt;A systematic approach to executing untrusted dynamic code — tag blocklists, module allowlists, execution budgets, source pattern analysis — this policy model can be extracted and applied to any browser-side dynamic code execution scenario.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Browser ESM Module Graph Materialization
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;fetch → rewrite imports → blob URL&lt;/code&gt; pipeline solves a problem that browser standards have not yet natively addressed — bare specifiers are not usable in browsers. This module loading strategy can be extracted as a standalone utility.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Strategy over Convention
&lt;/h3&gt;

&lt;p&gt;Key components throughout the system employ the Strategy pattern — transpilers (Babel/esbuild), sandbox modes (Worker/iframe/ShadowRealm), LLM providers (five built-in implementations), module loaders — all are swappable implementations behind interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Zero-Configuration React Compatibility
&lt;/h3&gt;

&lt;p&gt;LLMs generate standard React code that transparently executes on the Preact compat runtime — no additional configuration or special handling required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Renderify represents an important infrastructure layer in LLM application development — it solves the last-mile problem between "an LLM can generate code" and "users can see and interact with that UI." Its value stems from a set of composable engineering capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-build runtime rendering&lt;/strong&gt;: Fully browser-side transpilation and module resolution via Babel Standalone + JSPM CDN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defense-in-depth security&lt;/strong&gt;: Seven independent defense layers ensuring LLM-generated untrusted code is executed safely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser ESM module graph materialization&lt;/strong&gt;: The fetch → rewrite → blob URL pipeline, constructing module dependency graphs in the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming rendering&lt;/strong&gt;: Efficient change detection based on FNV-1a hashing, delivering real-time incremental UI previews.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal API&lt;/strong&gt;: A single line of code from RuntimePlan to fully rendered interactive UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Renderify provides a solid technical foundation for building the next generation of AI-driven dynamic UI applications. Whether it's rich interactive components in chat interfaces, AI Agent-generated data dashboards, or natural-language-driven low-code platforms, Renderify turns LLM UI generation capabilities into tangible, interactive product experiences.&lt;/p&gt;

&lt;p&gt;A note on comparisons: cross-product size and performance claims should be substantiated with benchmarks under fixed versions, fixed scenarios, and fixed network conditions before drawing conclusions.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>showdev</category>
      <category>ui</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Fict – A compiler that makes JavaScript variables automatically reactive</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Wed, 31 Dec 2025 15:50:09 +0000</pubDate>
      <link>https://dev.to/unadlib/fict-a-compiler-that-makes-javascript-variables-automatically-reactive-36mb</link>
      <guid>https://dev.to/unadlib/fict-a-compiler-that-makes-javascript-variables-automatically-reactive-36mb</guid>
      <description>&lt;p&gt;Fict Repo - &lt;a href="https://github.com/fictjs/fict" rel="noopener noreferrer"&gt;https://github.com/fictjs/fict&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening: A Starting Point for Technical Exploration
&lt;/h2&gt;

&lt;p&gt;When developing with React, we often write code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The meaning expressed by these three lines is actually quite simple: &lt;code&gt;count&lt;/code&gt; is a number, and &lt;code&gt;doubled&lt;/code&gt; is twice its value.&lt;/p&gt;

&lt;p&gt;This raises a question: &lt;strong&gt;Is it possible for a compiler to automatically infer these dependencies?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modern compilers are already capable of analyzing control flow, performing type inference, and eliminating dead code—theoretically, automatically tracking variable dependencies seems feasible as well.&lt;/p&gt;

&lt;p&gt;Fict is a technical exploration based precisely on this idea.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Core Design Philosophy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What if variables just... worked?
&lt;/h3&gt;

&lt;p&gt;The core hypothesis of Fict is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the compiler can see your code, it can know which variables depend on which other variables.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's look at an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Marker: This is mutable state (reactive source)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;// Compiler inference: Depends on count&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Value: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;doubled&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="c1"&gt;// Compiler inference: Depends on doubled → Depends on count&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what is &lt;strong&gt;missing&lt;/strong&gt; here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;setCount&lt;/code&gt; (direct assignment)&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;useMemo&lt;/code&gt; (automatic inference)&lt;/li&gt;
&lt;li&gt;No dependency arrays (compiler analysis)&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;.value&lt;/code&gt; or explicit getter calls (just plain variables)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$state(0)&lt;/code&gt; is the only marker. Everything else is inferred by the compiler itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Feasibility Analysis
&lt;/h3&gt;

&lt;p&gt;This isn't magic; it's based on mature static analysis technology.&lt;/p&gt;

&lt;p&gt;The compiler constructs a High-Level Intermediate Representation (HIR, a high-level IR) and performs data flow analysis; with the right representation, dependency tracking turns into a "traversing the dependency graph" problem.&lt;/p&gt;

&lt;p&gt;In a simplified SSA (Static Single Assignment) perspective, you would see a dependency chain like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;count_1    = $state(0)                 // Reactive source
doubled_1  = count_1 * 2               // Uses count_1 → Depends on count
message_1  = `Value: ${doubled_1}`     // Uses doubled_1 → Transitive dependency on count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler knows &lt;code&gt;message&lt;/code&gt; depends on &lt;code&gt;count&lt;/code&gt; without you telling it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The above is an overview of Fict's core design philosophy and technical route. Subsequent chapters will detail the specific implementation methods.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2: Comparison with Other Frameworks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Syntax Comparison
&lt;/h3&gt;

&lt;p&gt;Let's look at how different frameworks handle the same problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│ React                                                       │
├─────────────────────────────────────────────────────────────┤
│ const [count, setCount] = useState(0)                       │
│ const doubled = useMemo(() =&amp;gt; count * 2, [count])           │
│ // Problem: Manual dependency arrays are error-prone;       │
│ // React Compiler automates memoization.                    │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Solid                                                       │
├─────────────────────────────────────────────────────────────┤
│ const [count, setCount] = createSignal(0)                   │
│ const doubled = createMemo(() =&amp;gt; count() * 2)               │
│ // Mental model: count vs count();                          │
│ // Destructuring props might lose reactivity (use splitProps)│
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Svelte 5                                                    │
├─────────────────────────────────────────────────────────────┤
│ let count = $state(0)                                       │
│ let doubled = $derived(count * 2)                           │
│ // Better, but derived intent still needs explicit $derived │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Fict                                                        │
├─────────────────────────────────────────────────────────────┤
│ let count = $state(0)                                       │
│ const doubled = count * 2                                   │
│ // No $derived: Compiler automatically infers within static │
│ // analysis scope.                                          │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2.2 Compiler Comparison
&lt;/h3&gt;

&lt;p&gt;Syntax is just the surface difference. A more essential distinction lies in: &lt;strong&gt;What responsibilities do the compilers (or runtimes) of each framework assume?&lt;/strong&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  React Compiler: Automatic Memoization (Does not change React Model)
&lt;/h4&gt;

&lt;p&gt;The goal of React Compiler is clear: &lt;strong&gt;Automatic memoization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its output often "looks like" it automatically added &lt;code&gt;React.memo / useMemo / useCallback&lt;/code&gt; for you, but implementation-wise, it doesn't necessarily generate these Hook calls; in public discussions, React Compiler explicitly stated it directly inlines dependency checks and caches values, avoiding the overhead of closures and dependency arrays associated with handwritten &lt;code&gt;useMemo/useCallback&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Input&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSorted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can understand the compiler's "conceptual" output as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Conceptual equivalent (for understanding, not necessarily actual output)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSorted&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sorted&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Automatic memoization: Caches calculation results, stabilizes references, reduces unnecessary re-computations and re-renders.&lt;/li&gt;
&lt;li&gt;✅ Skips as many updates as possible without changing React's render + reconciliation model.&lt;/li&gt;
&lt;li&gt;✅ Still allows developers to use &lt;code&gt;useMemo/useCallback&lt;/code&gt; as escape hatches (e.g., for stable effect dependencies).&lt;/li&gt;
&lt;li&gt;✅ Provides &lt;code&gt;"use no memo"&lt;/code&gt; as a temporary escape hatch: lets a specific function completely skip compiler optimization for troubleshooting incompatible code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it doesn't do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Does not turn React into a "compile to fine-grained DOM instructions" framework: React is still render + reconciliation (colloquially "VDOM + diff").&lt;/li&gt;
&lt;li&gt;❌ Does not replace the hooks system: You still write &lt;code&gt;useState/useEffect/...&lt;/code&gt;. The compiler just tries to automate "caching work" like memoization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React Compiler's design positioning is: &lt;strong&gt;Improve performance through automatic memoization without changing the logical model of React&lt;/strong&gt;.&lt;/p&gt;




&lt;h4&gt;
  
  
  Svelte 5: Template Compilation + Explicit Runes (Derivations/Side Effects capture dependencies at evaluation)
&lt;/h4&gt;

&lt;p&gt;Svelte's typical path is: &lt;strong&gt;Compile templates to DOM update code&lt;/strong&gt; (no VDOM), and use runes (&lt;code&gt;$state/$derived/$effect&lt;/code&gt;) to explicitly write out the intent of "this is state/derived/side-effect".&lt;/p&gt;

&lt;p&gt;The key point: Svelte 5's &lt;code&gt;$derived&lt;/code&gt; documentation clearly states dependency rules—&lt;strong&gt;any value read synchronously inside a &lt;code&gt;$derived&lt;/code&gt; expression (or &lt;code&gt;$derived.by&lt;/code&gt; function body) becomes a dependency&lt;/strong&gt;; when dependencies change, it is marked dirty and re-calculated on next read.&lt;br&gt;
&lt;code&gt;$effect&lt;/code&gt; similarly drives re-execution based on dependency changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$derived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;doubled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Template → DOM update code (no VDOM)&lt;/li&gt;
&lt;li&gt;✅ Runes provide explicit semantics: &lt;code&gt;$derived&lt;/code&gt; for derivations, &lt;code&gt;$effect&lt;/code&gt; for side effects, dependencies captured at evaluation and schedule updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it doesn't do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Does not do global SSA-level automatic derivation inference for "arbitrary JS blocks" to let you skip &lt;code&gt;$derived&lt;/code&gt;: In Svelte, derivation intent still needs to be expressed via &lt;code&gt;$derived&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;❌ UI components are still organized around &lt;code&gt;.svelte&lt;/code&gt; files (this is its ecosystem &amp;amp; DX choice).&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Solid: Compile-time JSX lowering / JSX compilation + Runtime Fine-grained Dependency Tracking (No VDOM)
&lt;/h4&gt;

&lt;p&gt;Solid's route is more like: &lt;strong&gt;Compiler is responsible for turning JSX into efficient DOM creation/binding&lt;/strong&gt;, while dependency tracking and update scheduling mainly happen at runtime (signals/memos/effects).&lt;/p&gt;

&lt;p&gt;Solid official documentation clearly warns: &lt;strong&gt;Direct destructuring of props is not recommended&lt;/strong&gt;, as it may break reactivity; need to use &lt;code&gt;props.xxx&lt;/code&gt;, wrapper functions, or &lt;code&gt;splitProps&lt;/code&gt;.&lt;br&gt;
Meanwhile, Solid's homepage explicitly emphasizes: &lt;strong&gt;No Virtual DOM / no extensive diffing&lt;/strong&gt;, updates can be precise to the DOM binding layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;doubled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ JSX → DOM templates/bindings (static optimization at compile time)&lt;/li&gt;
&lt;li&gt;✅ Runtime fine-grained dependency tracking: Whoever uses the signal subscribes to it; only updates relevant DOM bindings when changed (no VDOM).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Provides tools (like &lt;code&gt;splitProps&lt;/code&gt;) to safely handle props (avoiding loss of reactivity on destructuring).&lt;br&gt;
&lt;strong&gt;What it doesn't do:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ No "automatic derivation inference": Derived values usually need explicit &lt;code&gt;createMemo&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ Runtime model is "signals driven", not "compiler globally infers everything".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Vue Vapor: A "No VDOM" Exploration Direction (Still Evolving)
&lt;/h4&gt;

&lt;p&gt;In Vue's official documentation, Vapor Mode is described as &lt;strong&gt;a new compilation strategy being explored&lt;/strong&gt;: inspired by Solid, &lt;strong&gt;not relying on Virtual DOM&lt;/strong&gt;, and making stricter use of Vue's built-in reactivity system.&lt;br&gt;
Meanwhile, the &lt;code&gt;vue-vapor&lt;/code&gt; repository itself is in an archived (read-only) state, so it should be treated as experimental / in flux.&lt;/p&gt;


&lt;h3&gt;
  
  
  Compiler Comparison Table (Stricter Version)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: ✅ = Officially clearly described and presented as a stable capability; 🧪 = Officially defined as exploration/experimental direction; — = Not the main narrative of the framework/hard to draw a hard conclusion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;React + React Compiler&lt;/th&gt;
&lt;th&gt;Svelte 5&lt;/th&gt;
&lt;th&gt;Solid&lt;/th&gt;
&lt;th&gt;Vue Vapor&lt;/th&gt;
&lt;th&gt;Fict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Automatic memoization (reduce manual memo)&lt;/td&gt;
&lt;td&gt;✅ Automatic memoization, &lt;code&gt;useMemo/useCallback&lt;/code&gt; as escape hatch; supports &lt;code&gt;"use no memo"&lt;/code&gt; to skip optimization.&lt;/td&gt;
&lt;td&gt;❌ Derivations need explicit &lt;code&gt;$derived&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;❌ Derivations usually need &lt;code&gt;createMemo&lt;/code&gt; (explicit).&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Still render + reconciliation?&lt;/td&gt;
&lt;td&gt;✅ Yes.&lt;/td&gt;
&lt;td&gt;❌ (Template compiled to DOM updates)&lt;/td&gt;
&lt;td&gt;❌ (No VDOM/No diffing)&lt;/td&gt;
&lt;td&gt;🧪 Official exploration of "No VDOM" strategy.&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Are Derived/Side-effect intents explicit?&lt;/td&gt;
&lt;td&gt;✅ Hooks explicit; memoization can be automated by compiler.&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;$derived/$effect&lt;/code&gt; explicit; dependencies are captured from synchronous reads during evaluation.&lt;/td&gt;
&lt;td&gt;✅ Explicit memo/effect; dependency tracking at runtime.&lt;/td&gt;
&lt;td&gt;✅ (Vue default: computed/watch etc.; Vapor's commitment to not changing intent expression is not set in stone)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DX Form&lt;/td&gt;
&lt;td&gt;JS/JSX + Compiler&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.svelte&lt;/code&gt; + runes&lt;/td&gt;
&lt;td&gt;JS/JSX + signals&lt;/td&gt;
&lt;td&gt;SFC/Template-centric (Vapor is exploration)&lt;/td&gt;
&lt;td&gt;Pure JSX/JS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  2.3 Execution Model Comparison
&lt;/h2&gt;

&lt;p&gt;The compiler is only half the story; the other half is the execution model.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Does Component Code Re-execute?&lt;/th&gt;
&lt;th&gt;Update Granularity&lt;/th&gt;
&lt;th&gt;Control Flow Expression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;React (with Compiler)&lt;/td&gt;
&lt;td&gt;React still re-renders; the compiler memoizes values/functions to reduce work and stabilize props.&lt;/td&gt;
&lt;td&gt;Component/Subtree dominant (determined by reconciliation)&lt;/td&gt;
&lt;td&gt;Native JS (if/for)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solid&lt;/td&gt;
&lt;td&gt;Executes once on init; subsequent fine-grained updates driven by signal subscriptions (no VDOM/diff).&lt;/td&gt;
&lt;td&gt;DOM Binding Level&lt;/td&gt;
&lt;td&gt;Commonly uses &lt;code&gt;&amp;lt;Show&amp;gt;/&amp;lt;For&amp;gt;&lt;/code&gt; control flow components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Svelte 5&lt;/td&gt;
&lt;td&gt;Executes once on init; &lt;code&gt;$derived/$effect&lt;/code&gt; scheduled on dependency change.&lt;/td&gt;
&lt;td&gt;DOM update code + runes scheduling&lt;/td&gt;
&lt;td&gt;Template blocks (&lt;code&gt;{#if}/{#each}&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vue Vapor&lt;/td&gt;
&lt;td&gt;🧪 Exploring: Goal is rendering path not dependent on VDOM.&lt;/td&gt;
&lt;td&gt;🧪&lt;/td&gt;
&lt;td&gt;Template/Directives centric&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fict&lt;/td&gt;
&lt;td&gt;On-demand (Mixed)&lt;/td&gt;
&lt;td&gt;Fine-grained DOM update&lt;/td&gt;
&lt;td&gt;Native JS (if/for)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  An Intuitive Example: Re-execution Strategy and Slot Reuse
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Demo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mount once&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// First run&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;re-run with&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Re-runs when count changes&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;After clicking the button, the console will only append &lt;code&gt;re-run with 1/2/...&lt;/code&gt;. &lt;code&gt;mount once&lt;/code&gt; will not repeat, indicating that only the region reading the state is re-executed. The compiler achieves this by hoisting static parts outside the reactive region, or splitting the function into multiple regions.&lt;/li&gt;
&lt;li&gt;DOM will not be recreated: Signal slot reuse + binding updates ensure the button node, events, and refs remain in place, only the text node updates.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Part 3: Fict's "Full-Link Analysis" (Design Goal)
&lt;/h2&gt;

&lt;p&gt;One thing Fict attempts to do is: &lt;strong&gt;Analyze the entire JS function, not just the template part.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Value: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;doubled&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Special&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Main processing stages of the Fict compiler:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Build HIR (High-Level Intermediate Representation)&lt;/strong&gt;: Function body → Basic Blocks + CFG (including if/for/while/switch)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Convert to SSA&lt;/strong&gt;: Make assignment versions unique, facilitating explicit dependency edges&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Analyze Reactive Scopes&lt;/strong&gt;: Automatically turn expression regions dependent on &lt;code&gt;$state&lt;/code&gt; into memo/effect/bindings&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Detect Control Flow Reads&lt;/strong&gt;: When reactive values appear in branch tests etc., choose paths that "need re-execution"&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Generate Fine-grained DOM&lt;/strong&gt;: JSX → DOM instructions; Bindings → Precise effects&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Part 4: Fict's Mixed Execution Model
&lt;/h2&gt;

&lt;p&gt;The execution model designed by Fict:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If state is &lt;strong&gt;only read in JSX&lt;/strong&gt; → Component does not re-execute, only relevant DOM nodes update&lt;/li&gt;
&lt;li&gt;If state is &lt;strong&gt;read in control flow&lt;/strong&gt; (e.g., branch conditions in if/switch/loop) → Component needs re-execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The compiler analyzes and decides which update strategy to adopt at compile time. Developers don't need to rewrite code into special syntax like &lt;code&gt;&amp;lt;Show&amp;gt;/&amp;lt;For&amp;gt;&lt;/code&gt; or &lt;code&gt;{#if}&lt;/code&gt;; native &lt;code&gt;if/for&lt;/code&gt; works directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 5: How the Compiler Works
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Fict compiler transforms source code into efficient runtime code through several core stages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inside the compiler
&lt;/h3&gt;

&lt;p&gt;Fict compiler's core is a multi-stage pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plain JS/TS + JSX/TSX (compiled)
     ↓
  ┌─────────┐
  │  HIR    │  CFG (Basic Blocks + Control Flow Graph)
  └────┬────┘
       ↓
  ┌─────────┐
  │  SSA    │  Versioned Assignments + Dependency Analysis
  └────┬────┘
       ↓
  ┌─────────────────┐
  │ Reactive Scopes │  Reactive Scope Analysis + Region Grouping
  └────────┬────────┘
       ↓
  ┌─────────┐
  │ Codegen │  Fine-grained DOM Operations + bindings
  └─────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler performs &lt;strong&gt;Reactive Scope Analysis&lt;/strong&gt; to determine memoization boundaries, automatically identifying which expressions should be wrapped as memos, and their dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  HIR Construction (Schematic)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Special&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Normal&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// HIR (Schematic)&lt;/span&gt;
&lt;span class="nx"&gt;Block&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;$0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LoadLocal&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;
  &lt;span class="nx"&gt;$1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BinaryExpr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
  &lt;span class="nx"&gt;Branch&lt;/span&gt; &lt;span class="nx"&gt;$1&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Block1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Block2&lt;/span&gt;

&lt;span class="nx"&gt;Block&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;$2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JSXElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Special&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Return&lt;/span&gt; &lt;span class="nx"&gt;$2&lt;/span&gt;

&lt;span class="nx"&gt;Block&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;$3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JSXElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Return&lt;/span&gt; &lt;span class="nx"&gt;$3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SSA Conversion &amp;amp; Dependency Tracking (Schematic)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;

&lt;span class="c1"&gt;// SSA (Schematic)&lt;/span&gt;
&lt;span class="nx"&gt;x_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count_1&lt;/span&gt;
&lt;span class="nx"&gt;Branch&lt;/span&gt; &lt;span class="nx"&gt;cond&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Block1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Block2&lt;/span&gt;

&lt;span class="nx"&gt;Block1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;x_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count_1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;Jump&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Block3&lt;/span&gt;

&lt;span class="nx"&gt;Block2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;Jump&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Block3&lt;/span&gt;

&lt;span class="nx"&gt;Block3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nx"&gt;x_3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Phi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Block1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x_2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Block2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;Return&lt;/span&gt; &lt;span class="nx"&gt;x_3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the dependency relationship is very clear: &lt;code&gt;x_3&lt;/code&gt; ultimately depends on &lt;code&gt;count_1&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 6: Compilation Output Example (Simplified)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Input&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;doubled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Output (Simplified Schematic)&lt;/span&gt;
&lt;span class="c1"&gt;// User code stays ‘plain variables’; the generated code may use accessor calls internally.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// $state -&amp;gt; signal&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Derived value -&amp;gt; memo (Compiler inferred)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// DOM Creation&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Binding Update (Using fine-grained effect)&lt;/span&gt;
  &lt;span class="nf"&gt;bindText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;doubled&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="c1"&gt;// Event&lt;/span&gt;
  &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;button&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The characteristics of this compilation output are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No VDOM&lt;/li&gt;
&lt;li&gt;No diffing&lt;/li&gt;
&lt;li&gt;Only precise DOM operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;doubled&lt;/code&gt; automatically memoized&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Example with Control Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Input&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Panel&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Fallback&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Output (Simplified)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;__fictRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Control flow triggers re-execution, so the whole render function logic runs again&lt;/span&gt;
    &lt;span class="c1"&gt;// But signals are reused via slots, not recreated&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createConditional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* Panel's fine-grained DOM */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* Fallback's fine-grained DOM */&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;__fictRender&lt;/code&gt; re-executes the internal function when &lt;code&gt;show&lt;/code&gt; changes, but &lt;code&gt;__fictUseSignal&lt;/code&gt; reuses state via slots, so state is not lost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactivity of Props
&lt;/h3&gt;

&lt;p&gt;Fict automatically maintains the reactivity of props, even after destructuring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Input&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;doubled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Output (Simplified)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Destructured props automatically wrapped as getters&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useProp&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;__props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;__props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt; &lt;span class="c1"&gt;// Function type not wrapped&lt;/span&gt;

  &lt;span class="c1"&gt;// Derived values automatically become memos&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;__fictUseMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solves a common pain point in Solid: Destructuring props breaks reactivity. In Fict, you can destructure freely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 7: Compiler Safety Rails
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DX Protection Mechanisms
&lt;/h3&gt;

&lt;p&gt;The Fict compiler detects common error patterns and issues warnings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│ Code       │ Issue                   │ Severity             │
├─────────────────────────────────────────────────────────────┤
│ FICT-C003  │ Nested Component Def    │ Warning              │
│ FICT-M003  │ Memo with Side Effects  │ Warning              │
│ FICT-S002  │ State passed as arg     │ Warning              │
│ FICT-J002  │ List missing key        │ Warning              │
│ FICT-E001  │ Effect no deps          │ Warning              │
│ FICT-C004  │ Component no return     │ Warning              │
├─────────────────────────────────────────────────────────────┤
│ $state inside condition | Not Allowed | Compile Error       │
│ $state inside loop      | Not Allowed | Compile Error       │
│ Destructuring $state    | Not Allowed | Compile Error       │
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, defining nested components is a common anti-pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ⚠️ FICT-C003: Components should not be defined inside another component&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Child&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler will warn you to move &lt;code&gt;Child&lt;/code&gt; to module scope.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 8: Trade-offs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What Fict can't do (yet)
&lt;/h3&gt;

&lt;p&gt;I want to be honest about Fict's limitations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Dependency tracking inside black-box functions may be incomplete&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;someExternalLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Compiler cannot see inside compute callback, dependency tracking might be incomplete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solution: The compiler issues a warning (FICT-S002), you can use explicit getters or let the component take the re-execution path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Dynamic property access is limited&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDynamicKey&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Compiler doesn't know what key is&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solution: Degrade to object-level subscription + warning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. No Ecosystem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is common for new frameworks. No UI library, no complete SSR framework, no mature router. If you need to go to production today, Fict might not be the right choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Execution Model needs learning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fict's execution model differs from React (see Section 2.3):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Executes once&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Executes every time count changes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Developers from a React background might be confused: "Why doesn't A execute every time?" This requires understanding Fict's concept of reactive regions.&lt;/p&gt;

&lt;p&gt;We will provide Fict DevTools to visualize these regions to aid debugging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Compiler Complexity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fict's compiler is much more complex than Solid's. More code means more potential bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Known Escape Hatches / Mitigation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Explicit &lt;code&gt;$memo&lt;/code&gt; / &lt;code&gt;$effect&lt;/code&gt;: When automatic inference doesn't meet expectations, manually declare derivation or side-effect boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useProp/mergeProps&lt;/code&gt; helpers: Manually maintain reactivity when props access patterns are special.&lt;/li&gt;
&lt;li&gt;Control Flow Degradation: Scenarios that cannot be statically analyzed are handed over to the re-execution model, prioritizing correctness.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why I still think it's worth it
&lt;/h3&gt;

&lt;p&gt;Despite all these trade-offs, I believe what we get in return is worth it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The amount of code developers write every day is reduced.&lt;/li&gt;
&lt;li&gt;Mental burden is reduced.&lt;/li&gt;
&lt;li&gt;Beginners don't need to understand "why do I have to write useMemo".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React Compiler proved that "letting the compiler take more responsibility" is the right direction. Fict just pushes this idea a bit further.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 9: Extended APIs
&lt;/h2&gt;

&lt;p&gt;Fict also provides some extended APIs to handle scenarios that automatic inference cannot cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$store&lt;/code&gt;&lt;/strong&gt;: For fine-grained reactivity of nested objects. &lt;code&gt;$store&lt;/code&gt; is the recommended choice when path-level update tracking for deep objects is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$memo&lt;/code&gt;&lt;/strong&gt;: Escape hatch for explicitly creating memos. Although the compiler automatically infers derived values, developers can also manually control memoization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$effect&lt;/code&gt;&lt;/strong&gt;: Explicitly declare side effects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ErrorBoundary / Suspense / Transitions&lt;/strong&gt;: For error handling, async loading, and priority scheduling.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Fict's design philosophy is "reduce boilerplate + compiler automatic inference", these APIs serve as supplementary tools for advanced scenarios.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 10: Why Now
&lt;/h2&gt;

&lt;p&gt;The frontend framework field is undergoing some interesting changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;React Compiler achieved automatic memoization&lt;/strong&gt;: Reduces the need for manual memo without changing the React model.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Signals proposal is advancing in TC39&lt;/strong&gt;: Although still in early stages, it reflects the community's focus on reactive primitives.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Svelte 5 makes derivation/side-effect intent more explicit via runes&lt;/strong&gt;, with clear dependency rules (sync read equals dependency).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Vue is officially exploring Vapor Mode&lt;/strong&gt;: A compilation strategy that doesn't rely on VDOM and utilizes built-in reactivity more.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this context:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fict does not attempt to replace these excellent frameworks, but is a technical exploration: If we start from scratch based on these excellent frameworks, taking "compiler automatic dependency inference" as the core design principle, how far can we go?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Conclusion: Welcome to Try
&lt;/h2&gt;

&lt;p&gt;Fict is currently under active development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;fict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core compiler and runtime functions are basically stable, but the ecosystem is still under construction. If you are interested in trying it out, we look forward to your feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bug reports (edge cases are especially valuable)&lt;/li&gt;
&lt;li&gt;Suggestions for improving compiler output&lt;/li&gt;
&lt;li&gt;Usage patterns you think should be supported but are not yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for reading, and looking forward to communicating with you.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Rethinking Undo/Redo - Why We Need Travels</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Sun, 05 Oct 2025 13:44:56 +0000</pubDate>
      <link>https://dev.to/unadlib/rethinking-undoredo-why-we-need-travels-2lcc</link>
      <guid>https://dev.to/unadlib/rethinking-undoredo-why-we-need-travels-2lcc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR: If your app state is large (&amp;gt;10KB), needs persistence, or you care about memory usage and performance with long histories, Travels’ JSON Patch approach is worth considering. For simple scenarios, the default snapshot modes in Redux-undo or Zundo are actually simpler and more efficient.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where the Problem Starts
&lt;/h2&gt;

&lt;p&gt;Implementing usable undo/redo sounds easy: store a full snapshot for every state change and restore it on undo. The problem is that when the state object is large and changes are small (the usual case), snapshot memory = object size × history length. That linear growth is unacceptable for big objects. Worse, repeatedly deep-copying/patch-diffing complex structures pushes the main thread toward jank—this isn’t something you “optimize a bit” to fix; it’s a category error.&lt;/p&gt;

&lt;p&gt;Travels starts by making JSON Patch (RFC 6902) a first-class citizen: generate patches/inversePatches incrementally as changes happen, trading compute for storage and serialization efficiency—preserving full reversibility while drastically shrinking history size.&lt;/p&gt;

&lt;p&gt;Travels was created to resolve a fundamental tension: how to retain a complete history while minimizing memory and performance overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Mainstream Approaches Work
&lt;/h2&gt;

&lt;p&gt;Let’s first look at how two popular community solutions work in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redux-undo: Reference-Based Snapshot Storage
&lt;/h3&gt;

&lt;p&gt;Redux-undo is the classic solution in the Redux ecosystem. Its core logic looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// redux-undo/src/reducer.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newPast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;pastSliced&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_latestUnfiltered&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;newHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newPast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its strategy: &lt;strong&gt;store references to each state object&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;past&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;    &lt;span class="c1"&gt;// array of object references&lt;/span&gt;
  &lt;span class="nx"&gt;present&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;future&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s no deep copy here; it relies on Redux’s immutable update pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reducers return new objects each time&lt;/li&gt;
&lt;li&gt;Structural sharing reduces memory copying&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;past&lt;/code&gt; only holds references&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple, straightforward implementation&lt;/li&gt;
&lt;li&gt;Efficient enough for small state&lt;/li&gt;
&lt;li&gt;Supports fine-grained controls like &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;groupBy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With Redux-undo plus Immer or immutable updates, unmodified subtrees share references. But each change still creates new objects for the changed node and all of its ancestors. For deep structures, even a single-field change can rebuild an entire parent chain.&lt;/li&gt;
&lt;li&gt;Each history entry is effectively a full state snapshot&lt;/li&gt;
&lt;li&gt;Tightly coupled to Redux; not usable elsewhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a simple counter, this is perfectly fine. But for a complex document object, 100 history entries imply 100 state references &lt;strong&gt;plus&lt;/strong&gt; each one’s memory footprint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zundo: Optional Diff Optimization
&lt;/h3&gt;

&lt;p&gt;Zundo is a tiny (&amp;lt;700B) and flexible undo/redo middleware for Zustand.&lt;/p&gt;

&lt;p&gt;Core code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// zundo/src/temporal.ts&lt;/span&gt;
&lt;span class="nx"&gt;_handleSet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pastState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deltaState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;pastStates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;pastStates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deltaState&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;pastState&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;futureStates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note &lt;code&gt;deltaState || pastState&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Default stores the full state&lt;/strong&gt; (&lt;code&gt;pastState&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optionally stores a diff&lt;/strong&gt; (&lt;code&gt;deltaState&lt;/code&gt;, computed via user-provided &lt;code&gt;diff&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although Zundo exposes a diff option, you must pick and configure a diff library and translate results yourself. For many developers, that adds learning cost. More importantly, diffing a large state tree frequently can itself become a performance bottleneck.&lt;/p&gt;

&lt;p&gt;It’s a clever design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-cost abstraction&lt;/strong&gt;: don’t opt in to diffs, pay no cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: choose any diff algorithm (microdiff, fast-json-patch, etc.) or roll your own&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control&lt;/strong&gt;: pair with &lt;code&gt;partialize&lt;/code&gt; to track only part of the state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports diff-based storage; can optimize memory&lt;/li&gt;
&lt;li&gt;Elegant API&lt;/li&gt;
&lt;li&gt;Deep integration with Zustand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You must implement the diff logic yourself&lt;/strong&gt;—not trivial&lt;/li&gt;
&lt;li&gt;Zustand-only&lt;/li&gt;
&lt;li&gt;Default behavior still stores full snapshots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The catch: building a reliable diff is non-trivial. You must:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick the right diff library&lt;/li&gt;
&lt;li&gt;Write transformation code (like the example)&lt;/li&gt;
&lt;li&gt;Handle edge cases (null, undefined, cycles, etc.)&lt;/li&gt;
&lt;li&gt;Ensure reversibility (correct undo/redo)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And for very large trees, the diff stage itself can be expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Travels: JSON Patch as a First-Class Citizen
&lt;/h2&gt;

&lt;p&gt;This is where Travels comes in. Its core idea: &lt;strong&gt;use JSON Patch as the built-in, default storage format&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createTravels&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Doc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// ... potentially a very large object&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Internally, Travels stores:&lt;/span&gt;
&lt;span class="c1"&gt;// {&lt;/span&gt;
&lt;span class="c1"&gt;//   patches: [{ op: "replace", path: ["title"], value: "New Title" }],&lt;/span&gt;
&lt;span class="c1"&gt;//   inversePatches: [{ op: "replace", path: ["title"], value: "My Doc" }]&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;

&lt;span class="c1"&gt;// You can set { patchesOptions: { pathAsArray: true } } to make `path` a JSON path string.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No configuration required—JSON Patch is default.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Mutative?
&lt;/h3&gt;

&lt;p&gt;Travels is built on &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;Mutative&lt;/a&gt;. That choice matters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Mutative core capability&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mutative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nextState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inversePatches&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enablePatches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// patches: [{ op: "replace", path: ["count"], value: 1 }]&lt;/span&gt;
&lt;span class="c1"&gt;// inversePatches: [{ op: "replace", path: ["count"], value: 0 }]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mutative provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Draft API&lt;/strong&gt; – identical ergonomics to Immer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native JSON Patch generation&lt;/strong&gt; – no extra diff library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High performance&lt;/strong&gt; – official benchmarks show up to 10× over Immer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero configuration&lt;/strong&gt; – patch generation is built-in, not optional&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This lets Travels leverage Mutative’s strengths directly, without forcing users to implement diffs like Zundo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real Memory Differences
&lt;/h3&gt;

&lt;p&gt;A test with a 100KB complex object and 100 tiny edits (2 fields per edit):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux-undo:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Stores full-state references&lt;/span&gt;
&lt;span class="nx"&gt;pastStates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 100KB object */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 100KB object */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// 100 history entries: ~11.8 MB growth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Zundo (no diff):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Default stores full state&lt;/span&gt;
&lt;span class="nx"&gt;pastStates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 100KB object */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 100KB object */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// 100 history entries: ~11.8 MB growth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Travels:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Automatically stores JSON Patches&lt;/span&gt;
&lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;   &lt;span class="c1"&gt;// ~50 bytes&lt;/span&gt;
  &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;field2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;newer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="c1"&gt;// ~50 bytes&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// 100 histories: ~0.32 MB growth (≈97.3% saved)&lt;/span&gt;
&lt;span class="c1"&gt;// After serialization only ~20.6 KB (≈99.8% smaller than snapshots)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gap is stark. For large objects with small edits, Travels can deliver ~40× memory savings, and &lt;strong&gt;500×+&lt;/strong&gt; on serialized size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Framework-Agnostic by Design
&lt;/h3&gt;

&lt;p&gt;Another advantage: Travels is framework-agnostic. The core is a plain state manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// React&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSyncExternalStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useTravel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSyncExternalStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// for SSR&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getControls&lt;/span&gt;&lt;span class="p"&gt;()];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Vue&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useTravel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Plain JS&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it anywhere: React, Vue, Svelte, Angular, or vanilla JS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side-by-Side Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Redux-undo&lt;/th&gt;
&lt;th&gt;Zundo&lt;/th&gt;
&lt;th&gt;Travels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Snapshot references&lt;/td&gt;
&lt;td&gt;Snapshot by default, diff&lt;/td&gt;
&lt;td&gt;Built-in JSON Patch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Config complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium (you write the diff)&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Medium (sharing helps)&lt;/td&gt;
&lt;td&gt;Low→High (depends on diff)&lt;/td&gt;
&lt;td&gt;High (out of the box)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistence fit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Poor (large data)&lt;/td&gt;
&lt;td&gt;Poor (large data)&lt;/td&gt;
&lt;td&gt;Excellent (compact + standard)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frameworks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Redux only&lt;/td&gt;
&lt;td&gt;Zustand only&lt;/td&gt;
&lt;td&gt;Framework-agnostic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Highlights&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;filter, groupBy&lt;/td&gt;
&lt;td&gt;partialize, custom diff&lt;/td&gt;
&lt;td&gt;Auto/manual archive, mutable mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core LOC (approx.)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~440&lt;/td&gt;
&lt;td&gt;~250&lt;/td&gt;
&lt;td&gt;~640&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  A Few Neat Designs in Travels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Auto/Manual Archive Modes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Auto: each setState becomes a history entry&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// +1 history&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// +1 history&lt;/span&gt;

&lt;span class="c1"&gt;// Manual: batch multiple changes into one entry&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;autoArchive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// record only 0→3 as one history entry&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manual mode is ideal for complex interactions. E.g., a drag operation might trigger dozens of updates, but you want it to undo as one unit.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Mutable Mode for Reactive Frameworks
&lt;/h3&gt;

&lt;p&gt;In Vue/MobX (Proxy-based reactivity), replacing object references breaks reactivity. Travels offers &lt;code&gt;mutable&lt;/code&gt; mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Vue example&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reactive&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mutable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Travels mutates in place, keeping the Proxy reference&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Vue reactivity stays intact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementation sketch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mutable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mutable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pendingState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// keep the reference stable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;S&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows seamless use in reactive frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Sliding Window via &lt;code&gt;maxHistory&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxHistory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 5 consecutive ops&lt;/span&gt;
&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 5&lt;/span&gt;

&lt;span class="c1"&gt;// History window: [2, 3, 4, 5]&lt;/span&gt;
&lt;span class="c1"&gt;// You can undo back to 2, but not to 0 or 1 due to the window size&lt;/span&gt;
&lt;span class="c1"&gt;// however, reset() can return to the initial state 0.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great for memory-constrained environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On Experience
&lt;/h2&gt;

&lt;p&gt;I refactored a collaborative editor with Travels. Based on benchmark projections for a 100KB doc over 100 edits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: ~11.8MB (snapshots) → ~0.32MB (&lt;strong&gt;−97%&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence size&lt;/strong&gt;: ~11.7MB → ~116KB (&lt;strong&gt;−99%&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serialization speed&lt;/strong&gt;: ~12ms → ~0.06ms (&lt;strong&gt;≈200× faster&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code volume&lt;/strong&gt;: ~40% less (no custom diff code)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Undo/redo&lt;/strong&gt;: still sub-millisecond (≈0.69ms undo / 0.27ms redo in the real-library test)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the API is intuitive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Update&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Time travel&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;     &lt;span class="c1"&gt;// undo&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// redo&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// jump to position 5&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// back to initial&lt;/span&gt;

&lt;span class="c1"&gt;// History info&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHistory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPosition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;canBack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;canForward&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’ve used Immer or Mutative, there’s essentially no learning curve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;To validate the analysis, I wrote comprehensive benchmarks. Setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Object size&lt;/strong&gt;: ~100KB (nested objects/arrays)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ops&lt;/strong&gt;: 100 tiny edits (2 fields per op)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Env&lt;/strong&gt;: Node.js v22.21.1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: measured precisely with &lt;code&gt;--expose-gc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full code: &lt;a href="https://github.com/mutativejs/travels/tree/main/benchmarks" rel="noopener noreferrer"&gt;&lt;code&gt;./benchmarks/&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;The latest runs (Node v22.21.1) come from executing &lt;code&gt;yarn test:all&lt;/code&gt;, which runs both benchmark scripts with &lt;code&gt;node --expose-gc&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Simulated implementations (&lt;code&gt;memory-performance-test.js&lt;/code&gt;)
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Redux-undo&lt;/th&gt;
&lt;th&gt;Zundo&lt;/th&gt;
&lt;th&gt;Travels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory (MB)&lt;/td&gt;
&lt;td&gt;11.8&lt;/td&gt;
&lt;td&gt;11.8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.32&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setState (ms)&lt;/td&gt;
&lt;td&gt;42.74&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41.27&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;88.16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undo (ms)&lt;/td&gt;
&lt;td&gt;0.08&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.07&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;18.65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redo (ms)&lt;/td&gt;
&lt;td&gt;0.12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.02&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20.34&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serialized size (KB)&lt;/td&gt;
&lt;td&gt;11,626.66&lt;/td&gt;
&lt;td&gt;11,626.46&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20.6&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serialize (ms)&lt;/td&gt;
&lt;td&gt;12.86&lt;/td&gt;
&lt;td&gt;11.88&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.06&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deserialize (ms)&lt;/td&gt;
&lt;td&gt;23.6&lt;/td&gt;
&lt;td&gt;23.55&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.14&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Travels keeps simulated history sizes tiny (20.6 KB vs ~11 MB snapshots) and serializes &amp;gt;200× faster, while snapshot stores remain unbeatable for undo/redo latency.&lt;/li&gt;
&lt;li&gt;The Travels simulated &lt;code&gt;setState&lt;/code&gt; cost (88 ms for 100 updates) is roughly 2× the snapshot stores, which matches expectations for generating JSON Patch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Real libraries (&lt;code&gt;real-library-benchmark.js&lt;/code&gt;)
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Redux-undo&lt;/th&gt;
&lt;th&gt;Zundo&lt;/th&gt;
&lt;th&gt;Travels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory (MB)&lt;/td&gt;
&lt;td&gt;0.05&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.04&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;setState (ms)&lt;/td&gt;
&lt;td&gt;0.35&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.81&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undo (ms)&lt;/td&gt;
&lt;td&gt;0.25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.69&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redo (ms)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.07&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.15&lt;/td&gt;
&lt;td&gt;0.27&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serialized size (KB)&lt;/td&gt;
&lt;td&gt;11,742.03&lt;/td&gt;
&lt;td&gt;11,510.59&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;116.26&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serialize (ms)&lt;/td&gt;
&lt;td&gt;12.63&lt;/td&gt;
&lt;td&gt;11.59&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.61&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deserialize (ms)&lt;/td&gt;
&lt;td&gt;28.87&lt;/td&gt;
&lt;td&gt;22.66&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.42&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Even with real packages, Travels shrinks serialized history by roughly 100× and finishes (de)serialization well under a millisecond.&lt;/li&gt;
&lt;li&gt;Snapshot-based stacks still win hot-path operations (setState/undo/redo), so workloads that prioritize raw speed over persistence will continue to prefer Redux-undo/Zundo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance Conclusion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Snapshot approaches (Redux-undo / default Zundo):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Fastest &lt;code&gt;setState&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ Fastest undo/redo&lt;/li&gt;
&lt;li&gt;❌ Huge memory&lt;/li&gt;
&lt;li&gt;❌ Large serialized payloads&lt;/li&gt;
&lt;li&gt;❌ Poor fit for persistence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Travels (built-in JSON Patch):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚠️ Slower &lt;code&gt;setState&lt;/code&gt; (patch generation)&lt;/li&gt;
&lt;li&gt;⚠️ Slower undo/redo (patch application)&lt;/li&gt;
&lt;li&gt;✅ Low memory&lt;/li&gt;
&lt;li&gt;✅ Extremely small persistence ⭐&lt;/li&gt;
&lt;li&gt;✅ Zero-config, out of the box&lt;/li&gt;
&lt;li&gt;✅ Standard format, great for storage/analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple apps, unconcerned with memory → Redux-undo/Zundo default&lt;/li&gt;
&lt;li&gt;Need persistence, cross-framework, plug-and-play → &lt;strong&gt;Travels&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use It
&lt;/h2&gt;

&lt;p&gt;Travels isn’t a silver bullet; it shines when:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Good fit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State objects are large (&amp;gt;10KB)&lt;/li&gt;
&lt;li&gt;You need cross-framework reuse&lt;/li&gt;
&lt;li&gt;Memory-sensitive environments (mobile, embedded)&lt;/li&gt;
&lt;li&gt;You want fine-grained history control (manual archive, custom windows)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;❌ Less ideal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very simple state (a few fields—Redux-undo is simpler)&lt;/li&gt;
&lt;li&gt;Deeply invested in Zustand (Zundo is lighter)&lt;/li&gt;
&lt;li&gt;You don’t care about memory&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Redux-undo&lt;/strong&gt; is a dependable standard in the Redux ecosystem but is Redux-bound.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zundo&lt;/strong&gt; is elegantly designed and supports diff optimization, but pushes diff complexity onto users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Travels&lt;/strong&gt; treats JSON Patch as a first-class citizen—out-of-the-box memory savings, framework-agnostic, and high-performance where it matters for persistence.&lt;/p&gt;

&lt;p&gt;If you’re building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rich text editors&lt;/li&gt;
&lt;li&gt;Graphics/design tools&lt;/li&gt;
&lt;li&gt;Collaborative editing apps&lt;/li&gt;
&lt;li&gt;Complex form systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;—i.e., anything with frequent undo/redo—Travels is worth a try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JSON Patch Reversibility
&lt;/h3&gt;

&lt;p&gt;Travels stores both &lt;code&gt;patches&lt;/code&gt; and &lt;code&gt;inversePatches&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Change: count: 0 -&amp;gt; 1&lt;/span&gt;
&lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;span class="nl"&gt;inversePatches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;

&lt;span class="c1"&gt;// Redo: apply patches&lt;/span&gt;
&lt;span class="c1"&gt;// Undo: apply inversePatches&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This guarantees reliable time travel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Mutative Is Fast
&lt;/h3&gt;

&lt;p&gt;Mutative’s performance comes from:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Copy-on-write&lt;/strong&gt; – only copy what changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shallow copy&lt;/strong&gt; – shallow by default; deep when needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental patch generation&lt;/strong&gt; – not a post-hoc diff&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is typically faster than Immer and far more efficient than &lt;code&gt;JSON.parse(JSON.stringify())&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why JSON Patch Excels at Persistence
&lt;/h3&gt;

&lt;p&gt;Another key advantage: &lt;strong&gt;JSON Patch is extremely well suited to persistence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose you want “save the entire edit history locally and resume it on next launch”:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redux-undo / Zundo (full snapshots):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Data to persist&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataToSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;past&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Doc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;        &lt;span class="c1"&gt;// 100KB&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Doc v2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;     &lt;span class="c1"&gt;// 100KB&lt;/span&gt;
    &lt;span class="c1"&gt;// ... 100 histories&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;present&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* current state */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;future&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Write to localStorage/IndexedDB&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;history&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataToSave&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// Problem: 10MB+ of serialized JSON&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Travels (JSON Patch):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Data to persist&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataToSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;        &lt;span class="c1"&gt;// current state&lt;/span&gt;
  &lt;span class="na"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPatches&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;    &lt;span class="c1"&gt;// only patches, just a few KB&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPosition&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;  &lt;span class="c1"&gt;// index&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels-state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataToSave&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels-patches&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataToSave&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels-position&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataToSave&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Restore&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createTravels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels-state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;initialPatches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels-patches&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="na"&gt;initialPosition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;travels-position&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Practical comparison (100 histories, from the benchmark):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Redux-undo&lt;/th&gt;
&lt;th&gt;Zundo&lt;/th&gt;
&lt;th&gt;Travels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;localStorage usage&lt;/td&gt;
&lt;td&gt;~11.7 MB&lt;/td&gt;
&lt;td&gt;~11.5 MB&lt;/td&gt;
&lt;td&gt;~116 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;JSON.stringify&lt;/code&gt; time&lt;/td&gt;
&lt;td&gt;~12.6 ms&lt;/td&gt;
&lt;td&gt;~11.6 ms&lt;/td&gt;
&lt;td&gt;~0.61 ms (&lt;strong&gt;×20 faster&lt;/strong&gt;) ⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;JSON.parse&lt;/code&gt; time&lt;/td&gt;
&lt;td&gt;~28.9 ms&lt;/td&gt;
&lt;td&gt;~22.7 ms&lt;/td&gt;
&lt;td&gt;~0.42 ms (&lt;strong&gt;×55 faster&lt;/strong&gt;) ⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage savings&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;99%&lt;/strong&gt; ⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IndexedDB write speed&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;td&gt;Fast (100×+ less data)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why such a gap?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Size&lt;/strong&gt;: Patches are inherently compact&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(De)serialization&lt;/strong&gt;: tiny payloads make JSON faster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quotas&lt;/strong&gt;: localStorage caps at 5–10MB; Travels stores far more history&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Real-World Patterns
&lt;/h3&gt;

&lt;p&gt;This matters in many cases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Offline-first apps&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Save to local storage on every change&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Always-on autosave is feasible because data is tiny&lt;/span&gt;
  &lt;span class="nf"&gt;saveToLocalStorage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPatches&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPosition&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Next launch resumes with full undo/redo history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2) Collaborative editing operation logs&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Sync patches to server&lt;/span&gt;
&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// patches are standard JSON Patch (RFC 6902)&lt;/span&gt;
  &lt;span class="c1"&gt;// Send for:&lt;/span&gt;
  &lt;span class="c1"&gt;// - Operational history&lt;/span&gt;
  &lt;span class="c1"&gt;// - Conflict resolution&lt;/span&gt;
  &lt;span class="c1"&gt;// - Playback/replay&lt;/span&gt;
  &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;syncPatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3) Versioning &amp;amp; audit&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JSON Patch doubles as an operation log&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auditLog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPatches&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;patches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// standard, easy to review&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Can export to human-friendly formats:&lt;/span&gt;
&lt;span class="cm"&gt;/*
2024-01-01 10:00:00 - User A:
  - Changed /title from "Draft" to "Final"
  - Added /tags/0 = "published"

2024-01-01 10:05:00 - User B:
  - Replaced /content/paragraphs/3
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4) Product analytics&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Analyze editing patterns&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;analyzePatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;travels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPatches&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="cm"&gt;/*
{
  totalOperations: 150,
  avgPatchSize: 45,  // bytes
  mostEditedFields: ["/title", "/content/section[0]"],
  undoRate: 0.15
}
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, JSON Patch’s standardized, compact format is a huge win. Snapshot-based Redux-undo/Zundo are simple, but become unwieldy once persistence enters the picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Travels&lt;/strong&gt;: &lt;a href="https://github.com/mutativejs/travels" rel="noopener noreferrer"&gt;https://github.com/mutativejs/travels&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;use-travel&lt;/strong&gt;: &lt;a href="https://github.com/mutativejs/use-travel" rel="noopener noreferrer"&gt;https://github.com/mutativejs/use-travel&lt;/a&gt; (React hook)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;zustand-travel&lt;/strong&gt;: &lt;a href="https://github.com/mutativejs/zustand-travel" rel="noopener noreferrer"&gt;https://github.com/mutativejs/zustand-travel&lt;/a&gt; (Zustand middleware)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutative&lt;/strong&gt;: &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;https://github.com/unadlib/mutative&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Before writing this post, I read the source code of all three libraries carefully. Redux-undo and Zundo are both excellent and have their places.&lt;/p&gt;

&lt;p&gt;Travels isn’t a silver bullet; it targets a specific problem: &lt;strong&gt;when you need long histories, how do you minimize memory usage, reduce performance overhead, and stay as general and feature-complete as possible?&lt;/strong&gt; Its philosophy is to trade compute for memory, which pays off the most when state is large, changes are small, and histories are long. No need to pick a diff library, write conversion logic, or wrangle edge cases—those are built in.&lt;/p&gt;

&lt;p&gt;If you’re implementing or optimizing undo/redo—especially for collaborative editors, visual design tools, game editors, or any app that needs long operation histories and hits memory/perf ceilings—Travels is worth a try. It may not be the only answer, but it’s certainly one to consider.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article is based on source reviews of redux-undo v1.1.0, zundo v2.3.0, and travels v0.9.0. If anything is inaccurate, corrections are welcome.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Unlocking Multithreading for Smoother Web Applications</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Mon, 16 Dec 2024 17:36:02 +0000</pubDate>
      <link>https://dev.to/unadlib/unlocking-multiprocessing-for-smoother-web-applications-h2b</link>
      <guid>https://dev.to/unadlib/unlocking-multiprocessing-for-smoother-web-applications-h2b</guid>
      <description>&lt;p&gt;Coaction - An efficient and flexible state management library for building high-performance, multithreading web applications.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/coaction" rel="noopener noreferrer"&gt;https://github.com/unadlib/coaction&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Modern web applications are becoming increasingly complex, pushing the boundaries of what's possible in the browser. Single-threaded JavaScript, while powerful, often struggles to keep up with the demands of sophisticated UIs, real-time interactions, and data-intensive computations. This bottleneck leads to performance issues, laggy or unresponsive interfaces, limitations in request connections, and ultimately, a compromised user experience.&lt;/p&gt;

&lt;p&gt;While Web Workers (or SharedWorker) offer a path towards parallelism and improved performance, they introduce a new set of challenges. Managing state across threads, synchronizing data efficiently, and maintaining coherent application logic can quickly become a daunting task. Existing state management solutions often fall short in addressing these specific needs, either by being too tightly coupled to the worker thread or by introducing complex abstractions that hinder developer productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5evufb1gl36bu7haj7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5evufb1gl36bu7haj7g.png" alt="Coaction Concept" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Coaction&lt;/code&gt; was created out of the need for a state management solution that truly embraces the multithreading nature of modern web applications.&lt;/strong&gt; It recognizes that performance and developer experience shouldn't be mutually exclusive. By leveraging the power of Web Workers and Shared Workers, &lt;code&gt;Coaction&lt;/code&gt; allows developers to offload computationally intensive tasks and state management logic from the worker thread, resulting in a more responsive and fluid user interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More than just performance, &lt;code&gt;Coaction&lt;/code&gt; is about enabling a more scalable and maintainable architecture for complex applications.&lt;/strong&gt; The library's intuitive API, inspired by Zustand, ensures a smooth learning curve and a productive development workflow. Its support for Slices, namespaces, and computed properties promotes modularity and code organization, making it easier to manage large and evolving codebases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Coaction&lt;/code&gt;'s integration with &lt;code&gt;data-transport&lt;/code&gt; unlocks a new level of flexibility in state synchronization.&lt;/strong&gt; By supporting generic transport protocols, it opens up possibilities for various communication patterns and architectures, catering to the unique needs of different applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In essence, &lt;code&gt;Coaction&lt;/code&gt; empowers developers to build the next generation of web applications without sacrificing performance, developer experience, or architectural integrity.&lt;/strong&gt; It bridges the gap between the increasing complexity of web applications and the need for efficient, maintainable, and performant state management across threads. It's a tool designed for developers who strive to create exceptional user experiences in a world where parallelism and responsiveness are no longer optional, but essential. It also supports remote synchronization, making it suitable for building any CRDTs application as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concepts and Features
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Coaction&lt;/code&gt; aims to provide a secure and efficient solution for sharing and synchronizing state in multithreading environments (such as Web Workers, Shared Workers, or even across processes and devices) in web applications.&lt;/p&gt;

&lt;p&gt;Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multithreading Sync&lt;/strong&gt;: Supports sharing state between webpage thread and the worker thread. With &lt;code&gt;data-transport&lt;/code&gt; for generic communication, developers can avoid the complexities of message passing and serialization logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutable State with Optional Mutability&lt;/strong&gt;: Powered by the &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;Mutative&lt;/a&gt; library, the core provides an immutable state transition process while allowing performance optimization with mutable instances when needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patch-Based Updates&lt;/strong&gt;: Enables efficient incremental state changes through patch-based synchronization, simplifying its use in CRDTs applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in Computed&lt;/strong&gt;: Supports derived properties based on state dependencies, making it easier to manage and retrieve computed data from core states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slices Pattern&lt;/strong&gt;: Easily combine multiple slices into a store with namespace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible Middleware&lt;/strong&gt;: Allows for middleware to enhance the store's behavior, such as logging, time-travel debugging, or integration with third-party tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with 3rd-Party Libraries&lt;/strong&gt;: Supports popular frameworks like React, Angular, Vue, Svelte, and Solid, as well as state management libraries such as Redux, Zustand, and MobX.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Operating Modes and Fundamentals
&lt;/h2&gt;

&lt;p&gt;This library operates in two primary modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard Mode

&lt;ul&gt;
&lt;li&gt;In a standard webpage environment, the store is managed entirely within the webpage thread. Patch updates are disabled by default to ensure optimal performance in standard mode.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Shared Mode

&lt;ul&gt;
&lt;li&gt;The worker thread serves as the primary source of the shared state, utilizing transport for synchronization.&lt;/li&gt;
&lt;li&gt;Webpage thread act as clients, accessing and manipulating the state asynchronously through a store.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In shared mode, the library automatically determines the execution context based on the transport parameters, handling the synchronization thread seamlessly.&lt;/p&gt;

&lt;p&gt;You can easily use &lt;code&gt;Coaction&lt;/code&gt; in your application to support multiple tabs, multithreading, or multiprocessing.&lt;/p&gt;

&lt;p&gt;For example, for a &lt;a href="https://github.com/unadlib/coaction/blob/main/examples/3d-scene/src/windowsManager.ts" rel="noopener noreferrer"&gt;3D scene&lt;/a&gt; shared across several tabs, you can effortlessly handle their state management using &lt;code&gt;Coaction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/user-attachments/assets/9eb9f4f8-8d47-433a-8eb2-85f044d6d8fa" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/9eb9f4f8-8d47-433a-8eb2-85f044d6d8fa&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared Mode - Sequence Diagram
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijzkcwryfs9j38n52cn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijzkcwryfs9j38n52cn9.png" alt="Image description" width="800" height="634"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Measure(ops/sec) to update 50K arrays and 1K objects, bigger is better(&lt;a href="//./scripts/benchmark.ts"&gt;view source&lt;/a&gt;). [Coaction v0.1.5 vs Zustand v5.0.2]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w46yayakzw6poso5qk5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w46yayakzw6poso5qk5.jpg" alt="Benchmark" width="800" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Coaction x 5,272 ops/sec ±3.08% (63 runs sampled)
Coaction with Mutative x 4,626 ops/sec ±2.26% (83 runs sampled)
Zustand x 5,233 ops/sec ±2.68% (79 runs sampled)
Zustand with Immer x 253 ops/sec ±0.26% (93 runs sampled)

The fastest method is Coaction,Zustand
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;According to the provided performance data, Coaction's performance is comparable to Zustand's performance. However, Coaction with Mutative demonstrates a significant performance advantage compared to Zustand with Immer.&lt;/p&gt;

&lt;p&gt;While standard Coaction achieves approximately 5,272 (ops/sec) and standard Zustand reaches around 5,233 (ops/sec), the most striking difference is observed with Zustand with Immer, which drastically drops to a mere 253 (ops/sec). Furthermore, Coaction with Mutative achieves around 4,626 (ops/sec). This means Coaction with Mutative is approximately 18.3X faster than Zustand with Immer (4626 / 253 ≈ 18.3). The data clearly indicates that Coaction offers superior performance characteristics compared to Zustand, and this advantage is especially pronounced when contrasted with Zustand's Immer implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We will also provide more complete benchmarking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Difference between Coaction and Zustand
&lt;/h2&gt;

&lt;p&gt;Coaction's design philosophy is to provide a necessary and sufficiently simple API, making it easy for developers to use. Therefore, Coaction inherits the advantages of Zustand's API design and includes built-in support for features that Zustand does not offer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;coaction&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Zustand&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Built-in multithreading&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support getter accessor&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in computed properties&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in namespace Slice&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in auto selector for state&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built-in multiple stores selector&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to implement middleware&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support &lt;code&gt;this&lt;/code&gt; in getter/action&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install &lt;code&gt;@coaction/react&lt;/code&gt; for React application via npm, yarn, or pnpm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;coaction @coaction/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use the core library without any framework, you can install &lt;code&gt;coaction&lt;/code&gt; via npm, yarn, or pnpm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;coaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Standard Mode Store
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@coaction/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CounterComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Count: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shared Mode Store
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;counter.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@coaction/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;worker.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@coaction/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@coaction/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CounterComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Count in Worker: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Slices Pattern And Derived Data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@coaction/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// derived data without cache&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;tripleCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// derived data with cache&lt;/span&gt;
  &lt;span class="na"&gt;doubleCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// you can use `this` to access the slice state&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;counter&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In essence, &lt;code&gt;Coaction&lt;/code&gt; empowers developers to build the next generation of web applications without sacrificing performance, developer experience, or architectural integrity.&lt;/strong&gt; It bridges the gap between the increasing complexity of web applications and the need for efficient, maintainable, and performant state management across threads. It's a tool designed for developers who strive to create exceptional user experiences in a world where parallelism and responsiveness are no longer optional, but essential. It also supports remote synchronization, making it suitable for building any CRDTs application as well.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/coaction" rel="noopener noreferrer"&gt;https://github.com/unadlib/coaction&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>react</category>
    </item>
    <item>
      <title>How to Build High-Performance Front-End Applications Based on Multithreading</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Fri, 19 Jan 2024 15:31:57 +0000</pubDate>
      <link>https://dev.to/unadlib/how-to-build-high-performance-front-end-applications-based-on-multi-processing-3dda</link>
      <guid>https://dev.to/unadlib/how-to-build-high-performance-front-end-applications-based-on-multi-processing-3dda</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;As modern front-end applications become larger, leveraging the device's CPU multi-cores to improve performance is becoming an important trend.&lt;/p&gt;

&lt;p&gt;Front-end applications often run in a single browser window, where JavaScript executes on a single thread. This means that common web applications cannot fully utilize a CPU's multiple cores. As applications become larger and more complex, this can lead to performance problems and a poor user experience.&lt;/p&gt;

&lt;p&gt;However, there is good news: modern browsers widely support various types of workers, including Shared Workers, as IE and Safari v16 are gradually being phased out (regarding Shared Worker support). Shared Workers are a mature technology allowing multiple threads of JavaScript code to share data and communicate with each other. This makes them ideal for building multithreaded front-end applications.&lt;/p&gt;

&lt;p&gt;Multithreaded front-end applications offer several benefits. They can better handle computation-intensive and slow-running JavaScript, which can improve performance and responsiveness. They can also increase the number of concurrent requests that can be processed, which can further improve the application's responsiveness.&lt;/p&gt;

&lt;p&gt;Therefore, we aim to explore a web application framework that leverages multithreading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web application with Multithreading
&lt;/h2&gt;

&lt;p&gt;In a multithreaded web architecture, we can leverage the Shared Web Apps concept of reactant-share to expand upon general multithreading programming.&lt;/p&gt;

&lt;p&gt;Shared Web Apps allows web applications to run in multiple browser windows or workers. It uses a unique front-end server (such as a Shared Worker) to facilitate sharing across web apps, including code, local storage, state, and more. Regardless of the number of browser windows opened, there is always only one server application instance shared among multiple client applications in Shared Web Apps. This enables web tabs to focus solely on rendering, thereby better utilizing the device's multi-cores and ensuring the smooth operation of the web application.&lt;/p&gt;

&lt;p&gt;Shared Web Apps offers the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduces the mental burden of multithreading programming by implementing Isomorphism through a universal modular model. Isomorphism refers to the ability to execute the same code on the server thread, client thread, or other threads, simplifying multithreading programming.&lt;/li&gt;
&lt;li&gt;Ensures the smooth operation of the front-end server thread by transferring compute-intensive tasks to another thread. This frees up the front-end server thread to focus on business logic and the client thread on rendering, improving performance and responsiveness.&lt;/li&gt;
&lt;li&gt;Improves request concurrency through a more efficient multithreading model.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Coworker based on reactant-share
&lt;/h2&gt;

&lt;p&gt;Building upon reactant-share, we have implemented the Coworker model, which facilitates state sharing across multiple threads, synchronizes state, and minimizes state changes using patches to ensure optimal performance in multithreaded execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1jb9ro8hshk0aqyarzr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1jb9ro8hshk0aqyarzr.png" alt="Workflow" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Coworker model comprises three types of threads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;client thread: The rendering thread, responsible for accepting shared state and solely rendering the web UI. Its lightweight nature ensures smooth rendering.&lt;/li&gt;
&lt;li&gt;server thread: The main thread, responsible for executing the majority of the application's business logic. Smooth operation is also crucial for this thread.&lt;/li&gt;
&lt;li&gt;Coworker thread: This thread handles compute-intensive business logic or request-intensive logic. This frees the server thread to focus on business logic. This allows the server thread to reduce blocking caused by JavaScript and makes it less susceptible to the impact of request-intensive logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In 'Base' mode, Reactant Shared Apps has only two threads: the Tab thread and the Coworker thread. By default, the Coworker thread utilizes a Web Worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation of Coworker
&lt;/h2&gt;

&lt;p&gt;For details on the underlying principles of Reactant-Share, please refer to the following link: &lt;a href="https://reactant.js.org/blog/2021/10/03/how-to-make-web-application-support-multiple-browser-windows" rel="noopener noreferrer"&gt;https://reactant.js.org/blog/2021/10/03/how-to-make-web-application-support-multiple-browser-windows&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coworker comprises two modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CoworkerAdapter:&lt;/strong&gt; Provides a communication channel between the server thread and the coworker thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CoworkerExecutor:&lt;/strong&gt; Manages the synchronization of shared state between threads and custom Coworker type modules (used for proxy execution of coworkers). Coworker state is synchronously sent to the main thread in one direction. Each time a Coworker synchronizes its state, it includes a sequence tag. If the sequence is out of order, a complete Coworker state synchronization is automatically triggered to ensure the consistency of the shared state between the Coworker and the main thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Concepts and Advantages of Coworker
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isomorphism:&lt;/strong&gt; The ability for all threads to execute the same code enhances the maintainability of multithreading programming in JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread Interaction based on the Actor Model:&lt;/strong&gt; By leveraging the Actor model, this approach reduces the cognitive load associated with multithreading programming in JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generic Transport Model:&lt;/strong&gt; Coworker supports any transport mechanism based on data-transport (&lt;a href="https://github.com/unadlib/data-transport" rel="noopener noreferrer"&gt;https://github.com/unadlib/data-transport&lt;/a&gt;), enabling it to run in any container that supports transport, including SharedWorker. The following is a list of supported transports:

&lt;ul&gt;
&lt;li&gt;iframe&lt;/li&gt;
&lt;li&gt;Broadcast&lt;/li&gt;
&lt;li&gt;Web Worker&lt;/li&gt;
&lt;li&gt;Service Worker&lt;/li&gt;
&lt;li&gt;Shared Worker&lt;/li&gt;
&lt;li&gt;Browser Extension&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;WebRTC&lt;/li&gt;
&lt;li&gt;Electron&lt;/li&gt;
&lt;li&gt;Any other port based on data-transport&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;High Performance Based on Mutative:&lt;/strong&gt; &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;Mutative&lt;/a&gt; offers high performance, being faster than a naive handcrafted reducer and 10 times faster than Immer. Mutative also maintains good performance when updating immutable data. Patches generated from shared state updates are used for state synchronization.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;High Performance:&lt;/strong&gt; Because Coworker handles a large number of requests and compute-intensive tasks, the main thread and rendering thread can maintain extremely high performance and a superior user experience.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Support for Large Applications:&lt;/strong&gt; Reactant offers a complete module model design, including dependency injection and a class-first approach, along with various modular design patterns and dynamic module injection capabilities.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Separation of Service and Rendering View Modules:&lt;/strong&gt; Service modules, primarily focused on business logic, can execute independently from view modules. This not only achieves separation of concerns but also allows each thread to have its own containerization.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Graceful Degradation:&lt;/strong&gt; If the JavaScript host environment does not support SharedWorker, Coworker gracefully degrades to a regular SPA. This does not affect the behavior of existing applications.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  API
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;delegate()&lt;/code&gt; - This function forwards execution to the specified module and function proxies within the Coworker, drawing inspiration from the Actor model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;We will create a Counter application using Coworker based on the 'Base' pattern.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, create &lt;code&gt;app.tsx&lt;/code&gt;, which contains the &lt;code&gt;ProxyCounter&lt;/code&gt; module that will be executed in the Coworker.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Its calling method, &lt;code&gt;delegate(this.proxyCounter, 'increase', [])&lt;/code&gt;, is identical to that used in general Shared Web Apps. Whether it is executed with a proxy in the Coworker depends on the configuration of &lt;code&gt;createApp&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ViewModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useConnector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactant-share&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ProxyCounter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProxyCounter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;state&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;action&lt;/span&gt;
  &lt;span class="nf"&gt;increase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AppView&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppView&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ViewModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;proxyCounter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProxyCounter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;state&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;action&lt;/span&gt;
  &lt;span class="nf"&gt;increase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;proxyCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConnector&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proxyCounter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          +
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;proxy in coworker&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;proxyCount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;delegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proxyCounter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          +
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the main file, &lt;code&gt;index.ts&lt;/code&gt;. Here, we configure &lt;code&gt;ProxyCounter&lt;/code&gt; as a module of Coworker and set &lt;code&gt;isCoworker&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reactant-web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Coworker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ICoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reactant-share&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ProxyCounter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;Coworker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;useModules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ProxyCounter&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./coworker.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="na"&gt;isCoworker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ICoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SharedWorkerApp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the Coworker file, &lt;code&gt;coworker.ts&lt;/code&gt;. Here, we also configure &lt;code&gt;ProxyCounter&lt;/code&gt; as a module of Coworker, but this time set &lt;code&gt;isCoworker&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Coworker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ICoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reactant-share&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ProxyCounter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;Coworker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;useModules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ProxyCounter&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;isCoworker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ICoworkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SharedWorkerApp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus far, we have created a basic application using a Coworker. Users trigger the &lt;code&gt;delegate(this.proxyCounter, 'increase', [])&lt;/code&gt; function in the main thread via the UI. This action is forwarded to the coworker to execute the &lt;code&gt;increase&lt;/code&gt; function of &lt;code&gt;proxyCounter&lt;/code&gt;, and the shared state automatically synchronizes back to the main thread. The rendering update is handled by the &lt;code&gt;useConnector()&lt;/code&gt; Hook.&lt;/p&gt;

&lt;h2&gt;
  
  
  Q&amp;amp;A
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. What are the challenges of multithreaded programming with Coworker based on reactant-share?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;State sharing and synchronization among threads in multithreaded programming are inherently complex. Fortunately, Reactant-share ensures robustness through a consistent shared state design. The dependencies between isomorphic modules within Coworker should also be considered. During development, adopting concepts like Domain-Driven Design is recommended to prevent improper module design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What are the potential use cases for Coworker?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request Queue:&lt;/strong&gt; Coworker is particularly well-suited for modules handling a high volume of requests. Running these within Coworker prevents them from occupying the main thread's request queue, allowing other main thread requests to execute unimpeded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large Task Execution Blocking:&lt;/strong&gt; To avoid blocking the application's main thread during the execution of computationally intensive tasks, such tasks are ideal for asynchronous execution within Coworker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolatable Modules:&lt;/strong&gt; Coworker can also serve as a sandbox to isolate the execution of specific modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Are there specific examples demonstrating how Coworker can improve application performance?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In production, we have implemented Coworker in specific scenarios for modules involving text matching with large data volumes. This resulted in a substantial performance improvement, in some cases up to 10x, significantly enhancing the user experience. Previously, such computationally intensive text matching would require users to wait over 1 second, during which the webpage would be completely blocked. However, after implementing Coworker, the webpage blockage was reduced to less than 100ms (the actual degree of improvement varies depending on data size).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Is Coworker usable across different browsers, or is its support limited to within browser tabs? Can Coworker be used across tabs in different domains?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Coworker is a multithreaded model built upon reactant-share, which in turn is based on data-transport. Therefore, utilizing the WebRTC transport from data-transport within Coworker's CoworkerAdapter is sufficient to achieve cross-browser support. Additionally, to enable usage across tabs in different domains, we can implement Coworker under cross-domain tabs using an iframe and shared worker approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Front-end development is at a turning point, driven by advancements in front-end technology and browser capabilities. Multi-core CPUs and multithreading tools like Shared Workers and other Workers are now being utilized effectively in front-end development. The emergence of Shared Web Apps with Coworker introduces a novel multithreading model for front-end applications, significantly improving application performance, user experience, and code maintainability. For developers, this signifies more technical choices and challenges, but also greater opportunities and potential.&lt;/p&gt;

&lt;p&gt;Multithreaded programming for front-end applications is likely to become a key solution for enhancing front-end performance. This will result in a smoother, more efficient, and more responsive user experience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reactant-share Document：&lt;a href="https://reactant.js.org/docs/shared-app" rel="noopener noreferrer"&gt;https://reactant.js.org/docs/shared-app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;reactant-share Repo: &lt;a href="https://github.com/unadlib/reactant/tree/master/packages/reactant-share" rel="noopener noreferrer"&gt;https://github.com/unadlib/reactant/tree/master/packages/reactant-share&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Announcing Mutative 1.0 - A New Era in Efficient Immutable Updates</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Fri, 15 Dec 2023 19:57:50 +0000</pubDate>
      <link>https://dev.to/unadlib/announcing-mutative-10-a-new-era-in-efficient-immutable-updates-nml</link>
      <guid>https://dev.to/unadlib/announcing-mutative-10-a-new-era-in-efficient-immutable-updates-nml</guid>
      <description>&lt;p&gt;In the world of JavaScript development, managing immutable state efficiently is a cornerstone for high-performance applications. Today, we are excited to introduce Mutative 1.0, a JavaScript library that redefines the way we handle immutable updates. With performance that is 2-6x faster than naive handcrafted reducers and over 10x faster than Immer, Mutative 1.0 is set to transform our approach to immutable state management and make it more efficient.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;https://github.com/unadlib/mutative&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features and Benefits
&lt;/h2&gt;

&lt;p&gt;Mutative brings a suite of features designed to optimize performance and flexibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High Performance&lt;/strong&gt;: At its core, Mutative is engineered for speed. It excels in scenarios involving large data structures, making it an ideal choice for complex applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutable Updates with Ease&lt;/strong&gt;: Supporting a range of data structures including objects, arrays, Sets, Maps, and more customizable types, Mutative ensures that immutable updates are not just efficient but also straightforward to implement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Configuration&lt;/strong&gt;: The library offers optional freezing of immutable data, strict mode and supports the JSON Patch standard, providing developers with the flexibility to tailor it to their specific needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Reducer by object
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Naive handcrafted reducer
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// baseState type: Record&amp;lt;string, { value: number }&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;key0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Mutative
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ruubbh0evnajvwqpxb7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ruubbh0evnajvwqpxb7.jpg" alt="Mutative vs Reducer benchmark by object"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Measure(seconds) to update the 1K-100K items object, lower is better(&lt;a href="https://github.com/unadlib/mutative/blob/main/test/performance/benchmark-object.ts" rel="noopener noreferrer"&gt;view source&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Mutative is up to &lt;code&gt;2x&lt;/code&gt; faster than naive handcrafted reducer for updating immutable objects.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducer by array
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Naive handcrafted reducer
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// baseState type: { value: number }[]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Mutative
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4pk56xb3agl2n18rag4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4pk56xb3agl2n18rag4.jpg" alt="Mutative vs Reducer benchmark by array"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Measure(seconds) to update the 1K-100K items array, lower is better(&lt;a href="https://github.com/unadlib/mutative/blob/main/test/performance/benchmark-array.ts" rel="noopener noreferrer"&gt;view source&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Mutative is up to &lt;code&gt;6x&lt;/code&gt; faster than naive handcrafted reducer for updating immutable arrays.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutative vs Immer Performance
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Mutative passed all of Immer's test cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Measure(ops/sec) to update 50K arrays and 1K objects, bigger is better(&lt;a href="https://github.com/unadlib/mutative/blob/main/test/performance/benchmark.ts" rel="noopener noreferrer"&gt;view source&lt;/a&gt;). [Mutative v1.0.0 vs Immer v10.0.3]&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5zydnaqfzptfea8zvsb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5zydnaqfzptfea8zvsb.jpg" alt="Benchmark"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Naive handcrafted reducer - No Freeze x 4,361 ops/sec ±0.99% (90 runs sampled)
Mutative - No Freeze x 6,178 ops/sec ±1.41% (95 runs sampled)
Immer - No Freeze x 5.79 ops/sec ±0.33% (19 runs sampled)

Mutative - Freeze x 849 ops/sec ±0.19% (96 runs sampled)
Immer - Freeze x 383 ops/sec ±0.77% (94 runs sampled)

Mutative - Patches and No Freeze x 764 ops/sec ±0.20% (96 runs sampled)
Immer - Patches and No Freeze x 5.72 ops/sec ±0.34% (19 runs sampled)

Mutative - Patches and Freeze x 418 ops/sec ±1.23% (94 runs sampled)
Immer - Patches and Freeze x 279 ops/sec ±0.54% (90 runs sampled)

The fastest method is Mutative - No Freeze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;yarn benchmark&lt;/code&gt; to measure performance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OS: macOS 12.6, CPU: Apple M1 Max, Node.js: 16.14.2&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Immer relies on auto-freeze to be enabled, if auto-freeze is disabled, Immer will have a huge performance drop and Mutative will have a huge performance lead, especially with large data structures it will have a performance lead of more than 50x.&lt;/p&gt;

&lt;p&gt;So if you are using Immer, you will have to enable auto-freeze for performance. Mutative is disabled auto-freeze by default. With the default configuration of both, we can see the 16x performance gap between Mutative (&lt;code&gt;6,178 ops/sec&lt;/code&gt;) and Immer (&lt;code&gt;383 ops/sec&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Overall, Mutative has a huge performance lead over Immer in &lt;a href="https://github.com/unadlib/mutative/tree/main/test/performance" rel="noopener noreferrer"&gt;more performance testing scenarios&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison with Immer
&lt;/h2&gt;

&lt;p&gt;While Immer has been a popular choice for handling immutable data, Mutative 1.0 takes it a step further, and Mutative is over 10x faster than Immer. It not only matches all of Immer's test cases but also introduces additional features such as custom shallow copy, strict mode, and a default setting that does not freeze data. These enhancements make Mutative more efficient, especially in handling large-scale applications. Here’s a quick comparison of the two libraries:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Mutative&lt;/th&gt;
&lt;th&gt;Immer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Custom shallow copy&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No data freeze by default&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-invasive marking&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complete freeze data&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-global config&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;async draft function&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fully compatible with JSON Patch spec&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mutative has fewer bugs such as accidental draft escapes than Immer, &lt;a href="https://github.com/unadlib/mutative/blob/main/test/immer-non-support.test.ts" rel="noopener noreferrer"&gt;view details&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Integrating Mutative into your JavaScript projects is straightforward. You can install it using Yarn or NPM, and its API is intuitive and easy to grasp. Here’s a quick start example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Mutative using Yarn or NPM:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add mutative
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Import the &lt;code&gt;create&lt;/code&gt; function from Mutative and use it to create a new immutable state:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mutative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;learning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple code snippet demonstrates the ease with which you can manage immutable state using Mutative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we unveil Mutative 1.0, we're not just releasing a new library; we're inviting JavaScript developers to step into a future where state management is no longer a bottleneck but a catalyst for performance and innovation. Mutative 1.0 stands as a testament to what modern JavaScript can achieve - a blend of speed, efficiency, and ease of use that elevates coding from a task to an art.&lt;/p&gt;

&lt;p&gt;This library is more than a tool; it's a paradigm shift in how we approach immutable updates. With its unparalleled performance, Mutative 1.0 is poised to redefine best practices in JavaScript development, making cumbersome state management a thing of the past. It's an invitation to developers to push the boundaries of what's possible, to build applications that are not just functional but phenomenally fast and responsive.&lt;/p&gt;

&lt;p&gt;As the JavaScript landscape continues to evolve, Mutative 1.0 will undoubtedly play a pivotal role in shaping the future of state management. We encourage the community to explore its potential, to integrate it into their projects, and to contribute to its growth. Together, we can drive the evolution of JavaScript development, making our applications not just faster, but smarter, and more intuitive than ever before.&lt;/p&gt;

&lt;p&gt;Join us in embracing the future with Mutative 1.0 - where efficiency meets innovation, and where every line of code brings us closer to the zenith of JavaScript potential.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>react</category>
    </item>
    <item>
      <title>Mutative - 10x faster than Immer</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Sat, 31 Dec 2022 15:22:48 +0000</pubDate>
      <link>https://dev.to/unadlib/mutative-10x-faster-than-immer-2060</link>
      <guid>https://dev.to/unadlib/mutative-10x-faster-than-immer-2060</guid>
      <description>&lt;p&gt;&lt;strong&gt;Mutative&lt;/strong&gt; - A JavaScript library for efficient immutable updates, 10x faster than Immer by default, even faster than naive handcrafted reducer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2g8dowf7w3tryhcmxli.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm2g8dowf7w3tryhcmxli.jpg" alt="Benchmark"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Writing immutable updates by hand is usually difficult, prone to errors, and cumbersome. Immer helps us write simpler immutable updates with "mutative" logic.&lt;/p&gt;

&lt;p&gt;But its &lt;a href="https://github.com/immerjs/immer/issues?q=is%3Aissue+is%3Aopen+performance" rel="noopener noreferrer"&gt;performance issue&lt;/a&gt; causes a runtime performance overhead. Immer must have auto-freeze enabled by default(Performance will be worse if auto-freeze is disabled), such immutable state with Immer are not common. In scenarios such as cross-processing, remote data transfer, etc., we have to constantly freeze these immutable data.&lt;/p&gt;

&lt;p&gt;There are more parts that could be improved, such as better type inference, non-intrusive markup, support for more types of immutability, Safer immutability, and so on.&lt;/p&gt;

&lt;p&gt;This is why Mutative was created.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;https://github.com/unadlib/mutative&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutative vs Immer Performance
&lt;/h2&gt;

&lt;p&gt;Measure(ops/sec) to update 50K arrays and 1K objects, bigger is better(&lt;a href="https://github.com/unadlib/mutative/blob/main/test/performance/benchmark.ts" rel="noopener noreferrer"&gt;view source&lt;/a&gt;).[Mutative v0.3.2 vs Immer v9.0.18]&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Naive handcrafted reducer - No Freeze x 3,713 ops/sec ±0.86% (89 runs sampled)
Mutative - No Freeze x 5,323 ops/sec ±1.69% (93 runs sampled)
Immer - No Freeze x 8 ops/sec ±0.88% (23 runs sampled)

Mutative - Freeze x 875 ops/sec ±1.20% (95 runs sampled)
Immer - Freeze x 320 ops/sec ±0.45% (92 runs sampled)

Mutative - Patches and No Freeze x 752 ops/sec ±0.16% (96 runs sampled)
Immer - Patches and No Freeze x 7 ops/sec ±1.32% (23 runs sampled)

Mutative - Patches and Freeze x 425 ops/sec ±0.33% (95 runs sampled)
Immer - Patches and Freeze x 239 ops/sec ±0.99% (89 runs sampled)

The fastest method is Mutative - No Freeze


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;yarn benchmark&lt;/code&gt; to reproduce them locally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;OS: macOS 12.6, CPU: Apple M1 Max, Node.js: 16.14.2&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Immer relies on auto-freeze to be enabled, if auto-freeze is disabled, Immer will have a huge performance drop and Mutative will have a huge performance lead, especially with large data structures it will have a performance lead of more than 50x.&lt;/p&gt;

&lt;p&gt;So if you are using Immer, you will have to enable auto-freeze for performance. Mutative is disabled auto-freeze by default. With the default configuration of both, we can see the performance gap between Mutative (&lt;code&gt;5,323 ops/sec&lt;/code&gt;) and Immer (&lt;code&gt;320 ops/sec&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Overall, Mutative has a huge performance lead over Immer in &lt;a href="https://github.com/unadlib/mutative/tree/main/test/performance" rel="noopener noreferrer"&gt;more performance testing scenarios&lt;/a&gt;. Run &lt;code&gt;yarn performance&lt;/code&gt; to get all the performance results locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features and Benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mutation makes immutable updates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support apply patches&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optional freezing state&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom shallow copy&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Immutable and mutable data markable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Strict mode for safer mutable data access&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support for JSON patches&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support for reducer&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Difference between Mutative and Immer
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;-&lt;/th&gt;
&lt;th&gt;Mutative&lt;/th&gt;
&lt;th&gt;Immer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Custom shallow copy&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict mode&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No data freeze by default&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-invasive marking&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complete freeze data&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-global config&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support IE browser&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mutative has fewer bugs such as accidental draft escapes than Immer, &lt;a href="https://github.com/unadlib/mutative/blob/main/test/immer-non-support.test.ts" rel="noopener noreferrer"&gt;view details&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mutative size is &lt;code&gt;4.16KB&lt;/code&gt; with minified and gzipped. Immer size with same features is &lt;code&gt;4.67 KB&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yarn &lt;span class="nb"&gt;install &lt;/span&gt;mutative &lt;span class="c"&gt;# npm install mutative&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mutative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foobar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;learning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;create(baseState, (draft) =&amp;gt; void, options?: Options): newState&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The first argument of &lt;code&gt;create()&lt;/code&gt; is the base state. Mutative drafts it and passes it to the arguments of the draft function, and performs the draft mutation until the draft function finishes, then Mutative will finalize it and produce the new state.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;create()&lt;/code&gt; for more advanced functions by setting &lt;code&gt;options&lt;/code&gt;, which also supports currying.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strict - &lt;code&gt;boolean&lt;/code&gt;, the default is false.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Forbid accessing non-draftable values in strict mode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;enablePatches - &lt;code&gt;boolean&lt;/code&gt;, the default is false.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Enable patch, and return the patches and inversePatches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;enableAutoFreeze - &lt;code&gt;boolean&lt;/code&gt;, the default is false.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Enable autoFreeze, and return frozen state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;mark - &lt;code&gt;() =&amp;gt; ('mutable'|'immutable'|function)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Set a mark to determine if the object is mutable or if an instance is an immutable, and it can also return a shallow copy function(AutoFreeze and Patches should both be disabled).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  FAQs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why doesn't Mutative support IE?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mutative is a library that relies heavily on the use of the Proxy object, which is a feature of modern web browsers that allows the interception of various operations on objects. As such, Mutative may not be fully compatible with older browsers that do not support the Proxy object, such as Internet Explorer. However, these older browsers make up a very small percentage of the overall browser market, so the impact on compatibility is likely minimal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why does Mutative have such good performance?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mutative optimization focus is on shallow copy optimization, more complete lazy drafts, finalization process optimization, and more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm already using Immer, can I migrate smoothly to Mutative?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes. Unless you have to be compatible with Internet Explorer, Mutative supports almost all of Immer features, and you can easily migrate from Immer to Mutative.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Migration is also not possible for React Native that does not support Proxy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Mutative is inspired by Immer.&lt;/p&gt;

&lt;p&gt;Mutative aims at efficient immutable updates, focusing on performance improvements and better APIs to bring better development experience. If you think Mutative is good, feel free to give it a star!&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/mutative" rel="noopener noreferrer"&gt;https://github.com/unadlib/mutative&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to make Web application support multiple browser windows</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Sun, 03 Oct 2021 04:57:19 +0000</pubDate>
      <link>https://dev.to/unadlib/how-to-make-web-application-support-multiple-browser-windows-28pa</link>
      <guid>https://dev.to/unadlib/how-to-make-web-application-support-multiple-browser-windows-28pa</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;When we develop a Single-Page Application, we usually only define its behavior in a single browser window, and even if the same application is opened on multiple browser windows, in most cases it is only synchronized with the local storage, and the state of each application in each window is not synchronized in real time (unless the server synchronizes), they run in isolation and are relatively independent.&lt;/p&gt;

&lt;p&gt;However, this means that more browser windows will generate more and more independent application instances, which may have different UI states and often inevitably have the same network requests or WebSocket connections, which may also mean a bad user experience (as users may have become accustomed to) and excessive usage of server resources.&lt;/p&gt;

&lt;p&gt;So what does it mean to have applications that supports multiple browser windows?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application instance sharing: code sharing, local storage sharing, state sharing, and more&lt;/li&gt;
&lt;li&gt;Lower server resource usage&lt;/li&gt;
&lt;li&gt;Better user consistency experience&lt;/li&gt;
&lt;li&gt;Smoother web applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it's not easy to keep large Web applications running smoothly.&lt;/p&gt;

&lt;p&gt;Web applications are still primarily built in JavaScript, which is a single-threaded programming language, and slow JavaScript code can prevent the browser’s rendering. The good news is that mainstream browsers are gradually supporting more different types of workers, especially Service Workers, which are used to implement PWAs (Progressive Web Apps) that greatly enhance the user experience. And the latest modern browsers also provide Web Worker, Shared Worker. With IE becoming deprecated this year, there is &lt;a href="https://caniuse.com/?search=worker" rel="noopener noreferrer"&gt;good support for these workers&lt;/a&gt;. Currently, only &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=149850" rel="noopener noreferrer"&gt;Safari lacks support for Shared Worker&lt;/a&gt; among modern browsers.&lt;/p&gt;

&lt;p&gt;So what does it mean for Web applications to be "multi-threaded" with Worker?&lt;/p&gt;

&lt;p&gt;"&lt;a href="https://www.smashingmagazine.com/2021/06/web-workers-2021/" rel="noopener noreferrer"&gt;The State Of Web Workers In 2021&lt;/a&gt;" post covers a number of unpredictable performance issues. With these browser workers we will likely be better able to deal with computationally complex and slow-running JS code to keep web applications smooth.&lt;/p&gt;

&lt;p&gt;It's time to rethink why we can't make web applications support multiple browser windows and improve the performance of web applications. New architectural requirements bring new framework requirements, and such applications we call it &lt;strong&gt;&lt;code&gt;Shared Web Apps&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared Web Apps
&lt;/h2&gt;

&lt;p&gt;Even though we want users to open as few application windows as possible, the fact remains that many users will open the same application in multiple browser windows.&lt;/p&gt;

&lt;p&gt;Shared Web Apps supports running web applications in multiple browser windows.&lt;/p&gt;

&lt;p&gt;It has a unique Server thread to share the Shared Web Apps, whether it's code sharing, local storage sharing, state sharing, and so on. No matter how many browser windows are opened, Shared Web Apps always has only one server app instance for multiple client apps sharing. We all know that DOM operations are expensive. In Shared Web Apps, the client app instance is only responsible for rendering, and except for state sync the client app will become very lightweight and almost all business logic will run in the server app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The client app only renders UI, making better use of the device's multiple cores to ensure that the client app is smooth&lt;/li&gt;
&lt;li&gt;Solve the problems caused by multiple browser windows&lt;/li&gt;
&lt;li&gt;Better separation of concerns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  reactant-share - A framework for building Shared Web Apps
&lt;/h2&gt;

&lt;p&gt;reactant-share Repo: &lt;a href="https://github.com/unadlib/reactant" rel="noopener noreferrer"&gt;reactant&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To build such Shared Web Apps, &lt;code&gt;reactant-share&lt;/code&gt; was created. reactant-share is based on the &lt;code&gt;reactant&lt;/code&gt; framework and &lt;code&gt;react&lt;/code&gt; library, which supports the following features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependency injection&lt;/li&gt;
&lt;li&gt;Immutable state management&lt;/li&gt;
&lt;li&gt;View module&lt;/li&gt;
&lt;li&gt;Redux plug-in module&lt;/li&gt;
&lt;li&gt;Test bed for unit testing and integration testing&lt;/li&gt;
&lt;li&gt;Routing module&lt;/li&gt;
&lt;li&gt;Persistence module&lt;/li&gt;
&lt;li&gt;Module dynamics&lt;/li&gt;
&lt;li&gt;Shared web app support multiple browser windows

&lt;ul&gt;
&lt;li&gt;Shared tab&lt;/li&gt;
&lt;li&gt;SharedWorker&lt;/li&gt;
&lt;li&gt;ServiceWorker&lt;/li&gt;
&lt;li&gt;Browser extension&lt;/li&gt;
&lt;li&gt;Detached window&lt;/li&gt;
&lt;li&gt;iframe&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;reactant-share&lt;/code&gt; is very easy to use, you can use it to quickly build a Shared Web Apps. it greatly reduces the complexity of supporting multi-browser window application architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;When reactant-share starts, it creates a server app instance and multiple client app instances (one per browser window) in the browser, but the only instance that is really running in full is the server app instance, which is responsible for almost all of the application's logic, and multiple client app instances simply synchronize state and render. The state model of reactant-share uses immutable state, and reactant is based on Redux, so we trigger state sync from server app to client app via Redux's &lt;code&gt;dispatch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1veuvfbfx3gf9q0d50pg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1veuvfbfx3gf9q0d50pg.jpg" alt="workflow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user triggers the client app proxy method through DOM events&lt;/li&gt;
&lt;li&gt;This proxy method is executed on the server app.&lt;/li&gt;
&lt;li&gt;The server app state is synchronized back to the client app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;The overall workflow of the reactant-share is shown in the figure below. Here is an example of a shared-worker type counter app.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we define a counter app module and view module in &lt;code&gt;app.view.tsx&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ViewModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useConnector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactant-share&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;counter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;state&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;action&lt;/span&gt;
  &lt;span class="nf"&gt;increase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppView&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ViewModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConnector&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, we use &lt;code&gt;createSharedApp()&lt;/code&gt; to create the client app, whose options must contain &lt;code&gt;workerURL&lt;/code&gt;, the worker url that will create a shared worker (if it hasn't been created yet).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactant-web&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSharedApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactant-share&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorkerApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;workerURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;worker.bundle.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// render only&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finally, we just create the worker file &lt;code&gt;worker.tsx&lt;/code&gt; and build it as &lt;code&gt;worker.bundle.js&lt;/code&gt; for the &lt;code&gt;workerURL&lt;/code&gt; option.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSharedApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactant-share&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.view&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorkerApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// render less&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The specific workflow of &lt;code&gt;increase&lt;/code&gt; looks like this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user clicks the button in client app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spawn(this.counter, "increase", [])&lt;/code&gt; will be executed, which passes the parameters about the proxy execution to the server app.&lt;/li&gt;
&lt;li&gt;The server app will execute &lt;code&gt;this.counter.increase()&lt;/code&gt;, and sync the updated state back to each client apps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;spawn()&lt;/code&gt; in reactant-share is inspired by the &lt;a href="https://en.wikipedia.org/wiki/Actor_model" rel="noopener noreferrer"&gt;actor model&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  reactant-share Framework
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multiple modes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Shared tab - It is suitable for running in browsers that do not support SharedWorker/ServiceWorker. The server app is an instance with rendering that also runs in a browser window. In multiple browser windows, there is also only one server app, and after it is closed or refreshed, one instance of the other client apps will be converted to a server app.&lt;/li&gt;
&lt;li&gt;SharedWorker - If there is no &lt;a href="https://caniuse.com/?search=sharedworker" rel="noopener noreferrer"&gt;browser compatibility&lt;/a&gt; requirement, reactant-share is highly recommended to use this mode, and reactant-share also does a graceful degradation, so if the browser does not support SharedWorker then the app will run in Shared-Tab mode.&lt;/li&gt;
&lt;li&gt;ServiceWorker - If Shared Web Apps are intended to be PWA (Progressive Web Apps), then using this mode would be ideal, and it also supports the automatic graceful degradation to Shared-Tab mode.&lt;/li&gt;
&lt;li&gt;Browser extension - The browser extension allows a background thread, the server app of reactant-share can run in this background thread, and the UI can run in the client app.&lt;/li&gt;
&lt;li&gt;Detached window - reactant-share allows sub-applications to run as Detached windows or to be quickly merged into a more complete application.&lt;/li&gt;
&lt;li&gt;iframe - reactant-share allows each child application to run on an iframe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example repo: &lt;a href="https://github.com/unadlib/reactant/tree/master/examples/reactant-share-sharedworker" rel="noopener noreferrer"&gt;SharedWorker/Detached window/iframe&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  User Experience
&lt;/h3&gt;

&lt;p&gt;Since reactant-share's multiple instances are logic-sharing and state-sharing, when a user opens the same reactant-share application in multiple browser windows, the only instance that is actually running in full is the server app.&lt;/p&gt;

&lt;p&gt;The rendering-only client app will be so smooth that it will almost never freeze due to JS code, and the consistent application state will allow users to switch between multiple browser windows without any worries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Development Experience
&lt;/h3&gt;

&lt;p&gt;reactant-share provides CLI and full support for Typescript, as well as support for Shared-Tab, SharedWorker, ServiceWorker and Browser extension, and other different types of runtime modes out of the box. Built-in testbed for module testing, Routing and Persistence modules, and module dynamics support for lazy loading of reactant-share applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Discovery / Communications
&lt;/h3&gt;

&lt;p&gt;Since reactant-share uses &lt;a href="http://github.com/unadlib/data-transport" rel="noopener noreferrer"&gt;data-transport&lt;/a&gt;, reactant-share supports almost all the transports supported by data-transport.The client app and the server app, whichever is loaded first, the client app will wait for the server app to finish starting and get all the initial application state from it.&lt;/p&gt;

&lt;p&gt;Using the actor model in the client app to design spawn(), we can do &lt;code&gt;spawn(counterModule, 'increase', [])&lt;/code&gt; to let the server app proxy the execution of the module method and respond and sync both the state and the result back to the client app.&lt;/p&gt;

&lt;p&gt;But if we need direct communication between the client app and the server app, then we need to use the &lt;code&gt;PortDetector&lt;/code&gt; module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;portDetector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PortDetector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;portDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// result should be `hello, 42`&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;portDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClient&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tracking/Debugging
&lt;/h3&gt;

&lt;p&gt;Since reactant-share is based on Redux, it fully supports Redux DevTools, and the immutable time travel that Redux brings will make debugging easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fault Tolerance / Data Consistency
&lt;/h3&gt;

&lt;p&gt;Since state synchronization after the client app uses &lt;code&gt;spawn()&lt;/code&gt; to get the server app proxy to execute each time may cause it to be out of order in edge cases for various reasons, reactant-share integrates &lt;code&gt;reactant-last-action&lt;/code&gt;, which provides sequence markers to keep If the client app receives a synchronized action that checks for an exception in the sequence, the client app will launch a full state synchronization to correct the action sequence.&lt;/p&gt;

&lt;p&gt;In addition, when the browser does not support the Worker API, reactant-share will perform a graceful degradation (e.g. SharedWorker mode -&amp;gt; Shared-Tab mode -&amp;gt; SPA mode).&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolation
&lt;/h3&gt;

&lt;p&gt;Regardless of modes such as Shared-Tab, SharedWorker or ServiceWorker, each application instance runs in isolation and their basic interactions can only be triggered by &lt;code&gt;spawn()&lt;/code&gt; to synchronize state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;reactant-share provides CLI, you just need to run &lt;code&gt;npx reactant-cli init shared-worker-example -t shared-worker&lt;/code&gt; to get a project of reactant-share with SharedWorker mode. If you want to change its mode, you just need to change the configuration of &lt;code&gt;createSharedApp()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;createSharedApp({
&lt;/span&gt;  modules: [],
  main: AppView,
  render,
  share: {
    name: 'ReactantExampleApp',
    port: 'client',
&lt;span class="gd"&gt;-   type: 'SharedWorker',
&lt;/span&gt;&lt;span class="gi"&gt;+   type: 'ServiceWorker',
&lt;/span&gt;    workerURL: 'worker.bundle.js',
  },
}).then((app) =&amp;gt; {
  app.bootstrap(document.getElementById('app'));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, we can quickly turn SharedWorker mode into ServiceWorker mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transport/Performance
&lt;/h3&gt;

&lt;p&gt;Since the client app only renders and receives synchronized state. So the client app keeps running smoothly when the size of each dispatch update state does not exceed 50M. reactant uses &lt;a href="https://immerjs.github.io/immer/patches/" rel="noopener noreferrer"&gt;Immer patch&lt;/a&gt; to update, usually this patch will be very small and reactant also does DEV checking for patch minimization updates. In fact, in most scenarios, the patch will not be that large.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Update state size&lt;/th&gt;
&lt;th&gt;Volume of data&lt;/th&gt;
&lt;th&gt;Deserialization&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;30 Array * 1,000 items&lt;/td&gt;
&lt;td&gt;1.4 M&lt;/td&gt;
&lt;td&gt;14 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 Array * 1,0000 items&lt;/td&gt;
&lt;td&gt;14 M&lt;/td&gt;
&lt;td&gt;130 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000 Array * 1,000 items&lt;/td&gt;
&lt;td&gt;46 M&lt;/td&gt;
&lt;td&gt;380 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Notebook: 1 GHz Intel Core M / 8 GB 1600 MHz DDR3&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;benchmarking of the reactant-share module with &lt;a href="(https://reactant.js.org/docs/api/reactant-module/modules/_decorators_computed_)"&gt;derived data cache&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Number of modules and states&lt;/th&gt;
&lt;th&gt;Total number of states&lt;/th&gt;
&lt;th&gt;Each state update&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100 modules * 20 states&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;td&gt;3 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200 modules * 30 states&lt;/td&gt;
&lt;td&gt;6,000&lt;/td&gt;
&lt;td&gt;9 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;300 modules * 100 states&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;44 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Notebook: 1 GHz Intel Core M / 8 GB 1600 MHz DDR3&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, reactant-share still performs well in large projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexity
&lt;/h3&gt;

&lt;p&gt;Whether it's practicing &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" rel="noopener noreferrer"&gt;clean architecture&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design" rel="noopener noreferrer"&gt;DDD&lt;/a&gt;, OOP or even FP, reactant-share has more openness to architect highly complex projects at will. reactant-share provides a few optional features, but the only one that shouldn't be missed is DI. reactant-share's DI is inspired by Angular, and it is very similar to Angular's DI. The complexity of coding that comes with architectural design is often determined by the final specification of the practice, but reactant-share hopes to help with such complex architectural design at the framework level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;For reactant-share applications, the communication between server/client only serializes and deserializes state and parameters, so it is almost impossible to cause framework-level security issues. Of course, enabling https and using&lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/Security/Subresource_Integrity" rel="noopener noreferrer"&gt;Subresource Integrity&lt;/a&gt; are both necessary for any project that values front-end security, and we should also be concerned about &lt;a href="https://reactjs.org/docs/dom-elements.html#style" rel="noopener noreferrer"&gt;XSS security&lt;/a&gt; in React documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;reactant-share provides &lt;code&gt;testBed()&lt;/code&gt; to facilitate module testing. For example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;testBed&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For integration testing of server app/client app interactions, reactant-share also provides &lt;code&gt;mockPairTransports()&lt;/code&gt; for mock transport.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mockPairTransports&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorkerApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;transports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// render only&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;createSharedApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;share&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorkerApp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SharedWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;transports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// render less&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After mocking transport like this, &lt;code&gt;clientApp&lt;/code&gt; and &lt;code&gt;serverApp&lt;/code&gt; can be easily tested for integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  APIs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@injectable()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use &lt;code&gt;@injectable()&lt;/code&gt; to decorate a module that can be injected and then use the &lt;code&gt;emitDecoratorMetadata&lt;/code&gt; using TypeScript, or &lt;code&gt;@inject()&lt;/code&gt; to inject the dependency.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@state&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;@state&lt;/code&gt; is used to decorate a class property that will create a reducer for Redux.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@action&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It updates the redux state with mutations via the class method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;state&lt;/span&gt;
  &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;action&lt;/span&gt;
  &lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ViewModule&lt;/code&gt;/&lt;code&gt;useConnector()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;ViewModule&lt;/code&gt; is a view module with a component, which is completely different from React class component. The component of &lt;code&gt;ViewModule&lt;/code&gt; is a function component that is used for the state connection between the module and the UI (using &lt;code&gt;useConnector()&lt;/code&gt;) and for the application view bootstrap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;spawn()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;spawn()&lt;/code&gt; transfers class methods execution from the client app to the server app and synchronizes the state to all client apps. It is inspired by the Actor model, but unlike other actor models, reactant-share's &lt;code&gt;spawn()&lt;/code&gt; does not create new threads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;createSharedApp()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;reactant-share supports multiple modes, and you can use &lt;code&gt;createSharedApp()&lt;/code&gt; to create multiple different Shared Web Apps that interact with each other via transport APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Q&amp;amp;A
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Can reactant-share completely solve the complexity of the architecture?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although reactant-share tries to reduce some complexity at the framework level, the complexity of large applications does not depend entirely on the framework itself, so even using reactant-share to architect a large project does not completely guarantee that it is absolutely clean, efficient, and maintainable. It involves testing strategy, code specification, CI/CD, development process, module design, and many other point.&lt;/p&gt;

&lt;p&gt;But in terms of module model and shared model, reactant-share already provides as clean a design as possible. If you are interested in &lt;a href="https://github.com/unadlib/reactant/tree/master/packages/reactant-share" rel="noopener noreferrer"&gt;reactant-share&lt;/a&gt;, you can try it quickly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does reactant-share have no cons at all? Are there any limitations to using it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;reactant-share is a framework for building Shared Web Apps. But such a model is not free, and it will face performance issues with data transfer (The high maintenance cost of the SharedArrayBuffer has forced us to abandon it for now as well. In fact this is a problem caused by the fact that JS "multithreading" does not share memory efficiently).&lt;/p&gt;

&lt;p&gt;Although Shared Web Apps lets the client App run in a render-only client thread, it introduces the additional overhead of synchronous state transfer. We must ensure that it is lightweight and efficient enough. While reactant-share does state patch based on Immer, it is always difficult to ensure that each patch is minimally updated.&lt;/p&gt;

&lt;p&gt;reactant-share provides a development option &lt;code&gt;enablePatchesChecker&lt;/code&gt;. In development mode, it is enabled by default. Any mutation operation that is not a valid mutation will be alerted, usually eliminating the alert, and reactant-share will try to keep the update size as minimal as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Front-end frameworks and architectures are always evolving. With full Worker support in modern browsers and an increasing number of multi-core CPU devices, we have reached a mature stage in our exploration of some multi-threaded running Web Apps. We have reasons to believe that the future Web App will be designed with lower complexity and run smoothly with multiple threads. It can fully utilize the user's device resources and give the user a good experience, and the developer does not need to have too many multi-threaded programming burden.&lt;/p&gt;

&lt;p&gt;This is what reactant-share wants to try and work on.&lt;/p&gt;

&lt;p&gt;If you think reactant-share is interesting, feel free to give it a star.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/reactant" rel="noopener noreferrer"&gt;reactant&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A progressive micro frontends framework - Fronts</title>
      <dc:creator>Michael Lin</dc:creator>
      <pubDate>Sat, 03 Jul 2021 02:31:41 +0000</pubDate>
      <link>https://dev.to/unadlib/a-progressive-micro-frontends-framework-fronts-3kn1</link>
      <guid>https://dev.to/unadlib/a-progressive-micro-frontends-framework-fronts-3kn1</guid>
      <description>&lt;h2&gt;
  
  
  Micro Frontends
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;An architectural style where independently deliverable frontend applications are composed into a greater whole.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As front-end development becomes increasingly complex, traditional large front-end projects should likely end up being difficult to maintain due to over-coupling, and therefore Micro Frontends is also gaining attention in front-end architectures.&lt;/p&gt;

&lt;p&gt;Front-end application modules dynamic will become one of the new trends in front-end development, and it will be possible to solve the problem of code base maintainability and delivery efficiency more thoroughly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits and Value of Micro Frontends
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt; Independence and Autonomy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only if the overall process of application development can be developed, deployed and managed independently of the code base, etc., then the front-end project can have true independence guaranteed. And this possibility of team autonomy is also in line with Conway's Law, which states that "Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure", thus bringing about a possible new form of organizational management.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Technology Agnostic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technology agnostic facilitates the collaboration of multiple teams with different technology stacks. The smooth migration of technology stacks also brings greater convenience to the continuous iteration and technology upgrade of the older business system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runtime Integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In modern front-end development processes, we most often see build-time integration. Whereas before, runtime integration happened to separate modules more independently. Micro frontends also happen to integrate well with such micro module concepts and keep such modules independent and dependency sharing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decoupled Modularity &amp;amp; Composable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In large front-end projects, we have high requirements for modular decoupling, often based on different types of divisions, such as business type modularity, technical service type modularity, and so on. The composable of individual micro frontends particles in turn allows for good module consistency and overall customization differentiation across multiple deliverable families, and can greatly reduce business duplication.&lt;/p&gt;

&lt;p&gt;In general, the proper practice of micro frontends architecture will bring far-reaching value to the long-term maintenance of some large front-end projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Among the many micro frontends solutions, single-spa and Module Federation are the best of them.&lt;/p&gt;

&lt;p&gt;single-spa is a micro frontends framework based on router configuration. The centralization of configuration brings some limitations, such as it is difficult to granulate nestable micro frontends, module granularity control, module sharing, and so on.&lt;/p&gt;

&lt;p&gt;In 2019, Zack Jackson proposed and implemented Module Federation. Module Federation is a completely different concept from single-spa, and allows a JavaScript application to dynamically load code from another application. It completely solves the problem of code dependency sharing and runtime modularity. The idea is true - A game-changer in JavaScript architecture as mentioned in Zack Jackson's article. And it's currently supported by Webpack, Next.js, and Rollup.&lt;/p&gt;

&lt;p&gt;Although the Module Federation concept is so amazing, it has not yet gone further to provide a more complete and fully targeted micro frontends framework implementation, and this is what Fronts is trying to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hotspots of Micro Frontends Framework
&lt;/h2&gt;

&lt;p&gt;Based on the current mainstream micro frontends frameworks or concepts, the following is a compilation of the main hotspots involved.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should the granularity level be application level or module level&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Module level is obviously more advantageous in terms of flexibility and granularity, but there is clearly an advantage to supporting application level in order to be compatible with some not so modern front-end projects, so we need a framework that supports both. If application-level runtime integration is required, it is clear that just using Module Federation's Webpack is not enough, we also need a runtime application-level granular entry point loader.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether the entry point file is HTML or JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a modern engineering perspective, most front-end application entry points are JS-based, and some previous front-end projects have used HTML alone as the entry point. The trade-off is that building a micro frontends system for applications where HTML is the main entry point is bound to be a longer and more complex of processes. Such a library would be better suited as a standalone sub-package, while the overall framework should take JS files as the entry point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it necessary to support perfect module sharing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Module sharing is a problem that must be solved by micro frontends frameworks, otherwise the duplication of resources at runtime will make micro frontends less valuable. Currently, only Webpack with Module Federation allows such module sharing to be handled at build time, with dynamic dependency sharing at runtime. No better solution than Module Federation has yet emerged.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS/JS isolation trade-off&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Isolation of CSS is almost required and is supported by many micro frontends frameworks. We may have to do all kinds of hijacking to ensure the security, performance and stability, and also consider the compatibility of different browsers. However, JS isolation is relatively expensive to implement, and the fact that such isolation is required for modern front-end engineering depends on the actual situation of each micro frontend.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic micro frontend and support multiple containers with multiple modes (Or SSR, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In large front-end projects, it is often not just about building a single web application, but possibly multiple web applications, or even more front-end application types, such as Electron applications, browser extensions, native applications, etc. So a good micro frontends framework should be able to run more kinds of containers and build a variety of application types, but also preferably compatible with building traditional SPA and micro frontends applications. Module Federation also initially implemented in the next.js implementation of SSR support.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Version control and dependency management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With rapid iteration and business growth, various module management becomes very important, so when a large front-end project practices micro frontends architecture at a later stage, version control and dependency management will become especially important, which will determine the delivery efficiency and maintainability.&lt;/p&gt;

&lt;p&gt;To solve these problems, Fronts was created.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Fronts
&lt;/h2&gt;

&lt;p&gt;Fronts is a progressive micro frontends framework for building Web applications, and it's based on the module federation of Webpack.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/fronts"&gt;https://github.com/unadlib/fronts&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Non-module-federation&lt;/strong&gt; - Although Fronts is based on the concept of module federation, it also supports &lt;code&gt;non-module-federation&lt;/code&gt; mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decentralized configuration&lt;/strong&gt; - Configure &lt;code&gt;site.json&lt;/code&gt; for dependency management in each Fronts app, support for nested micro frontends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross frameworks&lt;/strong&gt; - No framework or technology stack is restricted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code splitting &amp;amp; lazy loading&lt;/strong&gt; - Support code splitting within the Fronts app as a module, it can be lazy loaded by other Fronts app as a dependent module.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS isolation&lt;/strong&gt; - Optional CSS isolation solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle&lt;/strong&gt; - Fronts provide concise lifecycle for Fronts app entry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Components &amp;amp; iFrame&lt;/strong&gt; - Support for multiple frontend containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple patterns&lt;/strong&gt; - Support for building &lt;code&gt;micro-frontends&lt;/code&gt; app and &lt;code&gt;non-micro-frontends&lt;/code&gt; app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo &amp;amp; TypeScript&lt;/strong&gt; - Friendly support for Monorepo and TypeScript, which are mutually appropriate technology stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version control&lt;/strong&gt; - It's used for efficient and dynamic delivery apps such as canary release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero hijacking&lt;/strong&gt; - Fronts didn't do any hijacking, maintaining originality and possible loss of performance and security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generic Communication&lt;/strong&gt; - Fronts provides concise and generic communication APIs, which supports almost all frontend environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits of Fronts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fronts is a concise and easy to understand micro frontends framework.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;site.json&lt;/code&gt; to define a micro frontend, similar to a &lt;code&gt;package.json&lt;/code&gt; in Node.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/bootstrap"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;control&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;looks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;like:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nl"&gt;"app2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"app2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3002/remoteEntry.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"shared"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"singleton"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"singleton"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fronts is progressive.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If every front-end application does not support Module Federation, it will still work well as a micro frontend, with on-demand runtime modes, and as projects are upgraded, they can gradually be made to support Module Federation and eventually version control can be enabled. With support for multiple granularity levels, build types, module types, shared types, runtime types, and communication types, Fronts can almost meet all kinds of micro frontends architectures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fronts APIs are clean and simple.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fronts provides three sets of loaders &lt;code&gt;useApp()&lt;/code&gt;, &lt;code&gt;useWebComponents()&lt;/code&gt; and &lt;code&gt;useIframe()&lt;/code&gt;. It also provides an micro frontend launcher &lt;code&gt;boot()&lt;/code&gt; and a Webpack configuration generator &lt;code&gt;createWebpackConfig()&lt;/code&gt;. With these APIs, you will be able to do micro frontends development quickly and efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;We will build a micro frontends project based on Fronts, where &lt;code&gt;app1&lt;/code&gt; is the main entry point and it will depend on &lt;code&gt;app2&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can follow this article(&lt;a href="https://dev.to/rogeliosamuel621/react-without-create-react-app-webpack-5-1b1o"&gt;React without create-react-app Webpack 5&lt;/a&gt;) to quickly create &lt;code&gt;app1&lt;/code&gt; and &lt;code&gt;app2&lt;/code&gt; React projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Assuming you've completed these steps, let's get started with a quick taste of the wonderful micro frontends development of Fronts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;code&gt;fronts-react&lt;/code&gt; and &lt;code&gt;fronts-bundler&lt;/code&gt; in the projects.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# with NPM&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;fronts-react fronts-bundler

&lt;span class="c"&gt;# or with Yarn&lt;/span&gt;
yarn add fronts-react fronts-bundler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set up &lt;code&gt;site.json&lt;/code&gt; and &lt;code&gt;webpack.config.js&lt;/code&gt; in the projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We define &lt;code&gt;app1&lt;/code&gt; as a parent micro frontend and it depends on &lt;code&gt;app2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app1/site.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"app2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3002/remoteEntry.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app2&lt;/code&gt; doesn't have any dependencies, it acts as a micro frontend and we define it to export &lt;code&gt;./src/bootstrap&lt;/code&gt; as a micro frontends entry, this entry of &lt;code&gt;app2&lt;/code&gt; end will be used by &lt;code&gt;app1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app2/site.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/bootstrap"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wrap the Webpack config with &lt;code&gt;createWebpackConfig()&lt;/code&gt; in &lt;code&gt;config/webpack.config.js&lt;/code&gt; in the projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createWebpackConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fronts-bundler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createWebpackConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalWebpackConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Define the default exported bootstrap function in &lt;code&gt;app2/src/bootstrap.jsx&lt;/code&gt; and use &lt;code&gt;boot()&lt;/code&gt; to get it booted.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;boot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fronts-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unmountComponentAtNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;boot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Load &lt;code&gt;app1/src/App.jsx&lt;/code&gt; with &lt;code&gt;useApp()&lt;/code&gt; to import &lt;code&gt;app2&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fronts-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app2/src/bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App2&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;yarn start&lt;/code&gt;, and &lt;code&gt;app2&lt;/code&gt; is rendered as a micro frontend on &lt;code&gt;app1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example repo：&lt;a href="https://github.com/unadlib/fronts-example"&gt;https://github.com/unadlib/fronts-example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Built-in packages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mainstream front-end frameworks are still React, Vue and Angular. When a micro frontend uses one of them, it is recommended to use Fronts' built-in packages, such as &lt;code&gt;fronts-react&lt;/code&gt;, &lt;code&gt;fronts-vue&lt;/code&gt; and &lt;code&gt;fronts-ng&lt;/code&gt;, and when it comes to other frameworks not supported by the built-in packages or no framework, then please use &lt;code&gt;fronts&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built-in Package API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each built-in package contains three sets of loaders &lt;code&gt;useApp()&lt;/code&gt;, &lt;code&gt;useWebComponents()&lt;/code&gt;, &lt;code&gt;useIframe()&lt;/code&gt;. &lt;code&gt;useApp()&lt;/code&gt; provides loose CSS isolation, &lt;code&gt;useWebComponents()&lt;/code&gt; provides strict CSS isolation, and &lt;code&gt;useIframe()&lt;/code&gt; provides native strict CSS isolation and JS isolation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Version Control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fronts does not have full version control suite support and currently only supports self-built registry server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monorepo &amp;amp; TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Large front-end projects often mean a high level of complexity, so Fronts are well suited for use in a combination of technology stacks like Monorepo and TypeScript. You get a great development experience in type safety, code management and runtime integration. when each micro frontend is used as a Monorepo sub-package, you just run &lt;code&gt;SPA=true yarn start&lt;/code&gt; and switch the micro frontends development mode to the traditional SPA development mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The front-end architecture based on Fronts, Monorepo, and TypeScript will significantly improve codebase management, type safety, business development and delivery efficiency, and enable multiple combination of product business capabilities, high reuse and consistency of business code, and diversity of application types.&lt;/p&gt;

&lt;p&gt;Every large front-end project that tries to implement micro frontends architecture has different or similar requirements, so by analyzing the demands and needs of their own large front-end projects and using them to build or choose their own micro front-end architecture, they can really solve their own main engineering problems.&lt;/p&gt;

&lt;p&gt;With a general module concept based on Module Federation, Fronts tries to solve the main problems of micro frontends in a more targeted and systematic way, such as cross-framework, dependency sharing, dependency management, version control, compatibility with multiple runtime containers and patterns, etc.&lt;/p&gt;

&lt;p&gt;Fronts wants to evolve from more micro frontends architecture requirements to an efficient micro frontends framework.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/unadlib/fronts"&gt;https://github.com/unadlib/fronts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>microfrontends</category>
      <category>javascript</category>
      <category>react</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
