<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: James Lovallo</title>
    <description>The latest articles on DEV Community by James Lovallo (@jameslovallo).</description>
    <link>https://dev.to/jameslovallo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F259250%2F837a92ff-8519-46ce-ad19-7b1697c8dd20.jpeg</url>
      <title>DEV Community: James Lovallo</title>
      <link>https://dev.to/jameslovallo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jameslovallo"/>
    <language>en</language>
    <item>
      <title>Ardi: Welcome to the Weightless Web</title>
      <dc:creator>James Lovallo</dc:creator>
      <pubDate>Wed, 12 Oct 2022 18:52:48 +0000</pubDate>
      <link>https://dev.to/jameslovallo/ardi-welcome-to-the-weightless-web-1041</link>
      <guid>https://dev.to/jameslovallo/ardi-welcome-to-the-weightless-web-1041</guid>
      <description>&lt;p&gt;👋🏻 Hi all, this is my first post here. Be nice 😝&lt;/p&gt;

&lt;p&gt;I've been working on a new Web Component framework called &lt;a href="https://ardi.netlify.app" rel="noopener noreferrer"&gt;Ardi&lt;/a&gt;. Ardi packs a ton of features into a tiny 3kb package.&lt;/p&gt;




&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reactive props&lt;/li&gt;
&lt;li&gt;Reactive state management&lt;/li&gt;
&lt;li&gt;Declarative rendering

&lt;ul&gt;
&lt;li&gt;Conditional rendering&lt;/li&gt;
&lt;li&gt;Loops (supporting keyed elements)&lt;/li&gt;
&lt;li&gt;@event handlers in the template&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;FAST&lt;/em&gt; rendering thanks to &lt;a href="https://github.com/WebReflection/uhtml" rel="noopener noreferrer"&gt;µhtml&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A ready() helper to handle effects after the initial render&lt;/li&gt;

&lt;li&gt;A intersect() helper to handle effects after the component is scrolled into view, i.e.

&lt;ul&gt;
&lt;li&gt;Lazy-loading data&lt;/li&gt;
&lt;li&gt;Scroll-triggered animations&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Works out-of-the-box with React, Vue, Svelte, Angular, etc

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ardi.netlify.app/docs.html#frameworks" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Allows developers to bring their own templating library, i.e. &lt;a href="https://ardi.netlify.app/playground.html?component=helloHbs" rel="noopener noreferrer"&gt;Handlebars&lt;/a&gt; or &lt;a href="https://ardi.netlify.app/playground.html?component=helloJsx" rel="noopener noreferrer"&gt;JSX&lt;/a&gt;.&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Goals
&lt;/h2&gt;

&lt;p&gt;The question you're probably already asking is "for f***'s sake, why do we need another web component framework?" and that's a really good question. I had a few specific goals in mind when I started working on Ardi.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make web components fast&lt;/li&gt;
&lt;li&gt;Make web components fun and familiar&lt;/li&gt;
&lt;li&gt;Make web components work with any existing framework&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Make web components fast
&lt;/h2&gt;

&lt;p&gt;Though I love custom elements, there are a few issues that make them problematic for production work.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Client-side custom elements either 1) cause horrible CLS when they load or 2) need to block rendering until they are loaded to prevent CLS. &lt;strong&gt;Solution&lt;/strong&gt;: That means the framework itself needs to be &lt;em&gt;tiny&lt;/em&gt; and fast itself. Compressed and minified, Ardi is only 3kb, and you can load it from NPM or a CDN.&lt;/p&gt;

&lt;h3&gt;
  
  
  Efficient Rendering
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: With declarative rendering in other libraries, oftentimes entire DOM trees are re-painted because of simple prop or state changes that could have been handled faster by imperative DOM manipulation. I wanted a framework that, like Lit, only updated content or attributes that had changed instead of re-painting entire DOM elements and trees. &lt;strong&gt;Solution&lt;/strong&gt;: I chose &lt;a href="https://github.com/WebReflection/uhtml" rel="noopener noreferrer"&gt;µhtml&lt;/a&gt; for the default templating system because it accomplishes this goal and other advanced templating features in a &lt;em&gt;tiny&lt;/em&gt; bundle size. To make rendering even faster and smoother, I throttled uhtml's rendering using requestAnimationFrame.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the devtools on the right, notice how the whole element isn't re-painted, just the parts that have changed.&lt;/p&gt;
&lt;/blockquote&gt;

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




&lt;h2&gt;
  
  
  2. Make web components fun and familiar
&lt;/h2&gt;

