<?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: Dario Mannu</title>
    <description>The latest articles on DEV Community by Dario Mannu (@dariomannu).</description>
    <link>https://dev.to/dariomannu</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%2F1100953%2Ff28eae25-f448-4f8d-b41d-30241be597b1.png</url>
      <title>DEV Community: Dario Mannu</title>
      <link>https://dev.to/dariomannu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dariomannu"/>
    <language>en</language>
    <item>
      <title>Composable UI contracts and an algebraic approach to layout, style and interaction</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Mon, 05 Jan 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/dariomannu/composable-ui-contracts-an-algebraic-approach-to-layout-style-and-interaction-3jh9</link>
      <guid>https://dev.to/dariomannu/composable-ui-contracts-an-algebraic-approach-to-layout-style-and-interaction-3jh9</guid>
      <description>&lt;p&gt;Experienced frontend developers already know the uncomfortable truth: UI complexity does not come from CSS syntax or framework choice. It comes from &lt;em&gt;implicit responsibility&lt;/em&gt;. Who owns spacing. Who controls size. Who is allowed to style descendants. Who captures input. What happens when text grows. What breaks when layouts switch at a breakpoint.&lt;/p&gt;

&lt;p&gt;Most UI systems rely on conventions, reviews, and experience to keep this under control. That works, until it doesn’t. Deep nesting, design system growth, accessibility requirements, theming, responsiveness, and motion all push the same weak spots.&lt;/p&gt;

&lt;p&gt;This article proposes a different approach.&lt;/p&gt;

&lt;p&gt;Not a framework. Not a CSS methodology. Not a component library.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;compositional model&lt;/strong&gt; for UI, where layout, style, and interaction are treated as &lt;em&gt;explicit contracts&lt;/em&gt; that can be reasoned about, composed safely, and eventually formalised.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;N.B.: When we use the term Algebraic UI, we’re not referring to algebraic effects, UI state machines, or functional control flow.&lt;br&gt;
We’re using “algebraic” in the structural sense: UI paradigms are treated as composable algebraic objects with explicit compatibility rules, identity elements, and substitution laws.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The core idea: UI as responsibility contracts
&lt;/h2&gt;

&lt;p&gt;Instead of thinking in terms of HTML elements and CSS rules, we model UI as a tree of &lt;strong&gt;responsibility zones&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each zone makes explicit promises:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what it controls&lt;/li&gt;
&lt;li&gt;what it forbids&lt;/li&gt;
&lt;li&gt;what it expects from its parent&lt;/li&gt;
&lt;li&gt;what it guarantees to its children&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Composition becomes safe when:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a child’s requirements are satisfied by its parent’s guarantees&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This simple rule turns layout bugs into type errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Paradigms, not properties
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;paradigm&lt;/strong&gt; is a stable bundle of rules that govern responsibility.&lt;/p&gt;

&lt;p&gt;Paradigms are &lt;em&gt;not&lt;/em&gt; visual patterns.&lt;br&gt;
They are &lt;em&gt;laws&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Examples people already recognise intuitively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stack&lt;/li&gt;
&lt;li&gt;grid&lt;/li&gt;
&lt;li&gt;overlay&lt;/li&gt;
&lt;li&gt;modal&lt;/li&gt;
&lt;li&gt;card&lt;/li&gt;
&lt;li&gt;button&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What changes here is that each paradigm is defined explicitly, not socially.&lt;/p&gt;




&lt;h2&gt;
  
  
  Concerns: the dimensions of responsibility
&lt;/h2&gt;

&lt;p&gt;Instead of ad-hoc rules, each paradigm is defined as a vector over a small number of &lt;strong&gt;concerns&lt;/strong&gt;. Each concern has a closed set of allowed values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layout concerns (example set)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flow&lt;/strong&gt;: none | block | inline | axis(horizontal|vertical) | grid | overlay&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spacing ownership&lt;/strong&gt;: parent | child | shared | forbidden&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spacing propagation&lt;/strong&gt;: inherit | isolate | reset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sizing authority&lt;/strong&gt;: intrinsic | constrained | imposed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Margin emission&lt;/strong&gt;: allowed | forbidden&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boundary strength&lt;/strong&gt;: transparent | soft | hard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text growth tolerance&lt;/strong&gt;: flexible | bounded | fixed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptivity&lt;/strong&gt;: static | adaptive | responsive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These do not describe &lt;em&gt;how&lt;/em&gt; layout is implemented. They describe &lt;em&gt;who is responsible&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Style as authority, not decoration
&lt;/h2&gt;

&lt;p&gt;Style is not just colour and typography. Style is &lt;em&gt;visual authority&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Style paradigms answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who may style whom&lt;/li&gt;
&lt;li&gt;how far styles propagate&lt;/li&gt;
&lt;li&gt;whether tokens may be overridden&lt;/li&gt;
&lt;li&gt;whether the cascade participates or is isolated&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Style concerns (example set)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Style scope&lt;/strong&gt;: self | children | subtree&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance&lt;/strong&gt;: inherit | block | explicit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token dependency&lt;/strong&gt;: none | consume | override&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual authority&lt;/strong&gt;: parent | component | shared&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cascade participation&lt;/strong&gt;: isolated | layered | global&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reset behaviour&lt;/strong&gt;: none | partial | full&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once these are explicit, subtree styling stops being an accident.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interaction and animation as contracts
&lt;/h2&gt;

&lt;p&gt;Interaction is not business logic. It is &lt;strong&gt;input and time responsibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Animation is not decoration. It is &lt;strong&gt;temporal state change&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interaction and motion concerns (example set)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input capture&lt;/strong&gt;: none | child | parent | exclusive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event propagation&lt;/strong&gt;: bubble | capture | intercept | isolate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interaction ownership&lt;/strong&gt;: component | container | shared&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporal authority&lt;/strong&gt;: self | parent | external&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interruptibility&lt;/strong&gt;: non-interruptible | interruptible | reversible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced-motion sensitivity&lt;/strong&gt;: insensitive | adaptive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes modals, sliders, drawers, and carousels first-class citizens instead of special cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Components vs layout paradigms
&lt;/h2&gt;

&lt;p&gt;A core distinction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Layout paradigms&lt;/strong&gt; organise children&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component paradigms&lt;/strong&gt; define a single interactive unit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;code&gt;Stack&lt;/code&gt; and a &lt;code&gt;Button&lt;/code&gt; are not competing abstractions. They are orthogonal.&lt;/p&gt;

&lt;p&gt;A real component combines them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;external contract: element-level&lt;/li&gt;
&lt;li&gt;internal implementation: layout paradigms sealed behind boundaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This cleanly handles components that are &lt;em&gt;both&lt;/em&gt; layout and element internally, such as sliders or tabs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Schemes and themes: separating meaning from values
&lt;/h2&gt;

&lt;p&gt;Design systems fit naturally once responsibilities are explicit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Schemes&lt;/strong&gt; define semantic slots and what can be changed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Themes&lt;/strong&gt; assign concrete values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typography, spacing scales, colour roles, motion curves all live here.&lt;/p&gt;

&lt;p&gt;Paradigms never care about values. They care about &lt;em&gt;tolerance&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A layout does not decide font size. It decides whether text growth is allowed to affect structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Accessibility as an invariant, not a feature
&lt;/h2&gt;

&lt;p&gt;Accessibility is not a separate paradigm.&lt;/p&gt;

&lt;p&gt;It is a set of &lt;strong&gt;constraints that must hold across layout, style, and interaction&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;focus must be reachable&lt;/li&gt;
&lt;li&gt;motion must be interruptible or adaptive&lt;/li&gt;
&lt;li&gt;contrast must meet thresholds&lt;/li&gt;
&lt;li&gt;text must remain readable under scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ARIA attributes and semantic tags become implementation details, not design crutches.&lt;/p&gt;

&lt;p&gt;If the contracts hold, accessibility follows mechanically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Responsive design = paradigm substitution
&lt;/h2&gt;

&lt;p&gt;Breakpoints are not layout logic.&lt;/p&gt;

&lt;p&gt;They are &lt;strong&gt;context signals&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Responsive behaviour becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;substitute paradigm A with paradigm B&lt;br&gt;
when condition C holds&lt;br&gt;
provided external contracts remain valid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Grid → Stack&lt;br&gt;
Sidebar → Overlay drawer&lt;br&gt;
Cluster → Flow&lt;/p&gt;

&lt;p&gt;No half-states. No accidental overrides.&lt;/p&gt;




&lt;h2&gt;
  
  
  A model to create design systems and frameworks
&lt;/h2&gt;

