<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://justinfagnani.com/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Justin Fagnani</title>
    <link>https://justinfagnani.com/</link>
    <atom:link href="https://justinfagnani.com/rss/index.xml" rel="self" type="application/rss+xml" />
    <description>Programming and things</description>
    <language>en</language>
    <item>
      <title>What should a native DOM templating API look like?</title>
      <link>https://justinfagnani.com/2025/06/30/what-should-a-dom-templating-api-look-like/</link>
      <description>&lt;p&gt;If you read my previous post, &lt;a href=https://justinfagnani.com/2025/06/26/the-time-is-right-for-a-dom-templating-api/ &gt;The time is right for a DOM templating API&lt;/a&gt;, you might be wondering what such an API would look like.&lt;/p&gt;&lt;p&gt;Let&#39;s dive into that question now.&lt;/p&gt;&lt;h2&gt;What are we building?&lt;/h2&gt;&lt;p&gt;First, let&#39;s clarify what we&#39;re trying to design here, because when people hear the abstract template API idea described, before there&#39;s a concrete proposal or examples, they can sometimes think of very different things.&lt;/p&gt;&lt;p&gt;In &lt;a href=https://github.com/WICG/webcomponents/issues/1069&gt;webcomponents/1069&lt;/a&gt; I propose that we add a &quot;declarative JavaScript templating API&quot;&lt;/p&gt;&lt;p&gt;Declarative means that the developer is describing &lt;em&gt;what&lt;/em&gt; they want, not &lt;em&gt;how&lt;/em&gt; to achieve it. What exactly constitutes &quot;declarative&quot; is often debatable, and under every declarative API is an imperative implementation, but hopefully people can align on the spirit of the word.&lt;/p&gt;&lt;p&gt;By &quot;templating&quot; we mean the ability to describe the DOM that the developer wants to create and update in a form that resembles the output. This includes syntaxes like JSX and lit-html, which for some people count as something other than templating. For our purposes, they are.&lt;/p&gt;&lt;p&gt;Taken together, &quot;declarative DOM templating&quot; is something that is very, very common. All major frameworks today have declarative templating at their core.&lt;/p&gt;&lt;p&gt;But we&#39;re going to narrow our focus a bit &lt;em&gt;JavaScript&lt;/em&gt; APIs.&lt;/p&gt;&lt;p&gt;By &quot;JavaScript API&quot; we mean methods, classes, etc. that are part of the overall DOM JavaScript API surface. Something that&#39;s a sibling and alternative to &lt;code&gt;innerHTML&lt;/code&gt;, &lt;code&gt;importNode()&lt;/code&gt;, and a bunch of other DOM APIs that web developers and frameworks use to create and update DOM. But also, we mean that script-like abilities will be left to JavaScript, not added to markup.&lt;/p&gt;&lt;p&gt;It&#39;s also important to not that we&#39;re not talking about components at all, just templated DOM creation and updating. Most frameworks intertwine the two concepts, so some people aren&#39;t aware that there can be a distinction. One of the use cases for this proposal is to be a primitive that frameworks can use, so it&#39;s necessary that components can be added on top of templates, but any such feature to do that should be as generic and minimal as possible.&lt;/p&gt;&lt;h2&gt;What&#39;s guiding us?&lt;/h2&gt;&lt;p&gt;In my experience, we can derive the general API shape for this feature from its constraints and requirements, with a dash of opinion about good APIs on top. Listing these helps us see what things must be a certain way vs which things can flex as part of the decision space for the problem.&lt;/p&gt;&lt;h3&gt;Constraints&lt;/h3&gt;&lt;p&gt;Because we&#39;re designing a native DOM API, and not a framework, we have more constraints to deal with. A native API has to work within the current platform, can&#39;t break existing sites, and has to be viable within the standards process.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Web compatibility: The proposal can&#39;t introduce any breaking changes to the platform.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Standard file types: While a proposal could introduce a new file type just for templates, that&#39;s unlikely to make it through the web standards process without incredibly compelling reasons. We&#39;ll take using the existing file types as a hard constraint.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Standard JavaScript: It&#39;s also possible to try to simultaneously introduce changes to both the DOM and JavaScript, but this is also less likely to succeed because we would be dealing with two separate standards bodies and a much larger overall addition to the platform.&lt;/p&gt;&lt;p&gt;JavaScript is not just a web language anymore, and the JavaScript side would likely have to be useful for non-web use-cases to move forward, dramatically raising the complexity of a proposal.&lt;/p&gt;&lt;p&gt;So we&#39;ll also take it as a hard constraint that this API works with today&#39;s standard JavaScript.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Low implementation security risk: The proposal should not require drastic and potentially-unsafe HTML parser changes. Implementors are just extremely reluctant to make large HTML parser changes, since they are prime targets for attackers and previous changes (like &lt;code&gt;&amp;lt;template&gt;&lt;/code&gt;) &lt;em&gt;did&lt;/em&gt; introduce security bugs.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;No performance regressions on existing sites. Slowing down existing sites, or benchmarks like Speedometer, will sink a proposal when it&#39;s implemented.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Security: New APIs have a much higher security bar to clear than previous platform changes. They need to be secure by default.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;No required compiler: This is not universal, but many web platform maintainers insist that web APIs should be directly usable by developers and not require a compiler to be useful. This does not preclude an API from being a good compile target for alternate syntaxes.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Coherence with the platform. Also not universal, but it will be drastically easier to get a proposal accepted if it&#39;s coherent with the existing platform. This would prevent us from introducing a new &quot;better DOM&quot;, for instance.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Requirements&lt;/h3&gt;&lt;p&gt;Next we need to look at our requirements. What does this proposal have to do to be useful and successful? The actual proposal will need to detail its target use cases, but we can list some requirements now:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ergonomic API: This API should be nice to use directly for developers.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Usable from JavaScript libraries: Libraries should be able to adopt this API as an internal implementation helper.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;JavaScript for control flow and expressions: We don&#39;t want to introduce a new JavaScript-like expression language. That would increase the size of the proposal, be less likely to get agreement on, and introduce security concerns.&lt;/p&gt;&lt;p&gt;It would also introduce a different lexical environment that developers would have to get their data into. It&#39;s much easier on developers and tooling if template expressions exist within the same lexical scope as their data.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Ability to set attributes, properties, and event listeners: DOM elements have three major key/value style APIs that developers are used to setting declaratively from templates. Because these APIs are truly independent in the DOM, we require the ability to set them each unambiguously.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Support full HTML syntax: elements, attributes, children, comments, etc. We need to be able to create any structure that can be created with HTML.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Security: More specific than the platform constraint, we need templates to be safe from XSS and gadget attacks, etc.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Performance: The API must be fast for initial rendering and updates with DOM stability.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Composability: Developers should be able to build templates from pieces, and abstract over templates and rendering.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Extensibility: One template API is not going to be able to have every feature that all developers need. It needs to have hooks for extending the system with new behavior.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Open to evolution and extension of HTML and the DOM: The system should assume that the platform will evolve and that elements, attributes, and events can be added in userland. It should avoid special casing specific DOM elements and attributes.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Opinions&lt;/h3&gt;&lt;p&gt;Then we have opinions, which people might or might not agree with. Things that make the API good, elegant, maximally general and flexible. These are my personal opinions, but I hope they&#39;re very reasonable and shared by a lot of other people.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The APIs should work with functional-style programming. One of the motivating reasons to have a declarative template API is to reduce the amount of imperative code need to build UIs. An API compatible with function-style programming can still be used in imperative contexts.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Composition should be a core feature that other features are built on. For example, instead of specific and special constructs for conditionals and loops, we should be able to rely on JavaScript and composition to dynamically construct a template.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The underlying DOM creation approach should be HTML template cloning. HTML templates - the &lt;code&gt;&amp;lt;template&gt;&lt;/code&gt; tag has a few performance advantages over other DOM creation approaches. &lt;code&gt;&amp;lt;template&gt;&lt;/code&gt;s can use a simpler HTML parser, and cloning nodes is faster than re-parsing HTML as needed with &lt;code&gt;innerHTML&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The API should support support multiple models of reactivity and DOM updates, possibly through userland extension.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Template re-rendering should be a core supported feature because it is extremely fast and generalizes to many types of data.&lt;/li&gt;&lt;li&gt;Fine-grained reactivity should be supported for native observable data types, which will hopefully soon include Signals.&lt;/li&gt;&lt;li&gt;DOM diffing with various algorithms should be possible to add with userland utilities.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The API should have good layering. DOM update mechanisms should utilize lower-level platform APIs, like DOM Parts and a tree-aware task scheduler, that can be used by libraries that aren&#39;t using the templating API.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The API should not introduce any new component abstractions, but it should have stateful hooks that allow a framework to easily attach their own component instances to the DOM.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Template syntax&lt;/h2&gt;&lt;p&gt;In &lt;a href=https://justinfagnani.com/2025/06/26/the-time-is-right-for-a-dom-templating-api/ &gt;my previous post&lt;/a&gt; I made the claim that we know what good template syntax looks like. While some people took exception with that claim, I stand by it because of how fundamentally similar all the popular template syntaxes are. The claim is even stronger when considering JavaScript-based APIs.&lt;/p&gt;&lt;p&gt;The core similarity is that HTML templates are all markup with interpolations and control flow.&lt;/p&gt;&lt;p&gt;Compare:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;React&lt;pre class=language-tsx&gt;&lt;code class=language-tsx&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Click Me&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Vue&lt;pre class=language-html&gt;&lt;code class=language-html&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ name }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;@click&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click Me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;v-for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;item in items&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      {{ item.message }}
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Angular&lt;pre class=language-html&gt;&lt;code class=language-html&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ name }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;(click)&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;handleClick()&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click Me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    @for (item of items) {
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        {{ item.message }}
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    }
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Lit&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;h1&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/h1&gt;
  &amp;lt;button @click=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;handleClick&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;Click Me&amp;lt;/button&gt;
  &amp;lt;ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;li&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/ul&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Polymer&lt;pre class=language-html&gt;&lt;code class=language-html&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{{ name }}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;on-click&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Click Me&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dom-repeat&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{{ items }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token attr-name&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        {{ item.message }}
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;li&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;FAST&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;html&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;MyElement&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;h1&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/h1&gt;
  &amp;lt;button @click=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;Click Me&amp;lt;/button&gt;
  &amp;lt;ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; html&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;li&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; i&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/ul&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To me, these &lt;em&gt;are&lt;/em&gt; in fact very similar:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The HTML portion is described in markup&lt;/li&gt;&lt;li&gt;Bindings can appear in text and attribute value positions&lt;/li&gt;&lt;li&gt;Bindings expressions are (usually) delimited by some kind of separator&lt;/li&gt;&lt;li&gt;Control flow can conditionally render a subtree/sub-template&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Yes, there are some differences.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Different expression delimiters&lt;/li&gt;&lt;li&gt;Some systems delimit all expressions, some don&#39;t in certain cases (bound attributes)&lt;/li&gt;&lt;li&gt;Expression language differences&lt;/li&gt;&lt;li&gt;Property and event listener delineation&lt;/li&gt;&lt;li&gt;Control flow: attributes (directives), templates, non-markup syntax, control-flow-is-JS-expressions&lt;/li&gt;&lt;li&gt;Some template-literal-based systems require bindings to contain closures.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I personally don&#39;t think these differences are actually all that big. Most of them are surface syntax.&lt;/p&gt;&lt;p&gt;The biggest difference in my mind are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Whether the syntax is HTML-based or JavaScript-based&lt;/li&gt;&lt;li&gt;Control flow syntax and placement among the HTML-based syntaxes&lt;/li&gt;&lt;li&gt;Whether bindings require closures in JavaScript-based syntaxes&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;When we narrow our choices based on the fact that we and proposing a JavaScript API, most of the differences fall away. Expressions are JS, control flow is just expressions, expression delimiters are fixed.&lt;/p&gt;&lt;h2&gt;Template expressions&lt;/h2&gt;&lt;p&gt;One of my strongly held opinions in this area is that templates should be side-effect free expressions that return a value that describes the intended DOM. This is a functional-style API that&#39;s extremely flexible and simple. This is what most JSX transforms (ie, React&#39;s) do, what Lit does, and most other templates-in-JS systems do.&lt;/p&gt;&lt;p&gt;In addition, I believe that template expressions should be able to be re-evaluated to generate a new description of DOM, also how React and Lit work. This ensures that any data available in the lexical scope of the template can be consumed by templates, and any trigger that indicates that data has changed can be used to initiate a template re-evaluation.&lt;/p&gt;&lt;p&gt;The approach of expressions generating descriptions of DOM lends itself to a wide variety of powerful techniques.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Abstraction: template results can be evaluated and returned by functions, accepted by functions, and computed over. It enables patterns like higher-order templates and render props.&lt;/li&gt;&lt;li&gt;Transformation: Utilities can walk over the DOM description and transform it into a different description.&lt;/li&gt;&lt;li&gt;Lazy evaluation: template expressions naturally work with lazily evaluated JavaScript constructs like ternaries, short-circuiting operators, defaults for parameters and object destructuring.&lt;/li&gt;&lt;li&gt;Alternate render functions: The process of rendering a DOM description isn&#39;t locked off to platform code. Alternate ways of applying a description to live DOM, like DOM morphing libraries, can take these DOM descriptions and render them in userland. This can even be a means of polyfill future new features of the template system.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Alternatives to template expressions&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Static template definitions. This is how FAST, Polymer, Angular, and some others work. A template is a property of a component class, and is interpreted by the component instances. I believe this ties templates and components too closely together for a native API, and instead of just accessing variables in a JavaScript lexical scope (ie, function scope or class instance scope in a method) expressions have to be bound to some scope object, which make this not play very well with plain functions and functional style programming.&lt;/li&gt;&lt;li&gt;Side-effectful statements. These mutate DOM as they are evaluated. Google&#39;s internal framework, Wiz, worked this way when I left the company. It seemed to me to cause a lot friction for abstraction, as there was no way to programmatically access the template definition or result. The best you could do is pass around an opaque closure with the instructions in it.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Template container syntax.&lt;/h2&gt;&lt;p&gt;Aside from the internal template syntax, like bindings and such, we need a container for templates. Let&#39;s look at the relevant constraints and requirements:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;No compiler required, only standard syntax&lt;/li&gt;&lt;li&gt;Templates resemble output, ie markup&lt;/li&gt;&lt;li&gt;Full support for HTML&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This first constraint rules out using JSX (until and unless JSX becomes a standard). And without JSX, the next two items pretty much require that our templates be contained in strings. Nested function calls (like React&#39;s &lt;code&gt;createElement()&lt;/code&gt; or Hyperscript&#39;s &lt;code&gt;h()&lt;/code&gt;) or object-based builder-style APIs just don&#39;t look enough like HTML.&lt;/p&gt;&lt;p&gt;So we want the HTML portion of a template to be strings, like:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;h1&gt;Hello World&amp;lt;/h1&gt;&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But we also need a way to include expressions, and one of our requirements is that we use JavaScript instead of a new expression language.&lt;/p&gt;&lt;p&gt;This rules out something like:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;h1&gt;Hello {{ name }}&amp;lt;/h1&gt;&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;because this &lt;code&gt;{{ name }}&lt;/code&gt; bit is inside the string and can&#39;t reference variables in the containing JavaScript scope. You could try to do a format-string style of API with a separate data bag of named parameters:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;h1&gt;Hello {{ name }}&amp;lt;/h1&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;World&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;but that&#39;s pretty ugly, and JavaScript has much a nicer syntax for doing this same thing already!&lt;/p&gt;&lt;h3&gt;Tagged template literals&lt;/h3&gt;&lt;p&gt;The most straightforward way to embed markup in standard JavaScript is with &lt;a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&gt;tagged template literals&lt;/a&gt;. In fact, embedding a DSL like HTML in JavaScript is exactly what tagged template literals were designed for - and they have some special features to make doing so efficient and safe.&lt;/p&gt;&lt;p&gt;We&#39;ll call our tag the most obvious thing: &lt;code&gt;html&lt;/code&gt;. Templates expressions are then template literals tagged with the &lt;code&gt;html&lt;/code&gt; tag:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;div&gt;Hello World&amp;lt;/div&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This ends up looking a lot like JSX, but with the markup inside of a string instead of as part of the outer language grammar.&lt;/p&gt;&lt;p&gt;With tagged template literals, our expression delimiter syntax is chosen for us: &lt;code&gt;${}&lt;/code&gt;. So expressions look like:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;div&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/div&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Benefits of tagged template literals&lt;/h3&gt;&lt;p&gt;It&#39;s worth taking a moment to talk about tagged template literals, because I think they&#39;re one of the least appreciated and understood parts of ES2015.&lt;/p&gt;&lt;p&gt;Like I said above, tagged template literals were specifically designed to enable embedding of external DSLs (like HTML, SQL, or GraphQL) into JavaScript, and they have a few features that make this possible.&lt;/p&gt;&lt;p&gt;A tagged template literal is prefixed by a reference to a tag function, and a tag function has this signature:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;strings&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TemplateStringsArray&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(where &lt;code&gt;R&lt;/code&gt; is the return type of the specific tag function)&lt;/p&gt;&lt;p&gt;The important features for DSLs:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;The tag function receives the static strings and values separately.&lt;/p&gt;&lt;p&gt;This means that we can process the static strings and values separately, which is great for both performance and security. We can skip most work for the static strings, and use them to make a cloneable &lt;code&gt;&amp;lt;template&gt;&lt;/code&gt; element. We trust the static strings as developer-authored and allow them to create HTML; we distrust the values as potentially user-controlled and make the browser escape them before inserting into the DOM.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The tag function can return any type of value, not only strings.&lt;/p&gt;&lt;p&gt;This means that while template expressions may look a lot of string interpolation, they are quite a bit more powerful. Our &lt;code&gt;html&lt;/code&gt; tag will simply return an object holding the static strings and the values.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The static strings array passed to the tag function is the &lt;em&gt;same&lt;/em&gt; array instance every time a tagged template literal is evaluated.&lt;/p&gt;&lt;p&gt;This is a little subtle. If you have a tagged template literal expression that can be evaluated multiple time, say if it&#39;s in a function that&#39;s called multiple times, that the tag function will receive the same strings array on every evaluation.&lt;/p&gt;&lt;p&gt;Here&#39;s a simple example:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token comment&quot;&gt;// A template tag function that simply returns the strings array&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;tag&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;strings&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// A function that evaluates returns the result of tag&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; tag&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;abc &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;x&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; def&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This means that we can perform one-time setup work based on the strings, and then use the strings array as a cache key to retrieve that work on future evaluations. We can also use the strings array as a key to check whether a template has already been been rendered to a DOM location so that we only update the changed values.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The tag can identify the embedded language. Any template literal using the tag &lt;code&gt;html&lt;/code&gt; contains HTML. Lots of IDEs and other tools key off of the tag name to automatically give developers syntax highlighting and other checks.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Downsides of tagged template literals&lt;/h3&gt;&lt;p&gt;Of course, tagged template literals aren&#39;t &lt;em&gt;perfect&lt;/em&gt;, otherwise there&#39;s a good chance that the React team would have used them instead of inventing JSX. Two things that may or may not matter much depending on your personal preferences are related to verbosity:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;More symbols than JSX for templates and bindings. The &lt;code&gt;html&lt;/code&gt; tag and backticks are 6 more characters per template expression than JSX with one root element, though only one more character for a JSX expression wrapped in a fragment. The binding delimiter of &lt;code&gt;${}&lt;/code&gt; is one more character than &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Verbose for userland components. This one is more significant. In tagged template literals, element names are strings in the static side of the template. This means they can&#39;t hold JavaScript references to component definitions. String tage names work well with custom elements because components, like &lt;code&gt;&amp;lt;my-element&gt;&lt;/code&gt;, are registered by name. For JSX-style references you would need to use binding syntax like &lt;code&gt;&amp;lt;${MyComponent}&gt;&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This is why it&#39;s important that this template API can be a good compile target for JSX. If we want userland component systems to be able to use the API, they will need to allow their users to write templates in their most preferred syntax, and can then compile to something that may require more characters.&lt;/p&gt;&lt;p&gt;By the way, JSX&#39;s convention of capitalized tag names being JS references and lower-cased names being string literals is one of my biggest worries about the standardization of JSX. I haven&#39;t heard anyone on TC39 opine on this yet, but it seems like the kind of odd rule that works well enough in practice, but that some people will object to. It&#39;s entirely possible that to make it through standardization a proposal would need a more explicit differentiator between strings and references anyway.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Aren&#39;t strings bad?&lt;/h3&gt;&lt;p&gt;Some people critique lit-html and similar APIs as being too &quot;string based&quot;. The complaint being that a string can contain anything and isn&#39;t checked for correctness by JavaScript parsers. I think this complaint is usually overblown. All programming languages are strings. JavaScript, HTML, and CSS are strings. What makes them structured languages are their grammars and tools that understand them.&lt;/p&gt;&lt;p&gt;This holds true for these tagged template literals. There is a syntax and grammar to them, which is just standard HTML and can be checked by tools and runtimes. Developers who use these style of templates today usually add editor and compiler extensions to their toolchain to give them all the benefits of good PL tools support: syntax highlighting, syntax checking, type-checking, intellisense, linting, and formatting.&lt;/p&gt;&lt;p&gt;The biggest difference between an embedded syntax like this and an extension syntax like JSX is that in the actual browser runtime syntax errors will happen at template expression evaluation time rather than module parse time. This difference should be mitigated by edit and built-time tools that check template syntax.&lt;/p&gt;&lt;h2&gt;Bindings and template parts&lt;/h2&gt;&lt;p&gt;Because we have static template vs dynamic expression separation, we can mark exactly which portions of the DOM will change and which won&#39;t. Expressions in templates - really the gaps where expressions go - create &lt;em&gt;DOM Parts&lt;/em&gt; that we can update with new values.&lt;/p&gt;&lt;p&gt;&lt;a href=https://github.com/WICG/webcomponents/blob/gh-pages/proposals/DOM-Parts.md&gt;DOM Parts&lt;/a&gt; are a proposal for a new DOM object that can be attached to a specific location in the DOM and updated over time. It&#39;s a lower-level templating feature that will need to be worked on as part of any proposal here. A goal with DOM Parts is being usable by frameworks and template libraries. If a framework can&#39;t take advantage of the template API for some reason, hopefully it can use the DOM Parts APIs directly.&lt;/p&gt;&lt;h2&gt;Attributes, properties, and events&lt;/h2&gt;&lt;p&gt;After we have our container syntax, we have another bit of template system to figure out: how to differentiate between attribute, properties, and events.&lt;/p&gt;&lt;p&gt;Attribute, properties, and events are three separate key/value-style namespaces on elements that developers expect to be able to set declaratively from templates.&lt;/p&gt;&lt;p&gt;Frameworks and templating libraries take different approaches to this. Some try to merge them into a single namespace and differentiate them with runtime introspection, conventions, and/or special case lists. Others disambiguate with prefixes or sigils on the attribute name to signify properties and events.&lt;/p&gt;&lt;p&gt;Some examples:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;React: special case lists, runtime introspection, and &lt;code&gt;on&lt;/code&gt; prefix for events.&lt;/li&gt;&lt;li&gt;Vue: runtime introspection and specific syntax.&lt;/li&gt;&lt;li&gt;Angular: specific syntax&lt;/li&gt;&lt;li&gt;Lit: specific syntax&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Runtime introspection is potentially error-prone, and there an element could potentially have an attribute, property, and event of the same name and require specific disambiguation to setup properly.&lt;/p&gt;&lt;p&gt;Vue and Lit both use a similar shorthand syntax for properties and events:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;.&lt;/code&gt; prefix for setting properties.&lt;/li&gt;&lt;li&gt;&lt;code&gt;@&lt;/code&gt; prefix for setting event listeners&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In addition Lit has a useful &lt;code&gt;?&lt;/code&gt; prefix for opting into boolean attribute behavior.&lt;/p&gt;&lt;p&gt;I think this is a nice, concise, and pretty intuitive syntax. A proposal will go into more detail on the rationale for this choice, but here&#39;s what it would look like in a template:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;input
    name=&quot;foo&quot;
    .value=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;v&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    ?required=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;isRequired&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    @input=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;handleInput&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Isn&#39;t this not &quot;just HTML&quot; anymore?&lt;/h3&gt;&lt;p&gt;These sigils do give special meaning to attribute that plain HTML doesn&#39;t have, but they entirely valid standard HTML. So the syntax is standard while the semantics have been augmented for our DOM templating purposes.&lt;/p&gt;&lt;h2&gt;Composition, conditionals, and looping&lt;/h2&gt;&lt;p&gt;Any template system needs control flow and composition capabilities. One thing that React and JSX taught us is that control flow can be implemented in terms of composition, leaving all control flow features to JavaScript.&lt;/p&gt;&lt;p&gt;Start with simple composition: a template expression can contain a reference to another template:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hello &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span&gt;Hello&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;h1&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;hello&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; World!&amp;lt;/h1&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now you can use JavaScript for conditionals:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hello &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span&gt;Hello&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; goodbye &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span&gt;Goodbye&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isLeaving&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;h1&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;isLeaving &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; goodbye &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; hello&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; World!&amp;lt;/h1&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like JSX, ternaries aren&#39;t the only conditional you can use. Any conditional expression or function works.&lt;/p&gt;&lt;p&gt;Then we need to support nesting lists of nested-templates as well:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;renderList&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;li&gt;One&amp;lt;/li&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;li&gt;Two&amp;lt;/li&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/ul&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And we get looping:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;renderList&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;ul&gt;
    &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;li&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;i&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/li&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  &amp;lt;/ul&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Updating and reactivity&lt;/h2&gt;&lt;p&gt;Once we have a way to express templates we need a way to actually render them to the DOM, and like my last post pointed out, it&#39;s critical that we have ways to efficiently update that DOM from the same template later.&lt;/p&gt;&lt;p&gt;The React and Lit &lt;code&gt;render()&lt;/code&gt; API for this is pretty simple, and would work well for a built-in API.&lt;/p&gt;&lt;p&gt;Those APIs take a renderable value and a container to render into. But since we&#39;re imagining a native API, we can introduce a new &lt;code&gt;render()&lt;/code&gt; method on Element that takes a template result:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; containerEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;h1&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&amp;lt;/h1&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Updates can work in two ways: template re-rendering, and fine-grained updates.&lt;/p&gt;&lt;h3&gt;Template re-rendering&lt;/h3&gt;&lt;p&gt;Template re-rendering works by recording what template was rendered to a DOM location, and checking any new template to be rendered there against the previous template. If they&#39;re different, then the DOM is cleared and the new template is rendered. If they&#39;re the same, then just the dynamic values that changed are updated.&lt;/p&gt;&lt;p&gt;This is quite often the same result you get from VDOM diffing, especially if you key your top-level elements in a JSX fragment. It&#39;s essentially keying the fragment by the template identity.&lt;/p&gt;&lt;p&gt;This approach is a lot more efficient than VDOM diffing because it&#39;s a single identity check for the template instance, then a dirty check for each value. We&#39;re diffing on the value side, and by running through a linear list of new and old values rather than traversing a VDOM tree.&lt;/p&gt;&lt;h3&gt;Fine-grained reactivity&lt;/h3&gt;&lt;p&gt;Fine-grained reactivity approaches, like signals, can be even more efficient in some cases. And they can have ergonomic benefits if your shared data is inside of observable containers as far-flung uses of that data will all update when the data changes.&lt;/p&gt;&lt;p&gt;There&#39;s a &lt;a href=https://github.com/tc39/proposal-signals&gt;proposal to add Signals to JavaScript&lt;/a&gt;. If that moves forward, signals could be easily supported within templates for fine-grained reactivity:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Signal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Fred&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

containerEl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;h1&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&amp;lt;/h1&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// DOM: &amp;lt;h1&gt;Hello Fred!&amp;lt;/h1&gt;&lt;/span&gt;

name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Ambrose&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// DOM: &amp;lt;h1&gt;Hello Ambrose!&amp;lt;/h1&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are a lot of important details to work out around batching and scheduling of updates and efficient list updating, but I think it&#39;s important to have a path forward to built-in fine-grained reactivity. I&#39;ve seen a lot of web developers asking for something like this.&lt;/p&gt;&lt;h2&gt;Why not JSX again?&lt;/h2&gt;&lt;p&gt;The big reason not to pursue standardizing JSX as part of this proposal is that it would make the proposal much larger and much harder to move forward.&lt;/p&gt;&lt;p&gt;I do hope that TC39 tackles some addition to JavaScript that meets the JSX demand, and in that case the templating API should accept whatever data type JSX expressions produce. I hope that if a templating API is added to the platform before JSX that it would really help inform the capabilities we need out of a JSX-like addition.&lt;/p&gt;&lt;p&gt;In the meantime, people can develop and use JSX transforms for the template API, and that&#39;s an important goal of this API idea. This has already been done for Lit, and Preact&#39;s html library should that you can make the JSX-&gt;template literal association in the other direction too.&lt;/p&gt;&lt;h2&gt;Why not templates in HTML itself?&lt;/h2&gt;&lt;p&gt;We already have the &lt;code&gt;&amp;lt;template&gt;&lt;/code&gt; element, but &lt;code&gt;&amp;lt;template&gt;&lt;/code&gt; only supports cloning its inert contents, and a lot of developers want something more powerful like data-binding support.&lt;/p&gt;&lt;p&gt;I also think that we can do this, but it&#39;s a larger task than a JavaScript API - we&#39;d have to specify binding syntax, expressions, and control flow that are already done for us in JavaScript.&lt;/p&gt;&lt;h2&gt;Isn&#39;t this just standardizing lit-html?&lt;/h2&gt;&lt;p&gt;Honestly? Yes, and no. Though I think it&#39;s more accurate to say that this proposal and lit-html look similar because they share similar constraints and goals, and this API shape is the most obvious way to accomplish them.&lt;/p&gt;&lt;p&gt;The reason why lit-html looks the way it does is precisely because the Polymer team had these same constraints and requirements that the web platform does. This was partly the disposition of the team members at the time, but largely because as part of the Chrome organization, that was our mission. A large part of our job was to polyfill and prototype upcoming standards, and experiment with things that potentially could be standards proposals one day.&lt;/p&gt;&lt;p&gt;Once Polymer moved from using HTML Imports to JavaScript modules, its HTML-based template system became a big drag. Compared to a more JavaScript-oriented solution, it was more code to implement, had more custom concepts and cognitive overhead, slower in many cases, and created a division between JavaScript and template lexical environments that added friction to development.&lt;/p&gt;&lt;p&gt;lit-html was our response to those issues, still working within our constraints of no required compiler, no forking the web&#39;s core languages, and potentially standardizable features and API shapes. This simply led us to the same place that this proposal is going.&lt;/p&gt;&lt;p&gt;And we weren&#39;t the only ones. Preact&#39;s htm library, Microsoft&#39;s FAST, and HyperHtml look extremely similar, for similar reasons.&lt;/p&gt;&lt;p&gt;In fact, I&#39;m not aware of a client-side templating library that meets these constraints and requirements and &lt;em&gt;doesn&#39;t&lt;/em&gt; look a lot like lit-html (or HyperHTML or htm or FAST). I would love to see examples if there are any.&lt;/p&gt;&lt;p&gt;So it seems like just a natural way to do things given the way JavaScript and the DOM work. I think that&#39;s a strong indicator of the style of API being ready for standardization.&lt;/p&gt;&lt;p&gt;Not everything in lit-html is standardizable in my opinion, and any proposal here should be derived on its own from its own requirements, not copied from lit-html, so I don&#39;t think this proposal would look exactly like lit-html. But if this API were added to the platform I do think it would largely obsolete lit-html. But that&#39;s also one of the goals of the Lit née Polymer team: to eventually be obsoleted by the platform itself.&lt;/p&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;p&gt;I think that&#39;s a pretty good overview of the type of API I think that the web should standardize on. The end result is something that looks and feels like the templating portions of React and other popular frameworks in a lot of ways, but works with the standard JavaScript we have today.&lt;/p&gt;&lt;p&gt;This can be a controversial area of web development to wade into, so any proposal here is going to have to be extremely well researched, argued, socialized, and detailed early to have any hope of success. I hope to have time to push these ideas forward over the next few months.&lt;/p&gt;&lt;p&gt;If you&#39;re interested in collaborating, please let me know by commenting on &lt;a href=https://github.com/WICG/webcomponents/issues/1069&gt;webcomponents#1069&lt;/a&gt;, or reach out to me on &lt;a href=https://bsky.app/profile/justinfagnani.com&gt;Bluesky&lt;/a&gt;!&lt;/p&gt;&lt;h3&gt;&lt;a target=_blank href=https://bsky.app/profile/justinfagnani.com/post/3lsttcl4dtc2g&gt;&lt;bluesky-likes src=https://bsky.app/profile/justinfagnani.com/post/3lsttcl4dtc2g&gt;&lt;img src=https://justinfagnani.com/client/__root__/node_modules/bluesky-likes/logo.svg alt=&quot;&quot; slot=prefix&gt; likes on Bluesky&lt;/bluesky-likes&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;bluesky-likers src=https://bsky.app/profile/justinfagnani.com/post/3lsttcl4dtc2g&gt;&lt;/bluesky-likers&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 30 Jun 2025 08:00:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2025/06/30/what-should-a-dom-templating-api-look-like/</guid>
    </item>
    <item>
      <title>The time is right for a DOM templating API</title>
      <link>https://justinfagnani.com/2025/06/26/the-time-is-right-for-a-dom-templating-api/</link>
      <description>&lt;blockquote&gt;&lt;p&gt;Update: See my follow up post, &lt;a href=https://justinfagnani.com/2025/06/30/what-should-a-dom-templating-api-look-like/ &gt;What should a native DOM templating API look like?&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;TL;DR: I want to propose adding &lt;a href=https://github.com/WICG/webcomponents/issues/1069&gt;a declarative templating API&lt;/a&gt; to the web platform. Here&#39;s why...&lt;/p&gt;&lt;/blockquote&gt;&lt;hr&gt;&lt;p&gt;The web platform is the most successful application runtime of all time. While the largest reason for this is the web&#39;s reach, it wouldn&#39;t be possible without the DOM API, which turns a mostly static document viewer into a highly dynamic and expressive runtime.&lt;/p&gt;&lt;p&gt;For as much hate as the DOM sometimes receives (some of that deserved, but some really not!) the DOM is undeniably a very powerful API. This is easily shown by all the amazing and highly dynamic web applications out there - even an app as complex as Photoshop is available as a web app, and its entire UI is built with web components!&lt;/p&gt;&lt;p&gt;Yet the DOM is missing one of the most important and popular features in modern web development: templating. Currently there is no ergonomic way in the standard DOM APIs to create a chunk of DOM nodes, from data, event listeners added, properties set on elements, safe against XSS attacks; and then to efficiently update that chunk with new data.&lt;/p&gt;&lt;p&gt;This kind of templating is the cornerstone of all modern web frameworks and rendering libraries these days, all of which let you declaratively combine markup with data. This includes React, Vue, Angular, Preact, Lit, Svelte, SolidJS, Stencil, Quik, Ember, FAST, Polymer, Marko, and just about every other framework out there.&lt;/p&gt;&lt;p&gt;The reasons that declarative templating are so popular and foundational may be obvious, but let&#39;s recount them anyway:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The ergonomics are far superior to imperative DOM APIs. Declarative interpolation - plus features that go beyond plain HTML, like event listeners and property setting - help preserve the locality of behavior, making templates much easier to write and read than imperative code.&lt;/li&gt;&lt;li&gt;It&#39;s easier to be secure against XSS attacks, since templates can automatically escape interpolations.&lt;/li&gt;&lt;li&gt;Performance can be faster than all but the best hand-written code. Good template systems take great care to update only the DOM that needs to change.&lt;/li&gt;&lt;li&gt;Static analysis is easier. Most template systems support some kind of type-checking and intellisense. Many similar static analysis passes are much more difficult to do with imperative APIs.&lt;/li&gt;&lt;li&gt;Efficient server-side rendering becomes possible, due to the ability to interpret declarative template definitions outside of the full browser environment.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It&#39;s rare to see a technique that wins so completely on so many axes; that&#39;s good for DX &lt;em&gt;and&lt;/em&gt; UX, for security, and portability, and is so extremely popular as to be ubiquitous.&lt;/p&gt;&lt;p&gt;So templating is great, but what&#39;s the problem with the current situation?&lt;/p&gt;&lt;p&gt;The biggest thing to me is that there&#39;s an extremely core need of nearly all web applications that&#39;s just not being met by the platform. The web platform should adapt to meet such clearly demonstrated developer needs, and in the case of templating it hasn&#39;t yet. And it&#39;s such an obvious thing to add, similar to how &lt;a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl&gt;internationalization&lt;/a&gt; and a &lt;a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal&gt;great datetime API&lt;/a&gt; are now part of the platform, or how &lt;a href=https://developer.mozilla.org/en-US/docs/Web/API/Scheduler&gt;scheduler&lt;/a&gt; and &lt;a href=https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API&gt;sanitizer&lt;/a&gt; APIs are hopefully coming soon too.&lt;/p&gt;&lt;p&gt;But we also have real consequences of the lack of templating, it&#39;s bad for everyone:&lt;/p&gt;&lt;p&gt;Users suffer from longer app download times, rendering overhead, and/or insecure apps. They often need to wait for library code to download before their application is usable. For templating, this can range from only a few kB in the best cases, to upwards of 100kB or more in the worst. A few kB might not seem that bad, but it can be a pretty large portion of an ideal budget for initial interactive rendering of an app.&lt;/p&gt;&lt;p&gt;Developers need to reach for a library, and thus tools like npm or a CDN, to do many basic things. This adds to the overhead of getting started. It makes simple static files and devtools less useful than they could be. There&#39;s no fundamental templating knowledge that&#39;s portable between stacks, and native DOM creation APIs like innerHTML are unsafe by default.&lt;/p&gt;&lt;p&gt;Frameworks are harder to build because they have to implement templating. Templating libraries are challenging to build and maintain because they&#39;re under massive constraints: they must be ergonomic, fast to render, fast to update, secure, and as small as possible. Libraries very often have to make hard trade-offs between features, performance, and code size.&lt;/p&gt;&lt;p&gt;And the platform suffers from this friction as it competes with native platforms that are far less sensitive to a few kB here and there. Competing platforms like Flutter, SwiftUI, Jetpack Compose, etc. not only all have templating-like systems built-in, but they work on app installs, use compiled languages, and also don&#39;t have to worry as much about things like a few kB in app bundle size.&lt;/p&gt;&lt;h2&gt;Why right now is a great time to add templating&lt;/h2&gt;&lt;p&gt;There have been proposals to add things close to templating to the platform before. &lt;a href=https://en.wikipedia.org/wiki/ECMAScript_for_XML&gt;E4X&lt;/a&gt; was a big one that actually shipped in Firefox and Flash. E4H was a simplification of that idea by Ian Hixie that I can&#39;t find any references for anymore. At some point around 2012 there were even prototypes of a built-in `html` template-literal tag. Those failed, and for the better I think, because they might have helped with creating DOM, but not with updating it.&lt;/p&gt;&lt;p&gt;But now I think we can revisit this feature. In fact, I think that right now is a &lt;em&gt;particularly&lt;/em&gt; good time to address this situation and add a templating API to the DOM.&lt;/p&gt;&lt;p&gt;A big reason why I think we can do this now is that frameworks have worn great cowpaths to pave. And while it&#39;s true that there&#39;s a lot of variety in userland template solutions, they&#39;re actually very similar in a lot of ways, and they seem to be getting more similar over time. We understand ergonomic template syntaxes and reactivity models a lot better than 13 years ago.&lt;/p&gt;&lt;p&gt;But also, not everyone uses frameworks and there&#39;s a lot of pent-up developer demand for ergonomic DOM manipulation and reactivity APIs from so-called &quot;vanilla&quot; developers and the web components communities.&lt;/p&gt;&lt;p&gt;There are in-flight proposals for very low-level DOM update primitives, like &lt;a href=https://github.com/WICG/webcomponents/blob/gh-pages/proposals/DOM-Parts.md&gt;DOM Parts&lt;/a&gt;, which target framework implementations, but I think higher-level APIs like full declarative templating can take even more load off, help prove out and complete the lower-level API proposals, and be really impactful for developers and users.&lt;/p&gt;&lt;h3&gt;We know what good syntax for templating looks like&lt;/h3&gt;&lt;p&gt;The popular client-side template systems out there all share fundamentally similar syntax of markup with bindings. While there are small differences in expression delimiters, control flow constructs, binding type designators; the similarities are far greater than the differences. Even across the HTML-based (Vue, Angular, Svelte) and JavaScript-based (React, Lit, Solid) spectrum.&lt;/p&gt;&lt;p&gt;Things get even more similar when you look at JavaScript-based APIs (which any new DOM API would be): templates are usually expressions, composition is done via nesting template expressions or references to them, and control flow is just JavaScript.&lt;/p&gt;&lt;p&gt;There&#39;s also a lot of similarity in semantics. The most popular JavaScript-API-based systems return a description of the DOM from a template expression, then apply that description with a separate render function call. Most of those also update the DOM with the same render function call (though some eschew that altogether for fine-grained reactivity).&lt;/p&gt;&lt;p&gt;Previous platform proposals didn&#39;t match these semantics. Both E4X and E4H added new syntax to JavaScript to embed markup in JavaScript similar to JSX, but they critically didn&#39;t return a description of DOM, but a fragment of DOM itself. This made them good for initial DOM creation, but bad for updates, which were still imperative.&lt;/p&gt;&lt;h3&gt;We can build an API for today&#39;s JavaScript&lt;/h3&gt;&lt;p&gt;It&#39;s been here for a while, but it&#39;s worth reminding readers: we have a built-in JavaScript feature for embedded DLS like HTML: &lt;a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates&gt;tagged template literals&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;So we can describe templates in a DOM API without having to add new features to JavaScript. And we have popular libraries that prove this approach works well. That&#39;s a big deal for realistically being able to move a proposal forward.&lt;/p&gt;&lt;h3&gt;We can also plan for tomorrow&#39;s JavaScript&lt;/h3&gt;&lt;p&gt;Tagged template literals are great - they&#39;re an often unsung hero feature of ES2015 - but they have a bit more syntactic overhead than JSX, especially with userland component systems. And, people love JSX.&lt;/p&gt;&lt;p&gt;So some people might ask: why don&#39;t we just add JSX to JavaScript too?&lt;/p&gt;&lt;p&gt;Well, the problem with JSX is that it&#39;s all syntax and no semantics. This means that in order to standardize it we can&#39;t just add new syntax to JavaScript, we have to define the semantics. Treating JSX as a call to an ambiently-defined createElement() call is out of the question. Creating a tree of objects is possible, but that&#39;s one of the least efficient ways to use JSX as it irretrievably mixes static unchangeable parts of the tree with dynamic parts of the tree, precluding more efficient update patterns. If the Records and Tuples proposal were progressing, JSX could maybe create Records with boxes, but that proposal has been stalled, especially on the record identity and box parts that would make it suitable for a JSX semantics.&lt;/p&gt;&lt;p&gt;Nailing down the semantics is already probably the hardest part of a hypothetical JSX proposal, but there&#39;s also a chicken-and-egg problem when it comes to templating. In order to ensure that a JSX-like syntax and semantics is suitable for full-expressive DOM templating, we need a target templating system to verify it against. It might seem like React already provides this, but in some ways React&#39;s templating is less powerful and expressive than other systems. For instance, React doesn&#39;t provide a way to explicitly bind to properties and events of DOM elements, or provide directives that apply to an element.&lt;/p&gt;&lt;p&gt;But again, people love JSX, and JSX has absolutely proven the popularity of embedding markup in JavaScript. So I do believe that the platform should eventually take a look at adding something like it. I&#39;m just a realist about how much work that is and think that we can do templating with today&#39;s JavaScript much sooner.&lt;/p&gt;&lt;p&gt;Luckily, the good thing about today&#39;s non-standard JSX is that it&#39;s pure syntax with no runtime semantics. This means that we can build JSX-to-tagged-template-literal compilers, as many have done for things like JSX-to-Lit. A transform for JSX to a native template API would make the template API a compile target, where developers could choose a syntax they prefer, with little-to-no runtime overhead charged against users.&lt;/p&gt;&lt;p&gt;Then, if work to standardize JSX is picked up by someone, it&#39;ll have a concrete system to target. The template system may have to adapt to accept the data type that a JSX expression evaluates to, but this is eminently possible, and a better direction to adapt in that having a native JSX syntax and semantics that we later realize are insufficient for native templating.&lt;/p&gt;&lt;h3&gt;We can lay the groundwork for HTML-based templating&lt;/h3&gt;&lt;p&gt;Many web developers have been asking for a full-features HTML-based templating system. This is across communities like web components users, framework users, and &quot;vanilla&quot; developers. Many developers expected this kind of templating from the `&amp;lt;template&gt;` element, or from declarative shadow DOM, or web components in general, and are disappointed that it&#39;s not the case. And a very large fraction of frameworks use HTML-based templates instead of JavaScript-based templates: Vue, Angular, Polymer, Svelte…&lt;/p&gt;&lt;p&gt;So they might ask why we don&#39;t pursue an HTML-based API first instead of a JavaScript-based API?&lt;/p&gt;&lt;p&gt;My answer would be that an HTML-based system is just a much, much larger undertaking. The beauty of React and JSX is that it leaves so many things to plain JavaScript while the JSX part only concerns itself with markup and bindings. Control flow and expressions are just script. An HTML-based template system would need to invent binding syntax, an expression language, control flow constructs, plus all of the template update mechanisms that a JavaScript-API has to.&lt;/p&gt;&lt;p&gt;We also don&#39;t have a native way to load HTML-based template definitions. The HTML Imports feature of the web components v0 spec is gone, and HTML Modules aren&#39;t here yet. This means that we&#39;d have to embed HTML templates inside JavaScript modules, and at that point it&#39;s nicer to have your expressions just be JavaScript in the same lexical scope as your data. In fact, this is exactly the reason that Polymer 3, (which moved the HTML templates of Polymer 2 into JavaScrip) led directly to Lit. It was less code and a better experience to just let JavaScript handle all the script-like things.&lt;/p&gt;&lt;p&gt;So a JavaScript API is a subset of an HTML-based API, and will be a huge stepping stone towards an HTML-based API. Once the JavaScript API is in and proven, the HTML API only takes defining bindings, expressions, control flow, and a module system (ok, yes, that&#39;s still a massive amount of work).&lt;/p&gt;&lt;h3&gt;We&#39;ve explored the reactivity landscape&lt;/h3&gt;&lt;p&gt;While early DOM templating proposals didn&#39;t include updating, userland systems have thoroughly&lt;br&gt;explored the landscape by now, and discovered good mental models and better and worse implementation approaches. I think we can now zero-in on a system that combines the best features from the different approaches.&lt;/p&gt;&lt;p&gt;The most popular reactivity approaches can be grouped into a few main categories:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;VDOM and diffing as used in React&lt;/li&gt;&lt;li&gt;Template identity as used in Lit&lt;/li&gt;&lt;li&gt;Signals and similar fine-grained reactivity as used in Solid (and an increasing number of frameworks like Svelte, Vue, Angular)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Diffing is great because on the surface it&#39;s a very comprehensible model, and it works with any data. Unfortunately, it&#39;s slow compared to other approaches, and variations in diffing algorithms could be observable. I think it&#39;d be difficult to standardize one diffing algorithm, and difficult to convince platform engineers to accept an approach with that much overhead.&lt;/p&gt;&lt;p&gt;Template identity - which updates the DOM if it was rendered with the current template, replaces it otherwise - is fast and gives very similar results to diffing in a majority of use cases, and it&#39;s easy to understand. It fits very well with tagged-template literals, alternate JSX transforms, and HTML-based templates, and has a nice simple semantics. It would be straightforward to specify.&lt;/p&gt;&lt;p&gt;Signals… are great, IMO. I strongly support &lt;a href=https://github.com/tc39/proposal-signals&gt;the proposal to add them to JavaScript&lt;/a&gt;, and think that they should be a part of any new reactive DOM APIs including a template API.&lt;/p&gt;&lt;p&gt;Signals aren&#39;t a native part of the platform yet, and not guaranteed to be in. Signals-based systems also require all your data to be wrapped in signals - they work best when you&#39;re all in on them. But there&#39;s a lot of data that&#39;s not in signal form, and a lot of platform APIs that don&#39;t produce signals. Re-rendering is an easy way to pick up changes to non-signal data.&lt;/p&gt;&lt;p&gt;It&#39;s pretty easy to have a system that supports both template updating and fine-grained signals updating as co-existing modes of reactivity. A signal-pure template - one that only passes signals to bindings - would never need to be &quot;re-rendered&quot; - it could always only update via signals. A template that possibly references non-signal data needs to be re-rendered. Typically re-rendering is done automatically by the component or framework layer which will have reactivity, like reactive component properties.&lt;/p&gt;&lt;p&gt;I think this makes template identity with signals a winning combination that&#39;s fast, comprehensible, flexible, and possible to to specify.&lt;/p&gt;&lt;h2&gt;A path to a proposal&lt;/h2&gt;&lt;p&gt;I brought up the topic of a native declarative JS templating API in &lt;a href=https://github.com/WICG/webcomponents/issues/1069&gt;this GitHub issue&lt;/a&gt;, and I think what&#39;s vaguely outlined there is a logical and valuable next step for DOM creation APIs; for vanilla web developers, web components developers, and future framework evolution.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;It&#39;s immediately useful to vanilla web developers as an ergonomics and secure DOM creation primitive.&lt;/li&gt;&lt;li&gt;It&#39;s immediately useful to many existing web component libraries, such as Lit, FAST, HyperElement, etc.&lt;/li&gt;&lt;li&gt;It&#39;s immediately useful to raw web component API users, and a stepping stone to a more complete ergonomic reactive component definition API.&lt;/li&gt;&lt;li&gt;New frameworks can be built around it.&lt;/li&gt;&lt;li&gt;Existing frameworks could use it as a compile target, runtime backend, or possibly support the templating API directly.&lt;/li&gt;&lt;li&gt;It&#39;s useful for reactivity - both for &quot;re-rendering&quot; techniques and for use with Signals&lt;/li&gt;&lt;li&gt;It&#39;s a good stepping stone to declarative HTML templating and declarative custom elements.&lt;ul&gt;&lt;li&gt;It&#39;s a much smaller API to agree on and specify&lt;/li&gt;&lt;li&gt;It helps define the semantics for templates&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;It will require the completion of the DOM Parts proposal, and help define it and prove its usefulness.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This is no small undertaking though. The surface API and syntax aren&#39;t huge, but the behavior space and the underlying DOM Parts API are large. Fine-grained reactivity also requires some kind of DOM scheduler. So there are a large number of things to enumerate, agree on, specify, and add tests for.&lt;/p&gt;&lt;p&gt;It&#39;s going to have to be a collaborative effort, but I think it can be done and deliver huge value for web developers and users. I&#39;ll be working on a proposal as much as I have time for, and hopefully I can get other developers, especially some platform engineers interested too.&lt;/p&gt;&lt;p&gt;Please comment on &lt;a href=https://github.com/WICG/webcomponents/issues/1069&gt;webcomponents#1069&lt;/a&gt;, or reach out to me on &lt;a href=https://bsky.app/profile/justinfagnani.com&gt;Bluesky&lt;/a&gt; if you&#39;re interested!&lt;/p&gt;&lt;h3&gt;&lt;a target=_blank href=https://bsky.app/profile/justinfagnani.com/post/3lsjc6ju2722x&gt;&lt;bluesky-likes src=https://bsky.app/profile/justinfagnani.com/post/3lsjc6ju2722x&gt;&lt;img src=https://justinfagnani.com/client/__root__/node_modules/bluesky-likes/logo.svg alt=&quot;&quot; slot=prefix&gt; likes on Bluesky&lt;/bluesky-likes&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;bluesky-likers src=https://bsky.app/profile/justinfagnani.com/post/3lsjc6ju2722x&gt;&lt;/bluesky-likers&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 26 Jun 2025 08:00:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2025/06/26/the-time-is-right-for-a-dom-templating-api/</guid>
    </item>
    <item>
      <title>Stop Using CustomEvent</title>
      <link>https://justinfagnani.com/2025/06/25/stop-using-custom-event/</link>
      <description>&lt;p&gt;I see a lot web developers out there firing &lt;code&gt;CustomEvent&lt;/code&gt;s from their component code. So much that it seems like many developers think that &lt;code&gt;CustomEvent&lt;/code&gt; is the only way for their code to fire &lt;em&gt;custom&lt;/em&gt; (with a little &quot;c&quot;) events, and maybe even the only way to fire their own events at all.&lt;/p&gt;&lt;p&gt;It&#39;s understandable. It&#39;s right in the name: &quot;Custom&quot; event. It feels like the designated tool for the job. It even sounds like it goes right along with &quot;custom element&quot;. But I always tell developers to not use &lt;code&gt;CustomEvent&lt;/code&gt;. There&#39;s no reason for it. Why?&lt;/p&gt;&lt;h2&gt;What&#39;s wrong with CustomEvent?&lt;/h2&gt;&lt;p&gt;First, let me be honest here: using &lt;code&gt;CustomEvent&lt;/code&gt; isn&#39;t the end of the world. In terms of bad practices in web developer, this is hardly a nine alarm fire. It&#39;s barely even leaving a candle burning. &lt;code&gt;CustomEvent&lt;/code&gt; works, and using it won&#39;t harm the users that matter most: application end users.&lt;/p&gt;&lt;p&gt;That said, this is apparently something I rant a bit in various web dev circles, so it&#39;s probably better I put my arguments down in one place.&lt;/p&gt;&lt;h3&gt;CustomEvent shouldn&#39;t exist!&lt;/h3&gt;&lt;p&gt;&lt;code&gt;CustomEvent&lt;/code&gt; only exists because subclassing native classes wasn&#39;t well-supported when it was introduced. Adding a details object via the event init options was the platform-blessed way to add a custom payload to an Event. I presume you could also patch properties onto any &lt;code&gt;Event&lt;/code&gt; instance, but maybe some quirk of the spec or IE meant that you couldn&#39;t rely on the same &lt;code&gt;Event&lt;/code&gt; instance arriving at every listener.&lt;/p&gt;&lt;p&gt;Then ES2015 came out and suddenly we could subclass native classes like &lt;code&gt;Array&lt;/code&gt;, &lt;code&gt;HTMLElement&lt;/code&gt;, and &lt;code&gt;Event&lt;/code&gt;! Had ES6 (what we used to call ES2015) come out earlier, &lt;code&gt;CustomEvent&lt;/code&gt; would never had happened. I&#39;ve heard this directly from browser engineers responsible for the DOM APIs at that time.&lt;/p&gt;&lt;h3&gt;CustomEvent is a leaky implementation detail&lt;/h3&gt;&lt;p&gt;When you fire a &lt;code&gt;CustomEvent&lt;/code&gt;, you&#39;re forcing the user (the &lt;em&gt;developer&lt;/em&gt; user) of your component to deal with the &lt;code&gt;detail&lt;/code&gt; property. They have to know that the data they need is tucked away in this arbitrary container.&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token comment&quot;&gt;// The consumer experience with CustomEvent&lt;/span&gt;
someElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-event&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CustomEvent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;MyEventDetail&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Why the extra step?&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bar &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;detail&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a leaky abstraction. Your users shouldn&#39;t have to care about the implementation detail that you chose &lt;code&gt;CustomEvent&lt;/code&gt;. They should be interacting with an event that feels as native and intuitive as a &lt;code&gt;MouseEvent&lt;/code&gt; or a &lt;code&gt;KeyboardEvent&lt;/code&gt;.&lt;/p&gt;&lt;h2&gt;What to use instead of CustomEvent&lt;/h2&gt;&lt;p&gt;So, what should you use instead, and why?&lt;/p&gt;&lt;p&gt;Obviously, since &lt;code&gt;CustomEvent&lt;/code&gt; was added due to a lack of subclassing, the main alternative is to subclass the native &lt;code&gt;Event&lt;/code&gt; class. But I&#39;ll get into that in one bit. First, let me suggest alternatives that don&#39;t involve subclassing: using a plain &lt;code&gt;Event&lt;/code&gt; or using a built-in event subclass.&lt;/p&gt;&lt;h3&gt;Do you really need custom data?&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;Event&lt;/code&gt; constructor takes an event name and options (for bubbling, composed, etc). If you don&#39;t need additional data with your event, you can just new up a plain &lt;code&gt;Event&lt;/code&gt;. And I think that many &lt;code&gt;CustomEvent&lt;/code&gt;s don&#39;t actually need their &lt;code&gt;detail&lt;/code&gt; object.&lt;/p&gt;&lt;p&gt;Consider that many platform events and simply a notification that something happened, and a reference back to the thing it happened to: the event target. For instance, when an &lt;code&gt;&amp;lt;input&gt;&lt;/code&gt; element fires a &lt;code&gt;&#39;input&#39;&lt;/code&gt; event, the event doesn&#39;t carry a new value. Instead you look at the event target and get the current value directly from that.&lt;/p&gt;&lt;p&gt;The nice thing about getting data this way is that it&#39;s robust against the value changing after the event is handled. You can take code that works synchronously with the &lt;code&gt;&#39;input&#39;&lt;/code&gt; event, wrap it in a debounce, and it&#39;ll still work.&lt;/p&gt;&lt;p&gt;Payloadless events are also more general and reusable. You could fire an &lt;code&gt;&#39;input&#39;&lt;/code&gt; event from an element that has a different data type, or multiple pieces of relevant data, without changing the event. Many platform events are payloadless and just a plain &lt;code&gt;Event&lt;/code&gt; instance, like &lt;code&gt;&#39;input&#39;&lt;/code&gt;, &lt;code&gt;&#39;change&#39;&lt;/code&gt;, &lt;code&gt;&#39;select&#39;&lt;/code&gt;, &lt;code&gt;&#39;load&#39;&lt;/code&gt;...&lt;/p&gt;&lt;p&gt;So, first, I would consider if you can rely on &lt;code&gt;event.target&lt;/code&gt; instead of a payload.&lt;/p&gt;&lt;p&gt;Now, this is a subjective choice, because many people find having data right on the event to be easier to use. And maybe you do need to record the data as it was when the event was fired. These are fine reasons to use a custom payload.&lt;/p&gt;&lt;p&gt;Also, you may want to subclass &lt;code&gt;Event&lt;/code&gt; even if you don&#39;t have a custom payload, for some of the other benefits I mention below.&lt;/p&gt;&lt;h3&gt;Is there a native event that meets your needs?&lt;/h3&gt;&lt;p&gt;Second, I would consider if a native event has the semantics you need. This could be a native event that uses a generic &lt;code&gt;Event&lt;/code&gt; instance, or a native subclass of &lt;code&gt;Event&lt;/code&gt;. The advantage of using a built-in event name and class is that your users and their tools may already be familiar with that event.&lt;/p&gt;&lt;p&gt;For example, when a component loads something, you can fire a &lt;code&gt;load&lt;/code&gt; event. Or if you want to report an error from a component you can fire an &lt;a href=https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent/ErrorEvent&gt;&lt;code&gt;ErrorEvent&lt;/code&gt;&lt;/a&gt;. If your component has open and close states, consider firing a &lt;a href=https://developer.mozilla.org/en-US/docs/Web/API/ToggleEvent&gt;&lt;code&gt;ToggleEvent&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Just make sure that your event&#39;s semantics match the platform event&#39;s semantics exactly. They should be fired for the same reasons, at the same timing, with the same options (eg, bubbles).&lt;/p&gt;&lt;h3&gt;Subclassing Event&lt;/h3&gt;&lt;p&gt;Since we &lt;em&gt;can&lt;/em&gt; subclass &lt;code&gt;Event&lt;/code&gt; when we need to, this is my main and most general recommended alternative to &lt;code&gt;CustomEvent&lt;/code&gt;. &lt;code&gt;Event&lt;/code&gt; subclasses are better all-around.&lt;/p&gt;&lt;p&gt;This is an example of my basic pattern for subclassing &lt;code&gt;Event&lt;/code&gt;:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token comment&quot;&gt;/**
 * An event that&#39;s fired when foo happens.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyEvent&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Event&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; eventName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;my-event&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; foo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; bar&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;foo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bar&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyEvent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; bubbles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; composed&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;foo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bar&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Look at what this gives us.&lt;/p&gt;&lt;p&gt;First, it&#39;s easier to use and plain nicer. The event&#39;s data is directly on the event object. It feels just like a native event.&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token comment&quot;&gt;// The consumer experience with a proper Event subclass&lt;/span&gt;
someElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyEvent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;eventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MyEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// So much cleaner.&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; foo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bar &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Second, the event subclass serves as its own documentation. The class definition is a natural place to use JSDoc to explain what the event is for and what its properties mean.&lt;/p&gt;&lt;p&gt;Third, and the most important for program correctness, it provides a single source of truth for the event&#39;s creation. The constructor ensures that every time &lt;code&gt;MyEvent&lt;/code&gt; is instantiated and dispatched it has the same name and the same options, like &lt;code&gt;bubbles&lt;/code&gt; and &lt;code&gt;composed&lt;/code&gt;. You could achieve something similar with a factory function for &lt;code&gt;CustomEvent&lt;/code&gt;, but at that point, you&#39;re just writing a poor man&#39;s class.&lt;/p&gt;&lt;p&gt;Finally, the &lt;code&gt;Event&lt;/code&gt; subclass is its own type. This is a huge win for TypeScript users. Instead of fumbling with &lt;code&gt;CustomEvent&amp;lt;MyDetailType&gt;&lt;/code&gt;, you just use the event class itself as the type. It&#39;s simpler and more accurate.&lt;/p&gt;&lt;p&gt;In many cases it even makes sense to register the event type globally too:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;declare&lt;/span&gt; global &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GlobalEventHandlersEventMap&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&#39;my-event&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MyEvent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then your users will automatically get correctly-typed event handlers when using &lt;code&gt;addEventListener()&lt;/code&gt;. Of course, you can do this with &lt;code&gt;CustomEvent&lt;/code&gt; too, so should do this in the same cases, either way.&lt;/p&gt;&lt;h2&gt;Further reading&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://bsky.app/profile/tbroyer.ltgt.net&gt;Thomas Broyer&lt;/a&gt; recently updated MDN to mention subclassing Event on the &lt;a href=https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#adding_custom_data_%E2%80%93_subclassing_event&gt;Creating and triggering events&lt;/a&gt; page!&lt;/li&gt;&lt;li&gt;&lt;a href=https://bsky.app/profile/stuffbreaker.bsky.social&gt;Burton Smith&lt;/a&gt; is writing on the topic and has &lt;a href=https://dev.to/stuffbreaker/creating-strongly-typed-events-for-web-components-1jem&gt;a piece on better typing CustomEvent&lt;/a&gt;. I hear there is a Part 2 coming soon that talks about subclassing.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;&lt;a target=_blank href=https://bsky.app/profile/justinfagnani.com/post/3lsgumiddt22f&gt;&lt;bluesky-likes src=https://bsky.app/profile/justinfagnani.com/post/3lsgumiddt22f&gt;&lt;img src=https://justinfagnani.com/client/__root__/node_modules/bluesky-likes/logo.svg alt=&quot;&quot; slot=prefix&gt; likes on Bluesky&lt;/bluesky-likes&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;bluesky-likers src=https://bsky.app/profile/justinfagnani.com/post/3lsgumiddt22f&gt;&lt;/bluesky-likers&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 25 Jun 2025 08:00:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2025/06/25/stop-using-custom-event/</guid>
    </item>
    <item>
      <title>Composite Map Keys in JavaScript with Bitsets</title>
      <link>https://justinfagnani.com/2024/11/09/composite-map-keys-in-javascript-with-bitsets/</link>
      <description>&lt;p&gt;Sometimes you need to store and retrieve information related to &lt;em&gt;groups&lt;/em&gt; of objects.&lt;/p&gt;&lt;p&gt;In JavaScript, Maps seem like they should be the right tool for this, but it&#39;s trickier to do than you might think. JavaScript has very minimal object and collection interfaces. Unlike some languages, like Java, there is no built-in concept of custom equality or hashcodes.&lt;/p&gt;&lt;p&gt;Maps and Sets in JavaScript work based on &lt;em&gt;reference equality&lt;/em&gt; for objects. You can use an object as a key, but you can only set and get the data for an object if you use the exact same object instance - that is, if they are &lt;code&gt;===&lt;/code&gt; to each other. Two different object instances, even with the same values for the same properties, are always different, unique map keys. If you set a value with an array key, like &lt;code&gt;map.set([1, 2, 3], &#39;foo&#39;)&lt;/code&gt;, you can not then retrieve that value with &lt;code&gt;map.get([1, 2, 3])&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The &lt;a href=https://github.com/tc39/proposal-record-tuple&gt;Records and Tuples language proposal&lt;/a&gt; is supposed to help with this problem by adding objects with value semantics to the language. Then &lt;code&gt;map.set(#[1, 2, 3], &#39;foo&#39;)&lt;/code&gt; and &lt;code&gt;map.get(#[1, 2, 3])&lt;/code&gt; &lt;em&gt;would&lt;/em&gt; work how we want. But that proposal is taking a long time and not here yet, and it might never be.&lt;/p&gt;&lt;p&gt;So what do we do today?&lt;/p&gt;&lt;p&gt;The two main approaches that I&#39;ve mainly used and nested Maps and generating composite string keys, and another interesting technique came up in the Lit Discord: using BigInts bitsets as composite keys.&lt;/p&gt;&lt;h2&gt;Nested Maps&lt;/h2&gt;&lt;p&gt;Nested Maps work by doing successive lookups with your keys, like &lt;code&gt;map.get(o1)?.get(o2)&lt;/code&gt;. The problem is that you need a lot of Map instances. You&#39;re building a tree of maps, so there can be reuse due to branching, but at the limit, for a set of key size of &lt;code&gt;K&lt;/code&gt; objects and &lt;code&gt;N&lt;/code&gt; keys you need up to &lt;code&gt;N * (K - 1)&lt;/code&gt; Maps. That can cause a lot of memory overhead.&lt;/p&gt;&lt;p&gt;You also have to be able to use your keys in a stable order. You need to read and write &lt;code&gt;o1&lt;/code&gt; then &lt;code&gt;o2&lt;/code&gt; always, because &lt;code&gt;o2&lt;/code&gt; then &lt;code&gt;o1&lt;/code&gt; would be a different key.&lt;/p&gt;&lt;p&gt;I use nested Maps occasionally, but not usually for what I would consider the composite key use cases. It&#39;s more for when my data already has a hierarchical relationship - but then you can often use the leaf nodes as keys, or roll the data you need to store into your data model.&lt;/p&gt;&lt;h2&gt;Composite string keys&lt;/h2&gt;&lt;p&gt;More commonly, I&#39;ve uses strings as composite keys instead. Strings work well because they have value semantics. You can create the same string contents twice and they will act as the same key for Maps and Sets (and plain objects). So if you can generate the same string for a group of objects, you have yourself a composite key.&lt;/p&gt;&lt;h3&gt;When your keys are already strings&lt;/h3&gt;&lt;p&gt;The simplest case is when your keys are already strings. Then you can just concatenate the strings with a separator to make a composite key:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compositeKey&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;keys&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;--&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The joiner string (&lt;code&gt;&#39;--&#39;&lt;/code&gt;) should not appear in your keys. If if could, escape the keys.&lt;/p&gt;&lt;p&gt;If you need to be able to supply keys in any order, you can sort them before joining:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compositeKey&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;keys&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;--&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There is a performance concern here when dealing with long string keys and/or many objects in your key sets: you may be frequently generating new string instances and causing native Map code to do full string comparisons rather than reference checks. Be aware of your data and profile as needed!&lt;/p&gt;&lt;h3&gt;When your keys are objects&lt;/h3&gt;&lt;p&gt;If your keys are objects, a nice pattern is to generate synthetic unique IDs for objects, then concatenate those to build the composite key.&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token comment&quot;&gt;// Stores the sequential ID we generate for each object&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ids &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WeakMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; nextId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getId&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nextId&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we can sort and join those IDs to build the composite key:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compositeKey&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;keys&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;--&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And use the composite key in a regular Map:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; map &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;setValue&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o3&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compositeKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getValue&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compositeKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;BigInt Bitsets&lt;/h3&gt;&lt;p&gt;Strings work well as composite keys because we can generate them and they have value semantics. Number also have those properties, so another technique we can use is to use bitsets represented as numbers as our composite Map keys.&lt;/p&gt;&lt;p&gt;Each object&#39;s presence in the key would be represented by a binary digit in the key. So instead of a composite key of &lt;code&gt;0--1--2&lt;/code&gt; for the first three objects seen, you would have &lt;code&gt;0b111&lt;/code&gt; or &lt;code&gt;7&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This will make for much more compact keys than strings and remove the need for sorting. The only problem is that you could run out of digits. Using bitwise operations on plain numbers in JavaScript limits you to 32 bits, so you could only store 32 objects with plain numbers.&lt;/p&gt;&lt;p&gt;But in modern JavaScript we now have BigInts that can store any number of bits! So we&#39;ll assign sequential IDs to objects as before, but now we&#39;ll use those as number places, generate a bitmask for each object with a single bit turned on, then combine the per-object masks with a bitwise OR to generate our bitset key.&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ids &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WeakMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; nextId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getBitMask&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nextId&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Generate a mask with a single bit set in the `id`-th place&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1n&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;compositeKey&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;keys&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  keys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; o&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; k &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getBitMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a really cool technique because it got a lot simpler in ES2020 with the addition of BigInt. You could encode bitsets in strings, but it&#39;s not as easy or obvious how to do so.&lt;/p&gt;&lt;p&gt;Using BigInts as bitsets and Map keys was actually suggested by Claude (as relayed by our Lit teammate Steve), so I presume someone is already doing this. I couldn&#39;t find anything written up about it in a quick search though, so I hope this is useful to people out there.&lt;/p&gt;&lt;p&gt;You can like and discuss this post &lt;a href=https://bsky.app/profile/did:plc:ec64xv7n5dszeizw56yr6b5h/post/3lak5dwp5zc25&gt;on BlueSky&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Happy hacking!&lt;/p&gt;&lt;h3&gt;&lt;a target=_blank href=https://bsky.app/profile/justinfagnani.com/post/3lak5dwp5zc25&gt;&lt;bluesky-likes src=https://bsky.app/profile/justinfagnani.com/post/3lak5dwp5zc25&gt;&lt;img src=https://justinfagnani.com/client/__root__/node_modules/bluesky-likes/logo.svg alt=&quot;&quot; slot=prefix&gt; likes on Bluesky&lt;/bluesky-likes&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;bluesky-likers src=https://bsky.app/profile/justinfagnani.com/post/3lak5dwp5zc25&gt;&lt;/bluesky-likers&gt;&lt;/p&gt;</description>
      <pubDate>Sat, 09 Nov 2024 08:00:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2024/11/09/composite-map-keys-in-javascript-with-bitsets/</guid>
    </item>
    <item>
      <title>I&#39;m Going to Need to Blog a Lot More</title>
      <link>https://justinfagnani.com/2024/10/16/im-going-to-need-to-blog-a-lot-more/</link>
      <description>&lt;p&gt;In January 2017, after having witnessed how much terrible disinformation spread on Facebook and certainly affected the presidential election, I made one final post calling for people to donate to some worthwhile charities and signed off. I haven&#39;t posted or commented on Facebook since.&lt;/p&gt;&lt;p&gt;I tried to do something similar with Twitter when Musk bought it. He seemed clearly intent on using the Twitter for his personal alt-right, trans- and xenophobic, conspiracy theory speading mission.&lt;/p&gt;&lt;p&gt;That much was right. But after trying to use Mastodon for the type of tech, urbanist, and cultural interactions I got from Twttier, to very limited success, I decided that there was simply too much in my industry circles still happening on Twitter to fully abandon it. So I limped back on to the site to at least be able to talk about web development and such. Slowly I slipped back into just as much activity as I had pre-Musk.&lt;/p&gt;&lt;p&gt;But that might not be so tenable for me anymore. Musk changing how blocking works, de-ranking posts with external links, and obviously promoting pro-Trump and right-wing posts makes it morally questionable to me to continue to use the site. I do not want to be making the richest man on the planet, someone as repulsive and wrong as Musk, &lt;em&gt;more&lt;/em&gt; money be providing content and eyeballs for his personal disinformation system.&lt;/p&gt;&lt;p&gt;The problem is that I still find the Twitter alternatives to be severely lacking. The biggest problem is that they simply don&#39;t have comparable levels of community or activity. I hear Mastodon is doing ok, but I find discoverability of people and conversations there to be really, really bad. Threads? Bluesky? I&#39;m not sure what has the critical mass I&#39;m looking for. Everything seems so fragmented.&lt;/p&gt;&lt;p&gt;So with wanting to drastically cut back on my Twitter usage and not seeing a viable new homebase to migrate to, where that leave me? The most obvious answer to me is to cut back on social media &lt;em&gt;in general&lt;/em&gt; and to &lt;strong&gt;own more of my own content&lt;/strong&gt;. Then I can promote my content on several sites, and not be very attached to them.&lt;/p&gt;&lt;p&gt;Luckily, I already have a space for that here!&lt;/p&gt;&lt;p&gt;It won&#39;t be as easy as Tweeting, but maybe that&#39;s good. Maybe we could all use a little more time and space to put our thoughts together before publishing them to the whole world.&lt;/p&gt;&lt;p&gt;These things do get easier with practice. I&#39;ll need to get in the habit of quickly writing and publishing a post when I feel the need, instead of working on something for weeks and never finishing as I often do. This post here, in fact, is a bit of that practice.&lt;/p&gt;&lt;p&gt;Compared the the last 9 years though, I&#39;m going to need to blog a &lt;em&gt;lot&lt;/em&gt; more. I think you should too. It&#39;ll be good for us all.&lt;/p&gt;</description>
      <pubDate>Wed, 16 Oct 2024 08:00:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2024/10/16/im-going-to-need-to-blog-a-lot-more/</guid>
    </item>
    <item>
      <title>Reactive State with Signals in Lit</title>
      <link>https://justinfagnani.com/2024/10/09/reactive-state-with-signals-in-lit/</link>
      <description>&lt;p&gt;Yesterday the &lt;a href=https://lit.dev&gt;Lit&lt;/a&gt; project &lt;a href=https://lit.dev/blog/2024-10-08-signals/ &gt;released the new &lt;code&gt;@lit-labs/signals&lt;/code&gt; package&lt;/a&gt; that I&#39;ve been working for a few months. &lt;code&gt;@lit-labs/signals&lt;/code&gt; integrates the &lt;a href=https://github.com/tc39/proposal-signals&gt;Signals TC39 Proposal&lt;/a&gt; with Lit 🎉 so that elements that use signals will automatically update when they change.&lt;/p&gt;&lt;p&gt;I&#39;m really excited about this one! Partly because it&#39;s the first big new feature I&#39;ve landed in Lit since leaving Google, but mostly because I think standardized signals can be a game-changer for web components, Lit, and all kinds of state management libraries.&lt;/p&gt;&lt;p&gt;So, what’s the big deal?&lt;/p&gt;&lt;h2&gt;Lit Reactivity Overview&lt;/h2&gt;&lt;p&gt;Well, first let&#39;s take a look at the current state of reactivity in Lit.&lt;/p&gt;&lt;p&gt;Lit has one main reactive environment - the &lt;code&gt;ReactiveElement&lt;/code&gt; base class&#39;s &quot;reactive update lifecycle&quot;. This is an asynchronously enqueued set of steps that perform the update of an element, including rendering in &lt;code&gt;LitElement&lt;/code&gt;&#39;s case.&lt;/p&gt;&lt;p&gt;A reactive update can be triggered in any number of ways, but the main way is via reactive properties: class instance properties that request an update when they change.&lt;/p&gt;&lt;p&gt;This is a simple and quite effective system that composes quite well.&lt;/p&gt;&lt;p&gt;When using Lit elements in declarative template systems, a parent element setting properties on a child element will cause that child to enqueue an update microtask. Setting several properties, which is quite common, will enqueue just one task. Deep &quot;property drilling&quot; will cause a cascade of async microtasks that update elements in tree-order, each in their own batch.&lt;/p&gt;&lt;p&gt;Change detection in the reactive property setters means that elements will only enqueue an update if their data actually changed. This means that only the part of a Lit element subtree that needs re-rendering will even try to re-render. Change detection in the template bindings means that only DOM that&#39;s bound to changed data will update.&lt;/p&gt;&lt;p&gt;It&#39;s a very efficient and pretty simple system that limits the effect scope of data changes and performs minimal DOM updates, all for a small amount of code. On top of that, it&#39;s not centrally coordinated and it&#39;s &lt;em&gt;interoperable&lt;/em&gt;. Any other web component that responds to property changes by enqueuing microtasks will benefit from the same, emergent, in-order, batched, naturally tree-pruning behavior!&lt;/p&gt;&lt;h3&gt;Lit dataflow demo&lt;/h3&gt;&lt;p&gt;Here&#39;s a demo that shows how components only update when their own data changes, and how that makes data flow down the tree.&lt;/p&gt;&lt;p&gt;Each node has a &lt;code&gt;baseValue&lt;/code&gt; and &lt;code&gt;rightValue&lt;/code&gt; and displays their sum, but the &lt;code&gt;rightValue&lt;/code&gt; is only bound to the right child. The elements flash when they re-render, and delay their updates by 100ms.&lt;/p&gt;&lt;p&gt;You can see that changing &lt;code&gt;baseValue&lt;/code&gt; updates the whole tree because that value flows to every node, but changing &lt;code&gt;rightValue&lt;/code&gt; only updates the right-most branch of the tree.&lt;/p&gt;&lt;p&gt;&lt;playground-project id=lit-dataflow-project project-src=/samples/lit-dataflow/project.json&gt;&lt;/playground-project&gt;&lt;/p&gt;&lt;p&gt;&lt;playground-preview project=lit-dataflow-project&gt;&lt;/playground-preview&gt;&lt;/p&gt;&lt;details&gt;&lt;summary&gt;Edit the files in this demo&lt;/summary&gt;&lt;playground-tab-bar project=lit-dataflow-project editor=lit-dataflow-editor class=playground-theme-seti&gt;&lt;/playground-tab-bar&gt;&lt;playground-file-editor id=lit-dataflow-editor project=lit-dataflow-project filename=demo-node.ts class=playground-theme-seti style=&quot;height: 800px&quot;&gt;&lt;/playground-file-editor&gt;&lt;/details&gt;&lt;h2&gt;Great, so what&#39;s missing?&lt;/h2&gt;&lt;p&gt;Lit&#39;s system is awesome (I know... I&#39;m biased), but it purposefully doesn&#39;t handle a lot of data management cases, and it&#39;s &lt;em&gt;shallow&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Lit, in the spirit of interoperable web components, is inherently local. Elements only control their own API surface. They don&#39;t dictate what kind of data you use, they don&#39;t patch other objects or globals. They don&#39;t interject Proxies into your data objects.&lt;/p&gt;&lt;p&gt;This means that Lit&#39;s reactive properties have a sometimes limited view of state changes - they only see changes on the elements themselves. This is similar to React which can only &quot;see&quot; top-level changes to props and state from &lt;code&gt;useState()&lt;/code&gt;. Observing deep changes is out of scope.&lt;/p&gt;&lt;p&gt;For developers, there are two main implications:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Elements may not update automatically in response to deep property changes.&lt;/li&gt;&lt;li&gt;Lit may do more work than strictly necessary to render a template because it assumes any state could have changed. (Though no-op updates are very fast)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;So how do elements respond to data changes deep within objects or collections?&lt;/p&gt;&lt;p&gt;The answer is it&#39;s left up to developers.&lt;/p&gt;&lt;p&gt;And this isn&#39;t a bad answer in my opinion. There are a &lt;em&gt;lot&lt;/em&gt; of ways to try to get deep observability of data, with few clear winners, and a lot of downsides to various approaches.&lt;/p&gt;&lt;p&gt;You have systems that lean on immutability, like Redux, and actually work pretty great with Lit&#39;s reactivity out of the box. Old proposals like &lt;code&gt;Object.observe()&lt;/code&gt;. Systems that use Proxies to wrap data and detect mutations. Systems that patch a bunch of globals like Array, Map, Set., etc. to detect mutations. Patterns based on &lt;code&gt;EventTarget&lt;/code&gt;, or Observables. Systems that let you build complex graphs of observable objects that work like generic versions of Lit&#39;s reactivity.&lt;/p&gt;&lt;p&gt;What&#39;s nice about Lit (via the &lt;code&gt;ReactiveElement&lt;/code&gt; base class) is that all of these observation systems can be plugged into Lit in the same way: use their custom observation API, and call &lt;code&gt;.requestUpdate()&lt;/code&gt; when something changes to provoke a Lit updates. There are Lit adapters for MobX, Redux, Preact Signals, RxJS, XState, etc., etc.&lt;/p&gt;&lt;p&gt;And of course, element authors can just call &lt;code&gt;this.requestUpdate()&lt;/code&gt; if an element knows some data has changed, like in an event handler that performs a mutation.&lt;/p&gt;&lt;h2&gt;Lit + Signals&lt;/h2&gt;&lt;p&gt;Before rambling on more, let&#39;s check out the new &lt;code&gt;@lit-labs/signals&lt;/code&gt; package.&lt;/p&gt;&lt;p&gt;The main thing is exports is the &lt;code&gt;SignalWatcher&lt;/code&gt; mixin. Using it is incredibly simple: Apply it to your element, use some signals, and your element will update when the signals change. That&#39;s it!&lt;/p&gt;&lt;p&gt;Here&#39;s a very basic demo of a &lt;em&gt;shared&lt;/em&gt; signal that can be read and written to by multiple elements:&lt;/p&gt;&lt;p&gt;&lt;playground-project id=signals-basic-project project-src=/samples/signals-basic/project.json&gt;&lt;/playground-project&gt;&lt;/p&gt;&lt;p&gt;&lt;playground-tab-bar project=signals-basic-project editor=signals-basic-editor class=playground-theme-seti&gt;&lt;/playground-tab-bar&gt;&lt;playground-file-editor id=signals-basic-editor project=signals-basic-project class=playground-theme-seti style=&quot;height: 800px&quot;&gt;&lt;/playground-file-editor&gt;&lt;/p&gt;&lt;p&gt;&lt;playground-preview project=signals-basic-project&gt;&lt;/playground-preview&gt;&lt;/p&gt;&lt;p&gt;This is just the simplest demo. You can get much more involved: put signals on instance fields of elements, use computed signals, build complex objects out of signals, share signals with the WCCG Context protocol, etc...&lt;/p&gt;&lt;h2&gt;Cool, but why am I so excited about signals? 🤔&lt;/h2&gt;&lt;p&gt;Fundamentally, the new signals integration is just more of the same: a helper that wraps the Lit update lifecycle to watch it and call &lt;code&gt;this.requestUpdate()&lt;/code&gt; when it sees that signals have changed. There are some subtle niceties around skipping full re-renders for pinpoint DOM updates and such, but the approach is the same as with, say, MobX.&lt;/p&gt;&lt;p&gt;What&#39;s different with the TC39 Signals proposal is that it advocates for adding a reactive primitive &lt;em&gt;directly to JavaScript&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;This means that we won&#39;t have to bring along a library to use signals, but three things are even more impactful, in my opinion:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Any library based on the JavaScript standard signals API will be &lt;em&gt;interoperable&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;JavaScript will have a universal reactive primitive that can be pervasively used by libraries and relied on by other parts of the web platform, like the DOM.&lt;/li&gt;&lt;li&gt;Other web standards can use signals&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Interoperable signals&lt;/h3&gt;&lt;p&gt;A future MobX based on standard signals will produce objects that are deeply observable by any library or framework that supports watching standard signals. No special MobX integration needed. Signal-backed collections, like those in the package &lt;a href=https://github.com/proposal-signals/signal-utils&gt;&lt;code&gt;signal-utils&lt;/code&gt;&lt;/a&gt;, can be mixed and matched from different libraries and seamlessly used in components, effects, etc.&lt;/p&gt;&lt;p&gt;The interoperability of standard signals is perfectly aligned with web components and will increase web components interoperability as well. Now multiple web components built with multiple libraries, or none at all, can share the same observable data and react to it, without having to use the same non-standard library.&lt;/p&gt;&lt;h3&gt;Universal reactive primitive&lt;/h3&gt;&lt;p&gt;As a universal reactive primitive, more libraries will choose to make signals part of their APIs. A remote data-syncing library might make all of its data object be backed by signals, so they then just plug into this ecosystem of observers.&lt;/p&gt;&lt;p&gt;I also think there&#39;s huge potential for using signal-based constructs to build very rich, observable, headless data models that are easily usable from any UI layer.&lt;/p&gt;&lt;p&gt;Many developers currently use utilities on the UI side of an app for dealing with async data, for instance. Think things like TanStack Query or Lit&#39;s Task helper. These are extremely useful, but I think even better patterns emerge when your data model itself can handle fetching more data, caching, metadata, and synchronization. You can make very nice APIs that abstract away details that are unimportant for components (usually the how) and focus on what is important (the what), and the data can be portably used in any signal-aware environment.&lt;/p&gt;&lt;h4&gt;Example: AsyncComputed&lt;/h4&gt;&lt;p&gt;In my own code I&#39;ve been moving away from using Lit&#39;s Task, which is a reactive controller that&#39;s tied to a single element, and towards using the &lt;a href=&quot;https://github.com/proposal-signals/signal-utils?tab=readme-ov-file#asynccomputed&quot;&gt;&lt;code&gt;AsyncComputed&lt;/code&gt; utility from &lt;code&gt;signal-utils&lt;/code&gt;&lt;/a&gt; (a utility I contributed).&lt;/p&gt;&lt;p&gt;&lt;code&gt;AsyncComputed&lt;/code&gt; lets you construct signals based on async computations. It&#39;s actually very similar to Lit&#39;s &lt;code&gt;Task&lt;/code&gt;, but instead of hooking Lit&#39;s reactive lifecycle, it reads from signals and publishes its state as various signals.&lt;/p&gt;&lt;p&gt;This is a port of the &lt;a href=&quot;https://lit.dev/playground/#sample=examples/async-task&quot;&gt;Lit Task example&lt;/a&gt; to use &lt;code&gt;AsyncComputed&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The interesting thing here is that the async work was moved into a UI-layer agnostic data model object. All the component has to do is read and write to the object. As data is fetched, the signals of the &lt;code&gt;AsyncComputed&lt;/code&gt; that hold the result are updated, and the components that use it are automatically updated as well.&lt;/p&gt;&lt;p&gt;&lt;playground-project id=async-computed-project project-src=/samples/async-computed/project.json&gt;&lt;/playground-project&gt;&lt;/p&gt;&lt;p&gt;&lt;playground-tab-bar project=async-computed-project editor=async-computed-editor class=playground-theme-seti&gt;&lt;/playground-tab-bar&gt;&lt;playground-file-editor id=async-computed-editor project=async-computed-project class=playground-theme-seti style=&quot;height: 800px&quot;&gt;&lt;/playground-file-editor&gt;&lt;/p&gt;&lt;p&gt;&lt;playground-preview project=async-computed-project style=&quot;height: 400px&quot;&gt;&lt;/playground-preview&gt;&lt;/p&gt;&lt;p&gt;I find this pattern especially useful for applications that navigate large object graphs with lazy loaded edges. I also have a wrapper on &lt;code&gt;AsyncComputed&lt;/code&gt; for lazy-loaded collections that helps with metadata like collection size and pagination. Using those collections from the UI layer is super easy.&lt;/p&gt;&lt;h3&gt;A reactive type for web standards&lt;/h3&gt;&lt;p&gt;One of the biggest changes that signals could bring, and only if they&#39;re standardized, is integration into other web standards like the DOM.&lt;/p&gt;&lt;p&gt;Imagine being able to assign a signal to an attribute or some text content and have the DOM automatically update when the signal changes!&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Signal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;amy123&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userNameSpan &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&#39;#user&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;name`&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// An imagined new API, but bear with me...&lt;/span&gt;
userNameSpan&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setTextContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Later...&lt;/span&gt;
userName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;joe456&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// And the &amp;lt;span&gt; updates to &amp;lt;span&gt;joe456&amp;lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&#39;m not sure about this &lt;code&gt;setTextContext()&lt;/code&gt; API I just dreamed up above, but I do think we have a potential lead on this type of reactivity with the DOM Parts proposal which aims to add markers and objects that directly represent dynamic segments of DOM - perfect for signals integration.&lt;/p&gt;&lt;pre class=language-html&gt;&lt;code class=language-html&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;template&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;parseparts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Current user: {{}}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; parts&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; template&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cloneWithParts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parts&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
userPart&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Later...&lt;/span&gt;
userName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;joe456&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// And the &amp;lt;p&gt; updates to &amp;lt;p&gt;Current user: joe456&amp;lt;/p&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the DOM ever gets a declarative JavaScript template API, like I&#39;m proposing in &lt;a href=https://github.com/WICG/webcomponents/issues/1069&gt;WICG/webcomponents#1069&lt;/a&gt;, we could do this with great ergonomics:&lt;/p&gt;&lt;pre class=language-ts&gt;&lt;code class=language-ts&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;html&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HTMLElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Signal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;amy123&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;html&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;p&gt;Current user: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/p&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Later...&lt;/span&gt;
userName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;joe456&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// And the &amp;lt;p&gt; updates to &amp;lt;p&gt;Current user: joe456&amp;lt;/p&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&#39;s a huge potential for built-in reactivity in the DOM, that could be unlocked by standard signals.&lt;/p&gt;&lt;h3&gt;Looking forward with &lt;code&gt;@lit-labs/signals&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;If you can&#39;t tell, I&#39;m pretty thrilled by everything related to standardized signals right now: the TC39 signals proposal, our integration with Lit, and the seemingly endless possibilities ahead of us.&lt;/p&gt;&lt;p&gt;Like all standards work, it&#39;s going to take a little while. So we have some time to shore up how things work on the Lit end.&lt;/p&gt;&lt;p&gt;A few things I&#39;d like to see added soon:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Support for auto-updating templates outside of &lt;code&gt;LitElement&lt;/code&gt; and &lt;code&gt;ReactiveElement&lt;/code&gt;: A lot of use cases are satisfied by simple templates, without the need for full-blown components. We&#39;ll need a scheduler interface in lit-html to make this work.&lt;/li&gt;&lt;li&gt;Signal aware &lt;code&gt;repeat()&lt;/code&gt; directive: Signal-oriented frameworks have optimizations built into their loop constructs that we can copy over to Lit.&lt;/li&gt;&lt;li&gt;Signal-backed &lt;code&gt;@property()&lt;/code&gt;: We can replace Lit&#39;s reactive property storage with signals and make integration into signals patterns even more powerful. Combined with effects would also address requests for property observers in Lit. Instead of a special Lit feature, you just read LitElement properties in a regular effect.&lt;/li&gt;&lt;li&gt;Batched effects in the standard signals API: I&#39;ve made a &lt;a href=https://github.com/tc39/proposal-signals/issues/239&gt;feature request&lt;/a&gt; to the signals proposal to allow for batching of signal updates, with an immediate flush of batched effects. This would allow us to move to synchronous rendering in Lit, by using signal-backed &lt;code&gt;@property()&lt;/code&gt;s and rendering in a batched effect, retaining our efficient DOM batching and tree-order rendering.&lt;/li&gt;&lt;li&gt;A tree-aware DOM scheduler API: Shared signals can introduce out-of-tree-order rendering without a central scheduler, but web components don&#39;t share a common scheduler, outside of built-ins like the microtask and task queues or animation frames, adn those aren&#39;t tree aware. I want to propose a &lt;a href=https://github.com/WICG/webcomponents/issues/1055&gt;tree-aware task scheduler for the DOM&lt;/a&gt; so that all web components, frameworks, and general DOM updating code can ensure that updates run in batched, top-down order.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;On the Lit team, we&#39;ll be working hard on our libraries and standards proposals to help bring about our glorious, interoperable, reactive future 😎&lt;/p&gt;&lt;p&gt;In the meantime, please try out the new &lt;code&gt;@lit-labs/signals&lt;/code&gt; package, &lt;code&gt;signal-utils&lt;/code&gt;, and build your own projects with signals and let us know how things work, or don&#39;t, for you!&lt;/p&gt;&lt;p&gt;Find the Lit team and community on &lt;a href=https://lit.dev/discord/ &gt;Discord&lt;/a&gt; or &lt;a href=https://github.com/lit/lit/discussions&gt;GitHub Discussions&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Links:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://lit.dev/blog/ &gt;Lit Blog Post on &lt;code&gt;@lit-labs/signals&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://lit.dev/docs/data/signals/ &gt;Docs for &lt;code&gt;@lit-labs/signals&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://github.com/lit/lit/discussions/4779&gt;&lt;code&gt;@lit-labs/signals&lt;/code&gt; Feedback Discussion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://github.com/tc39/proposal-signals&gt;Signals Proposal&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://github.com/proposal-signals/signal-utils&gt;&lt;code&gt;signal-utils&lt;/code&gt; repo&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description>
      <pubDate>Wed, 09 Oct 2024 08:00:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2024/10/09/reactive-state-with-signals-in-lit/</guid>
    </item>
    <item>
      <title>How to Publish Web Components to NPM</title>
      <link>https://justinfagnani.com/2019/11/01/how-to-publish-web-components-to-npm/</link>
      <description>&lt;p&gt;Publishing JavaScript to npm is a controversial affair. What should be a simple process, in my opinion, is fraught with a large number of correlated choices that are dependent not just on technical factors, but social factors like what users are used to, and how web-centric their point-of-view is.&lt;/p&gt;&lt;p&gt;Web components, being a superset of JavaScript, bring their own set of choices on top of this.&lt;/p&gt;&lt;p&gt;What follows is my personal checklist for publishing web components to npm. This checklist attempts to maximize compatibility, standards compliance, flexibility, and usefulness to your users.&lt;/p&gt;&lt;p&gt;These are my personal opinions, yes, but they are hard-won, toiled over, and hopefully well-reasoned opinions, so I (a bit obviously) think they&#39;re really the right way to go.&lt;/p&gt;&lt;h3&gt;Justin&#39;s Checklist for Publishing Web Components to NPM™&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;Publish standard ES2017&lt;/li&gt;&lt;li&gt;Publish standard JavaScript modules&lt;/li&gt;&lt;li&gt;Do not use .mjs file extensions&lt;/li&gt;&lt;li&gt;Only publish a single build&lt;/li&gt;&lt;li&gt;Important &lt;code&gt;package.json&lt;/code&gt; fields:&lt;ul&gt;&lt;li&gt;Set &lt;code&gt;&quot;type&quot;&lt;/code&gt; to &lt;code&gt;&quot;module&quot;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Set &lt;code&gt;&quot;main&quot;&lt;/code&gt; to the main entry point &lt;em&gt;module&lt;/em&gt;&lt;/li&gt;&lt;li&gt;Set &lt;code&gt;&quot;module&quot;&lt;/code&gt; to the same file as &lt;code&gt;&quot;main&quot;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Include polyfills in &lt;code&gt;devDependencies&lt;/code&gt;, not &lt;code&gt;dependencies&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Do not bundle&lt;/li&gt;&lt;li&gt;Do not minify&lt;/li&gt;&lt;li&gt;Always self-define elements&lt;/li&gt;&lt;li&gt;Export element classes&lt;/li&gt;&lt;li&gt;Do not import polyfills into modules&lt;/li&gt;&lt;li&gt;Import dependencies with &quot;bare&quot; or &quot;named&quot; import specifiers&lt;/li&gt;&lt;li&gt;Always include file extensions in import specifiers&lt;/li&gt;&lt;li&gt;Publish a &lt;code&gt;custom-elements.json&lt;/code&gt; file documenting your elements&lt;/li&gt;&lt;li&gt;Include good TypeScript typings&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now let&#39;s get into the *why *for each recommendation.&lt;/p&gt;&lt;h2&gt;Publish standard ES2017&lt;/h2&gt;&lt;p&gt;Modern JavaScript is smaller, faster, and more capable than the same code transpiled to an old version of JS like ES5, and the vast majority of users have browsers that support it.&lt;/p&gt;&lt;p&gt;So it&#39;s very preferable to send the most modern JavaScript to users that you can. But you can&#39;t send modern JS to browsers if you don&#39;t have it to begin with. Consumers of your packages can compile the code to a lower language level if they need to, but they can&#39;t &lt;em&gt;un-compile&lt;/em&gt; your code to a newer language version.&lt;/p&gt;&lt;p&gt;Another way to frame this is that only applications know their exact browser support levels. Some applications need to support very old browsers. Some, maybe running in Electron, only need to support the latest Chrome. Reusable libraries can&#39;t know what the browser requirements are, and should publish modern JS to give the most flexibility to applications.&lt;/p&gt;&lt;p&gt;But how modern? This is the tricky part. I choose ES2017 because &lt;a href=https://kangax.github.io/compat-table/es2016plus/ &gt;it&#39;s very widely supported across Chrome, Safari, Firefox, and Edge&lt;/a&gt;. This means that for most browsers you don&#39;t need to compile at all.&lt;/p&gt;&lt;p&gt;I once had tried to come up with a convention that would describe what language version to publish, like &quot;ESY-1&quot;, meaning in 2019 publish ES2018, but Edge has slipped a bit and doesn&#39;t support object spread/rest, so this didn&#39;t hold. I think the situation will be a little clearer when Edge ships with the Chromium backend, hopefully soon.&lt;/p&gt;&lt;p&gt;What do users do who need to support IE11? They need to compile dependencies inside &lt;code&gt;node_modules/&lt;/code&gt;. This is something that should be more common, because it solves a lot of problems with JS distribution. If this is slow with some tools, my opinion is that those tools need to cache intermediate build results better because you should only recompile dependencies when they change.&lt;/p&gt;&lt;h2&gt;Publish standard JavaScript modules&lt;/h2&gt;&lt;p&gt;All modern browsers and tool-chains support standard JavaScript modules, and browsers &lt;em&gt;don&#39;t&lt;/em&gt; natively support any other module format. This means that if you publish modules, they can load uncompiled.&lt;/p&gt;&lt;p&gt;This is especially nice for development, where the less transforms on code you do the better the debugging experience is. Native modules are great to use during development without bundling too. A static file server that properly sends &lt;code&gt;304&lt;/code&gt; response codes for unmodified files will take maximum advantage of the browser&#39;s cache and only send the files that changed.&lt;/p&gt;&lt;p&gt;Most applications are not serving native modules to browsers yet, but the application&#39;s tool chain can certainly handle modules as input and transform and bundle them to whatever format the app is using.&lt;/p&gt;&lt;h2&gt;Do not use .mjs file extensions&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;.mjs&lt;/code&gt; file extension is as useless for browsers as it is controversial. There&#39;s really no benefit at all from using it. Browsers only care about the mime type of files, not the file extension, so &lt;code&gt;.mjs&lt;/code&gt; does nothing there. And tools look to &lt;code&gt;package.json&lt;/code&gt; to determine if a package contains modules, so there&#39;s no benefit there.&lt;/p&gt;&lt;p&gt;There are downsides to &lt;code&gt;.mjs&lt;/code&gt; though: not every tool in the world understands it. Some static file servers may not send the right mime-type header, meaning that the file won&#39;t load as a module in browsers.&lt;/p&gt;&lt;p&gt;The best thing is to just avoid it altogether and always write and publish modules, and always use the &lt;code&gt;.js&lt;/code&gt; extension.&lt;/p&gt;&lt;h2&gt;Only publish a single build&lt;/h2&gt;&lt;p&gt;It&#39;s pretty common on npm to publish multiple builds. This is a bad and outdated practice that can lead to bloat in application bundles. The reason is that multiple libraries may share a common dependency, but if they import different builds, the bundles will end up with slightly different duplicates of the dependency.&lt;/p&gt;&lt;p&gt;In the case of web components, this is especially dangerous, since we really need there to be a single definition of a component. Multiple versions here is a bigger headache than just bloat.&lt;/p&gt;&lt;p&gt;And again, if the application consumes standard JS modules in its build pipeline, it can transform that to whatever single format it needs. There is really no need to publish multiple builds ever.&lt;/p&gt;&lt;p&gt;I really recommend holding this line against the inevitable issues and PRs that will ask you to add an ES5 UMD build.&lt;/p&gt;&lt;h2&gt;Important package.json fields&lt;/h2&gt;&lt;h3&gt;Set &quot;type&quot; to &quot;module&quot;&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;&quot;type&quot;&lt;/code&gt; field is the standard way to indicate that JavaScript files in an npm package are modules. Tools like CDNs and bundlers can use this to properly parse files with module parse goal.&lt;/p&gt;&lt;p&gt;With this field you do &lt;em&gt;not&lt;/em&gt; need to use the &lt;code&gt;.mjs&lt;/code&gt; extension, even in Node.&lt;/p&gt;&lt;h3&gt;Set &quot;main&quot; to the main entry point module&lt;/h3&gt;&lt;p&gt;This is just standard practice with the slight difference that most packages today publish some kind of non-modules build and point &lt;code&gt;&quot;main&quot;&lt;/code&gt; to that. It&#39;ll be unusal to some to point this field to a module, but it&#39;s semantically correct, goes along with &lt;code&gt;&quot;type&quot;: &quot;module&quot;&lt;/code&gt;, and npm requires a &lt;code&gt;&quot;main&quot;&lt;/code&gt; entry.&lt;/p&gt;&lt;h3&gt;Set &quot;module&quot; to the same file as &quot;main&quot;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;&quot;type&quot;: &quot;module&quot;&lt;/code&gt; is the most correct way to specify that a package contains modules, but tools have supported the &lt;code&gt;&quot;module&quot;&lt;/code&gt; field for a while, and we&#39;ll have to use this for a while yet before all tools support the &lt;code&gt;&quot;type&quot;&lt;/code&gt; field.&lt;/p&gt;&lt;h3&gt;Include polyfills in devDependencies, not dependencies&lt;/h3&gt;&lt;p&gt;Polyfills are an application concern, so the application should depend directly on them. Packages may need to depend on polyfills for tests and demos, so if they&#39;re needed, they should only go in &lt;code&gt;&quot;devDependencies&quot;&lt;/code&gt;.&lt;/p&gt;&lt;h2&gt;Do not bundle&lt;/h2&gt;&lt;p&gt;This one has a little bit of wiggle room depending on the structure of your package.&lt;/p&gt;&lt;p&gt;The most important advice here is to not bundle dependencies. This keeps you from causing bloat by duplicating dependencies into multiple package bundles.&lt;/p&gt;&lt;p&gt;As long as you don&#39;t bundle dependencies, you may decide to bundle your package in order to hide implementation modules. If you do, make sure you preserve all the valid entry points of your package as separate entry point files into a set of bundles with shared chunks.&lt;/p&gt;&lt;p&gt;That is, if you support importing &lt;code&gt;&#39;my-library/element-a.js&#39;&lt;/code&gt; and &lt;code&gt;&#39;my-library/element-b.js&lt;/code&gt; don&#39;t bundle them together. The browser&#39;s module loader acts as a natural tree-shaker, in that it only loads the modules it needs. It&#39;s important then to keep modules relatively small and single-purposed. Let consumers import just the parts of your package that they need. Bundlers will have an easier time of creating small bundles too. So don&#39;t let per-package bundling lead to bloat for applications.&lt;/p&gt;&lt;p&gt;I find it simpler to just not bundle libraries at all. The application&#39;s build pipeline will take of it how it sees fit.&lt;/p&gt;&lt;h2&gt;Do not minify&lt;/h2&gt;&lt;p&gt;Just like the recommendations to not publish builds less than ES2017 and to not bundle, minification should be an application concern. It&#39;s much easier to debug non-minified code, and minifiers get better over time, so don&#39;t bake this into your published files.&lt;/p&gt;&lt;h2&gt;Always self-define elements&lt;/h2&gt;&lt;p&gt;The module that declares the web component class should always include a call to &lt;code&gt;customElements.define()&lt;/code&gt; to define the element.&lt;/p&gt;&lt;p&gt;This is a contentious point, but currently there is no other practical choice. Some people would like to allow consumers of components to choose the tag name, so they advocate leaving out the &lt;code&gt;customElements.define()&lt;/code&gt; call, or putting it in a separate module, but this doesn&#39;t actually work out well.&lt;/p&gt;&lt;p&gt;Custom elements currently require that there be a strict one-to-one relationship between tag names and classes. This means that if a custom element doesn&#39;t self-define, it leaves open the possibility that multiple consumers try to register the element and only the first will succeed.&lt;/p&gt;&lt;p&gt;If consumers really want to choose a different tag name, they can create a trivial subclass of the element and register that:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;SomeElement&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;some-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-some-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; SomeElement&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will all change when we finally get &lt;a href=https://github.com/w3c/webcomponents/issues/716&gt;scoped custom element registries&lt;/a&gt;. Then consumers will be able to register elements into a scope that they fully control and can choose whatever that names they want.&lt;/p&gt;&lt;h2&gt;Export element classes&lt;/h2&gt;&lt;p&gt;In order to support the trivial subclassing pattern described above and subclassing in general, you should export the element class:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Do not import polyfills into modules&lt;/h2&gt;&lt;p&gt;This is important general advice, but it&#39;s worth repeating for web components.&lt;/p&gt;&lt;p&gt;To go along with the &quot;Only the application knows&quot; mantra, only the application knows what polyfills are necessary for it&#39;s target environments. Most users don&#39;t need the web components polyfills, so a well-constructed application will not serve them to those users, or will use the webcomponentsjs polyfill loader to only dynamically load them when necessary.&lt;/p&gt;&lt;p&gt;If your library directly imports polyfills, it makes it pretty tricky for applications to pull them out when they don&#39;t need them.&lt;/p&gt;&lt;h2&gt;Import dependencies with &quot;bare&quot; or &quot;named&quot; import specifiers&lt;/h2&gt;&lt;p&gt;It&#39;s common practice in Node and on npm to import external dependencies by package name.&lt;/p&gt;&lt;p&gt;Node natively supports this in CommonJS modules with &lt;code&gt;require()&lt;/code&gt; and node module resolution:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; otherLib &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;other-lib&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And developers these days are pretty used to writing standard JS module syntax that uses node module resolution:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; otherLib &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;other-lib&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These are called &quot;bare import specifiers&quot; or &quot;named imports&quot;, and &lt;strong&gt;browsers don&#39;t actually support them&lt;/strong&gt;! At least not yet. Browsers only support importing by URL. So all imports must by a full URL (&lt;code&gt;http://&lt;/code&gt;) or be a relative URL starting with &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;./&lt;/code&gt; or &lt;code&gt;../&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;What&#39;s happening to make bare specifiers work in browsers is that tools like Rollup and Webpack are performing node module resolution at build time and transforming these paths while they&#39;re building the whole application.&lt;/p&gt;&lt;p&gt;So if we want to publish standard modules to npm so that they can load without compilation, and we have dependencies that we need to import what do we do?&lt;/p&gt;&lt;p&gt;We could try to use relative paths to point to dependencies, like this:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; otherLib &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;../other-lib/index.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But this requires that we know exactly where &lt;code&gt;other-lib&lt;/code&gt; is located on the file system relative to the importing module. The problem is that npm can install modules in a number of different locations, so we can&#39;t possibly know the right path to use. Paths will be different when your package is the top package, and you dependencies will likely be at &lt;code&gt;./node_modules/&lt;/code&gt;, and when your package is installed as a dependencies might be at &lt;code&gt;../node_modules&lt;/code&gt;. Servers and build-systems could move files around too.&lt;/p&gt;&lt;p&gt;An even bigger problem is that most tools do not understand these kind of relative paths that reach out of package boundaries. VS Code and TypeScript get mightily confused in my experience.&lt;/p&gt;&lt;p&gt;So right now the best option is to import dependencies by name and let tools rewrite the import specifiers before they reach the browser. This works really well in practice. Since basically all tools support named specifiers, compatibility is good there, and a number of tools have popped up that only rewrite import specifiers and leave individual modules otherwise untouched to be loaded natively by browsers.&lt;/p&gt;&lt;p&gt;We pioneered this on my team with the Polymer CLI which rewrites specifiers on the fly in it&#39;s &lt;code&gt;polymer serve&lt;/code&gt; command, and other tools like &lt;code&gt;[es-dev-server](https://open-wc.org/developing/es-dev-server.html)&lt;/code&gt; and &lt;a href=https://unpkg.com/ &gt;the unpkg.com CDN with the &lt;code&gt;?module&lt;/code&gt; query parameter&lt;/a&gt; do this.&lt;/p&gt;&lt;p&gt;In the near future, browsers will support &lt;a href=https://github.com/WICG/import-maps&gt;&quot;import maps&quot;&lt;/a&gt; that will tell them how to translate names into URLs, so they too will support named imports. Yay!&lt;/p&gt;&lt;h2&gt;Always include file extensions in import specifiers&lt;/h2&gt;&lt;p&gt;Classic Node module resolution doesn&#39;t require file extensions because it does a search of the file system looking for one of several file extensions if one isn&#39;t given. When you import &lt;code&gt;some-package/foo&lt;/code&gt;, Node will import &lt;code&gt;some-package/foo.js&lt;/code&gt; if it exists. This isn&#39;t feasible over a network, so browsers will not do this kind of searching.&lt;/p&gt;&lt;p&gt;Import maps will allow mapping names to URLs, but they only have two type of mappings: exact and prefix. Here&#39;s an example for &lt;code&gt;lodash&lt;/code&gt;:&lt;/p&gt;&lt;pre class=language-json&gt;&lt;code class=language-json&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lodash&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/node_modules/lodash-es/lodash.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lodash/&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/node_modules/lodash-es/&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This means that we can easily map a bare specifier like &lt;code&gt;lodash&lt;/code&gt;, or a prefix + full file path, like &lt;code&gt;lodash/forEach.js&lt;/code&gt;, etc., but to support extensionless imports like &lt;code&gt;lodash/forEach&lt;/code&gt;, we&#39;d have to map every one to the full path, like:&lt;/p&gt;&lt;pre class=language-json&gt;&lt;code class=language-json&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;imports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lodash&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/node_modules/lodash-es/lodash.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lodash/&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/node_modules/lodash-es/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;lodash/forEach&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/node_modules/lodash-es/forEach.js&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We would have to do this for every extensionless import in the entire app. &lt;code&gt;lodash-es&lt;/code&gt; has &lt;em&gt;341&lt;/em&gt; modules that could be imported. Creating entries for each one that&#39;s imported without extensions would make for a bloated import map, so it&#39;s much better to just use extensions in imports and have only a prefix import map entry.&lt;/p&gt;&lt;h2&gt;Publish a custom-elements.json file documenting your elements&lt;/h2&gt;&lt;p&gt;Web components tools, like &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin&quot;&gt;IDE plugins&lt;/a&gt; and &lt;a href=https://catalog.open-wc.org/ &gt;catalogs&lt;/a&gt;, are  starting to converge on a common format for describing the custom elements publish in an npm package.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;custom-elements.json&lt;/code&gt; file describes the tag names, attributes, properties, events, etc., that an element supports. With this information IDEs can provide auto-completion, hover-over docs, etc; linters can check that you&#39;re using defined properties; type checkers can ensure property bindings are of the correct type; documentation viewers can display the information for human consumption; and catalogs like Storybook can generate &quot;knobs&quot; for components automatically.&lt;/p&gt;&lt;p&gt;Rune Mehlsen, an amazing developer who maintains the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin&quot;&gt;&lt;code&gt;lit-plugin&lt;/code&gt;&lt;/a&gt; VS Code plugin, also maintains &lt;a href=https://www.npmjs.com/package/web-component-analyzer&gt;&lt;code&gt;web-component-analyzer&lt;/code&gt;&lt;/a&gt; that outputs this format.&lt;/p&gt;&lt;p&gt;Including this file will greatly enhance the developer experience of your users.&lt;/p&gt;&lt;h2&gt;Include good TypeScript typings&lt;/h2&gt;&lt;p&gt;I&#39;m a huge fan of TypeScript, and one of my favorite things about its type system is how it&#39;s able to type APIs that use string keys.&lt;/p&gt;&lt;p&gt;One example is the &lt;code&gt;document.createElement()&lt;/code&gt; method. It&#39;s return type depends on the &lt;em&gt;value&lt;/em&gt; of the string parameter passed to it, so that &lt;code&gt;document.createElement(&#39;div&#39;)&lt;/code&gt; returns an &lt;code&gt;HTMLDivElement&lt;/code&gt; and &lt;code&gt;document.createElement(&#39;img&#39;)&lt;/code&gt; returns an &lt;code&gt;HTMLImageElement&lt;/code&gt;. This let&#39;s code like this type-check:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;div&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./image.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// error!&lt;/span&gt;
document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;img&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./image.jpg&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// fine :)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The best part about this is it&#39;s based on a mapping from tag name to class that &lt;em&gt;you can extend&lt;/em&gt;. It&#39;s called the &lt;code&gt;HTMLElementTagNameMap&lt;/code&gt;. To extend it to add your element, use TypeScript&#39;s interface augmentation.&lt;/p&gt;&lt;p&gt;A full custom element definition in TypeScript should look something like this:&lt;/p&gt;&lt;pre class=language-typescript&gt;&lt;code class=language-typescript&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LitElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-element&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;declare&lt;/span&gt; global &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElementTagNameMap&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;my-element&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MyElement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Of course you can just add this to your typings too if you&#39;re not writing your element in TypeScript. The benefits to your TypeScript users will be huge.&lt;/p&gt;&lt;h1&gt;Disagree? Comments and Questions?&lt;/h1&gt;&lt;p&gt;I know some of these recommendations are controversial, and the finer points can be open to interpretation and debate, but I firmly believe that this is the best way to publish web components in late 2019.&lt;/p&gt;&lt;p&gt;I don&#39;t have comments enabled on this blog for good reasons, but you can find me on Twitter at &lt;a href=https://twitter.com/justinfagnani&gt;@justinfagnani&lt;/a&gt;. I can&#39;t promise I&#39;ll have the time or inclination to debate these recommendations, but I try to answer questions. Of course, if you seriously disagree you can publish your own recommendations too! 😎&lt;/p&gt;</description>
      <pubDate>Fri, 01 Nov 2019 18:58:10 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2019/11/01/how-to-publish-web-components-to-npm/</guid>
    </item>
    <item>
      <title>Enhancing Mixins with Decorator Functions</title>
      <link>https://justinfagnani.com/2016/01/07/enhancing-mixins-with-decorator-functions/</link>
      <description>&lt;p&gt;Last time, in &lt;a href=http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/ &gt;&quot;Real&quot; Mixins with JavaScript Classes&lt;/a&gt;, we saw how we can create powerful ES6 mixins by using class expressions as subclass factories.&lt;/p&gt;&lt;p&gt;Now, let&#39;s look at some enhancements that make our mixins more powerful, in a way still requires no framework for mixin users, and is still easy to use for mixin authors.&lt;/p&gt;&lt;p&gt;First, we&#39;ll look at how subclass-factory-style mixins can be wrapped, or decorated, to add aditional features. Then we&#39;ll enable the caching of mixin applications, so that the same mixin definition applied to the same superclass multiple times reuses the same mixin application, and implement ES2015&#39;s &lt;code&gt;@@hasInstance&lt;/code&gt;[^1] method so that &lt;code&gt;instanceof&lt;/code&gt; works with mixins!&lt;/p&gt;&lt;h2&gt;The Technique and Some Groundwork&lt;/h2&gt;&lt;p&gt;We&#39;re going to add these enhancements at the mixin definition site, so that only the mixin author needs to do anything to get them.&lt;/p&gt;&lt;p&gt;Recall a mixin definition from the last post:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;MyMixin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Our new enhancements are built as functions that wrap the mixin function. Mixin declaration will now look like this:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MyMixin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BaseMixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;BaseMixin&lt;/code&gt; wraps the author&#39;s subclass factory in a function that does a little extra work before calling the factory. This is very much like &lt;a href=https://github.com/wycats/javascript-decorators&gt;ES.next decorators&lt;/a&gt;, just without the special &lt;code&gt;@BaseMixin&lt;/code&gt; syntax, so I&#39;ll call them decorator functions.&lt;/p&gt;&lt;p&gt;All kinds of behaviors can be added to mixins by adding more wrappers. Since we&#39;re going to implement caching and &lt;code&gt;@@hasInstance&lt;/code&gt; support, our mixin definitions might end up looking like this:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MyMixin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Cached&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HasInstance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;BaseMixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This should be fairly easy for authors to use, and mixin users don&#39;t need to do anything different. Mixin application still just works as function invocation:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyMixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyMixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or we can use &lt;code&gt;mix().with()&lt;/code&gt;:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyMixin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyMixin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;mix().with()&lt;/code&gt; is still just plain and optional sugar around function invocation.&lt;/p&gt;&lt;p&gt;If we implement &lt;code&gt;Cached&lt;/code&gt; and &lt;code&gt;HasInstance&lt;/code&gt; correctly, the mixins and classes suddenly have new powers:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

a &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;
b &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can use standard function composition to create a convenience decorator for the common behaviors:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Mixin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Cached&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;HasInstance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;BaseMixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MyMixin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Wrapping with Care&lt;/h3&gt;&lt;p&gt;We have to be a little more careful with wrapping mixin functions than usual because we want the final result of calling the decorators to be an object with certain properties, like &lt;code&gt;@@hasInstance&lt;/code&gt;. We don&#39;t know what decorators might be applied to our mixin, and we&#39;d like to avoid requiring a specific ordering of decorators, so we don&#39;t want to obscure properties added by one wrapper with a subsequent wrapper.&lt;/p&gt;&lt;p&gt;To solve this we&#39;ll create a &lt;code&gt;wrap&lt;/code&gt; utility that sets the prototype of the wrappers, and stores a property pointing to the original mixin function so that we have a canonical identity for a mixin:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; _originalMixin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;_originalMixin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;wrap&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wrapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wrapper&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_originalMixin&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    mixin&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_originalMixin&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; wrapper&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This makes our function wrapping behave a lot more like inheritance.&lt;/p&gt;&lt;p&gt;Next, we&#39;ll create a base mixin decorator that applies the mixin and stores a reference from the mixin application back to the mixin definition for later use in caching:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;BaseMixin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; application &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  application&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_mixinRef&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_originalMixin&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; application&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice the call to &lt;code&gt;wrap&lt;/code&gt;. This sets things up so that other mixin decorators can add properties to the mixin and have them be visible after wrapping.&lt;/p&gt;&lt;h2&gt;Caching Mixin Applications&lt;/h2&gt;&lt;p&gt;The whole purpose of mixins is to apply them to different superclasses so that using a mixin doesn&#39;t require a specific inheritance hierarchy. However, mixins may still be repeatedly applied to the same superclass.&lt;/p&gt;&lt;p&gt;Consider two classes, &lt;em&gt;B&lt;/em&gt; and &lt;em&gt;C&lt;/em&gt; which both extend &lt;em&gt;A&lt;/em&gt; and mixin &lt;em&gt;M1&lt;/em&gt; and &lt;em&gt;M2&lt;/em&gt;:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;M2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;M2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The simplest mixin implementation will produce two identical &lt;em&gt;A-with-M1&lt;/em&gt; and two identical &lt;em&gt;A-with-M1-with-M2&lt;/em&gt; prototypes.&lt;/p&gt;&lt;p&gt;&lt;img src=https://justinfagnani.com/content/images/2015/06/class-hierarchy-4-1.svg alt=&quot;&quot;&gt;&lt;/p&gt;&lt;p&gt;Instead we would like to share identical applications:&lt;/p&gt;&lt;p&gt;&lt;img src=https://justinfagnani.com/content/images/2015/06/class-hierarchy-5.svg alt=&quot;&quot;&gt;&lt;/p&gt;&lt;p&gt;We can do this by caching mixin applications on classes:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; _mixinRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;_mixinRef&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Cached&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Create a symbol used to reference a cached application from a superclass&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; applicationRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_cachedApplicationRef&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;applicationRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    applicationRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_cachedApplicationRef&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Look up an cached application of `mixin` to `superclass`&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;applicationRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; superclass&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;applicationRef&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Apply the mixin&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; application &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Cache the mixin application on the superclass&lt;/span&gt;
  superclass&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;applicationRef&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; application&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; application&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Hopefully the comments are easy to follow. The approach is to create a unique symbol per mixin, then store mixin applications in a property keyed by that symbol on the superclass of a mixin application. That allows us to look up and reuse previous applications of a mixin to a superclass.&lt;/p&gt;&lt;p&gt;If this seems like overkill, consider cases where you must extend a certain class, yet libraries would like to offer help in customizing those subclasses.&lt;/p&gt;&lt;p&gt;I&#39;m thinking of custom elements here, and specifically, libraries like Polymer. Custom elements need to extend one of the built-in elements - at the very least &lt;em&gt;HTMLElement&lt;/em&gt; - but Polymer does a lot of work by being on the prototype chain. Mixins make this easy to express:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyElement&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HTMLElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Polymer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But with naive mixins a new identical superclass of &lt;em&gt;HTMLElement-With-Polymer&lt;/em&gt; is created for every custom element class, wasting time and memory. With mixin application caching this can be easy &lt;em&gt;and&lt;/em&gt; efficient.&lt;/p&gt;&lt;h2&gt;Adding instanceof Support&lt;/h2&gt;&lt;p&gt;ES2015 has support for &lt;a href=http://people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator&gt;overriding the &lt;code&gt;instanceof&lt;/code&gt; operator&lt;/a&gt; via the &lt;code&gt;@@hasInstance&lt;/code&gt; method, which should be implemented by objects that appear of the &lt;em&gt;righthand&lt;/em&gt; side of an &lt;code&gt;instanceof&lt;/code&gt; operator[^2].&lt;/p&gt;&lt;p&gt;Ideally an expression like &lt;code&gt;o instanceof MyMixin&lt;/code&gt; would work as expected: if &lt;code&gt;o&lt;/code&gt; is an instance of a class that has mixed in &lt;code&gt;MyMixin&lt;/code&gt;, the expression should return true.&lt;/p&gt;&lt;p&gt;With mixins, the &quot;type&quot; is one of our subclass factory functions, so we need to patch the &lt;code&gt;@@hasInstance&lt;/code&gt; method into the mixin. The prototype setting we did in the groundwork section will ensure that this method is available even after subsequent wrapping.&lt;/p&gt;&lt;p&gt;Out patch looks like this:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;HasInstance&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;Symbol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hasInstance&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  mixin&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Symbol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hasInstance&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; originalMixin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_originalMixin&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_mixinRef&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;&amp;&lt;/span&gt; o&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_mixinRef&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; originalMixin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      o &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;o&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I can&#39;t find that this is actually implemented in any production VM yet, but it looks like Webkit has initial support, along with Babel under a flag.&lt;/p&gt;&lt;h2&gt;Writing Your Own Mixin Decorators&lt;/h2&gt;&lt;p&gt;&lt;a href=https://github.com/justinfagnani/mixwith.js&gt;mixwith.js&lt;/a&gt; includes the &lt;code&gt;wrap&lt;/code&gt; utility and some common symbols that help with writing mixin decorators. You can use these to write decorators that play well with each other. What kind of decorators might you want to write? Maybe a de-duplication, so that a mixin applied twice to a prototype chain only appears once in the chain, or a traits-like system that disallows overriding.&lt;/p&gt;&lt;p&gt;There are probably two main types of mixin decorators: those that need to wrap the mixin function, and those that just need to patch it.&lt;/p&gt;&lt;p&gt;If you need to wrap the mixin function, make sure you call &lt;code&gt;wrap&lt;/code&gt; and usually you want to invoke the mixin function. Sometimes you may want to conditionally invoke the mixin, like with de-duplication:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; wrap &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;mixwith&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DeDupe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mixin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mixinAlreadyApplied&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; superclass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you only need to patch the mixin function, just patch and return it:&lt;/p&gt;&lt;pre class=language-javascript&gt;&lt;code class=language-javascript&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Fooify&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  mixin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;foo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mixin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Follow the conversation&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=https://www.reddit.com/r/javascript/comments/3zw60e/enhancing_subclassfactorystyle_javascript_mixins/ &gt;reddit.com/r/javascript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;p&gt;[^1]: @@foo is shorthand for Symbol.foo in the &lt;a href=http://www.ecma-international.org/ecma-262/6.0/index.html#sec-well-known-symbols&gt;JavaScript specification&lt;/a&gt;&lt;/p&gt;&lt;p&gt;[^2]: This is fabulous for extensibility, since new types can accept an instance without having to modify the instance. You can implement any kind of type checking you want, say structural typing. It&#39;s terrible for static type checking, however.&lt;/p&gt;</description>
      <pubDate>Thu, 07 Jan 2016 08:16:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2016/01/07/enhancing-mixins-with-decorator-functions/</guid>
    </item>
    <item>
      <title>&quot;Real&quot; Mixins with JavaScript Classes</title>
      <link>https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/</link>
      <description>&lt;h2&gt;Mixins and Javascript: The Good, the Bad, and the Ugly.&lt;/h2&gt;&lt;p&gt;Mixins and JavaScript are a like the classic Clint Eastwood movie.&lt;/p&gt;&lt;p&gt;The good is that composing objects out of small pieces of implementation is even possible due to JavaScript&#39;s flexible nature, and that mixins are fairly popular in certain circles.&lt;/p&gt;&lt;p&gt;The bad is a long list: there&#39;s no common idea of what the concept of a mixin even is in JavaScript; there&#39;s no common pattern for them; they require helper libraries to use; more advanced composition (like coordination between mixins and prototypes) is complicated and does not fall out naturally from the patterns; they&#39;re difficult to statically analyze and introspect; finally, most mixin libraries mutate objects or their prototypes, causing problems for VMs and some programmers to avoid them.&lt;/p&gt;&lt;p&gt;The ugly is that the result of all this is a balkanized ecosystem of mixin libraries and mixins, with often incompatible construction and semantics across libraries. As far as I can tell, no particular library is popular enough to even be called common. You&#39;re more likely to see a project implement its own mixin function than see a mixin library used.&lt;/p&gt;&lt;p&gt;JavaScript mixins so far have simply fallen well short of their potential, of how mixins are described in academic literature and even implemented in a few good languages.&lt;/p&gt;&lt;p&gt;For someone who loves mixins, and thinks they should be used as much as possible, this is terrible. Mixins solve a number of issues that single-inheritance languages have, and to me, most of the complaints that the prototypal crowd has against classes in JavaScript. I would argue all inheritance should be mixin inheritance - subclassing is just a degenerate form of mixin application.&lt;/p&gt;&lt;p&gt;Luckily, there&#39;s light at the end of the tunnel with JavaScript classes. Their arrival finally gives JavaScript very easy to use syntax for inheritance. JavaScript classes are more powerful than most people realize, and are a great foundation for building &lt;em&gt;real&lt;/em&gt; mixins.&lt;/p&gt;&lt;p&gt;In this post I&#39;ll explore what mixins should do, what&#39;s wrong with current JavaScript mixins, and how simple it is to build a very capable mixin system in JavaScript that plays extremely well with classes.&lt;/p&gt;&lt;h2&gt;What, Exactly, are Mixins?&lt;/h2&gt;&lt;p&gt;To understand what a mixin implementation should do, let&#39;s first look at what mixins are:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A mixin is an abstract subclass; i.e. a subclass definition that may be applied to different superclasses to create a related family of modified classes.&lt;/p&gt;&lt;p&gt;&lt;cite&gt;Gilad Bracha and William Cook, &lt;a href=http://www.bracha.org/oopsla90.pdf&gt;Mixin-based Inheritance&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This is the best definition of mixins I&#39;ve been able to find. It clearly shows the difference between a mixin and a normal class, and strongly hints at how mixins can be implemented in JavaScript.&lt;/p&gt;&lt;p&gt;To dig deeper into the implications of this definition, let&#39;s add two terms to our mixin lexicon:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;mixin definition&lt;/em&gt;: The definition of a class that may be applied to different superclasses.&lt;/li&gt;&lt;li&gt;&lt;em&gt;mixin application&lt;/em&gt;: The application of a mixin definition to a specific superclass, producing a new subclass.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The mixin definition is really a &lt;em&gt;subclass factory&lt;/em&gt;, parameterized by the superclass, which produces mixin applications. A mixin application sits in the inheritance hierarchy between the subclass and superclass.&lt;/p&gt;&lt;p&gt;The real, and only, difference between a mixin and normal subclass is that a normal subclass has a fixed superclass, while a mixin definition doesn&#39;t yet have a superclass. Only the &lt;em&gt;mixin applications&lt;/em&gt; have their own superclasses. You can even look at normal subclass inheritance as a degenerate form of mixin inheritance where the superclass is known at class definition time, and there&#39;s only one application of it.&lt;/p&gt;&lt;h3&gt;Examples&lt;/h3&gt;&lt;p&gt;Here&#39;s an example of &lt;a href=https://www.dartlang.org/articles/mixins/ &gt;mixins in Dart&lt;/a&gt;, which has a nice syntax for mixins while being similar to JavaScript:&lt;/p&gt;&lt;pre class=language-dart&gt;&lt;code class=language-dart&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;M&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here &lt;em&gt;A&lt;/em&gt; is a base class, &lt;em&gt;B&lt;/em&gt; the subclass, and &lt;em&gt;M&lt;/em&gt; a mixin. The mixin application is the specific combination of &lt;em&gt;M&lt;/em&gt; mixed into &lt;em&gt;A&lt;/em&gt;, often called &lt;em&gt;A-with-M&lt;/em&gt;. The superclass of &lt;em&gt;A-with-M&lt;/em&gt; is &lt;em&gt;A&lt;/em&gt;, and the actual superclass of &lt;em&gt;B&lt;/em&gt; is not &lt;em&gt;A&lt;/em&gt;, as you might expect, but &lt;em&gt;A-with-M&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Some class declarations and diagrams might be helpful to show what&#39;s going on.&lt;/p&gt;&lt;p&gt;Let&#39;s start with a simple class hierarchy, with class &lt;em&gt;B&lt;/em&gt; inheriting from class &lt;em&gt;A&lt;/em&gt;:&lt;/p&gt;&lt;pre class=language-dart&gt;&lt;code class=language-dart&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=https://justinfagnani.com/content/images/2015/06/class-hierarchy-1-1.svg alt=&quot;&quot;&gt;&lt;/p&gt;&lt;p&gt;Now let&#39;s add the mixin:&lt;/p&gt;&lt;pre class=language-dart&gt;&lt;code class=language-dart&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;M&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=https://justinfagnani.com/content/images/2015/06/class-hierarchy-2.svg alt=&quot;&quot;&gt;&lt;/p&gt;&lt;p&gt;As you can see, the mixin application &lt;em&gt;A-with-M&lt;/em&gt; is inserted into the hierarchy between the subclass and superclass.&lt;/p&gt;&lt;p&gt;Note: I&#39;m using long-dashed line to represent the mixin declartion (&lt;em&gt;B&lt;/em&gt; includes &lt;em&gt;M&lt;/em&gt;), and the short-dashed line to represent the mixin application&#39;s definition.&lt;/p&gt;&lt;h4&gt;Multiple Mixins&lt;/h4&gt;&lt;p&gt;In Dart, multiple mixins are applied in left-to-right order, resulting in multiple mixin applications being added to the inheritance hierarchy:&lt;/p&gt;&lt;pre class=language-dart&gt;&lt;code class=language-dart&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; M1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; M2 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; M1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; M2 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=https://justinfagnani.com/content/images/2015/06/class-hierarchy-3.svg alt=&quot;&quot;&gt;&lt;/p&gt;&lt;h2&gt;Traditional JavaScript Mixins&lt;/h2&gt;&lt;p&gt;The ability to freely modify objects in JavaScript means that it&#39;s very easy to copy functions around to achieve code reuse without relying on inheritance.&lt;/p&gt;&lt;p&gt;Mixin libraries like &lt;a href=https://github.com/onsi/cocktail&gt;Cocktail&lt;/a&gt;, &lt;a href=http://soft.vub.ac.be/~tvcutsem/traitsjs/ &gt;traits.js&lt;/a&gt;, and patterns described in many blog posts (like one of the latest to hit Hacker News: &lt;a href=http://raganwald.com/2015/06/26/decorators-in-es7.html&gt;Using ES7 Decorators as Mixins&lt;/a&gt;), generally work by modifying objects in place, copying in properties from mixin objects and overwriting existing properties.&lt;/p&gt;&lt;p&gt;This is often implemented via a function similar to this:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;source&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; target&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; prop &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; source&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; source&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A version of this has even made it into JavaScript as &lt;a href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign&gt;Object.assign&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;code&gt;mixin()&lt;/code&gt; is usually then called on a prototype:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token function&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyMixin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and now &lt;code&gt;MyClass&lt;/code&gt; has all the properties defined in &lt;code&gt;MyMixin&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;What&#39;s So Bad About That?&lt;/h3&gt;&lt;p&gt;Simply copying properties into a target object has a few issues. Some of this can be worked around with smart enough mixin functions, but the common examples usually have these problems:&lt;/p&gt;&lt;h4&gt;Prototypes are modified in place.&lt;/h4&gt;&lt;p&gt;When using mixin libraries against prototype objects, the prototypes are directly mutated. This is a problem if the prototype is used anywhere else that the mixed-in properties are not wanted. Mixins that add state can create slower objects in VMs that try to understand the shape of objects at allocation time. It also goes against the idea that a mixin application should create a new class by composing existing ones.&lt;/p&gt;&lt;h4&gt;&lt;code&gt;super&lt;/code&gt; doesn&#39;t work.&lt;/h4&gt;&lt;p&gt;With JavaScript finally supporting &lt;code&gt;super&lt;/code&gt;, so should mixins: A mixin&#39;s methods should be able to delegate to an overridden method up the prototype chain. Since &lt;code&gt;super&lt;/code&gt; is essentially lexically bound, this won&#39;t work with copying functions.&lt;/p&gt;&lt;h4&gt;Incorrect precedence.&lt;/h4&gt;&lt;p&gt;This isn&#39;t necessarily always the case, but as often shown in examples, by overwriting properties, mixin methods take precedence over those in the subclass. They should only take precedence over methods in the superclass, allowing the subclass to override methods on the mixin.&lt;/p&gt;&lt;h4&gt;Composition is compromised&lt;/h4&gt;&lt;p&gt;Mixins often need to delegate to other mixins or objects on the prototype chain, but there&#39;s no natural way to do this with traditional mixins. Since functions are copied onto objects, naive implementations overwrite existing methods. More sophisticated libraries will remember the existing methods, and call multiple methods of the same name, but the library has to invent its own composition rules: What order the methods are called, what arguments are passed, etc.&lt;/p&gt;&lt;p&gt;References to functions are duplicated across all applications of a mixin, where in many cases they could be bundled in a shared prototype. By overwriting properties, the structure of protytpes and some of the dynamic nature of JavaScript is reduced: you can&#39;t easily introspect the mixins or remove or re-order mixins, because the mixin has been expanded directly into the target object.&lt;/p&gt;&lt;p&gt;If we actually use the prototype chain, all of this goes away with very little work.&lt;/p&gt;&lt;h2&gt;Better Mixins Through Class Expressions&lt;/h2&gt;&lt;p&gt;Now let&#39;s get to the good stuff: &lt;em&gt;Awesome Mixins™ 2015 Edition&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Let&#39;s quickly list the features we&#39;d like to enable, so we can judge our implementation against them:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Mixins are added to the prototype chain.&lt;/li&gt;&lt;li&gt;Mixins are applied without modifying existing objects.&lt;/li&gt;&lt;li&gt;Mixins do no magic, and don&#39;t define new semantics on top of the core language.&lt;/li&gt;&lt;li&gt;&lt;code&gt;super.foo&lt;/code&gt; property access works within mixins and subclasses.&lt;/li&gt;&lt;li&gt;&lt;code&gt;super()&lt;/code&gt; calls work in constructors.&lt;/li&gt;&lt;li&gt;Mixins are able to extend other mixins.&lt;/li&gt;&lt;li&gt;&lt;code&gt;instanceof&lt;/code&gt; works.&lt;/li&gt;&lt;li&gt;Mixin definitions do not require library support - they can be written in a universal style.&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Subclass Factories with this One Weird Trick&lt;/h3&gt;&lt;p&gt;Above I referred to mixins as &quot;subclass factories, parameterized by the superclass&quot;, and in this formulation they are literally just that.&lt;/p&gt;&lt;p&gt;We rely on two features of JavaScript classes:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;code&gt;class&lt;/code&gt; can be used as an expression as well as a statement. As an expression it returns a new class each time it&#39;s evaluated. (sort of like a factory!)&lt;/li&gt;&lt;li&gt;The &lt;code&gt;extends&lt;/code&gt; clause accepts arbitrary expressions that return classes or constructors.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The key is that classes in JavaScript are first-class: they are values that can be passed to and returned from functions.&lt;/p&gt;&lt;p&gt;All we need to define a mixin is a function that accepts a superclass and creates a new subclass from it, like this:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;MyMixin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;foo from MyMixin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we can use it in an &lt;code&gt;extends&lt;/code&gt; clause like this:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyMixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And &lt;code&gt;MyClass&lt;/code&gt; now has a &lt;code&gt;foo&lt;/code&gt; method via mixin inheritance:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prints &quot;foo from MyMixin&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Incredibly simple, and incredibly powerful! By just combining function application and class expressions we get a complete mixin solution, that generalizes well too.&lt;/p&gt;&lt;p&gt;Applying multiple mixins works as expected:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Mixin1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Mixin2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mixins can easily inherit from other mixins by passing the superclass along:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Mixin2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Mixin1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* Add or override methods here */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And you can use normal function composition to compose mixins:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;CompoundMixin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Mixin2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Mixin3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Benefits of Mixins as Subclass Factories&lt;/h3&gt;&lt;p&gt;This approach gives us a very good implementation of mixins&lt;/p&gt;&lt;h4&gt;Subclasses can override mixin methods.&lt;/h4&gt;&lt;p&gt;As I mentioned before, many examples of JavaScript mixins get this wrong, and mixins override the subclass. With our approach subclasses correctly override mixin methods which override superclass methods.&lt;/p&gt;&lt;h4&gt;&lt;code&gt;super&lt;/code&gt; works.&lt;/h4&gt;&lt;p&gt;One of the biggest benefits is that &lt;code&gt;super&lt;/code&gt; works inside methods of the subclass and the mixins. Since we don&#39;t ever over&lt;em&gt;write&lt;/em&gt; methods on classes or mixins, they&#39;re available for &lt;code&gt;super&lt;/code&gt; to address.&lt;/p&gt;&lt;p&gt;&lt;code&gt;super&lt;/code&gt; calls can be a little unintuitive for those new to mixins because the superclass isn&#39;t known at mixin definition, and sometimes developers expect &lt;code&gt;super&lt;/code&gt; to point to the declared superclass (the parameter to the mixin), not the mixin application. Thinking about the final prototype chain helps here.&lt;/p&gt;&lt;h4&gt;Composition is preserved.&lt;/h4&gt;&lt;p&gt;This is really just a consequence of the other benefits, but two mixins can define the same method, and as long as they call &lt;code&gt;super&lt;/code&gt;, both of them will be invoked then applied.&lt;/p&gt;&lt;p&gt;Sometimes a mixin will not know if a superclass even has a particular property or method, so it&#39;s best to guard the super call:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Mixin1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;foo from Mixin1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Mixin2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;extends&lt;/span&gt; superclass &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;foo from Mixin2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;S&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;foo from S&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Mixin1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Mixin2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;foo from C&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;prints:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;foo from C
foo from Mixin1
foo from Mixin2
foo from S
&lt;/code&gt;&lt;/pre&gt;&lt;h3&gt;Improving the Syntax&lt;/h3&gt;&lt;p&gt;I find applying mixins as functions to be both elegantly simple - describing exactly what&#39;s going on, but a little bit ugly at the same time. My biggest concern is that this construction isn&#39;t optimized for readers unfamiliar with this pattern.&lt;/p&gt;&lt;p&gt;I&#39;d like a syntax that was easier on the eyes and at least that gave new readers something to search for to explain what&#39;s going on, like the Dart syntax. I&#39;d also like to add some more features like memoizing the mixin applications and automatically implementing &lt;code&gt;instanceof&lt;/code&gt; support.&lt;/p&gt;&lt;p&gt;For that we can write a simple helper which applies a list of mixins to a superclass, in a fluent-like API:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;mix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MyBaseClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Mixin1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Mixin2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&#39;s the code:&lt;/p&gt;&lt;pre class=language-js&gt;&lt;code class=language-js&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mix&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MixinBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MixinBuilder&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;superclass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; superclass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;mixins&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mixins&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mixin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;superclass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That&#39;s it! It&#39;s still extremely simple for the features and nice syntax it enables.&lt;/p&gt;&lt;h3&gt;Constructors and Initialization&lt;/h3&gt;&lt;p&gt;Constructors are a potential source of confusion with mixins. They essentially behave like methods, except that overriden methods tend to have the same signature, while constructors in a inheritance hierarchy often have different signatures.&lt;/p&gt;&lt;p&gt;Since a mixin likely does not know what superclass it&#39;s being applied to, and therefore its super-constructor signature, calling &lt;code&gt;super()&lt;/code&gt; can be tricky. The best way to deal with this is to always pass along all constructor arguments to &lt;code&gt;super()&lt;/code&gt;, either by not defining a constructor at all, or by using the spread operator: &lt;code&gt;super(...arguments)&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This means that passing arguments specifically to a mixin&#39;s constructor is difficult. One easy workaround is to just have an explicit initialization method on the mixin if it requires arguments.&lt;/p&gt;&lt;h2&gt;Further Exploration&lt;/h2&gt;&lt;p&gt;This is just the beginning of many topics related to mixins in JavaScript. I&#39;ll post more about things like:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=http://justinfagnani.com/2016/01/07/enhancing-mixins-with-decorator-functions/ &gt;Enhancing Mixins with Decorator Functions&lt;/a&gt; new post that covers:&lt;/li&gt;&lt;li&gt;Caching mixin applications so that the same mixin applied to the same superclass reuses a prototype.&lt;/li&gt;&lt;li&gt;Getting &lt;code&gt;instanceof&lt;/code&gt; to work.&lt;/li&gt;&lt;li&gt;How mixin inheritance can address the fear that ES6 classes and classical inheritance are bad for JavaScript.&lt;/li&gt;&lt;li&gt;Using subclass-factory-style mixins in ES5.&lt;/li&gt;&lt;li&gt;De-duplicating mixins so mixin composition is more usable.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;The mixwith.js project&lt;/h2&gt;&lt;p&gt;I started a project on GitHub to build a library around this pattern: https://github.com/justinfagnani/mixwith.js It can be found on npm: https://www.npmjs.com/package/mixwith&lt;/p&gt;&lt;h2&gt;Follow the conversation&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=10809627&quot;&gt;Hacker News&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=https://www.reddit.com/r/javascript/comments/3xqmgy/real_mixins_with_javascript_classes/ &gt;reddit.com/r/javascript&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Response at &lt;a href=http://raganwald.com/2015/12/23/super-considered-hmmmful.html&gt;raganwald.com&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description>
      <pubDate>Mon, 21 Dec 2015 11:14:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/</guid>
    </item>
    <item>
      <title>Getting Things Done... Like This Blog!</title>
      <link>https://justinfagnani.com/2015/12/21/getting-things-done-like-this-blog/</link>
      <description>&lt;p&gt;I&#39;ve intended to launch a blog at &lt;a href=https://justinfagnani.com/2015/12/21/getting-things-done-like-this-blog/ &gt;justinfagnani.com&lt;/a&gt; for a very, very long time now. Prevailing over my procrastinating and complexifying nature I&#39;ve finally done it, but only by cutting &lt;em&gt;almost&lt;/em&gt; every corner possible.&lt;/p&gt;&lt;p&gt;After a brief flirtation with blogging about Dart at &lt;a href=https://justinfagnani.com/2015/12/21/getting-things-done-like-this-blog/ &gt;dartery.blogspot.com&lt;/a&gt;, I wanted a better writing experience for myself, reading experience for my visitors, and broader scope than just Dart programming. My main frustration was with Blogger and the difficulty of customizing it and writing posts with richer content, like code snippets, or embeds from other sites.&lt;/p&gt;&lt;p&gt;This first lead me down a path of building my own blogging engine in Dart (server and client, no less!) which included advanced routing, authentication middleware, custom elements in Polymer.dart &lt;em&gt;way&lt;/em&gt; before Polymer.dart was close to ready, wiring in non-Dart services like syntax highlighting and on, and on, and on...&lt;/p&gt;&lt;p&gt;Eventually and mercifully I declared bankruptcy on that idea (even thought I still hold out hope for a clean and simple Dart-based blogging engine), but my next attempt wasn&#39;t any more productive.&lt;/p&gt;&lt;p&gt;I researched blogging platforms, looked at their source code, their table layouts, theming engines, and confidently settled on Ghost. Great, but did I mention my complexifier nature? Sure enough, it got the better of me and suddenly was I neck deep in Docker, running Ghost unconventionally (as an Express module), Google Compute Engine options, all trying to achieve immutable infrastructure nirvana. To top it off I started my own Ghost theme using Polymer elements.&lt;/p&gt;&lt;p&gt;Whoa...&lt;/p&gt;&lt;p&gt;Realizing that way madness lied, at least if I ever wanted to &lt;em&gt;actually get my blog up&lt;/em&gt;, I took a step back and asked myself:&lt;/p&gt;&lt;p&gt;What&#39;s the minimal amount of work I can do to get up and running, while leaving myself &lt;em&gt;just&lt;/em&gt; enough flexibility to build what I want in the future?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Run my own server, so I can easily customize the blog, as well as run my own programs.&lt;/li&gt;&lt;li&gt;Control my URLs, and keep them from changing over time. I want to mount my blog at /blog so that I can put other things at the top level without fear of collisions.&lt;/li&gt;&lt;li&gt;Analytics&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And... that&#39;s about it. Themes, syntax highlighting, even comments, can all wait.&lt;/p&gt;&lt;p&gt;With that minimal goal, I looked at Google Compute Engine&#39;s &lt;a href=https://cloud.google.com/launcher&gt;Cloud Launcher&lt;/a&gt; and the &lt;a href=https://justinfagnani.com/2015/12/21/getting-things-done-like-this-blog/bitnami.com&gt;Bitnami&lt;/a&gt; Ghost installer. I was a little wary that there would be some catch with Bitnami: maybe they&#39;ve modified Ghost in some unscrupulous way, or charge extra money. I don&#39;t think this is the case, so I clicked the &quot;Get Started&quot; button, and 10 minutes later I had this blog.&lt;/p&gt;&lt;p&gt;Sweet!&lt;/p&gt;</description>
      <pubDate>Mon, 21 Dec 2015 10:55:00 GMT</pubDate>
      <dc:creator>Justin Fagnani</dc:creator>
      <guid>https://justinfagnani.com/2015/12/21/getting-things-done-like-this-blog/</guid>
    </item>
  </channel>
</rss>