&lt;p&gt;I wanted a simple and modern DX that lets me start exploring a new idea quickly without typing a bunch of boilerplate code first. I also wanted to make it easy for developers to bring their favorite templating systems like Handlebars or JSX.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boilerplate
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Many of the current web component libraries make you import and extend classes, write opinionated boilerplate code and manually define the custom element. &lt;strong&gt;Solution&lt;/strong&gt;: Reduce boilerplate code as much as possible.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="350" src="https://codepen.io/jameslovallo/embed/YzLddOK?height=350&amp;amp;default-tab=js,result&amp;amp;height=350&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  State Management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Custom elements do not provide any state management solution. State management is a huge part of what makes modern frameworks &lt;em&gt;modern&lt;/em&gt; and is an essential component of declarative rendering. &lt;strong&gt;Solution&lt;/strong&gt; Ardi provides its own reactivity solution in the form of this.state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ardi&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyboard-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;recording&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In the example above, the component's state contains a "recording" boolean and a "tracks" array. When this.state.recording is set to true, any note played on the keyboard is saved with a timestamp into a new array. When recording is set to false, the array of recorded notes is saved into the tracks array. When this.state.tracks is updated, the list of recorded tracks at the bottom of the component is updated immediately, just like you would expect if you were using React, Vue, or similar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning Curve
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: I've worked with a lot of developers who are very opinionated and passionate about one templating system, and who are therefore reluctant to try out new frameworks or new standards like custom elements. &lt;strong&gt;Solution&lt;/strong&gt;: Ardi is very &lt;em&gt;unopinionated&lt;/em&gt; and allows you to easily override the default render() function to support other templating libraries like &lt;a href="https://ardi.netlify.app/playground.html?component=helloHbs" rel="noopener noreferrer"&gt;Handlebars&lt;/a&gt; or &lt;a href="https://ardi.netlify.app/playground.html?component=helloJsx" rel="noopener noreferrer"&gt;JSX&lt;/a&gt; (click those links for demos).&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Make web components work with any existing framework
&lt;/h2&gt;

&lt;p&gt;The true magic of web components is being able to build them once and use them anywhere, but there are still some limitations to the API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactivity and Interoperability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Properties are not the same thing as attributes. When you (or React, or Vue) update an attribute on a custom element, nothing happens. That change is not reflected in the component's properties. Custom elements do provide an observedAttributes getter and attributeChangedCallback, but it is cumbersome to 1) define observed attributes, 2) recognize when those attributes have changed, 3) get the value of the attribute, 4) convert that value from a string to another data type, and 5) update the template appropriately. &lt;strong&gt;Solution&lt;/strong&gt;: Make it easy to create reactive props, each of which has a &lt;em&gt;setter function&lt;/em&gt; and an optional default value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ardi&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyboard-demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sitar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;acoustic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;piano&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;octaves&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;sustain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In the example above, if the "octaves" attribute is changed on the element, this.octaves will also be set to the value of Number(this.getAttribute('octaves')) and the template will be updated. If this.octaves is changed, the attribute will also be updated, along with the template. Data is kept perfectly in-sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ardi ❤️ React
&lt;/h3&gt;

&lt;p&gt;&lt;iframe height="500" src="https://codepen.io/jameslovallo/embed/XWqNNNo?height=500&amp;amp;default-tab=result&amp;amp;height=500&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Ardi ❤️ Vue
&lt;/h3&gt;

&lt;p&gt;&lt;iframe height="500" src="https://codepen.io/jameslovallo/embed/KKRgrrd?height=500&amp;amp;default-tab=result&amp;amp;height=500&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Check it out!
&lt;/h2&gt;

&lt;p&gt;If you're looking for a lightweight, un-opinionated and highly-optimized web component framework, I'd encourage you to check out the &lt;a href="https://ardi.netlify.app/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, play with the &lt;a href="https://ardi.netlify.app/#demos" rel="noopener noreferrer"&gt;demos&lt;/a&gt;, or try it out in the &lt;a href="https://ardi.netlify.app/playground.html" rel="noopener noreferrer"&gt;playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you like Ardi, like this post or  &lt;a href="https://github.com/jameslovallo/ardi" rel="noopener noreferrer"&gt;give it a star&lt;/a&gt;. If you have an issue or you're interested in contributing, feel free to &lt;a href="https://github.com/jameslovallo/ardi/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt; or &lt;a href="https://github.com/jameslovallo/ardi/pulls" rel="noopener noreferrer"&gt;create a pull request&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>dx</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