&lt;p&gt;This model is not a framework. It does not prescribe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML structure&lt;/li&gt;
&lt;li&gt;CSS syntax&lt;/li&gt;
&lt;li&gt;JavaScript framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contracts&lt;/li&gt;
&lt;li&gt;compatibility&lt;/li&gt;
&lt;li&gt;forbidden states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, frameworks can be built &lt;em&gt;on top&lt;/em&gt; of it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this enables
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Automatic validation of UI composition&lt;/li&gt;
&lt;li&gt;Deep nesting of elements, components or blocks&lt;/li&gt;
&lt;li&gt;Safe theming and scaling&lt;/li&gt;
&lt;li&gt;Predictable accessibility&lt;/li&gt;
&lt;li&gt;Refactoring without visual regressions&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;This article describes the model informally. These are the next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define paradigms as algebraic objects, formally&lt;/li&gt;
&lt;li&gt;define compatibility&lt;/li&gt;
&lt;li&gt;define composition and substitution operators&lt;/li&gt;
&lt;li&gt;identify the most useful settings for key concerns and build a conceptual paradigm on top&lt;/li&gt;
&lt;li&gt;build a design system modelled after that&lt;/li&gt;
&lt;li&gt;build a tiny example application using the above&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fb6dvvnukpwoz5icojypx.png" alt="Web Components with one Simple Function" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/web-components-without-classes-34hb"&gt;Web Components with one Simple Function&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&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%2Fb6dvvnukpwoz5icojypx.png" alt="Web Components with one Simple Function" width="64" height="64"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fpedm0tq9gt76jwfvcj50.png" alt="Do you think Observables suck? Read this first!" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/why-observables-suck-and-what-can-you-51cg"&gt;Do you think Observables suck? Read this first!&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&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%2Fndwgy9009y9loko9mo6h.png" alt="Do you think Observables suck? Read this first!" width="64" height="64"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Ffvz4rupi0mx6303ghwc2.png" alt="A Web Developer's guide to Stream-Oriented Programming" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/a-senior-developers-guide-to-stream-oriented-programming-3j24"&gt;A Web Developer's guide to Stream-Oriented Programming&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&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%2Ffvz4rupi0mx6303ghwc2.png" alt="A Web Developer's guide to Stream-Oriented Programming" width="64" height="64"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>css</category>
      <category>ui</category>
      <category>frontend</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>HTML strings vs the DOM API: from a small benchmark to a surprising result</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Tue, 25 Nov 2025 09:36:42 +0000</pubDate>
      <link>https://dev.to/dariomannu/html-strings-vs-the-dom-api-from-a-small-benchmark-to-a-surprising-result-5fo6</link>
      <guid>https://dev.to/dariomannu/html-strings-vs-the-dom-api-from-a-small-benchmark-to-a-surprising-result-5fo6</guid>
      <description>&lt;p&gt;Which of the following do you think is faster?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;direct DOM API calls (&lt;code&gt;createElement&lt;/code&gt;, &lt;code&gt;appendChild&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;assigning HTML strings to &lt;code&gt;innerHTML&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Chances are you'll say the former is faster and most people would agree.&lt;br&gt;
This belief is so deeply rooted in popular culture that even many framework authors chose to base their entire architecture around DOM API calls.&lt;/p&gt;

&lt;p&gt;Now, critical thinking to the rescue. Is this really, really true?&lt;/p&gt;

&lt;p&gt;At the end of the day, browsers have been optimised around parsing HTML for decades and writing HTML feels better than the raw DOM API, so... true or not, is is worth it at all?&lt;/p&gt;



&lt;p&gt;Thought it's time to test assumptions and hypotheses, both in extreme and more realistic scenarios. An extreme scenario is one where you render a view tens of thousands of times on a page. In a realistic scenario, you render a view once.&lt;/p&gt;
&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Two simple functions on the scene. One builds the view by hand with createElement, setAttribute, appendChild, the other generates the same structure with a single HTML template string.&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;// DOM API version (shortened)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domFn&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;container&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;div&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// HTML template version (shortened)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlFn&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="nx"&gt;target&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="s2"&gt;`
    &amp;lt;div&amp;gt;
      &amp;lt;header&amp;gt;&amp;lt;h1&amp;gt;Dashboard&amp;lt;/h1&amp;gt;&amp;lt;/header&amp;gt;
    &amp;lt;/div&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;Next, rinse and repeat. Render 1, 2, 4, 8, up to 1024 times.&lt;/p&gt;

&lt;h2&gt;
  
  
  First-run: surprise surprise!
&lt;/h2&gt;

&lt;p&gt;Before we get to which method is faster when we render many, many times, here is the shocking part: if you only set &lt;code&gt;innerHTML&lt;/code&gt; once, it's nearly always faster than building the DOM structure one &lt;code&gt;createElement&lt;/code&gt; at a time!&lt;/p&gt;

&lt;p&gt;It's not just an opinion, it's hard numbers in various scenarios.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a &lt;a href="https://stackblitz.com/edit/dom-vs-html-performance-test" rel="noopener noreferrer"&gt;very simple HTML structure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://stackblitz.com/edit/dom-vs-html-performance-test-bigger" rel="noopener noreferrer"&gt;more articulated one&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These links run on Stackblitz and show slighly different values than a local build. Feel free to download these projects and run the code yourself. The difference will be even more apparent on local.&lt;/p&gt;

&lt;p&gt;Before you get too excited, look at the numbers, though. We're still talking less than 1ms difference, which is totally negligible for an end user.&lt;/p&gt;

&lt;p&gt;This probably happens because HTML parsing is one of the most well optimised code paths in the browser. Turning a string into DOM nodes is fast. Meanwhile the DOM API version makes many small JavaScript calls before the engine has had time to optimise the function.&lt;/p&gt;

&lt;p&gt;So for the first render the HTML version comes out ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  After that everything flips
&lt;/h2&gt;

&lt;p&gt;As soon as the test repeats the operation more than once, the DOM API becomes faster.&lt;/p&gt;

&lt;p&gt;This is where the JavaScript engine steps in. Once the DOM-building function has run a couple of times the engine fully optimises it. The series of &lt;code&gt;createElement&lt;/code&gt; and &lt;code&gt;appendChild&lt;/code&gt; calls becomes predictable and efficient.&lt;/p&gt;

&lt;p&gt;The HTML version cannot use the same advantage. It always has to parse the whole template again. So from two runs onwards the DOM API pulls ahead and keeps widening the gap as the number of runs increases.&lt;/p&gt;

&lt;p&gt;The same pattern shows up locally and on StackBlitz. The exact numbers shift, but the behaviour is identical.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means in practice
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;HTML strings are not slow&lt;/em&gt;. Quite the opposite. Browsers can parse a view so quickly that the first render can match or beat manual DOM calls. This is useful because typical applications build a view once, not hundreds of times in a loop.&lt;/p&gt;

&lt;p&gt;For repeated updates or very frequent re-renders the DOM API becomes the better choice. Once the engine optimises the function it avoids parsing costs and becomes more stable.&lt;/p&gt;

&lt;p&gt;In most real apps the difference is small enough that the choice comes down to clarity. If a view is easier to express as a template string, it is a perfectly reasonable approach. You are not paying a penalty for using it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fb6dvvnukpwoz5icojypx.png" alt="Web Components with one Simple Function" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/web-components-without-classes-34hb"&gt;Web Components with one Simple Function&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&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%2Fb6dvvnukpwoz5icojypx.png" alt="Web Components with one Simple Function" width="64" height="64"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fpedm0tq9gt76jwfvcj50.png" alt="Do you think Observables suck? Read this!" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/why-observables-suck-and-what-can-you-51cg"&gt;Do you think Observables suck? Read this!&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&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%2Fndwgy9009y9loko9mo6h.png" alt="Do you think Observables suck? Read this!" width="64" height="64"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Ffvz4rupi0mx6303ghwc2.png" alt="A Web Developer's guide to Stream-Oriented Programming" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/a-senior-developers-guide-to-stream-oriented-programming-3j24"&gt;A Web Developer's guide to Stream-Oriented Programming&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&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%2Ffvz4rupi0mx6303ghwc2.png" alt="A Web Developer's guide to Stream-Oriented Programming" width="64" height="64"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>webperf</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Is your JS Framework slowing you down when you render something complex?

Rimmel.js allows you to create Custom Sinks to render anything you want the exact way you want

https://stackblitz.com/edit/rimmel-table-powersink</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Tue, 04 Nov 2025 15:16:12 +0000</pubDate>
      <link>https://dev.to/dariomannu/is-your-js-framework-slowing-you-down-when-you-render-something-complex-rimmeljs-allows-you-to-4mnf</link>
      <guid>https://dev.to/dariomannu/is-your-js-framework-slowing-you-down-when-you-render-something-complex-rimmeljs-allows-you-to-4mnf</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://stackblitz.com/edit/rimmel-table-powersink" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;stackblitz.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Working with WebSockets? No, it's never been simpler than this, ever!

https://stackblitz.com/edit/simplest-chat-app-deno-rimmel</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Tue, 28 Oct 2025 21:22:24 +0000</pubDate>
      <link>https://dev.to/dariomannu/working-with-websockets-no-its-never-been-simpler-than-this-ever-3p4m</link>
      <guid>https://dev.to/dariomannu/working-with-websockets-no-its-never-been-simpler-than-this-ever-3p4m</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://stackblitz.com/edit/simplest-chat-app-deno-rimmel" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;stackblitz.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




</description>
    </item>
    <item>
      <title>Workinng with WebSockets? No, it's never been simpler than this, ever!

https://stackblitz.com/edit/simplest-chat-app-deno-rimmel</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Tue, 28 Oct 2025 21:21:08 +0000</pubDate>
      <link>https://dev.to/dariomannu/workinng-with-websockets-no-its-never-been-simpler-than-this-ever-26fa</link>
      <guid>https://dev.to/dariomannu/workinng-with-websockets-no-its-never-been-simpler-than-this-ever-26fa</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://stackblitz.com/edit/simplest-chat-app-deno-rimmel" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;stackblitz.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Rediscovering Effect Management with Effect Maps</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Tue, 28 Oct 2025 18:54:20 +0000</pubDate>
      <link>https://dev.to/dariomannu/effect-maps-how-stream-oriented-programming-rethinks-effect-management-1d7o</link>
      <guid>https://dev.to/dariomannu/effect-maps-how-stream-oriented-programming-rethinks-effect-management-1d7o</guid>
      <description>&lt;p&gt;Many programming paradigms revolve around a single idea — whether that’s composition, purity, dataflow, or state isolation. But there’s one recurring question that keeps surfacing in every new language or framework: &lt;em&gt;how do we manage effects&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Effects are the unavoidable “real world” part of computation. They’re what make your program do something rather than just describe something. Logging, rendering, HTTP calls, I/O, and even user interaction — all are effects.&lt;/p&gt;

&lt;p&gt;Functional programming tried to solve this decades ago. Imperative programming ignored the problem entirely. Stream-Oriented Programming (SP) does something different: it turns effects into maps.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem with Traditional Effect Management
&lt;/h3&gt;

&lt;p&gt;If you’ve ever written pure functional code, you know that separating logic from effects isn’t as simple as it sounds. In theory, functions should be pure and side-effects handled by monadic constructs such as &lt;code&gt;IO&lt;/code&gt;, &lt;code&gt;Task&lt;/code&gt;, &lt;code&gt;Future&lt;/code&gt;, or similar abstractions. In practice, the code often turns into a tangled web of type constructors and continuations, all just to print a line or fetch data.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;monad&lt;/em&gt; pattern elegantly expresses effectful computation as data, but it also forces you to wrap and unwrap effects through chained continuations. Free and freer monads attempted to improve this by deferring interpretation — allowing you to “describe” effects and then interpret them later — but this only moves the complexity around. The price is boilerplate and a significant gap between your logic and what it actually does.&lt;/p&gt;

&lt;p&gt;The essence of the problem: &lt;strong&gt;you have to manually organise and synchronise effects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the hidden cost of functional purity. You must either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thread effects explicitly through monadic bind chains (&lt;code&gt;flatMap&lt;/code&gt;/&lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;), or&lt;/li&gt;
&lt;li&gt;Defer them into abstract syntax trees (via Free/Freeer monads), or&lt;/li&gt;
&lt;li&gt;Manage continuations to preserve purity across asynchronous boundaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s a lot of ceremony just to say “print this after reading that”.&lt;/p&gt;




&lt;h3&gt;
  
  
  HTML: The Most Powerful Effect Language Ever Created
&lt;/h3&gt;

&lt;p&gt;Web developers, ironically, have been dealing with effects all along — effortlessly.&lt;/p&gt;

&lt;p&gt;Every &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; in HTML is an effect declaration. Each element describes &lt;em&gt;what the program should do&lt;/em&gt; in the world — display text, handle clicks, submit forms — while keeping logic and structure separate.&lt;/p&gt;

&lt;p&gt;HTML doesn’t &lt;em&gt;execute&lt;/em&gt; effects, it &lt;em&gt;declares&lt;/em&gt; them. That’s the key.&lt;/p&gt;

&lt;p&gt;Stream-Oriented Programming builds on this insight. Instead of separating logic and effects through abstract monadic constructs, SP integrates them using &lt;em&gt;Effect Maps&lt;/em&gt; — templates that directly describe how streams (logic) connect to the world (effects).&lt;/p&gt;

&lt;p&gt;In this view, HTML isn’t just a markup language — it’s an &lt;strong&gt;Effect Declaration Language&lt;/strong&gt;. Every element, attribute, and event handler is an entry in the global effect map of your program.&lt;/p&gt;




&lt;h3&gt;
  
  
  From Functions to Streams
&lt;/h3&gt;

&lt;p&gt;In SP, logic isn’t built from functions, it’s built from reactive &lt;em&gt;streams&lt;/em&gt;. Streams are continuous values over time — observable sequences that represent both data, relationship and transition.&lt;/p&gt;

&lt;p&gt;The major conceptual shift is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Instead of passing functions around, you pass streams that continuously receive and emit values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means composition happens naturally. When you connect two streams, their relationship over time defines the behaviour — without rigidly defined "continuations".&lt;/p&gt;

&lt;p&gt;So while in functional programming you might see something 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="nf"&gt;readLine&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;input&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&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;println&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In SP, you’d simply declare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;said&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;effects&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
  &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Is an Effect Map?
&lt;/h3&gt;

&lt;p&gt;An Effect Map is a declarative structure that connects both ends of your streams to the external world. Think of it as a topological description of your application’s I/O system.&lt;/p&gt;

&lt;p&gt;Each key in an effect map corresponds to an effect endpoint — for instance, a DOM element, a console output, or a cloud event stream. Each value corresponds to a stream that feeds or reacts to that endpoint.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why It Works So Well
&lt;/h3&gt;

&lt;p&gt;SP defines state and logic as streams, which removes the need for continuations entirely. There’s no “after this, do that” — there’s just data flowing through pipelines and their intrinsic relationships naturally define what happens before or after (think of RxJS operators like &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;withLatestFrom&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So, effects are synchronised not by explicit control flow, but by the natural composition of streams. When one emits, another reacts. When nothing emits, nothing happens.&lt;/p&gt;

&lt;p&gt;This makes SP radically simpler for effectful programs: you get a model that is both reactive and declarative, with even more structural clarity than ever.&lt;/p&gt;




&lt;h3&gt;
  
  
  Comparing to Free and Freer Monads
&lt;/h3&gt;

&lt;p&gt;Free and freer monads aim to separate effect description from effect interpretation. You define an algebra of effects (e.g., &lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;Write&lt;/code&gt;, &lt;code&gt;Delay&lt;/code&gt;), build a program as a tree of these, and then provide an interpreter that executes them.&lt;/p&gt;

&lt;p&gt;Example (simplified pseudocode):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Console&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Read&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Write&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;

&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Free&lt;/span&gt; &lt;span class="kt"&gt;Console&lt;/span&gt;

&lt;span class="n"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;liftF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;liftF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Write&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You said: "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In SP, the same idea collapses into something simpler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pseudo language&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nc"&gt;You&lt;/span&gt; &lt;span class="nl"&gt;said:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nativeml&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
    &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;`&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The &lt;code&gt;(inputs) =&amp;gt; Template Maps&lt;/code&gt; Pattern
&lt;/h3&gt;

&lt;p&gt;At its core, every SP program follows the same structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(inputs) =&amp;gt; Template Maps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inputs are parameters or streams from the outside world — user events, messages, data feeds. The template map declares how these inputs feed into the application’s reactive logic, and how their results feed back out.&lt;/p&gt;

&lt;p&gt;This can scale from a trivial echo example to full reactive systems, web apps, or distributed services. The underlying concept stays the same: every program is a composition of streams mapped onto effect templates.&lt;/p&gt;

&lt;p&gt;That means an SP runtime for native, cloud, or server environments can use an HTML-like template syntax to describe effect connections — &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;file&lt;/code&gt;, &lt;code&gt;socket&lt;/code&gt;, &lt;code&gt;topic&lt;/code&gt;, &lt;code&gt;db&lt;/code&gt; — without needing to reinvent the language each time.&lt;/p&gt;

&lt;p&gt;HTML already solved the hard part: declaratively describing what should happen and where.&lt;/p&gt;




&lt;h3&gt;
  
  
  Generalising Beyond the Browser
&lt;/h3&gt;

&lt;p&gt;Imagine defining a microservice using the same principles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pipe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;apiml&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"get"&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/api/users"&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"${users}"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;}&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you swap out the &lt;code&gt;apiml&lt;/code&gt; template for another environment, the same logic runs elsewhere — in a CLI, a worker, or a serverless endpoint.&lt;/p&gt;

&lt;p&gt;This is what makes the model portable. The HTML-like language isn’t tied to the DOM; it’s just a declarative schema for effects.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why This Matters
&lt;/h3&gt;

&lt;p&gt;We’ve reached a point where logic is easy, but effects are hard. In most modern systems, the actual business logic of a program is tiny compared to the infrastructure code needed to orchestrate events, side-effects, and state synchronisation.&lt;/p&gt;

&lt;p&gt;Stream-Oriented Programming cuts through that by collapsing effect management into its natural form — a mapping between streams and their destinations. You no longer “manage” effects; you &lt;em&gt;describe&lt;/em&gt; them.&lt;/p&gt;

&lt;p&gt;This has several implications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Composability&lt;/strong&gt;: effect maps compose just like HTML fragments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency&lt;/strong&gt;: every effect is visible in the template; nothing hidden in callbacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability&lt;/strong&gt;: the same logic can target browser, server, or native backends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: streams can be simulated and observed without touching real I/O.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: new effect types can be declared simply by extending the template vocabulary.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  From Templates to Topologies
&lt;/h3&gt;

&lt;p&gt;Effect maps aren’t just about syntax — they’re about &lt;em&gt;topology&lt;/em&gt;.&lt;br&gt;
They describe how data flows through a system, not just what functions run. This allows compilers or runtimes to visualise, optimise, or even distribute the system automatically.&lt;/p&gt;

&lt;p&gt;An SP compiler could, for instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect if two streams form a feedback loop and isolate them.&lt;/li&gt;
&lt;li&gt;Parallelise independent streams automatically.&lt;/li&gt;
&lt;li&gt;Move effects to edge nodes or client devices dynamically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the program is a map, the runtime can reason about it.&lt;br&gt;
That’s something monadic chains can’t do, because the structure is hidden inside control flow.&lt;/p&gt;


&lt;h3&gt;
  
  
  The Future of Effect Languages
&lt;/h3&gt;

&lt;p&gt;HTML’s accidental genius was that it separated description from execution. SP borrows that insight and extends it to all domains. Whether it’s rendering UI, running cloud workers, or wiring hardware, the same idea applies: effects are declared, not controlled.&lt;/p&gt;

&lt;p&gt;As programming continues to shift toward reactivity and distribution, the need for clear, declarative effect systems grows. Stream-Oriented Programming offers a novel model that is not only simpler, but more general: an architecture where every effect is a node in a living map, every logic is a stream, and every application is the composition of both.&lt;/p&gt;


&lt;h3&gt;
  
  
  Closing Thought
&lt;/h3&gt;

&lt;p&gt;Effect Maps aren’t an abstraction &lt;em&gt;over&lt;/em&gt; effects; they’re an expression &lt;em&gt;of&lt;/em&gt; them.&lt;br&gt;
By treating logic as streams and using templates as maps, Stream-Oriented Programming eliminates one of the oldest dichotomies in computer science — between pure logic and messy side-effects — and replaces it with a single, flowing system that simply says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inputs → streams → effects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And perhaps that’s all we ever needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2F91ud88tyrxcjez7vkph4.png" alt="Callbacks vs Callforwards" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/from-callbacks-to-callforwards-a-simple-solution-to-reactivity-3l5e"&gt;From callbacks to callforwards: reactivity made simple?&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2F3ywsrw8azw1pmfizet7h.png" alt="State Management and the Mixed Wastewater Problem" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/the-core-problem-with-flux-redux-friends-fem"&gt;State Management and the Mixed Wastewater Problem&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Ffvz4rupi0mx6303ghwc2.png" alt="A Web Developer's guide to Stream-Oriented Programming" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/a-senior-developers-guide-to-stream-oriented-programming-3j24"&gt;A Web Developer's guide to Stream-Oriented Programming&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>programming</category>
      <category>functional</category>
      <category>streamorientedprogramming</category>
    </item>
    <item>
      <title>Contrarian JavaScript Frameworks: The Top 3</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Wed, 22 Oct 2025 14:30:00 +0000</pubDate>
      <link>https://dev.to/dariomannu/3-contrarian-js-frameworks-58fm</link>
      <guid>https://dev.to/dariomannu/3-contrarian-js-frameworks-58fm</guid>
      <description>&lt;p&gt;Every Friday morning, some junior developer trying to get noticed drops yet another “Top JavaScript Frameworks” list.&lt;/p&gt;

&lt;p&gt;Same line-up every time: Angular, React, Vue, Svelte, maybe Solid if they’re feeling bold. It’s like Groundhog Day for frontend devs.&lt;/p&gt;

&lt;p&gt;So let’s break the loop, shall we?&lt;/p&gt;

&lt;p&gt;Here are three frameworks/UI libraries that don’t quite play by the rules. Each one does things in a surprisingly different way that's worth a note.&lt;/p&gt;

&lt;p&gt;To run a comparison, we’ll pick a random UI task and see what their approach is like: let's create two buttons that, when both clicked, enable a third one.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTMX — The Antiscript
&lt;/h2&gt;

&lt;p&gt;Some people believe &lt;a href="https://htmx.org" rel="noopener noreferrer"&gt;HTMX&lt;/a&gt; is here to kill JavaScript, but what it really wants is to stop &lt;em&gt;you&lt;/em&gt; writing it.&lt;/p&gt;

&lt;p&gt;Instead of functions and event listeners, you describe behaviour directly in your HTML using attributes like &lt;code&gt;hx-get&lt;/code&gt;, &lt;code&gt;hx-trigger&lt;/code&gt;, and &lt;code&gt;hx-swap&lt;/code&gt;. It lets HTML talk to your backend — no scripts, no build tools, just markup that &lt;em&gt;acts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here’s how the same two-buttons-unlock-third example would look in HTMX’s world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@1.9.10"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/buttons"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"load"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on the server, you’d have something like this (using Express for simplicity):&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="nx"&gt;express&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;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&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;clicked1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;clicked2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;renderButtons&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;bothClicked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clicked1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;clicked2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;div id="app"&amp;gt;
    &amp;lt;button hx-post="/click1" hx-swap="outerHTML" hx-target="#app"&amp;gt;Button 1 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clicked1&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="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/button&amp;gt;
    &amp;lt;button hx-post="/click2" hx-swap="outerHTML" hx-target="#app"&amp;gt;Button 2 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clicked2&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="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/button&amp;gt;
    &amp;lt;button &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;bothClicked&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;Button 3&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;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;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/buttons&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;renderButtons&lt;/span&gt;&lt;span class="p"&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/click1&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;clicked1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;renderButtons&lt;/span&gt;&lt;span class="p"&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;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/click2&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;clicked2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;renderButtons&lt;/span&gt;&lt;span class="p"&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;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each button click sends a small POST request to the server, which updates its state and sends back the new HTML fragment. The browser replaces the old section automatically.&lt;/p&gt;

&lt;p&gt;That’s the real spirit of HTMX: &lt;strong&gt;make HTML dynamic again, by letting the backend do the work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bigskysoftware/htmx" rel="noopener noreferrer"&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%2F0lxreh9wwsz1rktnt5h8.png" alt="HTMX" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Hyperscript — Like plain English
&lt;/h2&gt;

&lt;p&gt;From the same folks behind HTMX comes &lt;a href="https://hyperscript.org" rel="noopener noreferrer"&gt;Hyperscript&lt;/a&gt;.&lt;br&gt;
If HTMX is "HTML that acts", Hyperscript is "HTML that talks".&lt;/p&gt;

&lt;p&gt;You literally write scripts in plain English:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on click add .active to me`, `wait 2s`, `remove @disabled from #btn3` 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Readable, no build step, no imports, no framework gymnastics.&lt;/p&gt;

&lt;p&gt;It’s imperative, surprisingly expressive, and kind of brilliant in its simplicity.&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="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://unpkg.com/hyperscript.org@0.9.12&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;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="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;on click add .clicked to me then call check()&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="mi"&gt;1&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;on click add .clicked to me then call check()&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="mi"&gt;2&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;btn3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="mi"&gt;3&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&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;text/hyperscript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;btn1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clicked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;btn2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clicked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;disabled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;btn3&lt;/span&gt;
      &lt;span class="nx"&gt;end&lt;/span&gt;
    &lt;span class="nx"&gt;end&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackblitz.com/edit/click-both-to-enable-hyperscript?file=index.html" rel="noopener noreferrer"&gt;Run on Stackblitz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s HTML that &lt;strong&gt;reads like English and behaves like JavaScript&lt;/strong&gt;.&lt;br&gt;
It doesn’t try to abstract your logic — it just makes it human-readable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bigskysoftware/_hyperscript" rel="noopener noreferrer"&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%2F9nb3sc0c0y7khh2b0kyw.png" alt="Hyperscript" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Rimmel — The Stream-Oriented Pioneer
&lt;/h2&gt;

&lt;p&gt;Third on the list comes &lt;a href="https://github.com/reactivehtml/rimmel" rel="noopener noreferrer"&gt;Rimmel&lt;/a&gt;, and it’s playing quite the opposite game.&lt;/p&gt;

&lt;p&gt;Rimmel is built on the idea that "everything is a stream", based on Stream-Oriented Programming: a novel paradigm with no state objects, no "actions" and no virtual DOM, only pure dataflows that describe how your app logic behaves over time.&lt;/p&gt;

&lt;p&gt;If you’ve ever worked on large and complex applications with RxJS (eg in Angular), you may be surprised to see how simpler it is in comparison.&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;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&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;rxjs&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;rml&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;rimmel&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;Component&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;first&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;BehaviorSubject&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;second&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;BehaviorSubject&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;second&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="nx"&gt;rml&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;Click&amp;lt;/button&amp;gt;
      &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;Both&amp;lt;/button&amp;gt;

      &amp;lt;button disabled="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;To enable&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&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;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="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Component&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://stackblitz.com/edit/click-both-to-enable" rel="noopener noreferrer"&gt;Run on Stackblitz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s no diffing, no re-rendering, no &lt;code&gt;setState&lt;/code&gt;. Just events and data flowing.&lt;br&gt;
It’s pioneering a novel paradigm — Stream-Oriented Programming — which reduces the whole process of software development to a mere composition of streams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ReactiveHTML/rimmel" rel="noopener noreferrer"&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%2Fb6e4ahb1pdw8rahwsizz.png" alt="Rimmel.js" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Which One Fits You
&lt;/h2&gt;

&lt;p&gt;If you like HTML doing the heavy lifting you may have a very good time with HTMX.&lt;br&gt;
If you want to try the breeze of scripting in plain English, perhaps you're writing something for non-developers, Hyperscript is genuinely refreshing.&lt;br&gt;
If you can think of events and data in terms of streams, if you want total control and you're creating complex applications, you may rely on Rimmel's strong computational model.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Small Print
&lt;/h2&gt;

&lt;p&gt;HTMX keeps HTML front and centre, but it only gets you so far — real logic still needs scripting and your users better have a fast, reliable internet connection that's always on.&lt;br&gt;
Hyperscript bridges that gap in a surprisingly natural way, though it’s best for small to medium projects. Complex logic is still complex logic. Don't expect everyone to understand it just because it's English.&lt;br&gt;
Rimmel shines for its sound computational model. It's simple to start, it's rock-solid at scale, but you need to learn how streams and RxJS work if you haven't already, which aren't exactly as simple as plain English.&lt;/p&gt;




&lt;p&gt;So, now we found a few frameworks that don’t try to be “the next React”. They’re doing their own thing, greatly challenging the status quo — and that’s what makes them worth knowing.&lt;/p&gt;

&lt;p&gt;Can you suggest other frameworks/UI libraries that break all rules and bring something truly different to the scene?&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fl73yimx6il20rb9b7jam.png" alt="Reactive Streams: Functional vs Imperative" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/stream-oriented-imperative-vs-functional-29h6"&gt;Reactive Streams: Functional vs Imperative&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fpedm0tq9gt76jwfvcj50.png" alt="Do you think Observables suck?" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/why-observables-suck-and-what-can-you-51cg"&gt;Do you think Observables suck?&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fxc4nfulx9d0nzt5wi1pl.png" alt="Vanilla JS is unscalable. Here is why" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/how-vanilla-js-is-unscalable-and-how-can-you-52f7"&gt;Vanilla JS is unscalable. Here is why&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>javascriptlibraries</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A Web Developer's guide to Stream-Oriented Programming</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Wed, 15 Oct 2025 14:30:00 +0000</pubDate>
      <link>https://dev.to/dariomannu/a-senior-developers-guide-to-stream-oriented-programming-3j24</link>
      <guid>https://dev.to/dariomannu/a-senior-developers-guide-to-stream-oriented-programming-3j24</guid>
      <description>&lt;p&gt;So you're interested or curious about Stream-Oriented Programming (SP).&lt;/p&gt;

&lt;p&gt;SP is a novel programming paradigm that makes it easy to create complex applications with advanced sync+async interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  An architectural mental model
&lt;/h2&gt;

&lt;p&gt;There is a core mantra in this paradigm: "Everything is a Stream".&lt;/p&gt;

&lt;p&gt;Obviously we still have strings, numbers, booleans and functions, but it's a mental model which allows us to focus on the building blocks of an application and their relationship rather than their shape and nuances.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Stream?
&lt;/h2&gt;

&lt;p&gt;A Reactive Stream is a high-level data construct that can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;(optionally) listen to events/messages&lt;/li&gt;
&lt;li&gt;(optionally) apply some transformations&lt;/li&gt;
&lt;li&gt;(optionally) emit data.&lt;/li&gt;
&lt;/ol&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%2F6dm1vnxtsgttlx4owssy.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%2F6dm1vnxtsgttlx4owssy.png" alt="The anatomy of a reactive stream" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are various implementations of reactive streams. In the JavaScript world the most well-known, mature, battle-tested and ubiquitous implementation is RxJS.&lt;/p&gt;

&lt;p&gt;Other incarnations of streams could be used, including Callbags, Callforwards and you can create your own, but we'll stick with RxJS in this guide for practical purposes.&lt;/p&gt;

&lt;p&gt;N.B.: RxJS is known to be one of the most difficult JavaScript libraries to master, but we'll show you how that's no longer the case in SP, where streams are first-class and not just yet another async primitive developers have to stitch to the rest.&lt;/p&gt;

&lt;p&gt;In SP the Observable is a low-level, read-only stream that you should probably never need to instantiate directly in your applications.&lt;/p&gt;

&lt;p&gt;Two other types of stream will play a fundamental role in all stream-oriented development. &lt;code&gt;Subject&lt;/code&gt; and &lt;code&gt;BehaviorSubject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Subject&lt;/code&gt; is the most basic implementation of a reactive stream that looks like data in =&amp;gt; data out.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BehaviorSubject&lt;/code&gt; is the stateful stream. You can think of it as the universal state manager and you'll use it extensively.&lt;/p&gt;

&lt;p&gt;If you come from React, this is a bit like the functional equivalent of &lt;code&gt;useState&lt;/code&gt;, but infinitely more powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operators (the top 3)
&lt;/h2&gt;

&lt;p&gt;Just like you have separation of concerns as a general principle in software engineering, you have an equivalent in Stream-Oriented programming, too, where you separate architecture from implementation.&lt;/p&gt;

&lt;p&gt;The architecture of an application is a graph of streams.&lt;br&gt;
The anatomy of a stream is a pipeline of operators, which break down all logic to a sequence of steps.&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%2F6dm1vnxtsgttlx4owssy.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%2F6dm1vnxtsgttlx4owssy.png" alt="The anatomy of a reactive stream" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  map
&lt;/h2&gt;

&lt;p&gt;The most basic and important operator is &lt;code&gt;map&lt;/code&gt;: it takes the input, applies a transformation function and re-emits the result synchronously. It behaves like &lt;code&gt;Array.map&lt;/code&gt;, but for event streams.&lt;/p&gt;

&lt;p&gt;Here is a simple stream that doubles its input.&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;doubler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&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;pipe&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;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;x&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;h2&gt;
  
  
  filter
&lt;/h2&gt;

&lt;p&gt;The second most important operator is &lt;code&gt;filter&lt;/code&gt;. Just like Array.filter, this takes a boolean function to decide synchronously whether to re-emit a given event to the next step or not.&lt;/p&gt;

&lt;p&gt;Here is a stream that takes numbers and only lets the odd ones through:&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;odds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&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;pipe&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;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&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;h2&gt;
  
  
  scan
&lt;/h2&gt;

&lt;p&gt;This is like a "progressive" Array.reduce. It performs the same functionality, just one-by-one, re-emitting synchronously a reduced value as data comes in.&lt;/p&gt;

&lt;p&gt;This operator will be used extensively nearly every time you need a state machine.&lt;/p&gt;

&lt;p&gt;Following is a basic "total" stream that takes numbers in, adds them up and emits the sum of all items received.&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;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&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;total&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;newValue&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;Here the initial value of the BehaviorSubject will be also used as the initial value of the operator, so the whole stream will emit 0 initially.&lt;/p&gt;

&lt;p&gt;Following is a "mergeUp" stream that takes objects in and merges their key-values into a single "state" object:&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;mergeUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&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;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;scan&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="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="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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other operators
&lt;/h2&gt;

&lt;p&gt;If you know JavaScript Promises you already know operators: &lt;code&gt;Promise.all&lt;/code&gt;, &lt;code&gt;Promise.allSettled&lt;/code&gt;, &lt;code&gt;Promise.then&lt;/code&gt;, &lt;code&gt;Promise.catch&lt;/code&gt; are all everyday examples of operators used by Promises.&lt;/p&gt;

&lt;p&gt;Streams can have their own. Since there are many more use cases for reactive streams than promises, there are also many more operators. RxJS sports around 200 but you'll actually count on your fingers the number of actual operators you'll use on a daily basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Composing Streams
&lt;/h2&gt;

&lt;p&gt;Streams have a key property that makes them perfectly suited to create applications: they can be composed, which means you can wrap many of them inside a larger stream which, seen from the outside, will also be a stream that in turn can be composed again, and again.&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%2Ft83u3a8ss84jxs15jsyi.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%2Ft83u3a8ss84jxs15jsyi.png" alt="A composite reactive stream" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is a Stream
&lt;/h2&gt;

&lt;p&gt;Back to the mantra of the paradigm. What does it mean that everything is a stream? Is that something like a "one size fits all" for programming?&lt;br&gt;
Essentially... yes.&lt;/p&gt;

&lt;p&gt;Everything stream-oriented programming is concerned about can be represented as a stream. A button, a textbox, a dialog box, a view, a page, a route, a router, an application.&lt;/p&gt;

&lt;p&gt;This is what makes stream-oriented programming as simple as building a house with LEGO bricks. They all fit together easily because they all have the same pluggable interface.&lt;br&gt;
Now, imagine using LEGO bricks if they all had slightly different sizes or shapes and you couldn't fit them together. That's object-oriented programming, or various other mixed paradigms. Every object has its own interface, its own methods with their names, their return values, or callbacks, getters and setters with various names, let alone sagas, stores, generators. You have to read the documentation of each, find the correct method to use, its parameters, its semantics. Sync methods work differently from async ones, some return promises, others return callbacks.&lt;/p&gt;

&lt;p&gt;In Stream-Oriented programming all streams have the same interface, &lt;code&gt;Stream&amp;lt;I,O&amp;gt;&lt;/code&gt;, so connecting them together becomes trivial.&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%2Fqa85pfo9ptgelxheghw1.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%2Fqa85pfo9ptgelxheghw1.png" alt="A dialog box is a stream in stream-oriented programming" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A collection of basic and advanced &lt;a href="https://stackblitz.com/orgs/github/ReactiveHTML/collections/dialog-boxes" rel="noopener noreferrer"&gt;Dialog Boxes&lt;/a&gt; demonstrates how those can be treated as streams and integrated in various UI scenarios.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Solving the "glue code" problem
&lt;/h2&gt;

&lt;p&gt;In a world where many objects each speak a different "language", creating an application means writing a log of "glue code" which is code that converts data emitted by one object and makes it usable in another, according to its semantics.&lt;br&gt;
A large amount of glue code necessarily means a larger bug surface and more code to maintain.&lt;/p&gt;

&lt;p&gt;Stream-Oriented programming solves this elegantly by making streams all speak the same language and letting frameworks take care of connecting them behind the scenes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Streams and Templates
&lt;/h2&gt;

&lt;p&gt;Streams on their own don't do anything. They are lazy, so they won't typically start processing any data until they get connected to the real world.&lt;/p&gt;

&lt;p&gt;This connection is what templates are for.&lt;/p&gt;

&lt;p&gt;A template is a declaration of where we want to connect our streams. &lt;a href="https://github.com/ReactiveHTML/reactive-markup" rel="noopener noreferrer"&gt;RML&lt;/a&gt; is an HTML-based template language designed to connect reactive streams in HTML.&lt;br&gt;
It allows you to put streams nearly anywhere and make them work with the DOM.&lt;/p&gt;

&lt;p&gt;The simplest example of a reactive stream in action is the classic "click-counter": a button that counts how many times you clicked it.&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;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;scan&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;rxjs&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;rml&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;rimmel&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;ClickCounter&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;count&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;BehaviorSubject&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;scan&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;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;scan&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;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&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;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rml&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;button onclick="&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="s2"&gt;"&amp;gt; click me &amp;lt;/button&amp;gt;

    count: &amp;lt;span&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="s2"&gt;&amp;lt;/span&amp;gt;
    double &amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;double&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/span&amp;gt;
    is even: &amp;lt;input type="checkbox" checked="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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="nc"&gt;ClickCounter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see this in action you can play with this &lt;a href="https://stackblitz.com/edit/click-counter-evenodd-double-rimmel" rel="noopener noreferrer"&gt;running example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The above was probably enough for a start, the rest is just larger components with more functionality, more streams and novel design patterns.&lt;/p&gt;

&lt;p&gt;To get started, you can learn more about the first JavaScript library for Stream-Oriented Programming, Rimmel.js, on Github or various posts here on dev.to&lt;/p&gt;

&lt;p&gt;Follow for more, reach out to say hi, show the world what you can do with streams before others!&lt;/p&gt;




&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2F539kd3bdsr9afxfhg75b.png" alt="You might actually not like React" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/you-might-not-actually-like-react-44b3"&gt;You might actually not like React&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fngt3gvs3j6asekv31yzu.png" alt="Effect Maps: How Stream-Oriented Programming rethinks effect management" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/effect-maps-how-stream-oriented-programming-rethinks-effect-management-1d7o"&gt;Effect Maps: How Stream-Oriented Programming rethinks effect management&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2F3tpwc24tp413pnj63dk5.png" alt="From Plain Functions to Reactive Streams: a mindset change with a thousand benefits" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/from-plain-functions-to-reactive-streams-a-mindset-change-with-a-thousand-benefits-aoa"&gt;From Plain Functions to Reactive Streams: a mindset change with a thousand benefits&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>functional</category>
    </item>
    <item>
      <title>Building a Stream-Oriented, Infinite-Scrolling DEV.to reader</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Sat, 11 Oct 2025 11:21:28 +0000</pubDate>
      <link>https://dev.to/dariomannu/building-an-infinite-scroll-devto-reader-in-the-stream-oriented-paradigm-1c8</link>
      <guid>https://dev.to/dariomannu/building-an-infinite-scroll-devto-reader-in-the-stream-oriented-paradigm-1c8</guid>
      <description>&lt;p&gt;This is a short, beginner-friendly walk-through for building an infinite scroll reader that loads articles from dev.to, showcasing Stream-Oriented Programming (SP).&lt;/p&gt;

&lt;p&gt;This is a great way to learn how streams can replace traditional event handlers, callbacks, and state variables with something cleaner and easier to reason about. You can run the full example here: &lt;a href="https://stackblitz.com/edit/dev-to-infinite-scroll-component" rel="noopener noreferrer"&gt;https://stackblitz.com/edit/dev-to-infinite-scroll-component&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why streams?
&lt;/h2&gt;

&lt;p&gt;Most UI frameworks revolve around components, lifecycle hooks, and state updates. &lt;a href="https://github.com/ReactiveHTML/rimmel" rel="noopener noreferrer"&gt;Rimmel.js&lt;/a&gt; is a stream-oriented UI library that takes a different approach: everything (user actions, async data, DOM updates) is treated as a stream of values that flow through transformations. Instead of thinking in terms of components "reacting" to events, you just describe how data moves. This eliminates glue code and makes your app easier to extend, debug, and test.&lt;/p&gt;

&lt;p&gt;In SP style, logic is expressed as data pipelines, not as nested callbacks with shared state. You get a clear separation between producers (events), transformers (logic), and consumers (UI updates).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Imports and a tiny Event Adapter
&lt;/h2&gt;

&lt;p&gt;Let’s start at the top of &lt;code&gt;main.ts&lt;/code&gt;. We import RxJS tools and Rimmel helpers.&lt;br&gt;
RxJS brings us essential stream operators like &lt;code&gt;scan&lt;/code&gt; (keep track of state as data flows through) and &lt;code&gt;concatMap&lt;/code&gt; (keep async events in the right order), while Rimmel lets us connect those streams directly to the DOM.&lt;/p&gt;

&lt;p&gt;Next comes a small but powerful pattern called &lt;a href="https://dev.to/dariomannu/using-event-mappers-with-rimmeljs-a-simple-introduction-1hj7"&gt;Event Adapter&lt;/a&gt;, which is used to turn the DOM's &lt;code&gt;Event&lt;/code&gt; objects into a predictable stream of data, in the exact format we want.&lt;br&gt;
We'll define one such event adapter called &lt;code&gt;Next&lt;/code&gt; that converts scroll events into sequential page numbers.&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;Next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputPipe&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&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;scan&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;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&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="mi"&gt;0&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;Before diving deeper, it’s important to understand what &lt;a href="https://dev.to/dariomannu/reverse-pipelines-of-reactive-streams-2nmb"&gt;&lt;code&gt;inputPipe&lt;/code&gt;&lt;/a&gt; really is. Unlike RxJS’s &lt;code&gt;.pipe()&lt;/code&gt; method, which applies transformations on the output of an Observable, &lt;code&gt;inputPipe&lt;/code&gt; is a Rimmel utility that sets up a pipeline on its input. It feeds a target stream with processed data as events occur. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why &lt;code&gt;scan&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;scan&lt;/code&gt; is an RxJS operator that keeps a running state over time, similar to &lt;code&gt;reduce&lt;/code&gt;, but for continuous streams. Here, it starts at 0 and increments each time the adapter receives an event. Instead of raw DOM events, we now get a stream of clean, numeric values: 0, 1, 2, 3… which represent page numbers to fetch. It’s a simple and declarative way to generate sequential data without mutable counters or shared state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: A simple article template
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;articleTemplate&lt;/code&gt; turns dev.to API results into HTML using Rimmel’s &lt;code&gt;rml&lt;/code&gt; syntax. It’s a pure function: data in, markup out.&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;articleTemplate&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tag_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;social_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&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;rml&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;article&amp;gt;
    &amp;lt;h3&amp;gt;&amp;lt;a href="&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="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;
    &amp;lt;img class="social-image" src="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;social_image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
    &amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;
    &amp;lt;div class="notes"&amp;gt;
      Tags: &amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tag_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="s2"&gt;&amp;lt;/span&amp;gt;
      &amp;lt;div&amp;gt;Posted by &amp;lt;a href="https://dev.to/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&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="s2"&gt;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/article&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: The page stream – fetching and rendering
&lt;/h2&gt;

&lt;p&gt;Now we define a stream named &lt;code&gt;page&lt;/code&gt;. It receives numbers (our page indexes) and emits HTML as output. Every time it gets a new number, it fetches that page from dev.to and turns the results into HTML.&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;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://dev.to/api/articles?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;per_page=10`&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="nf"&gt;concatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;posts&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;posts&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;articleTemplate&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&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="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLString&lt;/span&gt;&lt;span class="o"&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;Here’s what happens step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Subject&lt;/code&gt; is both an event receiver (Observer) and data emitter (Observable).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;concatMap&lt;/code&gt; ensures requests happen one after another, maintaining order. If page 3 starts before page 2 finishes, it waits, keeping results sequential.&lt;/li&gt;
&lt;li&gt;The second &lt;code&gt;concatMap&lt;/code&gt; unwraps the fetch &lt;code&gt;Response&lt;/code&gt; into JSON.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map&lt;/code&gt; transforms the JSON array into HTML via our template.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why &lt;code&gt;concatMap&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;concatMap&lt;/code&gt; is crucial for ordered async work. It queues up asynchronous operations (like fetches) and executes them in sequence. If you used &lt;code&gt;mergeMap&lt;/code&gt; or &lt;code&gt;switchMap&lt;/code&gt; instead, requests could overlap or cancel each other, breaking pagination. &lt;code&gt;concatMap&lt;/code&gt; ensures smooth, predictable flow (page 1, then page 2, then page 3) just as users expect when scrolling.&lt;/p&gt;

&lt;p&gt;This pipeline describes what to do with input numbers, not how or when. The order and timing are handled by the stream itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Connecting the UI
&lt;/h2&gt;

&lt;p&gt;The app template includes a &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; element and uses &lt;code&gt;AppendHTML&lt;/code&gt;: a Rimmel sink that appends whatever HTML the stream emits into the DOM.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;AppendHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&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;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don’t manually touch the DOM. When new HTML arrives, Rimmel will know how to update it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: The in-view marker that triggers new pages
&lt;/h2&gt;

&lt;p&gt;To make it scroll automatically, we use a custom element called &lt;code&gt;&amp;lt;inview-marker&amp;gt;&lt;/code&gt;. It emits an event when it enters the viewport. We connect that event to our &lt;code&gt;Next&lt;/code&gt; adapter so that every time the marker comes into view, the next page number flows through the pipeline.&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;inview&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt; &lt;span class="nx"&gt;oninview&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${Next(page)}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/inview-marker&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it: no scroll listeners, timers, or counters. Just streams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: The custom element logic
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;lib/in-view-marker.ts&lt;/code&gt;, we register the element and use the browser’s &lt;code&gt;IntersectionObserver&lt;/code&gt; API. When the element appears, it emits an &lt;code&gt;inview&lt;/code&gt; event.&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="nc"&gt;RegisterElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inview-marker&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;oninview&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;emit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oninview&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;load&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&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;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&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;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;emit&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;Event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;inview&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;observe&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="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rml&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;marker rml:onmount="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&amp;lt;/marker&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;This small bridge connects browser visibility events to your reactive stream world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Bootstrapping the app
&lt;/h2&gt;

&lt;p&gt;Finally, the app mounts itself by setting its root element’s &lt;code&gt;innerHTML&lt;/code&gt; to the Rimmel template output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.getElementById('app').innerHTML = App();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is reactive from that point forward. The first page loads, the marker enters view, and new pages stream in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this pattern improves code quality
&lt;/h2&gt;

&lt;p&gt;There’s no tangled state or complex lifecycle management. Each piece does one thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The adapter converts events into numbers.&lt;/li&gt;
&lt;li&gt;The stream defines how data flows.&lt;/li&gt;
&lt;li&gt;The sink updates the DOM.&lt;/li&gt;
&lt;li&gt;The marker triggers when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because every link in the chain is declarative, the behaviour is transparent and easy to debug. If you ever want to change behaviour—like preloading or adding filters—you modify one stream operator instead of rewriting your UI logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it live
&lt;/h2&gt;

&lt;p&gt;Try the complete demo here: &lt;a href="https://stackblitz.com/edit/dev-to-infinite-scroll-component" rel="noopener noreferrer"&gt;https://stackblitz.com/edit/dev-to-infinite-scroll-component&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down and watch new posts load automatically, one clean stream at a time.&lt;/p&gt;




&lt;p&gt;If you appreciate the clean, modern approach of the stream-oriented paradigm, join a growing community of forward-thinking developers and give the project a &lt;a href="https://github.com/reactivehtml/rimmel" rel="noopener noreferrer"&gt;⭐&lt;/a&gt; on GitHub&lt;/p&gt;




&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fngt3gvs3j6asekv31yzu.png" alt="Effect Maps: How Stream-Oriented Programming rethinks effect management" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/effect-maps-how-stream-oriented-programming-rethinks-effect-management-1d7o"&gt;Effect Maps: How Stream-Oriented Programming rethinks effect management&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fofc5jmb0bnr33egbuilv.png" alt="Lit vs Rimmel: tagged templates in OOP vs SP" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/lit-vs-rimmel-comparing-tagged-template-ui-libraries-o1d"&gt;Lit vs Rimmel: tagged templates in OOP vs SP&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fw9vxrmc6msch71ypvxd8.png" alt="Stream Oriented Programming: an introduction" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/streams-oriented-programming-1d63"&gt;Stream Oriented Programming: an introduction&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>tutorial</category>
      <category>frontend</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>From Plain Functions to Reactive Streams: a mindset change with a thousand benefits</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Wed, 08 Oct 2025 12:57:02 +0000</pubDate>
      <link>https://dev.to/dariomannu/from-plain-functions-to-reactive-streams-a-mindset-change-with-a-thousand-benefits-aoa</link>
      <guid>https://dev.to/dariomannu/from-plain-functions-to-reactive-streams-a-mindset-change-with-a-thousand-benefits-aoa</guid>
      <description>&lt;p&gt;Functions have been at the core of computer programming since the dawn of time. From the simplest &lt;code&gt;arguments in -&amp;gt; results out&lt;/code&gt; pure functions to async functions that return future values, to reentrant generators that can dynamically produce any number of results over time, sync or async.&lt;/p&gt;

&lt;p&gt;There is one thing functions share in common: they lack any sort of event awareness.&lt;/p&gt;

&lt;p&gt;Bad news in a world where literally everything revolves around events and a whole chain of reactions to be executed in response: a button click, a file upload, a form submission, a page refresh or a ticking timer.&lt;/p&gt;

&lt;p&gt;Streams can handle a multitude of events in input, perform some processing and emit some results. They can take the output of other streams as their own input and compose up new derived streams.&lt;/p&gt;

&lt;p&gt;A great analogy can be drawn with water pipelines or electrical circuits. Reactive streams treat data just like pipeline channel water and circuits enable the controlled flow of electricity.&lt;/p&gt;

&lt;h2&gt;
  
  
  From simple function to simple stream
&lt;/h2&gt;

&lt;p&gt;Let's take a function that returns its argument doubled:&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;// imperative&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An equivalent reactive stream that takes numbers and emits double the input value looks something like this:&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;// stream-oriented&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;double&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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;pipe&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may have noticed how streams take a single parameter, which seems a bit of a limitation given that functions can take many. This can be mitigated by passing objects instead of plain values and in practice, given that a stream should represent a single "thing", this won't even feel like a limitation.&lt;/p&gt;

&lt;p&gt;The difference is small, subtle, but fundamental. In the former case it's an imperative call that triggers the function and handles the result, in the latter case, the stream is something that can be fed and subscribed to, ideally by the framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  From async functions to streams
&lt;/h2&gt;

&lt;p&gt;The difference between sync or async streams is not as critical as it is between functions and async functions. At the end of the day, you combine streams the same way with the same operators (such as &lt;code&gt;zip&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt;, &lt;code&gt;withLatestFrom&lt;/code&gt;, etc) in a seamless way.&lt;/p&gt;

&lt;p&gt;Perhaps one little exception is when you use promises inside streams. Say you have one that calls an API and propagates its results. You can't just use the &lt;code&gt;map&lt;/code&gt; operator, as it would not wait for any &lt;code&gt;fetch()&lt;/code&gt; call to resolve. What you want to use instead is the &lt;code&gt;switchMap&lt;/code&gt; operator, which also cancels any in-flight operation before starting the new one.&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;// imperative&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getData&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="nx"&gt;number&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="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/data/&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="s2"&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;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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 javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// stream-oriented&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;number&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;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/data/&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="s2"&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;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;Actually this is an overly simplified example, because there's so much more to using &lt;code&gt;fetch&lt;/code&gt; and handling errors, but we only wanted to focus on the structure now and how to get from an async function to a stream. There is a &lt;a href="https://stackblitz.com/orgs/github/ReactiveHTML/collections/fetching-data" rel="noopener noreferrer"&gt;collection of examples&lt;/a&gt; showing how to fetch data and handle retries and errors. Perhaps we'll write about those in more detail some day.&lt;/p&gt;

&lt;p&gt;So, what's the key difference, in summary? In one case, in the imperative paradigm, you "call" the &lt;code&gt;getData()&lt;/code&gt; function and await the result. In the stream-oriented paradigm, you don't call anything. You only create pure streams and declare how you'd like those to be called. An example could be like the click on a button triggers the stream and its output goes into a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; somewhere on the page. HTML templates serve this exact purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of thinking in streams
&lt;/h2&gt;

&lt;p&gt;Embracing streams over traditional functions brings several practical and architectural benefits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Event awareness and composability.&lt;/strong&gt; Streams integrate seamlessly with events, which are the backbone of interactive systems. They let you model complex workflows as a network of dataflows rather than a series of callbacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. True asynchronicity.&lt;/strong&gt; Streams naturally handle asynchronous data over time without forcing developers into nested &lt;code&gt;then&lt;/code&gt; chains or async/await boilerplate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Declarative clarity.&lt;/strong&gt; Instead of describing &lt;em&gt;how&lt;/em&gt; to react to each event, you define &lt;em&gt;what&lt;/em&gt; should happen when it does. This leads to more maintainable, predictable, and testable code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Error resilience and recovery.&lt;/strong&gt; Operators like &lt;code&gt;catchError&lt;/code&gt;, &lt;code&gt;retry&lt;/code&gt;, or &lt;code&gt;switchMap&lt;/code&gt; give you built-in tools to manage transient errors or cancellation logic gracefully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Framework synergy.&lt;/strong&gt; Modern UI and data frameworks—especially those aligned with reactive programming—can automatically connect streams to views, enabling state updates without explicit imperative glue code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Better scalability.&lt;/strong&gt; As systems grow, adding new event sources or transformations doesn't require changing existing logic. Streams let you plug in new flows like components in a circuit.&lt;/p&gt;

&lt;p&gt;By shifting from functions to streams, you're no longer writing programs that merely execute from top to bottom; you're designing living systems that react, evolve, and adapt continuously in response to their environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fw9vxrmc6msch71ypvxd8.png" alt="Stream-Oriented Programming: An Introduction" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/streams-oriented-programming-1d63"&gt;Stream-Oriented Programming: An Introduction&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fx069m14p07arbmrwk7ej.png" alt="Contrarian JavaScript Frameworks: The Top 3" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/3-contrarian-js-frameworks-58fm"&gt;Contrarian JavaScript Frameworks: The Top 3&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2F9dghzt1pd1oujog7zgzp.png" alt="A Stream-Oriented App — building in public" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/a-stream-oriented-app-building-in-public-53kj"&gt;A Stream-Oriented App — building in public&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>streamorientedprogramming</category>
    </item>
    <item>
      <title>A Messagebus? Using Observable Streams? https://stackblitz.com/edit/tops-example #JavaScript #WebDev #WebDevelopment #FrontEnd #RxJS</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Mon, 15 Sep 2025 19:52:06 +0000</pubDate>
      <link>https://dev.to/dariomannu/a-messagebus-using-observable-streams-httpsstackblitzcomedittops-example-javascript-n3o</link>
      <guid>https://dev.to/dariomannu/a-messagebus-using-observable-streams-httpsstackblitzcomedittops-example-javascript-n3o</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://stackblitz.com/edit/tops-example" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;stackblitz.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Why Angular Isn’t the Observable Framework You Think It Is</title>
      <dc:creator>Dario Mannu</dc:creator>
      <pubDate>Sat, 13 Sep 2025 17:55:23 +0000</pubDate>
      <link>https://dev.to/reactivehtml/why-angular-isnt-the-observable-framework-you-think-it-is-56a3</link>
      <guid>https://dev.to/reactivehtml/why-angular-isnt-the-observable-framework-you-think-it-is-56a3</guid>
      <description>&lt;p&gt;When many developers hear "observables", one framework often jumps to mind: Angular. It’s been closely tied to RxJS for years, marketed as the reactive framework of choice.&lt;/p&gt;

&lt;p&gt;But here’s the catch: Angular doesn’t actually live in the observable world. Instead, it constantly forces you to switch gears — juggling RxJS streams on one side, and its own reactivity model (async pipes, now signals) on the other.&lt;/p&gt;

&lt;p&gt;And that’s where the cracks start to show.&lt;/p&gt;

&lt;p&gt;You’re wiring async pipes everywhere.&lt;/p&gt;

&lt;p&gt;You’re managing BehaviorSubjects by hand.&lt;/p&gt;

&lt;p&gt;You always have to unsubscribe.&lt;/p&gt;

&lt;p&gt;And now, with signals, you’re asked to learn yet another reactive abstraction.&lt;/p&gt;

&lt;p&gt;It’s not seamless. It’s not elegant. And it’s certainly not the pure observable experience RxJS developers dream about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Rimmel.js: Built on Streams from Day One
&lt;/h2&gt;

&lt;p&gt;Imagine a UI library where you don’t need two paradigms. Where event sources and data sinks just bind to streams and your UI is simply a declarative destination for your data. That’s what Rimmel.js was designed to do.&lt;/p&gt;

&lt;p&gt;This isn’t Angular with a bolt-on async pipe. This is [stream-oriented programming] — where observables aren’t guests at the table, they are the table.&lt;/p&gt;

&lt;p&gt;And the difference is dramatic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular vs Rimmel in Practice
&lt;/h2&gt;

&lt;p&gt;Counter Example&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/~/github.com/zeekrey/stackblitz-angular-simple-counter?file=src/main.ts" rel="noopener noreferrer"&gt;Angular version&lt;/a&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&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-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;button (click)="increment()"&amp;gt;+&amp;lt;/button&amp;gt;
    &amp;lt;span&amp;gt;{{ count$ | async }}&amp;lt;/span&amp;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;CounterComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;count&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;BehaviorSubject&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;count$&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;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&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="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="nf"&gt;next&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="nx"&gt;value&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackblitz.com/edit/click-counter-rimmel" rel="noopener noreferrer"&gt;Rimmel.js version&lt;/a&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;Counter&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;total&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;BehaviorSubject&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="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;scan&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;=&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;x&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rml&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;button onclick="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
      click me &amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/span&amp;gt;
    &amp;lt;/button&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;No async pipes. No imperative methods. Just streams, neatly and directly connected to the UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular Signals vs Rimmel Observables
&lt;/h2&gt;

&lt;p&gt;Angular’s recent push for signals looks shiny at first glance. They promise "fine-grained reactivity" and "fewer recalculations". But here’s what actually happens:&lt;/p&gt;

&lt;p&gt;You now have two reactive paradigms: signals and RxJS.&lt;/p&gt;

&lt;p&gt;Data from an observable still has to be bridged into a signal.&lt;/p&gt;

&lt;p&gt;Events from your UI still go through imperative steps.&lt;/p&gt;

&lt;p&gt;Your app ends up with split logic: streams for async work, signals for rendering.&lt;/p&gt;

&lt;p&gt;You learn one reactive model, then constantly translate it into another.&lt;/p&gt;

&lt;p&gt;That’s unnecessary complexity.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://github.com/reactivehtml/rimmel" rel="noopener noreferrer"&gt;Rimmel.js&lt;/a&gt;, you don’t need signals at all. Observables are already expressive, composable, and powerful enough to handle both async data and complex state. By cutting out the extra layer, you stay in one mental model: streams in, streams out.&lt;/p&gt;

&lt;p&gt;The result? Code that feels neat, light, direct, and more predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Developers
&lt;/h2&gt;

&lt;p&gt;Rimmel.js gives you:&lt;/p&gt;

&lt;p&gt;True first-class observables. No pipes, no wrappers.&lt;/p&gt;

&lt;p&gt;Cleaner code. Every part of your app speaks one language: streams.&lt;/p&gt;

&lt;p&gt;Future-proof thinking. Stream-oriented programming scales elegantly with complexity.&lt;/p&gt;

&lt;p&gt;Instant familiarity. If you know RxJS, you already know most of Rimmel.js.&lt;/p&gt;

&lt;p&gt;Instead of wrestling with multiple reactivity systems, you can finally focus on what matters: building features, not boilerplate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Angular might be the framework you think of when you think "observables", but the reality is that Angular’s observable support is skin-deep. It keeps you juggling async pipes, signals, and RxJS — a constant context-switching tax.&lt;/p&gt;

&lt;p&gt;Rimmel.js flips that script. By embracing a stream-oriented paradigm, it turns observables into the natural fabric of your application. Your knowledge of RxJS doesn’t just transfer — it thrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More
&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;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Ffvz4rupi0mx6303ghwc2.png" alt="A Web Developer's guide to Stream-Oriented Programming" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/a-senior-developers-guide-to-stream-oriented-programming-3j24"&gt;A Web Developer's guide to Stream-Oriented Programming&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2Fb6dvvnukpwoz5icojypx.png" alt="Web Components with one Simple Function" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/web-components-without-classes-34hb"&gt;Web Components with one Simple Function&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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%2F91ud88tyrxcjez7vkph4.png" alt="From callbacks to callforwards: reactivity made simple?" width="64" height="64"&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://dev.to/dariomannu/from-callbacks-to-callforwards-a-simple-solution-to-reactivity-3l5e"&gt;From callbacks to callforwards: reactivity made simple?&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
