<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>oli's rss feed</title>
  <subtitle>weird web person</subtitle>
  <link href="https://oliverjam.com/feed.xml" rel="self"/>
  <link href="https://oliverjam.com"/>
  <updated>2025-05-05T00:00:00.000Z</updated>
  <id>https://oliverjam.com</id>
  <author>
    <name>oli</name>
    <email>hello@oliverjam.com</email>
  </author>
  
  <entry>
    <title>Subtley better borders using transparency</title>
    <link href="https://oliverjam.com/articles/better-borders"/>
    <updated>2025-05-05T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/better-borders</id>
    <content type="html"><![CDATA[<style>
    
    .Example {
        color-scheme: light;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(14rem, auto));
        gap: 0.5lh;
        justify-content: center;
        padding: var(--gutter);
        background-color: white;
        color: #333;
        font-family: system-ui;
        &[gradient] {
            background: linear-gradient(
                to bottom right,
                hsl(120 100 80),
                hsl(172 96 45)
            )
        }
        label, input {
            all: revert;
        }
        label {
            display: grid;
            gap: 0.125lh;
            font-weight: 500;
            font-size: 16px;
        }
        input {
            --b: hsl(0 0 0 / 0.25);
            border-radius: 4px;
            border-width: 1px;
            border-style: solid;
            border-color: hsl(0 0 75);
            padding: 0.25rem;
            outline: 0;
            transition-property: border-color, outline-color, box-shadow;
            transition-duration: 0.2s;
            background-color: white;
            &:focus {
                border-color: hsl(0 0 40);
                --b: hsla(0 0 0 / 0.7);
            }
            &[trans] {
                border-color: var(--b);
                &:focus {
                    border-color: var(--b);
                }
            }
            &[clip] {
                background-clip: padding-box;
            }
            &[shadow] {
                box-shadow:
                    0 10px 15px -3px hsl(0 0 0 / 0.2),
                    0 4px 6px -4px hsl(0 0 0 / 0.2)
            }
            &[outline] {
                border: 0;
                outline: 1px solid var(--b);
            }
            &[bsb] {
                border: 0;
                box-shadow: 0 0 0 1px var(--b);
            }
        }
    }
</style>

<p>Here&#39;s an input. You can tell because it&#39;s got a border.</p>
<figure class="Example">
    <label>Your name
        <input>
    </label>
</figure>

<p>This border is just a solid grey colour: <code>hsl(0 0 75)</code>. I think it looks pretty nice as is, but there are some situations where it will struggle.</p>
<p>For example on a gradient background:</p>
<figure class="Example" gradient>
    <label>Your name
        <input>
    </label>
</figure>

<p>Now the grey border looks muddy and hard to see. That light grey doesn&#39;t stand out from the background at all. We&#39;d need to make the border darker to be properly visible here. Let&#39;s make it 25% darker with <code>hsl(0 0 50%)</code> and see how that looks:</p>
<figure class="Example" gradient>
    <label>Your name
        <input style="border-color: hsl(0 0 50)">
    </label>
</figure>

<p>This is better, but it&#39;s going to be annoying to manually set the border colour of our input every time we use it on a coloured background. It would be nice if we could make one version of the border that worked on any background.</p>
<p>Luckily we can, by using a semi-transparent border. This will allow some of the background colour to show through, which will make the border naturally appear darker on darker backgrounds. It will also slightly tint the border colour so it matches better.</p>
<p>Let&#39;s try setting the border to a transparent grey like <code>hsl(0 0 0 / 0.25)</code>. This is pure black but at 25% opacity, so it should be equivalent to our 75% lightness original grey colour.</p>
<figure class="Example">
    <label>Your name
        <input trans>
    </label>
</figure>

<p>It looks pretty much identical on a white background. Let&#39;s put the original back in so we can compare:</p>
<figure class="Example">
    <label>Solid border
        <input>
    </label>
    <label>Transparent border
        <input trans>
    </label>
</figure>

<p>Now let&#39;s see if it looks better on our gradient background:</p>
<figure class="Example" gradient>
    <label>Solid border
        <input>
    </label>
    <label>Transparent border
        <input trans>
    </label>
</figure>

<p>That&#39;s weird, it hasn&#39;t helped at all! It turns out that by default the background of an element extends up to the edge of its &quot;border box&quot;.</p>
<figure class="Example" style="font-family: ui-mono, monospace; font-size: 14px; line-height: 1; text-align: center">
    <div style="padding: 12px; background: hsl(55 100 95); border: 2px dashed hsl(55 100 50)">
        <div style="padding-bottom: 8px">margin</div>
        <div style="position: relative; border: 2px solid hsl(0 0 20)">
            <div style="position: absolute; top: 0; left: 0; padding: 2px; border-bottom-right-radius: 2px; background: hsl(0 0 20); color: white">border</div>
            <div style="padding: 12px; background: hsl(240 100 95);">
                <div style="padding-bottom: 8px">padding</div>
                <div style="padding: 12px; background: hsl(190 100 96)">
                    <div>content</div>
                </div>
            </div>
        </div>
    </div>	
</figure>

<p>That means the white background of the input is &quot;underneath&quot; the transparent border. This isn&#39;t what we want—for this trick to work we need the gradient background to show through the border.</p>
<p>Luckily there&#39;s a CSS property to control where an element&#39;s background extends to: <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip"><code>background-clip</code></a>. By default this is set to <code>border-box</code>, but we can change it to <code>padding-box</code> to tell the browser to stop drawing the input&#39;s background at the edge of the padding, before the border starts. Let&#39;s see how that looks:</p>
<figure class="Example" gradient>
    <label>Solid border
        <input>
    </label>
    <label>Transparent border
        <input trans clip>
    </label>
</figure>

<p>How much better does that look? Our input will stay distinct from the background no matter what.</p>
<p>There is another edge-case that we need to account for: shadows. Let&#39;s see how our inputs look with a nice shadow under them.</p>
<figure class="Example">
    <label>Solid border
        <input shadow>
    </label>
    <label>Transparent border
        <input trans clip shadow>
    </label>
</figure>

<p>That&#39;s annoying. Our borders blend into the shadow and disappear at the bottom. This makes the inputs look kind of weird and bad again.</p>
<p>I was initially confused about why the input with the transparent border looks the same here. Surely it should work the same as with the gradient background? Unfortunately it turns out that CSS box-shadows always start being drawn <em>after</em> the border-box of an element. As far as I can tell there&#39;s no way to make the shadow start after the padding-box (underneath the border).</p>
<p>Here&#39;s a visualisation of the problem:</p>
<figure class="Example" style="font-family: ui-mono, monospace; font-size: 14px; line-height: 1; text-align: center" gradient>
        <div style="position: relative; border: 10px solid hsl(0 0 0 / 0.2); box-shadow: 0 8px 16px hsl(0 100 50 / 0.8); padding: 16px; background: white; background-clip: padding-box">
            <div style="position: absolute; top: -10px; left: -10px; padding: 2px; border-bottom-right-radius: 2px; background: hsl(0 0 20); color: white">border</div>
            <div>padding (& content)</div>
        </div>
</figure>

<p>The border colour is transparent black, so the gradient background shows through and tints it green. However the red box-shadow doesn&#39;t show through—it starts <em>after</em> the border-box, and as far as I can tell there&#39;s no way to change this.</p>
<p>In order to work around this we have to stop using borders for our border. We need something that will render <em>outside</em> the element, so it sits on top of the box-shadow. Our two options are either <code>outline</code>, or more <code>box-shadow</code>.</p>
<p>Outline is by far the easiest to work with, since the syntax is the same as for borders. We can set <code>outline-color: hsla(0, 0%, 0%, 0.25)</code> and get the same result as before:</p>
<figure class="Example">
    <label>Solid border
        <input shadow>
    </label>
    <label>Transparent border
        <input outline shadow>
    </label>
</figure>

<p>This looks so much better with the shadow. The edge of the input is crisp, even right at the bottom where it meets the shadow. And it still looks great on the gradient background too:</p>
<figure class="Example" gradient>
    <label>Solid border
        <input shadow>
    </label>
    <label>Transparent border
        <input outline shadow>
    </label>
</figure>

<p>The downside to using an outline as a border is you can&#39;t also have an outline. For example if you wanted a more distinct separate focus style you&#39;d be a bit stuck here.</p>
<p>It&#39;s more complicated, but you can also simulate a border using box-shadow. You set zero offset and blur, and use the spread to control the thickness. For example: <code>box-shadow: 0 0 0 1px hsl(0 0 0 / 0.25)</code>.</p>
<figure class="Example">
    <label>Solid border
        <input>
    </label>
    <label>Transparent border
        <input bsb>
    </label>
</figure>

<p>This looks good on the gradient background too:</p>
<figure class="Example" gradient>
    <label>Solid border
        <input>
    </label>
    <label>Transparent border
        <input bsb>
    </label>
</figure>

<p>The only downside to this approach is that it&#39;s more fiddly to add another shadow, since we need to write multiple box-shadows. For example:</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector">input</span> <span class="token punctuation">{</span>
    <span class="token property">box-shadow</span><span class="token punctuation">:</span>
        <span class="token comment">/* The border */</span>
        <span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">1</span><span class="token unit">px</span> <span class="token function">hsl</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token operator">/</span> <span class="token number">0.25</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token comment">/* The actual shadow */</span>
        <span class="token number">0</span> <span class="token number">10</span><span class="token unit">px</span> <span class="token number">15</span><span class="token unit">px</span> <span class="token number">-3</span><span class="token unit">px</span> <span class="token function">hsl</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token operator">/</span> <span class="token number">0.2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token number">0</span> <span class="token number">4</span><span class="token unit">px</span> <span class="token number">6</span><span class="token unit">px</span> <span class="token number">-4</span><span class="token unit">px</span> <span class="token function">hsl</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token operator">/</span> <span class="token number">0.2</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
    </div><!-- prettier-ignore-end -->

<figure class="Example">
    <label>Solid border
        <input shadow>
    </label>
    <label>Transparent border
        <input style="
            border: 0;
            box-shadow:
            0 0 0 1px var(--b),
            0 10px 15px -3px hsl(0 0 0 / 0.2),
            0 4px 6px -4px hsl(0 0 0 / 0.2)">
    </label>
</figure>

<p>And finally, putting everything together, let&#39;s see how it looks on the gradient background with a shadow:</p>
<figure class="Example" gradient>
    <label>Solid border
        <input shadow>
    </label>
    <label>Transparent border
        <input style="
            border: 0;
            box-shadow:
            0 0 0 1px var(--b),
            0 10px 15px -3px hsl(0 0 0 / 0.2),
            0 4px 6px -4px hsl(0 0 0 / 0.2)">
    </label>
</figure>

<p>I love it! Some might argue that this is a lot of effort to go to for a pretty subtle enhancement, but I think that sweating the small UI details is what makes really great products stand out. You only have to write these styles once, but every time a user sees them they pay off.</p>
<p>One final bonus tip: if you&#39;re writing Tailwind this is as simple as switching from the <a href="https://tailwindcss.com/docs/border-width"><code>border</code></a> class to <a href="https://tailwindcss.com/docs/box-shadow#adding-a-ring"><code>ring</code></a>.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Better JS bundle caching with vendor chunks</title>
    <link href="https://oliverjam.com/articles/vendor-chunk"/>
    <updated>2024-08-06T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/vendor-chunk</id>
    <content type="html"><![CDATA[<p>Browser caching is an important part of web performance. You can tell the browser to keep a copy of a file around for later with the <code>cache-control</code> HTTP header. For example a response with this header set:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">cache-control: max-age=3600</code></pre>
    </div><p>will be cached for one minute (3600 seconds)</p>
<p>A one minute cache is not going to improve performance much though, since most users will visit the site again more than one minute later, leading to them waiting for the file to re-download.</p>
<p>We can&#39;t just set a much longer cache time, because we want the user to receive updates to this file. If we set a one year cache time the user will be stuck with the old file for that long.</p>
<p>Moder build tooling generally supports cache-busting using file hashes. When your app builds each static file will have a hash of the contents added to the filename. For example <code>main.js</code> might become <code>main-50b6a13c.js</code>. This hash will be the same as long as the file&#39;s contents are the same, but will change if a single character is different.</p>
<p>This lets us set files to cache effectively forever, since every version of our file is unique and immutable. Browsers generally won&#39;t cache for longer than one year:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">cache-control: max-age=604800, immutable</code></pre>
    </div><p>The <code>immutable</code> directive tells the browser to never even try to revalidate this response—it should never be different.</p>
<p>This is fantastic for performance, as now each user will only ever load each version of your app once. Every time they load the page the browser will instantly have access to all the static resources without having to wait for a response from your server.</p>
<p>There is still one downside: if <em>any</em> of our code changes the browser must re-download the entire file. Luckily we can mitigate this by splitting out our dependency code from our own.</p>
<p>When building modern JS apps it&#39;s common to have a large quantity of your code come from 3rd party dependencies. For example my <a href="https://rddit.netlify.app/r/all">Reddit app</a> requires 228kb of JS, 207kb of which is just React, React Router and Valibot. These dependencies rarely change, and I am in control of when I update them. If we split these into their own separate JS file we can avoid invalidating the cache for all this every time we change our own code. The dependencies will be cached until one of them is updated.</p>
<p>Each build tool has a different way of configuring &quot;vendor chunks&quot;, but here&#39;s how to do it <a href="https://v3.vitejs.dev/guide/build.html#chunking-strategy">in Vite</a>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// vite.config.js</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> defineConfig<span class="token punctuation">,</span> splitVendorChunkPlugin <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"vite"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> react <span class="token keyword">from</span> <span class="token string">"@vitejs/plugin-react"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">defineConfig</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">react</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">splitVendorChunkPlugin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">server</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">port</span><span class="token operator">:</span> <span class="token number">3000</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">build</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token string">"esnext"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We import the <code>splitVendorChunkPlugin</code> and add it to the config&#39;s <code>plugins</code> array. That&#39;s it. Here&#39;s the output of <code>vite build</code> <em>before</em> adding the plugin:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">✓ 54 modules transformed.
dist/index.html                      0.69 kB │ gzip:  0.46 kB
dist/assets/index-e032778f.css      10.35 kB │ gzip:  3.25 kB
dist/assets/missing-c45c8138.js      0.28 kB │ gzip:  0.22 kB
dist/assets/media-05d37584.js        1.67 kB │ gzip:  0.87 kB
dist/assets/media-bb4a63f2.js        2.12 kB │ gzip:  0.94 kB
dist/assets/post-3a754864.js         2.32 kB │ gzip:  1.04 kB
dist/assets/subreddit-f9f8913a.js    3.10 kB │ gzip:  1.39 kB
dist/assets/error-b1adb144.js        5.45 kB │ gzip:  1.91 kB
dist/assets/comments-ca3ad949.js     7.23 kB │ gzip:  2.86 kB
dist/assets/index-75cd0051.js      212.78 kB │ gzip: 68.89 kB
✓ built in 899ms</code></pre>
    </div><p>Note the <code>index.js</code> file at the bottom that is 212.78kb.</p>
<p>Here&#39;s after adding the plugin:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">✓ 54 modules transformed.
dist/index.html                      0.76 kB │ gzip:  0.48 kB
dist/assets/index-e032778f.css      10.35 kB │ gzip:  3.25 kB
dist/assets/missing-7ecbefcc.js      0.28 kB │ gzip:  0.22 kB
dist/assets/media-0f91f393.js        1.70 kB │ gzip:  0.89 kB
dist/assets/media-a9720384.js        2.16 kB │ gzip:  0.96 kB
dist/assets/post-65a175ad.js         2.36 kB │ gzip:  1.06 kB
dist/assets/subreddit-5fe07416.js    3.12 kB │ gzip:  1.41 kB
dist/assets/error-9e227f5f.js        5.46 kB │ gzip:  1.91 kB
dist/assets/index-f485a835.js        6.58 kB │ gzip:  2.64 kB
dist/assets/comments-af5f5540.js     7.26 kB │ gzip:  2.87 kB
dist/assets/vendor-fdd8423a.js     206.54 kB │ gzip: 66.64 kB
✓ built in 921ms</code></pre>
    </div><p>We now have a <code>vendor.js</code> that is 206.54kb. That&#39;s the vast majority of our original bundle split into a file that will never change until I update a dependency, meaning users will rarely have to re-download any of it.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Testing React components from scratch</title>
    <link href="https://oliverjam.com/articles/react-testing-from-scratch"/>
    <updated>2024-07-17T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/react-testing-from-scratch</id>
    <content type="html"><![CDATA[<p>Although React components <em>seem</em> like simple functions, they actually hide a lot of complexity that makes them difficult to test. You can&#39;t just call a component function and assert about its return value. Components usually have behaviour like state, event handlers and side effects that should be verified.</p>
<p>We&#39;re going to implement a very simplified version of a testing library for React that is based on the very popular <a href="https://testing-library.com/docs/react-testing-library/intro">React Testing Library</a>, so we can better understand what this dependency does for us.</p>

      <h2 id="how-components-work"><a class="hash" href="#how-components-work" aria-label="Link to heading"></a>How components work</h2>
    <p>There are two main steps to rendering a React component so we can test it. First we need to convert JSX syntax to regular JS, then we need to convert React&#39;s object representation of the UI into real DOM elements we can interact with.</p>
<p>For example this component:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Greeting</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>looks like this when converted to JS:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> jsx <span class="token keyword">as</span> _jsx <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react/jsx-runtime"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">Greeting</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">_jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>When called this function returns an object that looks something like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
    <span class="token property">"$$typeof"</span><span class="token operator">:</span> Symbol(<span class="token string">"react.element"</span>)<span class="token punctuation">,</span>
    <span class="token property">"props"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"children"</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"h1"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We can&#39;t really do much with this object other than assert that its props are correct. However this wouldn&#39;t be a very helpful test since we&#39;re passing those props in ourselves.</p>
<p>React components need to be rendered into a DOM using the <code>render</code> method. We create a &quot;React root&quot; for rendering elements into, then render our component into it:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> createRoot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/client"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#root"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> root <span class="token operator">=</span> <span class="token function">createRoot</span><span class="token punctuation">(</span>div<span class="token punctuation">)</span><span class="token punctuation">;</span>
root<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Greeting</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>In this case we&#39;re assuming we have access to a <code>document</code> that contains a div with an ID of &quot;root&quot;. That leads us to another problem.</p>

      <h2 id="environment-setup"><a class="hash" href="#environment-setup" aria-label="Link to heading"></a>Environment setup</h2>
    <p>Most testing environments do not have access to a DOM. For convenience we usually like to runs tests from our terminal, or in a CI job when we push a PR to GitHub. It is possible to run tests in a real browser (e.g. using <a href="https://qunitjs.com/">QUnit</a>), but almost nobody does anymore.</p>
<p>So to test React components we need to create a fake DOM within our testing environment. This usually means using the <a href="https://github.com/jsdom/jsdom">JSDom</a> library. I&#39;ve <a href="/articles/frontend-testing-node-jsdom">written about using JSDOM before</a>, so I won&#39;t go into detail now. Suffice to say it implements a large number of browser features in pure JavaScript so we can run code that is meant for the browser in Node or some other non-browser environment.</p>
<p>The simplest way to use JSDOM is via the <a href="https://github.com/modosc/global-jsdom">global-jsdom</a> package. This sets up a DOM and all the globals you would expect to use in the browser (<code>window</code>, <code>document</code>, <code>console</code> etc). It&#39;s as simple as importing a file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token string">"global-jsdom/register"</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h2 id="dealing-with-jsx"><a class="hash" href="#dealing-with-jsx" aria-label="Link to heading"></a>Dealing with JSX</h2>
    <p>Node doesn&#39;t understand JSX syntax. There are a couple of ways to deal with this: either compile your code in advance with something like esbuild or Babel, or use <a href="https://nodejs.org/api/module.html#transpilation">a Node module hook</a> to compile it on the fly as you import it.</p>
<p>To make things simpler here we&#39;re going to use the <a href="https://bun.sh">Bun</a> runtime, which supports JSX natively.</p>

      <h2 id="rendering-components"><a class="hash" href="#rendering-components" aria-label="Link to heading"></a>Rendering components</h2>
    <p>Now that we have a DOM we can render our component as above:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token string">"global-jsdom/register"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createRoot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/client"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">Greeting</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">let</span> div <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#root"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> root <span class="token operator">=</span> <span class="token function">createRoot</span><span class="token punctuation">(</span>div<span class="token punctuation">)</span><span class="token punctuation">;</span>
root<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Greeting</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>div<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;h1>Hello&lt;/h1></span></code></pre>
    </div>
      <h2 id="writing-a-render-function"><a class="hash" href="#writing-a-render-function" aria-label="Link to heading"></a>Writing a render function</h2>
    <p>It would be nice to abstract some of this rendering boilerplate so that testing looks as simple as this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> test<span class="token punctuation">,</span> expect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"bun:test"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> render <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./helpers.js"</span><span class="token punctuation">;</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Greeting renders correctly"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Greeting</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> h1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>h1<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeInstanceOf</span><span class="token punctuation">(</span>HTMLHeadingElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We want to write a <code>render</code> function that does three things:</p>
<ol>
<li>Create a new div element to render into</li>
<li>Put the div in the DOM</li>
<li>Render our React element into a new React root</li>
</ol>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> createRoot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/client"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token parameter">element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> root <span class="token operator">=</span> <span class="token function">createRoot</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
    root<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>If we run the example test from above it will fail:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Expected constructor: [class HTMLHeadingElement]
Received value: null</code></pre>
    </div><p>This is strange because everything should work fine now. If we try to log <code>document.body.innerHTML</code> after we call <code>render</code> we just get <code>&lt;div&gt;&lt;/div&gt;</code>. This implies that the container is being created and appended to the body, but the React root is not rendering.</p>
<p>Newer versions of React render asynchronously, which means we cannot rely on the render having completed before the rest of our code runs. We can verify that this is the problem by making our test async and awaiting a promise to push our test code to the back of the queue:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Greeting renders correctly"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Greeting</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> h1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>h1<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeInstanceOf</span><span class="token punctuation">(</span>HTMLHeadingElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>The test now passes, and the log shows the correct DOM containing the <code>&lt;h1&gt;</code>. This isn&#39;t really a proper solution though, just a hack to diagnose the issue. Luckily React provides a way to fix this.</p>

      <h2 id="using-the-act-function"><a class="hash" href="#using-the-act-function" aria-label="Link to heading"></a>Using the act function</h2>
    <p>The React team realised that tests would need a way to reliably render components and assert about them synchronously, so they provided the <a href="https://react.dev/reference/react/act"><code>act</code></a> function. React will make sure any any pending updates for the code wrapped in <code>act</code> are complete before the rest of your test code runs. We&#39;ll need to use <code>act</code> any time we render, or trigger state updates or effects.</p>
<p>We need to update our <code>render</code> function to wrap the React render in <code>act</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token parameter">element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> root <span class="token operator">=</span> <span class="token function">createRoot</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> root<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We can now get rid of the timeout in our test and see that it passes correctly:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Greeting renders correctly"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Greeting</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> h1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>h1<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeInstanceOf</span><span class="token punctuation">(</span>HTMLHeadingElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>It also logs the correct DOM:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><p>We now have a warning in the console from React:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Warning: The current testing environment is not configured to support act(...)</code></pre>
    </div><p>The <code>act</code> function is designed to only be used in testing environments, not real apps. So we need to tell React that this code is running inside a test, by setting a <a href="https://react.dev/reference/react/act#error-the-current-testing-environment-is-not-configured-to-support-act">special global variable</a>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">global<span class="token punctuation">.</span><span class="token constant">IS_REACT_ACT_ENVIRONMENT</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token parameter">element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>That&#39;s it as far as rendering goes. We can now render components and use normal DOM methods to query elements and make assertions about them.</p>

      <h2 id="cleaning-up-after-ourselves"><a class="hash" href="#cleaning-up-after-ourselves" aria-label="Link to heading"></a>Cleaning up after ourselves</h2>
    <p>Since the DOM is global every test is updating the same document. This could potentially cause one test to affect the result of another, which is a bad idea. Tests should always be isolated from each other so that when one fails you know it&#39;s a real failure and not a false negative caused by some other test.</p>
<p>If we add a second test that also logs the DOM we can see this accumulation:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Another thing renders correctly"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token operator">&lt;</span>span<span class="token operator">></span>goodbye<span class="token operator">&lt;</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> h1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>h1<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeInstanceOf</span><span class="token punctuation">(</span>HTMLHeadingElement<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This test logs:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>goodbye<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><p>The test also passes even though it shouldn&#39;t! We are searching the DOM for an <code>h1</code> and finding it, even though we rendered a <code>span</code>, because the <code>h1</code> is still there from the previous test.</p>
<p>We need to create a way to clean up the DOM to remove any containers we&#39;ve added, and to unmount any React roots we created. Most testing frameworks provide a way to run code after each test, so we can aim for something like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> test<span class="token punctuation">,</span> expect<span class="token punctuation">,</span> afterEach <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"bun:test"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> cleanup <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./helpers.js"</span><span class="token punctuation">;</span>

<span class="token function">afterEach</span><span class="token punctuation">(</span>cleanup<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We&#39;ll have to keep track of both the container and React roots we create during renders, so lets push them into an array:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> roots <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token parameter">element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    roots<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> root<span class="token punctuation">,</span> container <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Then we can write a <code>cleanup</code> function that loops over this array and deletes any DOM nodes and unmounts any React roots:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">cleanup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">{</span> root<span class="token punctuation">,</span> container <span class="token punctuation">}</span> <span class="token keyword">of</span> roots<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> root<span class="token punctuation">.</span><span class="token function">unmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    roots<span class="token punctuation">.</span>length <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">// empty the array once we're done</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Note that just like when we render into a React root, we also wrap the unmount in <code>act</code> to make sure it happens at the right time.</p>
<p>Now when we run our two tests again the second one fails as it should, since the DOM only contains the <code>span</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>goodbye<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h2 id="dispatching-events"><a class="hash" href="#dispatching-events" aria-label="Link to heading"></a>Dispatching events</h2>
    <p>Writing useful component tests requires interacting with them. Otherwise you&#39;re just verifying that you typed the right JSX. In order to test interactivity we need to be able to trigger events on the DOM elements the component rendered.</p>
<p>Let&#39;s try to test this counter component:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Counter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setCount</span><span class="token punctuation">(</span>count <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>First we need to render it as before:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Counter can increment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Counter</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>button<span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"could not find &lt;button>"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>To verify that the counter works we need to trigger a click event on the button element, then check that the text content has updated. We can do that using the <code>dispatchEvent</code> method on DOM elements:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Counter can increment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Counter</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>button<span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"could not find &lt;button>"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"0"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> click <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> bubbles<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    button<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>However this test fails: the text content does not update from &quot;0&quot; to &quot;1&quot;. We do get a helpful warning from React though:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Warning: An update to Counter inside a test was not wrapped in act(...).

When testing, code that causes React state updates should be wrapped into act(...)</code></pre>
    </div><p>This is the same problem as before—state updates are not handled synchonously, so our assertions run before React has finished re-rendering. We need to wrap the event dispatch in <code>act</code> to ensure everything happens in the right order:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Counter can increment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    <span class="token keyword">let</span> click <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> bubbles<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> button<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Now the DOM updates correctly and the test passes.</p>
<p>Creating and dispatching events like this is a little clunky. It would be nice to abstract this away into a helper function like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">fireEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> button<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Unfortunately that is not a simple undertaking. Different events require different constructor functions (i.e. &quot;click&quot; events must use <code>MouseEvent</code>, &quot;blur&quot; events must use <code>FocusEvent</code> etc). Different events also need different options: some bubble and some do not. React Testing Library maintains a <a href="https://github.com/testing-library/dom-testing-library/blob/main/src/event-map.js">~400 line object</a> mapping each event type to the required options to handle this.</p>
<p>The best we can do without adding a ton of complexity is hide the <code>act</code> call so tests don&#39;t need to import this from React:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">fireEvent</span><span class="token punctuation">(</span><span class="token parameter">event<span class="token punctuation">,</span> element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> element<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This simplifies the test very slightly:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Counter can increment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    <span class="token keyword">let</span> click <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fireEvent</span><span class="token punctuation">(</span>click<span class="token punctuation">,</span> button<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="input-value-updates"><a class="hash" href="#input-value-updates" aria-label="Link to heading"></a>Input value updates</h3>
    <p>There is another weird edge-case to take care of. React does some strange things when handling updates to the values of inputs and textareas. This makes normal event dispatches not work correctly. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Uppercase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> <span class="token punctuation">[</span>value<span class="token punctuation">,</span> setValue<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
        <span class="token operator">&lt;</span>input
            value<span class="token operator">=</span><span class="token punctuation">{</span>value<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
            onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
                console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token function">setValue</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token punctuation">}</span>
        <span class="token operator">/</span><span class="token operator">></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Counter can increment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token operator">&lt;</span>Uppercase <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>input<span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"could not find &lt;input>"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    input<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">"hello"</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> change <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">"change"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fireEvent</span><span class="token punctuation">(</span>change<span class="token punctuation">,</span> input<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>input<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"HELLO"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This test fails because the change event handler never runs (we never see the event logged by the component). There&#39;s a <a href="https://github.com/facebook/react/issues/10135">discussion on why this happens</a> from 2017. Unfortunately the solution is pretty weird. This is the most minimal version I can get to work:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">setValue</span><span class="token punctuation">(</span><span class="token parameter">element<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> proto <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> setter <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertyDescriptor</span><span class="token punctuation">(</span>proto<span class="token punctuation">,</span> <span class="token string">"value"</span><span class="token punctuation">)</span><span class="token operator">?.</span>set<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>setter<span class="token punctuation">)</span> <span class="token function">setter</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>element<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We find the prototype of the input element, then get the setter function for the <code>value</code> property and then bind it to the input element and call it with the new value we want to set. This bypasses React&#39;s hijacking of the update so the event handler actually runs.</p>
<p>We have to use this instead of setting the value directly on the input:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"Counter can increment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    <span class="token function">setValue</span><span class="token punctuation">(</span>input<span class="token punctuation">,</span> <span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> change <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Event</span><span class="token punctuation">(</span><span class="token string">"change"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">fireEvent</span><span class="token punctuation">(</span>change<span class="token punctuation">,</span> input<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">expect</span><span class="token punctuation">(</span>input<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"HELLO"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Even weirder this works fine in Jest with their JSDOM setup, but not in Bun using <code>global-jsdom</code>. This is another argument for using React Testing Library, since they have <a href="https://github.com/testing-library/dom-testing-library/blob/20d9894f0e5403e50c8d01b795a51532d72e8337/src/events.js#L106">a more robust implementation of this</a>.</p>

      <h2 id="conclusion"><a class="hash" href="#conclusion" aria-label="Link to heading"></a>Conclusion</h2>
    <p>Here&#39;s our final set of testing helpers:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token string">"global-jsdom/register"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createRoot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/client"</span><span class="token punctuation">;</span>

global<span class="token punctuation">.</span><span class="token constant">IS_REACT_ACT_ENVIRONMENT</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> roots <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token parameter">element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> root <span class="token operator">=</span> <span class="token function">createRoot</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> root<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    roots<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> root<span class="token punctuation">,</span> container <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">cleanup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">{</span> root<span class="token punctuation">,</span> container <span class="token punctuation">}</span> <span class="token keyword">of</span> roots<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> root<span class="token punctuation">.</span><span class="token function">unmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    roots<span class="token punctuation">.</span>length <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">fireEvent</span><span class="token punctuation">(</span><span class="token parameter">event<span class="token punctuation">,</span> element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> element<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">setValue</span><span class="token punctuation">(</span><span class="token parameter">element<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> proto <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> setter <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertyDescriptor</span><span class="token punctuation">(</span>proto<span class="token punctuation">,</span> <span class="token string">"value"</span><span class="token punctuation">)</span><span class="token operator">?.</span>set<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>setter<span class="token punctuation">)</span> <span class="token function">setter</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>element<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This hopefully demystifies React testing a bit—there&#39;s not much magic happening; it&#39;s mostly just regular DOM stuff with a few weird bits due to React&#39;s strange internals.</p>
<p>My main takeaway would be to just use React Testing Library, since it handles a lot of edge-cases for you and provides lots more convenient helpers too.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Speed up your SPA by preloading data requests</title>
    <link href="https://oliverjam.com/articles/preload-data"/>
    <updated>2023-12-14T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/preload-data</id>
    <content type="html"><![CDATA[
      <h2 id="quick-answer"><a class="hash" href="#quick-answer" aria-label="Link to heading"></a>Quick answer</h2>
    <p>If you just want the tl;dr solution: use <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload"><code>&lt;link rel=&quot;preload&quot;&gt;</code></a> to make the browser kick off <code>fetch</code> requests before it even starts downloading your JS files. That way the responses are ready by the time your app code runs.</p>

      <h2 id="the-problem"><a class="hash" href="#the-problem" aria-label="Link to heading"></a>The problem</h2>
    <p>One of the major downsides to a single-page app is that data fetching doesn&#39;t begin until your app&#39;s JavaScript runs. Depending on the size and complexity of the app it can be a non-trivial amount of time before your code actually calls <code>fetch</code>.</p>
<p>A typical &quot;naive&quot; client-side React app with a bunch of dependencies chosen by popularity (or at random) can easily end up loading over 1MB of JavaScript. If the first thing the app does is <code>fetch</code> some JSON from an API so that it can actually render content, that means the browser must:</p>
<ol>
<li>Download and parse the (mostly empty) HTML</li>
<li>Find the script tag(s) containing the app&#39;s JavaScript code</li>
<li>Download, parse and execute all the JavaScript</li>
<li>Execute any <code>fetch</code> requests it finds</li>
<li>Update the DOM once the requests are complete</li>
</ol>
<p>That 1MB+ of JS will take a while to download (especially on 3G), and potentially <em>even longer</em> to run (especially on mobile, since lots of Android phones have terrible single-core CPU performance). The user will be staring at a blank white screen (or maybe a janky loading spinner) while they wait.</p>
<blockquote>
<p>&quot;In fact, of the total time a page spends loading in a browser like Chrome, anywhere up to 30% of that time can be spent in JavaScript execution&quot;<br><a href="https://v8.dev/blog/cost-of-javascript-2019">The cost of JavaScript in 2019, V8 Blog</a>.</p>
</blockquote>

      <h2 id="the-solution"><a class="hash" href="#the-solution" aria-label="Link to heading"></a>The solution</h2>
    <p>Web browsers have a declarative API for preloading resources. You may have used this before for loading fonts or something to make sure your CSS doesn&#39;t block rendering. Well it turns out you can use the same API for preloading arbitrary JS <code>fetch</code> calls.</p>
<p>Here&#39;s a <code>fetch</code> to get the first 20 Pokémon from the PokéAPI:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Here&#39;s the exact same request triggered declaratively in HTML:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span>
    <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>preload<span class="token punctuation">"</span></span>
    <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://pokeapi.co/api/v2/pokemon<span class="token punctuation">"</span></span>
    <span class="token attr-name">as</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>fetch<span class="token punctuation">"</span></span>
    <span class="token attr-name">crossorigin</span>
<span class="token punctuation">/></span></span></code></pre>
    </div><p>When the browser parses the <code>&lt;link&gt;</code> tag in the HTML it will queue a request for that resource, then cache the response. If your JS code requests the <em>same</em> resource within a few seconds the browser will give it the cached version.</p>
<p>This means the browser can be fetching your API responses while it is still downloading your JS code, which can be a pretty big speedup if your JS is slow.</p>

      <h2 id="caveats"><a class="hash" href="#caveats" aria-label="Link to heading"></a>Caveats</h2>
    <p>It&#39;s important not to abuse this. If you preload something but don&#39;t use it within a few seconds the browser will put a big warning in the console. You&#39;ve just wasted the users bandwidth, and potentially slowed down the page load by having the browser spend time fetching something it didn&#39;t need.</p>
<p>The preload must match what you fetch <em>exactly</em>. If the requests are even a bit different the browser won&#39;t be able to match them and you&#39;ll see the same warning about not using a preloaded resource.</p>
<p>This is why we needed the <code>crossorigin</code> attribute in our example. The <code>&lt;link&gt;</code> tag doesn&#39;t use CORS by default because it&#39;s not needed for e.g. CSS files. However JS <code>fetch</code> requests have CORS enabled, so we need to specify it in the preload to match.</p>

      <h2 id="practical-example"><a class="hash" href="#practical-example" aria-label="Link to heading"></a>Practical example</h2>
    <p>I built a quick example to try and get some data on exactly how much this might help. Here&#39;s a simple JS app that lists Pokémon from the PokéAPI:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- pokemon go here --></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
    <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon"</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">json</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
            <span class="token keyword">let</span> pokes <span class="token operator">=</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span>
                json<span class="token punctuation">.</span>results<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">p</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
                    <span class="token keyword">let</span> poke <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span>p<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">let</span> li <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"li"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    li<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>poke<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">return</span> li<span class="token punctuation">;</span>
                <span class="token punctuation">}</span><span class="token punctuation">)</span>
            <span class="token punctuation">)</span><span class="token punctuation">;</span>
            list<span class="token punctuation">.</span><span class="token function">replaceChildren</span><span class="token punctuation">(</span><span class="token operator">...</span>pokes<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
    </div><p>Here&#39;s how the page renders:</p>
<ol>
<li>Browser downloads and starts parsing the HTML</li>
<li>Browser finds the script and starts parsing the JS</li>
<li>JS starts fetching the list of 20 Pokémon</li>
<li>JS waits for promise to resolve</li>
<li>JS starts fetching each of the 20 Pokémon</li>
<li>JS waits for all 20 to resolve</li>
<li>JS updates DOM</li>
</ol>

      <h3 id="initial-performance"><a class="hash" href="#initial-performance" aria-label="Link to heading"></a>Initial performance</h3>
    <p>In this case performance is pretty good. Our JS is inline, which means the browser doesn&#39;t have to make a separate HTTP request to download it. There&#39;s also hardly any of it, so it won&#39;t take long to parse and execute. We&#39;re also not accidentally fetching all the Pokémon serially, which is <a href="/articles/pitfalls-of-async-functions">easy to do with <code>await</code></a>.</p>
<p>If I simulate a &quot;Slow 3G&quot; connection this page fully renders in <strong>8.58s</strong> in Edge. Here&#39;s a visualisation of the requests:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">/index.html (2.01s)
                  └─ /pokemon (2.10s)
                                    ├─ /pokemon/1 (3.71s)
                                    ├─ /pokemon/2 (3.84s)
                                    ├─ /pokemon/1 (4.37s)
                                    ├─ ...etc</code></pre>
    </div><p>The HTML is done downloading in 2.01s, but the first <code>fetch</code> isn&#39;t queued until 2.05s after we start loading the page. That means it takes the browser 40ms to get ready to send the <code>fetch</code>, with this tiny amount of inlined JS.</p>

      <h3 id="make-it-realistic-slower"><a class="hash" href="#make-it-realistic-slower" aria-label="Link to heading"></a>Make it realistic (slower!)</h3>
    <p>We can simulate slower loading JS by putting a 2s timeout in the code. This will act as if we have a larger JS file to download. Note that this is probably unrealistically fast: if the 670B (0.00067MB) HTML file is taking 2.01s to download imagine how long a 1MB JS bundle will take to download, parse and execute.</p>
<p>With a 2000ms <code>setTimeout</code> wrapped around the JS code the page now fully renders in <strong>10.47s</strong>. This is roughly 2s slower than previously, which is what we&#39;d expect. The HTML still loads in 2.01s, but the first <code>fetch</code> now doesn&#39;t start until 4.05s in. This is exactly 2s slower than before.</p>

      <h3 id="fix-it-with-preload"><a class="hash" href="#fix-it-with-preload" aria-label="Link to heading"></a>Fix it with preload</h3>
    <p>Now lets try preloading our fetch requests. We can do this by adding <code>&lt;link&gt;</code> tags for each request to the HTML. In this case we need 21: one for the initial list request and one for each of the 20 pokémon requests.</p>
<p>This page now fully renders in <strong>6.69s</strong>. This is not only 4s faster than the <code>setTimeout</code> example, but still 2s faster than the initial version. If we visualise the requests we can see why:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">/index.html (2.06s)
                  ├─ /pokemon   (2.03s)
                  ├─ /pokemon/1 (3.82s)
                  ├─ /pokemon/2 (3.79s)
                  ├─ /pokemon/1 (3.89s)
                  ├─ ...etc</code></pre>
    </div><p>The initial HTML load took a bit longer because adding all those <code>&lt;link&gt;</code> tags made it grow from 670B to 2.7KB. However because the browser knows about all the data dependencies up front it can start downloading them all in parallel. This means that not only do we avoid the 2s delay waiting for the JS to execute, we also skip the 2.03s it took for the list of pokémon to download. That explains why the total load time was about 4s faster.</p>

      <h2 id="in-summary"><a class="hash" href="#in-summary" aria-label="Link to heading"></a>In summary</h2>
    <p>Obviously this technique will only work if you can know your data dependencies statically ahead of time. If your page needs some dynamic information (like localStorage state) to render then this technique won&#39;t work. However if you can make it work it feels like a no-brainer to leverage built-in browser primitives to speed up your single-page apps.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Writing a simple JSX to HTML renderer</title>
    <link href="https://oliverjam.com/articles/diy-jsx"/>
    <updated>2023-10-30T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/diy-jsx</id>
    <content type="html"><![CDATA[<p>I decided to write my own JSX renderer to better understand how it works (and to have a simple library I could use in side projects). You can skip all my rambling about why I like JSX and <a href="#building-my-own">jump straight to the code</a>.</p>
<p><strong>Update (May 2026):</strong> I published an improved version of this JSX renderer as part of my <a href="https://github.com/oliverjam/hypa">server-side app library</a>.</p>

      <h2 id="what-is-jsx"><a class="hash" href="#what-is-jsx" aria-label="Link to heading"></a>What is JSX?</h2>
    <p>JSX is an extension to JavaScript that lets you write HTML-like syntax, which would usually be invalid. This was invented for React, to make it easier to create DOM elements declaratively:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>my-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Hello world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code></pre>
    </div><p>JSX also provides a nice developer experience. Since it&#39;s embedded within JS you just use JS features to generate elements. I like not really having to shift mindsets as I jump from business logic to UI code. The popularity of React means JSX has great tooling support. For example syntax highlighting, autocompletion, warnings about accessibility errors.</p>
<p>That said, as much as I like JSX I don&#39;t want to write all my apps as React SPAs. Nowadays I default to <a href="/articles/simple-web-apps-bun">simple server-rendered apps</a>. However I do still like using JSX to render HTML strings. This is nicer than using template literals, since they&#39;re just unstructured strings with none of the benefits listed above. It&#39;s also harder to compose components together, since function calls don&#39;t look like HTML. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">html<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token html language-html">
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span><span class="token plain-text">
    ${Title({ children: "Hello" })}
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span>
</span><span class="token template-punctuation string">`</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Title</span></span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Title</span></span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">
</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h2 id="how-jsx-works"><a class="hash" href="#how-jsx-works" aria-label="Link to heading"></a>How JSX works</h2>
    <p>We need to understand what&#39;s actually going on before we can write our own renderer. JSX is one of those things that seems magical because several things combine to create a smooth experience. In a standard React app rendering is a 3-step process:</p>
<ol>
<li>JSX is &quot;transpiled&quot; to regular JS functions by a bundler</li>
<li>The function calls return objects</li>
<li>A special render function converts the object tree to DOM</li>
</ol>
<p>Here&#39;s an example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can&#39;t run this in the browser since JSX isn&#39;t valid JS. So we&#39;ll use <a href="https://esbuild.github.io/try/#dAAwLjE5LjUAeyBsb2FkZXI6ICJqc3giLCAianN4IjogImF1dG9tYXRpYyIgfQA8aDE+aGVsbG88L2gxPjs">esbuild</a> to transpile it (convert it to actual JS):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> jsx <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react/jsx-runtime"</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>You can see that JSX directly converts to simple functions. We can configure exactly what library the import comes from if we like, but for now let&#39;s stick with React. If we run this code we get this log output:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"h1"</span><span class="token punctuation">,</span>
  <span class="token property">"key"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span>
  <span class="token property">"ref"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span>
  <span class="token property">"props"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"children"</span><span class="token operator">:</span> <span class="token string">"hello"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"_owner"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span>
  <span class="token property">"_store"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>All the <code>jsx</code> function does is scaffold a simple object describing the element. If we had a more complex UI this object would have more objects nested inside the <code>children</code> property.</p>
<p>You can see that <a href="https://github.com/facebook/react/blob/0965fbcab3616523086d05c1069492cc171cbb80/packages/react/src/jsx/ReactJSXElement.js#L148">React&#39;s <code>jsx</code> implementation</a> really doesn&#39;t do much more than construct a simple object (plus a bunch of dev-only checks).</p>
<p>Finally to put DOM elements on the page we would use React&#39;s <code>render</code> method to convert this object tree to real DOM elements on the page:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> createRoot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/client"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">createRoot</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#root"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>If instead we wanted to render an HTML string on the server we could do this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> renderToString <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/server"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> html <span class="token operator">=</span> <span class="token function">renderToString</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// "&lt;h1>hello&lt;/h1>"</span></code></pre>
    </div><p>This two-step process is necessary because React uses a <em>virtual DOM</em> for rendering. This lets it compare the previous and next object trees to figure out just the bits it needs to update, so it doesn&#39;t have to change more of the DOM than necessary.</p>
<p>However on the server this overhead is not necessary, since our responses are one-off strings that get sent and never change. I was inspired by <a href="https://github.com/kitajs/html">kitajs/html</a>, which skips the render step entirely and just has a <code>jsx</code> function produce a string directly. Their code looks pretty complex though (I imagine for good reason), so I did what I always do and wrote my own way simpler version.</p>

      <h2 id="building-my-own"><a class="hash" href="#building-my-own" aria-label="Link to heading"></a>Building my own</h2>
    <p>Let&#39;s define our requirements by checking how different snippets of JSX are transpiled by esbuild. We can then write tests to make sure our code works, make the test pass, then add more features. TDD!</p>
<p>Here&#39;s the simple case:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token comment">// ↓</span>
<span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We need a <code>jsx</code> function that takes the tag name as a string, then an object containing the children as a string. We want this to return a string of valid HTML. Here&#39;s a test:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"simple"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> actual <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>actual<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1>Hello&lt;/h1></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Let&#39;s implement that as simply as we can to make the test pass:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> children <span class="token punctuation">}</span> <span class="token operator">=</span> props<span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>children<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> jsx <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="void-elements"><a class="hash" href="#void-elements" aria-label="Link to heading"></a>Void elements</h3>
    <p>That works great. However I&#39;ve just remembered that some HTML tags are <em>void</em> elements. This means they don&#39;t use a closing tag because they cannot contain anything. For example <code>&lt;input&gt;</code>, not <code>&lt;input&gt;&lt;/input&gt;</code>. We should write a test to cover this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"void elements"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> actual <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>actual<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;input></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Unfortunately there&#39;s no magic way to tell which elements are void; we&#39;ll have to check a list.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token constant">VOIDS</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
  <span class="token string">"area"</span><span class="token punctuation">,</span>
  <span class="token string">"base"</span><span class="token punctuation">,</span>
  <span class="token string">"br"</span><span class="token punctuation">,</span>
  <span class="token string">"col"</span><span class="token punctuation">,</span>
  <span class="token string">"embed"</span><span class="token punctuation">,</span>
  <span class="token string">"hr"</span><span class="token punctuation">,</span>
  <span class="token string">"img"</span><span class="token punctuation">,</span>
  <span class="token string">"input"</span><span class="token punctuation">,</span>
  <span class="token string">"link"</span><span class="token punctuation">,</span>
  <span class="token string">"meta"</span><span class="token punctuation">,</span>
  <span class="token string">"source"</span><span class="token punctuation">,</span>
  <span class="token string">"track"</span><span class="token punctuation">,</span>
  <span class="token string">"wbr"</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> children <span class="token operator">=</span> <span class="token string">""</span> <span class="token punctuation">}</span> <span class="token operator">=</span> props<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token constant">VOIDS</span><span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>children<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Sidenote: I originally had a big regexp here, but I performance tested it and the <code>Set</code> was 4 times faster ✨.</p>

      <h3 id="multiple-children"><a class="hash" href="#multiple-children" aria-label="Link to heading"></a>Multiple children</h3>
    <p>Cool, now we&#39;ll try a more complex example with multiple children:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">
</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token comment">// ↓</span>
<span class="token function">jsxs</span><span class="token punctuation">(</span><span class="token string">"header"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"world"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Looks like this passes the children as an array, and transpiles to a different function called <code>jsxs</code>, to allow implementations to handle this case separately. I think we can probably use the same function for both, and just alias the export.</p>
<p>Here&#39;s the new test:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"array children"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> actual <span class="token operator">=</span> <span class="token function">jsxs</span><span class="token punctuation">(</span><span class="token string">"header"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"world"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>actual<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;header>&lt;h1>Hello&lt;/h1>&lt;p>world&lt;/p>&lt;/header></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can make this pass by making sure we join any array children back to a string:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">join</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">join</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token operator">?</span> x<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span> <span class="token operator">:</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> jsx<span class="token punctuation">,</span> jsx <span class="token keyword">as</span> jsxs <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="html-attributes"><a class="hash" href="#html-attributes" aria-label="Link to heading"></a>HTML attributes</h3>
    <p>Now what happens if our elements have attributes?</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>x<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token comment">// ↓</span>
<span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"x"</span><span class="token punctuation">,</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Here&#39;s a new test:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"attributes"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token keyword">void</span> <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"x"</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"text"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;input id="x" type="text"></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> kids <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">"x"</span><span class="token punctuation">,</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>kids<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1 id="x">Hello&lt;/h1></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We&#39;ll need to loop over the non-children props and turn them into <code>key=value</code> pairs, whilst filtering out any falsy/null/undefined values:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> children <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token operator">...</span>rest <span class="token punctuation">}</span> <span class="token operator">=</span> props<span class="token punctuation">;</span>
  <span class="token keyword">let</span> attrs <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">[</span>key<span class="token punctuation">,</span> val<span class="token punctuation">]</span> <span class="token keyword">of</span> Object<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>v <span class="token operator">!==</span> <span class="token boolean">false</span> <span class="token operator">&amp;&amp;</span> v <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> attrs <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">="</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>val<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token constant">VOIDS</span><span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>attrs<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>attrs<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">join</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>HTML also has <a href="https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML">&quot;boolean attributes&quot;</a>. These are not key/value pairs, but instead are either just present or not present. This means any prop with a value of <code>true</code> should be set as just the key.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span> <span class="token attr-name">hidden</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token comment">// ↓</span>
<span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We&#39;ll write a test:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"boolean attributes"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> actual <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">hidden</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>actual<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1 hidden>Hello&lt;/h1></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We&#39;ll add a line into our attributes loop to handle this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">tag</span><span class="token operator">:</span> Type<span class="token punctuation">,</span> <span class="token literal-property property">props</span><span class="token operator">:</span> Props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">[</span>key<span class="token punctuation">,</span> val<span class="token punctuation">]</span> <span class="token keyword">of</span> Object<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span>rest<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>v <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> attrs <span class="token operator">+=</span> <span class="token string">" "</span> <span class="token operator">+</span> key<span class="token punctuation">;</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="custom-components"><a class="hash" href="#custom-components" aria-label="Link to heading"></a>Custom components</h3>
    <p>We&#39;ve pretty much covered all regular HTML now. It would be great to handle custom components too, since that&#39;s what makes composing UIs with JSX feel so nice.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Title</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> children <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>children<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Title</span></span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Title</span></span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token comment">// ↓</span>
<span class="token keyword">function</span> <span class="token function">Title</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> children <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">jsx</span><span class="token punctuation">(</span>Title<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can see that rather than a string as the tag name we get passed the component function itself. We&#39;ll need to call this function and return the resulting HTML.</p>
<p>Here&#39;s a test:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"component"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">function</span> <span class="token function">Title</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> children <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">let</span> actual <span class="token operator">=</span> <span class="token function">jsx</span><span class="token punctuation">(</span>Title<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>actual<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1>Hello&lt;/h1></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can add a check to the start of our implementation to handle this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">tag</span><span class="token operator">:</span> Type<span class="token punctuation">,</span> <span class="token literal-property property">props</span><span class="token operator">:</span> Props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> tag <span class="token operator">===</span> <span class="token string">"function"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">tag</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="fragments"><a class="hash" href="#fragments" aria-label="Link to heading"></a>Fragments</h3>
    <p>The final feature we&#39;re missing is &quot;fragments&quot;. Since JSX transpiles to nested function calls it requires a single top-level element (unlike HTML). Fragments allow us to render multiple elements without a parent:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token comment">// ↓</span>
<span class="token function">jsxs</span><span class="token punctuation">(</span>Fragment<span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"world"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Here we expect the fragment to render nothing in the HTML:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"fragment"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> actual <span class="token operator">=</span> <span class="token function">jsxs</span><span class="token punctuation">(</span>Fragment<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Hello"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token string">"p"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"world"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>actual<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1>Hello&lt;/h1>&lt;p>world&lt;/p></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We need to create a separate export for this that just renders its children (which will either be a string or array of strings):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Fragment</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">join</span><span class="token punctuation">(</span>props<span class="token punctuation">.</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> jsx<span class="token punctuation">,</span> jsx <span class="token keyword">as</span> jsxs<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h2 id="wrapping-up"><a class="hash" href="#wrapping-up" aria-label="Link to heading"></a>Wrapping up</h2>
    <p>That&#39;s it! Here&#39;s our entire JSX-to-HTML implementation in only 18 lines of code!</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token constant">VOIDS</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token string">"area"</span><span class="token punctuation">,</span> <span class="token string">"base"</span><span class="token punctuation">,</span> <span class="token string">"br"</span><span class="token punctuation">,</span> <span class="token string">"col"</span><span class="token punctuation">,</span> <span class="token string">"embed"</span><span class="token punctuation">,</span> <span class="token string">"hr"</span><span class="token punctuation">,</span> <span class="token string">"img"</span><span class="token punctuation">,</span> <span class="token string">"input"</span><span class="token punctuation">,</span> <span class="token string">"link"</span><span class="token punctuation">,</span> <span class="token string">"meta"</span><span class="token punctuation">,</span> <span class="token string">"source"</span><span class="token punctuation">,</span> <span class="token string">"track"</span><span class="token punctuation">,</span> <span class="token string">"wbr"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">jsx</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span> props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> tag <span class="token operator">===</span> <span class="token string">"function"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">tag</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> attrs <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> children <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">,</span> <span class="token operator">...</span>rest <span class="token punctuation">}</span> <span class="token operator">=</span> props<span class="token punctuation">;</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">[</span>key<span class="token punctuation">,</span> val<span class="token punctuation">]</span> <span class="token keyword">of</span> Object<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span>rest<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>v <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> attrs <span class="token operator">+=</span> <span class="token string">" "</span> <span class="token operator">+</span> key<span class="token punctuation">;</span>
    <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>v <span class="token operator">!==</span> <span class="token boolean">false</span> <span class="token operator">&amp;&amp;</span> v <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> attrs <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">="</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>val<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token constant">VOIDS</span><span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>attrs<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>attrs<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">join</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">Fragment</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">join</span><span class="token punctuation">(</span>props<span class="token punctuation">.</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> jsx<span class="token punctuation">,</span> jsx <span class="token keyword">as</span> jsxs<span class="token punctuation">,</span> Fragment <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><!-- prettier-ignore-end -->
]]></content>
  </entry>
      
  <entry>
    <title>Simple progressively enhanced web apps</title>
    <link href="https://oliverjam.com/articles/progressive-enhancement-htmx"/>
    <updated>2023-10-18T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/progressive-enhancement-htmx</id>
    <content type="html"><![CDATA[<p>This is a follow-up to my last article on <a href="/articles/simple-web-apps-bun">building simple server-rendered web apps</a>. We&#39;re going to enhance the user-experience of these apps with a little bit of client-side JS. If you want to skip the history lesson you can <a href="#building-our-own-mini-htmx">jump to the fun code</a>.</p>
<p><strong>Update (May 2026):</strong> I have published an improved version of what we built in this post as <a href="https://github.com/oliverjam/transclusion">Transclusion</a>.</p>

      <h2 id="the-lost-art-of-progressive-enhancement"><a class="hash" href="#the-lost-art-of-progressive-enhancement" aria-label="Link to heading"></a>The lost art of progressive enhancement</h2>
    <p>Progressive enhancement is the idea that you should layer more powerful features on top of functional basics. For example starting with a regular HTML form, then adding JS to intercept submits and update the page selectively rather than doing a full browser navigation.</p>
<p>A long time ago this was a pretty standard practice, since it was the only way to build more complex web apps. However as the JavaScript language and DOM APIs improved, full client-side frameworks like Knockout.js (2010), Ember.js (2011) and React (2013) emerged that allowed devs to build an entire app client-side. This paradigm became known as a &quot;Single-Page App&quot; (SPA), since the server only had to provide a single HTML page—the first one. Everything after that was rendered client-side by assembling fetched data with client-side templates.</p>
<p>Unfortunately the rise of SPAs meant the death of progressive enhancement. Almost by definition you can&#39;t progressively enhance without server-rendering. There is no &quot;minimum viable experience&quot; before JS loads, parses and runs—just a blank white page that eventually (hopefully) gets populated with content.</p>
<p>Developers got used to just slapping a click handler on a button (since <code>&lt;button onClick={}&gt;</code> is <em>so</em> convenient in React), and collectively forgot that forms had helpful behaviour if you didn&#39;t <code>e.preventDefault()</code> them.</p>

      <h2 id="whats-old-is-new-again"><a class="hash" href="#whats-old-is-new-again" aria-label="Link to heading"></a>What&#39;s old is new again</h2>
    <p>Progressive enhancement is making a comeback as frameworks like <a href="https://remix.run/">Remix</a> and <a href="https://kit.svelte.dev/">SvelteKit</a> provide simple APIs for interactivity where the easiest thing for devs to do is start with simple forms and links. For people not using JS metaframeworks as their backend the <a href="https://htmx.org/">HTMX</a> library has leapt into the spotlight.</p>

      <h2 id="htmx"><a class="hash" href="#htmx" aria-label="Link to heading"></a>HTMX</h2>
    <p>HTMX is a library for adding interactivity without writing your own JavaScript. It hooks into a set of declarative attributes in your HTML. These attributes coordinate behaviour like &quot;fetch a fragment of HTML from this URL and insert it into this element&quot;. This is a surprisingly nice way to sprinkle enhancements into an app that is already functional the old-fashioned way.</p>
<p>Interestingly HTMX is not particularly focused on progressive enhancement. The docs encourage patterns that are entirely reliant on JS:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">hx-post</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/clicked<span class="token punctuation">"</span></span> <span class="token attr-name">hx-swap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>outerHTML<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Click Me<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
    </div><p>However it has a subset of features for enhancing links and forms that are perfect for enhancement: <a href="https://htmx.org/docs/#boosting">boosting</a>. Adding <code>hx-boost</code> to links or forms opts in to a form of client-side routing (clicking/submitting will prevent the default behaviour and swap the new page into the <code>&lt;body&gt;</code>, avoiding a full page reload). Combining this with the <a href="https://htmx.org/attributes/hx-target/"><code>hx-target</code></a> attribute allows you to update specific subsets of the page following user interaction.</p>

      <h2 id="building-our-own-mini-htmx"><a class="hash" href="#building-our-own-mini-htmx" aria-label="Link to heading"></a>Building our own mini-HTMX</h2>
    <p>HTMX is kind of huge and complex, because it supports a ton of features I don&#39;t need (and IE11!). My favourite way to learn something properly is to rebuild a small part of it in a simpler way, so lets see how we could recreate the bits of HTMX we need.</p>
<p>We&#39;ll start with the basic counter from <a href="/articles/simple-web-apps-bun#counter-app">the previous article</a> and work our way up to full progressive enhancement. Here&#39;s the form we want to enhance:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diff<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>decrement<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>-<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span><span class="token punctuation">></span></span>{count}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diff<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>+1<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>increment<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>When the server receives the form&#39;s <code>POST</code> request it increments the count and redirects back to the same page. The browser reloads the entire page, which results in the new count showing in the <code>&lt;output&gt;</code>.</p>
<p><video src=/assets/media/default-counter.dc8f1017.mp4 controls autoplay muted loop playsinline></video></p>
<p>Note how the page refreshes after each click, resetting the timer and losing focus from the button.</p>

      <h3 id="boosting-forms"><a class="hash" href="#boosting-forms" aria-label="Link to heading"></a>Boosting forms</h3>
    <p>First we need to recreate exactly what the browser does when the form is submitted, only using our own JavaScript. The first step is to listen for form submissions and prevent the default behaviour if there&#39;s a <code>data-boost</code> attribute set on the element.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> boost <span class="token punctuation">}</span> <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>dataset<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>boost <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Since submit events bubble up we can just attach a single listener to the entire document to check all submissions. Any that aren&#39;t boosted will be ignored.</p>
<p>We now need to send a request to the server that matches what the browser would normally send. That means matching the <code>action</code> URL and <code>method</code> (we&#39;ll ignore <code>enctype</code> for simplicity). We&#39;ll write it as a separate function since this code is pretty self-contained:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">submit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> action<span class="token punctuation">,</span> method <span class="token punctuation">}</span> <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">;</span>
  <span class="token keyword">let</span> headers <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"application/x-www-form-urlencoded"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FormData</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">,</span> event<span class="token punctuation">.</span>submitter<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span>action<span class="token punctuation">,</span> <span class="token punctuation">{</span> method<span class="token punctuation">,</span> headers<span class="token punctuation">,</span> body <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><details>
<summary>There are a few of fun sidenotes here.</summary>

<p>First, I literally have to google the correct <code>content-type</code> for form submissions <em>every time</em>. I really hope there was a good reason <code>application/x-www-</code> was a necessary prefix.</p>
<p>Second, we can easily grab all the data from the form&#39;s inputs using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData"><code>FormData</code> interface</a>. I use this a lot, but I&#39;d never used the second argument to the constructor—this is the button that <em>submitted</em> the form. You have to pass this separately as there can be multiple buttons, but only the one used to submit is included in the payload, so this varies per submission event.</p>
<p>Third, although you <em>can</em> pass an instance of <code>FormData</code> as the request body, TypeScript will complain since it can contain values that are strings <em>or</em> blobs (because forms support file uploads). Blobs can&#39;t be encoded like this (we&#39;d have to use a multipart form), so TS helpfully warns us. Since we are deliberately not supporting files we can use <code>URLSearchParams</code> to encode the data as <code>?key=value</code> pairs. If there were files we&#39;d just end up with the file name strings as the values.</p>
</details>

<p>Finally we need to actually send the request, then update the page by swapping the body with the response&#39;s body. We can turn the textual HTML response into a DOM using <code>DOMParser</code>, then extract the body:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// ...</span>
event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">submit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> new_dom <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DOMParser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parseFromString</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token string">"text/html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">replaceChildren</span><span class="token punctuation">(</span><span class="token operator">...</span>new_dom<span class="token punctuation">.</span>body<span class="token punctuation">.</span>childNodes<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span></code></pre>
    </div><p>Fantastic! We&#39;ve written 18 lines of JS to achieve... the exact behaviour the browser already had (but with more bugs). However now that our code controls the process we can start to add enhancements.</p>

      <h3 id="targeting"><a class="hash" href="#targeting" aria-label="Link to heading"></a>Targeting</h3>
    <p>Currently page state is lost on reload—if a keyboard user had focused a button they&#39;ll have to tab their way back to it to continue incrementing the count</p>
<p>Ideally we want to surgically update just the bit of the page we know has changed, so the user doesn&#39;t lose their place and the app feels more &quot;dynamic&quot;. Lets implement a simple version of HTMX&#39;s <a href="https://htmx.org/attributes/hx-target/"><code>hx-target</code></a>. It should let us specify a CSS selector for the element that should be updated, like this:</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span> <span class="token attr-name">data-boost</span> <span class="token attr-name">data-target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>output<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->

<div class="Code">
      
      <pre><code class="CodeSyntax">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> boost<span class="token punctuation">,</span> target <span class="token punctuation">}</span> <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>dataset<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>boost <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    <span class="token keyword">let</span> replacee <span class="token operator">=</span> target <span class="token operator">?</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span> <span class="token operator">:</span> document<span class="token punctuation">.</span>body<span class="token punctuation">;</span>
    replacee<span class="token punctuation">.</span><span class="token function">replaceChildren</span><span class="token punctuation">(</span><span class="token operator">...</span>new_dom<span class="token punctuation">.</span>body<span class="token punctuation">.</span>childNodes<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Unfortunately this is now broken—we&#39;re replacing the content of the <code>&lt;output&gt;</code> with the <em>entire body</em> of the response. There are two ways to fix this.</p>

      <h3 id="redundant-responses"><a class="hash" href="#redundant-responses" aria-label="Link to heading"></a>Redundant responses</h3>
    <p>We don&#39;t <em>need</em> to send the entire new page when we receive a <code>fetch</code> request. Our server knows that the <code>&lt;output&gt;</code> will be updated in-place, and can send the minimal content required for the update.</p>
<p>HTMX sets custom headers like <code>HX-Request</code> and <code>HX-Boosted</code> so your server can customise its responses. However nowadays we can use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Dest"><code>sec-fetch-dest</code></a> header. The browser will set this to <code>document</code> for navigations from links or forms, and <code>empty</code> for <code>fetch</code> requests. So we can send different responses for the JS vs no-JS cases:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// ...</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>headers<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"sec-fetch-dest"</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">"empty"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span>count<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"text/html"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">303</span><span class="token punctuation">,</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">location</span><span class="token operator">:</span> <span class="token string">"/"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>The response is a bit of a hack here—we&#39;re sending invalid HTML (literally just a single digit), but browsers don&#39;t seem to care when parsing—the value of <code>new_dom.body</code> will be <code>&quot;1&quot;</code> (or whatever the count was).</p>

      <h3 id="selecting"><a class="hash" href="#selecting" aria-label="Link to heading"></a>Selecting</h3>
    <p>If you aren&#39;t willing (or are unable) to change your server response, HTMX supports extracting a subset of the HTML response using <a href="https://htmx.org/attributes/hx-select/"><code>hx-select</code></a>. Lets implement a simple version so we can grab the <code>&lt;output&gt;</code> from the response like this:</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span> <span class="token attr-name">data-boost</span> <span class="token attr-name">data-target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>output<span class="token punctuation">"</span></span> <span class="token attr-name">data-select</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>output<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->

<div class="Code">
      
      <pre><code class="CodeSyntax">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> boost<span class="token punctuation">,</span> target<span class="token punctuation">,</span> select <span class="token punctuation">}</span> <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>dataset<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>boost <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    <span class="token keyword">let</span> replacee <span class="token operator">=</span> target <span class="token operator">?</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span> <span class="token operator">:</span> document<span class="token punctuation">.</span>body<span class="token punctuation">;</span>
    <span class="token keyword">let</span> replacer <span class="token operator">=</span> select <span class="token operator">?</span> new_dom<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>select<span class="token punctuation">)</span> <span class="token operator">:</span> new_dom<span class="token punctuation">.</span>body<span class="token punctuation">;</span>
    replacee<span class="token punctuation">.</span><span class="token function">replaceChildren</span><span class="token punctuation">(</span><span class="token operator">...</span>replacer<span class="token punctuation">.</span>childNodes<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Either method here works—our client-side JS can now update just the parts of the DOM we need based on declarative attributes in the HTML. We don&#39;t even have to change anything about our server if we don&#39;t want to. This is a pretty powerful model!</p>
<p><video src=/assets/media/boosted-counter.4c4021c3.mp4 controls autoplay muted loop playsinline></video></p>
<p>Note how the timer keeps counting without interruption, and focus remains on the button.</p>

      <h3 id="swapping"><a class="hash" href="#swapping" aria-label="Link to heading"></a>Swapping</h3>
    <p>HTMX has a couple more features that make it possible to build even more dynamic UIs. Let&#39;s use the <a href="/articles/simple-web-apps-bun#tasks-app">to-do list</a> from the last post as an example. Here&#39;s the HTML:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Tasks<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>task<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your task<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Add task<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ol</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Do the thing<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/remove<span class="token punctuation">"</span></span> <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">display</span><span class="token punctuation">:</span> inline</span><span class="token punctuation">"</span></span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token entity named-entity" title="&times;">&amp;times;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ol</span><span class="token punctuation">></span></span></code></pre>
    </div><p>When the first form is submitted the backend stores the new task in the DB, then redirects back to the same page but with the new task added to the start of the <code>&lt;ol&gt;</code> (so the most recent tasks are listed first).</p>
<p><video src=/assets/media/default-tasks.2047713e.mp4 controls autoplay muted loop playsinline></video></p>
<p>We could enhance this form similarly to before. Our backend could return just the single new <code>&lt;li&gt;</code>, or we could use <code>data-select</code> to get just the first one from the full response:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span>
  <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-boost</span>
  <span class="token attr-name">data-target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ol<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-select</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>li:first-child<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>Since our implementation of <code>data-select</code> used <code>document.querySelector</code> we can use any valid CSS selector, allowing us to grab exactly the element we need using <code>:first-child</code>.</p>
<p>Unfortunately this won&#39;t quite work—we currently always replace all of the content of the target element with the selected element. So this code will remove all the existing todos.</p>
<p>HTMX has a way to control this: <a href="https://htmx.org/attributes/hx-swap/"><code>hx-swap</code></a>. This lets you specify <em>where</em> in the target you want to put the new HTML. Our current implementation defaults to <code>innerHTML</code>—i.e. replace everything inside.</p>
<p>In this case we&#39;d like to use what HTMX calls &quot;afterbegin&quot;, which inserts the response before the first child of the target. Let&#39;s add support for this in our client-side code:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> boost<span class="token punctuation">,</span> target<span class="token punctuation">,</span> select<span class="token punctuation">,</span> swap <span class="token operator">=</span> <span class="token string">"innerHTML"</span> <span class="token punctuation">}</span> <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>dataset<span class="token punctuation">;</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>swap <span class="token operator">===</span> <span class="token string">"afterbegin"</span><span class="token punctuation">)</span> replacee<span class="token punctuation">.</span><span class="token function">prepend</span><span class="token punctuation">(</span>replacer<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>swap <span class="token operator">===</span> <span class="token string">"innerHTML"</span><span class="token punctuation">)</span> replacee<span class="token punctuation">.</span><span class="token function">replaceChildren</span><span class="token punctuation">(</span><span class="token operator">...</span>replacer<span class="token punctuation">.</span>childNodes<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>And finally update our form:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span>
  <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-boost</span>
  <span class="token attr-name">data-target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ol<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-select</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>li:first-child<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-swap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>afterbegin<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>Now our example should insert new tasks into the beginning of the list.</p>

      <h3 id="targeting-revisited"><a class="hash" href="#targeting-revisited" aria-label="Link to heading"></a>Targeting revisited</h3>
    <p>Our to-do list also supports deleting tasks. Each task has a form like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Do the thing<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/remove<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token entity named-entity" title="&times;">&amp;times;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span></code></pre>
    </div><p>The backend will receive POST requests to <code>/remove</code>, read the submitted <code>id</code> from the body, delete the corresponding task from the DB, then redirect back to the same page, which will re-render with the task removed.</p>
<p>We can&#39;t boost these forms right now because we have no way of deleting an element, and no way of easily targeting the parent <code>&lt;li&gt;</code> (without adding an ID to each one). Luckily HTMX supports both with <code>hx-swap=&quot;delete&quot;</code> and <code>hx-target=&quot;closest li&quot;</code>. The first will ignore the response and just remove the element; the second allows us to target <em>up</em> the DOM tree from the form.</p>
<p>Let&#39;s add support for both to our client-side code:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">let</span> replacee <span class="token operator">=</span> target<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"closest"</span><span class="token punctuation">)</span>
    <span class="token operator">?</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">closest</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"closest "</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token operator">:</span> target
    <span class="token operator">?</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span>
    <span class="token operator">:</span> document<span class="token punctuation">.</span>body<span class="token punctuation">;</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>swap <span class="token operator">===</span> <span class="token string">"delete"</span><span class="token punctuation">)</span> replacee<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>And finally update our task forms:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Do the thing<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span>
    <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span>
    <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/remove<span class="token punctuation">"</span></span>
    <span class="token attr-name">data-boost</span>
    <span class="token attr-name">data-target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>closest li<span class="token punctuation">"</span></span>
    <span class="token attr-name">data-swap</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>delete<span class="token punctuation">"</span></span>
  <span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token entity named-entity" title="&times;">&amp;times;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span></code></pre>
    </div><p><video src=/assets/media/boosted-tasks.e7045229.mp4 controls autoplay muted loop playsinline></video></p>

      <h2 id="wrapping-up"><a class="hash" href="#wrapping-up" aria-label="Link to heading"></a>Wrapping up</h2>
    <p>We&#39;ve implemented a (very) small subset of HTMX in about 26 lines of JavaScript. This lets us enhance already functional server-side apps to make them feel more dynamic and improve their user-experience.</p>
<p>I think the HTMX model is a powerful alternative to both the old JQuery ad-hoc-DOM-manipulation model, <em>and</em> the new React duplicate-everything-client-side model. HTMX makes the server the source of truth, so you don&#39;t end up with the UI out of sync from the data. HTML attributes are just to control how HTMX reconciles server responses with the current UI.</p>
<p>I&#39;m probably going to expand the code we wrote here into a tiny library to use on side projects that don&#39;t need a full framework.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Build simpler web apps using Bun</title>
    <link href="https://oliverjam.com/articles/simple-web-apps-bun"/>
    <updated>2023-09-13T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/simple-web-apps-bun</id>
    <content type="html"><![CDATA[<p><a href="https://bun.sh/">Bun</a> is a new JavaScript runtime that aims to be more fully-featured and compliant with web standards than Node has historically been. For example it comes with a <a href="https://bun.sh/docs/cli/test">test runner</a>, <a href="https://bun.sh/docs/runtime/jsx">JSX</a> &amp; <a href="https://bun.sh/docs/runtime/typescript">TypeScript</a> support, an <a href="https://bun.sh/docs/api/http#bun-serve">HTTP server</a> based on <code>fetch</code>, <a href="https://bun.sh/docs/api/sqlite">SQLite storage</a>, <a href="https://bun.sh/docs/api/hashing">password hashing</a>, and other <a href="https://bun.sh/docs/api/utils#bun-escapehtml">convenient</a> tools.</p>
<p>It&#39;s worth noting that although I&#39;m focusing on Bun here, <a href="https://deno.com/">Deno</a> has most of these features (as does <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>, if you don&#39;t mind being locked into a platform). Also this competition has pushed Node to improve, so as of Node 18 it has a built-in <a href="https://nodejs.org/api/test.html">test runner</a> and support for <a href="https://nodejs.org/api/globals.html#fetch"><code>fetch</code></a>.</p>

      <h2 id="hello-world"><a class="hash" href="#hello-world" aria-label="Link to heading"></a>Hello world</h2>
    <p>Lets do a quick comparison between Node and Bun to render an HTML page. We&#39;ll use ES Modules since that&#39;s the modern standard (and Node supports it fine now). I&#39;ll try to write the most minimal version of each, just for fun.</p>
<p>Here&#39;s Node:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> createServer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"node:http"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> server <span class="token operator">=</span> <span class="token function">createServer</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1>Hello&lt;/h1></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
server<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">3000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Running http://localhost:3000</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Here&#39;s Bun:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> server <span class="token operator">=</span> Bun<span class="token punctuation">.</span><span class="token function">serve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token function-variable function">fetch</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;h1>Hello&lt;/h1></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Running http://localhost:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>server<span class="token punctuation">.</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can see that Bun uses modern web standards (like returning a JS <code>Response</code> object), rather than relying on APIs that only work in one specific runtime.</p>
<p>It&#39;s a good idea to define your application code separately from the server config (e.g. so you can test the app without starting the server), so from here on I&#39;ll be defining the app as a separate function without the <code>Bun.serve()</code> bit. All the following code will be executed like this:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        entry.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> app <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./app.jsx"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> server <span class="token operator">=</span> Bun<span class="token punctuation">.</span><span class="token function">serve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">fetch</span><span class="token operator">:</span> app <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Running http://localhost:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>server<span class="token punctuation">.</span>port<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h2 id="jsx-is-nice"><a class="hash" href="#jsx-is-nice" aria-label="Link to heading"></a>JSX is nice</h2>
    <p>Template literal strings are honestly pretty decent for throwing together HTML, but can get frustrating for non-trivial UIs that you want to break up into smaller components. Template literals require you to just chuck a bunch of function calls into your HTML, which sort of ruins my flow when my brain is in &quot;HTML-mode&quot;.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
    &lt;nav>
      &lt;ul>
        &lt;li>
          </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">NavLink</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Home"</span><span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">"/"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
        &lt;/li>
        &lt;li>
          </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">NavLink</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"About"</span><span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">"/about"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
        &lt;/li>
        &lt;li>
          </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">NavLink</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token string">"Contact"</span><span class="token punctuation">,</span> <span class="token literal-property property">href</span><span class="token operator">:</span> <span class="token string">"/contact"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
        &lt;/li>
      &lt;/ul>
    &lt;/nav>
  </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>JSX makes this a lot cleaner, and in my experience encourages better structure for your UI code.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>nav</span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">NavLink</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Home</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">NavLink</span></span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">NavLink</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/about<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">About</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">NavLink</span></span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">NavLink</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/contact<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Contact</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">NavLink</span></span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>nav</span><span class="token punctuation">></span></span>
    <span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>JSX also allows you to benefit from the wonderful world of JS-tooling. Since your HTML is defined as JS functions it can be checked by a linter or type system, which helps you avoid mistakes or accessibility problems. Template literals are just opaque strings from the perspective of your tooling.</p>
<p>(I know you could use a traditional templating language like Handlebars or Mustache and probably some kind of separate HTML linter, but honestly now that I&#39;ve tasted &quot;just use JS for templating&quot; I can&#39;t go back.)</p>

      <h3 id="configuring-jsx"><a class="hash" href="#configuring-jsx" aria-label="Link to heading"></a>Configuring JSX</h3>
    <p>To use JSX in Node you pretty much have to transpile your server code back to regular JS with something like Babel, ESBuild or SWC. There are libraries like <a href="https://babeljs.io/docs/babel-node"><code>@babel/node</code></a> but they aren&#39;t great for production usage. This ends up being such a faff that I never bother.</p>
<p>Bun supports JSX syntax <em>natively</em>, however by default it expects you to be using React, converting JSX like <code>&lt;h1&gt;Hello&lt;/h1&gt;</code> into <code>React.createElement(&quot;h1&quot;, {}, &quot;hello&quot;)</code>.</p>
<p>For simple server-side apps I prefer <a href="https://github.com/kitajs/html"><code>@kitajs/html</code></a>. Rather than constructing your UI as objects that must be converted to strings when you send a response, this turns the JSX directly into a string, saving a step.</p>
<p><strong>Update:</strong> I have written about <a href="/articles/diy-jsx">building my own JSX renderer</a> and published it <a href="https://github.com/oliverjam/hypa">as part of a library</a>.</p>
<p>JSX conversion is configured either in the specific config file for the runtime (<code>bunfig.toml</code>), or in a <code>tsconfig.json</code>/<code>jsconfig.json</code>. We&#39;ll use the latter since we want to keep this project runtime agnostic.</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        jsconfig.json
      </p>
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"jsx"</span><span class="token operator">:</span> <span class="token string">"react"</span><span class="token punctuation">,</span>
    <span class="token property">"jsxFactory"</span><span class="token operator">:</span> <span class="token string">"Html.createElement"</span><span class="token punctuation">,</span>
    <span class="token property">"jsxFragmentFactory"</span><span class="token operator">:</span> <span class="token string">"Html.Fragment"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now <code>&lt;h1&gt;Hello&lt;/h1&gt;</code> will be converted to <code>Html.createElement(&quot;h1&quot;, {}, &quot;hello&quot;)</code> (which returns an HTML string). We need to install the dependency with <code>bun add @kitajs/html</code>, then import <code>Html</code> wherever we use JSX.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> Html <span class="token keyword">from</span> <span class="token string">"@kitajs/html"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="counter-app"><a class="hash" href="#counter-app" aria-label="Link to heading"></a>Counter app</h2>
    <p>Lets make something <em>slightly</em> more involved. The traditional example for client-side frameworks seems to be a basic counter, so lets make one of those server-side.</p>

      <h3 id="basic-routing"><a class="hash" href="#basic-routing" aria-label="Link to heading"></a>Basic routing</h3>
    <p>Our app needs at least two routes: the home page should show the counter UI, and all other requests should get a 404 for now.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> Html <span class="token keyword">from</span> <span class="token string">"@kitajs/html"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> pathname <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">"&lt;!doctype html>"</span> <span class="token operator">+</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"text/html; charset=utf-8"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">"&lt;!doctype html>"</span> <span class="token operator">+</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Not found</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">404</span><span class="token punctuation">,</span>
        <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"text/html; charset=utf-8"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>(we need the <code>&lt;!doctype html&gt;</code> in our response to avoid browsers rendering the page in <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Quirks_Mode_and_Standards_Mode">quirks mode</a>.)</p>
<p>There&#39;s a lot of boilerplate for rendering HTML responses being repeated, so lets extract a quick helper function:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> Html <span class="token keyword">from</span> <span class="token string">"@kitajs/html"</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> pathname <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Not found</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token parameter">body<span class="token punctuation">,</span> status <span class="token operator">=</span> <span class="token number">200</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">"&lt;!doctype html>"</span> <span class="token operator">+</span> body<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    status<span class="token punctuation">,</span>
    <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"text/html; charset=utf-8"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="counter-ui"><a class="hash" href="#counter-ui" aria-label="Link to heading"></a>Counter UI</h3>
    <p>Okay, now we can actually start building our app. Since this is entirely server-rendered we can&#39;t rely on client-side JS, which means we need to use <code>&lt;form&gt;</code>s for any interactivity. In the React world it&#39;s so easy to forget how much the browser can handle for us.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> pathname <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diff<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>decrement<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
            -
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>count<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>diff<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>+1<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>increment<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
            +
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This form contains two different submit buttons. This means the form can send two different requests depending on which button is clicked. The decrement button will send a <code>POST</code> request to <code>/</code> with a body of <code>diff=-1</code>, whereas the increment button will send a body of <code>diff=+1</code>.</p>
<p>We&#39;ll just store the count in a variable for now. It will get reset whenever our server restarts, but that&#39;s fine for a demo. If we wanted it to persist we could store it in a cookie.</p>

      <h3 id="count-updates"><a class="hash" href="#count-updates" aria-label="Link to heading"></a>Count updates</h3>
    <p>Now we need to handle POST requests. The server should update the <code>count</code> variable by the amount specified in the request body, then redirect back to the home page so the user sees the updated UI.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"GET"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token comment">/*...*/</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token keyword">await</span> req<span class="token punctuation">.</span><span class="token function">formData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">let</span> diff <span class="token operator">=</span> body<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"diff"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        count <span class="token operator">+=</span> <span class="token function">Number</span><span class="token punctuation">(</span>diff <span class="token operator">??</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">303</span><span class="token punctuation">,</span>
          <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">location</span><span class="token operator">:</span> <span class="token string">"/"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Note that we had to make <code>app</code> an async function, since the methods for parsing request bodies return promises. Note also that this is an entirely standardised and built-in way to extract the body—no middleware or external dependencies required.</p>
<p>We return a redirect using the exact same API as the other responses, just specifying the right status code and location header so the browser knows how to handle it.</p>
<p>And that&#39;s it! A robust server-rendered counter app in under 50 lines of JS(X). Let&#39;s see if we can do something a bit more complicated.</p>

      <h2 id="tasks-app"><a class="hash" href="#tasks-app" aria-label="Link to heading"></a>Tasks app</h2>
    <p>The next step for every framework demo after a counter is tasks. This will be a little more complex and stateful.</p>

      <h3 id="sqlite-storage"><a class="hash" href="#sqlite-storage" aria-label="Link to heading"></a>SQLite storage</h3>
    <p>We need somewhere to store tasks. We could just keep them in memory like the count in the previous example, but lets push ourselves to do something more robust. SQLite is a great database, and Bun just so happens to have a driver built in.</p>
<p>We&#39;ll create a database and execute some SQL to create a table for storing tasks:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> Database <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"bun:sqlite"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> db <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Database</span><span class="token punctuation">(</span><span class="token string">"tasks.sqlite"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
db<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
  create table if not exists tasks (
    id integer primary key autoincrement,
    task text not null,
    created text default current_timestamp
  )
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Running this will create a new file named <code>tasks.sqlite</code> in our working directory.</p>
<p>We can now write SQL statements to create, list and remove tasks:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token parameter">task</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> db<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">insert into tasks (task) values (?)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> db<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">select * from tasks order by created desc</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">remove</span><span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> db<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">delete from tasks where id = ?</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="tasks-ui"><a class="hash" href="#tasks-ui" aria-label="Link to heading"></a>Tasks UI</h3>
    <p>Now lets put together a nice HTML form for adding new tasks. We&#39;ll stick to the rough routing structure from the counter example.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> pathname <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"GET"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Tasks</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>task<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your task<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Add task<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">+</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// @todo</span>
      <span class="token punctuation">}</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Not found</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">,</span> <span class="token number">404</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="task-updates"><a class="hash" href="#task-updates" aria-label="Link to heading"></a>Task updates</h3>
    <p>Now we need to handle the form submission, read the POST body, then save the task to the DB:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token comment">// ...</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token keyword">await</span> req<span class="token punctuation">.</span><span class="token function">formData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">let</span> task <span class="token operator">=</span> body<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"task"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">create</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">303</span><span class="token punctuation">,</span>
          <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">location</span><span class="token operator">:</span> <span class="token string">"/"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We can now save tasks, but they don&#39;t show up in the UI. We need to read them from the DB, then render as a list:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter">req</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"GET"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> tasks <span class="token operator">=</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Tasks</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>task<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Your task<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Add task<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">+</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ol</span><span class="token punctuation">></span></span><span class="token plain-text">
              </span><span class="token punctuation">{</span>tasks<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">t</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
                <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>t<span class="token punctuation">.</span>task<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
              <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ol</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="task-removal"><a class="hash" href="#task-removal" aria-label="Link to heading"></a>Task removal</h3>
    <p>Finally we need to add a delete button to each task. There are a couple of ways we could structure this:</p>
<ol>
<li>Add a form with its own submit button to each list item</li>
<li>Add a single form around the entire list</li>
</ol>
<p>I&#39;m going to do the second, purely because it&#39;ll have a bit less repetition.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">req</span><span class="token operator">:</span> Request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"GET"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> tasks <span class="token operator">=</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token function">send</span><span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token punctuation">{</span><span class="token comment">/* ... */</span><span class="token punctuation">}</span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POST<span class="token punctuation">"</span></span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/remove<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ol</span><span class="token punctuation">></span></span><span class="token plain-text">
                </span><span class="token punctuation">{</span>tasks<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">t</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
                  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token plain-text">
                    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>t<span class="token punctuation">.</span>task<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span><span class="token plain-text">
                    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>id<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>t<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Remove task<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
                      &amp;times;
                    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
                  </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
                <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
              </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ol</span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Clicking the delete button next to each task will send a POST request to <code>/remove</code>. The body will be <code>id=1</code>, with the value changing for each task depending on what button was clicked.</p>
<p>Finally we need to handle the POST request on the server. We should read the body, get the ID of the task to be deleted, then remove it from the DB and redirect back to the home page.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">app</span><span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">req</span><span class="token operator">:</span> Request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>pathname<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"/"</span><span class="token operator">:</span>
      <span class="token comment">// ...</span>
    <span class="token keyword">case</span> <span class="token string">"/remove"</span><span class="token operator">:</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token keyword">await</span> req<span class="token punctuation">.</span><span class="token function">formData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">let</span> id <span class="token operator">=</span> body<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">remove</span><span class="token punctuation">(</span>id <span class="token keyword">as</span> string<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">303</span><span class="token punctuation">,</span>
          <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">location</span><span class="token operator">:</span> <span class="token string">"/"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token comment">// ...</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>And that&#39;s it! A speedy server-rendered tasks app that persists information to a proper database in under 100 lines of JS(X).</p>

      <h2 id="a-simpler-world"><a class="hash" href="#a-simpler-world" aria-label="Link to heading"></a>A simpler world</h2>
    <p>I honestly love building apps like this. A fast, simple, batteries-included runtime plus SQLite can make quickly a breeze. You obviously lose out on dynamic client-side interactivity, so look out for my next post when we start progressively enhancing these forms.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Styling an element nested within itself in Tailwind</title>
    <link href="https://oliverjam.com/articles/tailwind-within-self"/>
    <updated>2023-07-26T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/tailwind-within-self</id>
    <content type="html"><![CDATA[<p>tl;dr here&#39;s the magic: <code>[&amp;_&amp;]</code>. Isn&#39;t he great? I&#39;m gonna call him Gill.</p>
<p>This &quot;arbitrary variant&quot; lets you apply styles when this element is nested inside another element with this class. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[&amp;_&amp;]:pl-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  ...
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
    </div><p>This list will only have <code>padding-left</code> applied if it inside another such list.</p>

      <h2 id="why-would-you-do-this"><a class="hash" href="#why-would-you-do-this" aria-label="Link to heading"></a>Why would you do this</h2>
    <p>I&#39;ve been building a simple app for reading Reddit because the native UI is awful and they killed all the good 3rd party apps. Reddit comments are <em>nested</em>. That is, unlike other platforms like <del>Twitter</del> 𝕏, every comment can have multiple separate threads of replies nested within.</p>
<p>These nested comment trees are usually rendered with progressively more space on the left, so that its obvious which parent the comments belong to. Here&#39;s a visualisation:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Parent 1
├─ 1st reply to parent 1
└─ 2nd reply to parent 1
   └─ 1st reply to 2nd reply to parent 1
      └─ 1st reply to 1st reply to 2nd reply to parent 1
Parent 2
├─ 1st reply to parent 2
└─ 2nd reply to parent 2</code></pre>
    </div>
      <h2 id="creating-the-nested-ui"><a class="hash" href="#creating-the-nested-ui" aria-label="Link to heading"></a>Creating the nested UI</h2>
    <p>I found this UI was best expressed with a recursive component. Using JSX:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Comments</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> comments <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>comments<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// Reddit's API has a "More" object at the end of the tree</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>List<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span>comments<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">child</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>child<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text">
            </span><span class="token punctuation">{</span><span class="token comment">/* Lots of comment markup removed for brevity*/</span><span class="token punctuation">}</span><span class="token plain-text">
            </span><span class="token punctuation">{</span>child<span class="token punctuation">.</span>replies <span class="token operator">&amp;&amp;</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Comments</span></span> <span class="token attr-name">comments</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>child<span class="token punctuation">.</span>replies<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">}</span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This component renders a list of comments, and inside of each comment (if there are replies) renders another copy of itself. Here&#39;s an example of the resulting markup:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>List<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>A comment with no replies<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>A comment with one reply<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>List<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>First reply<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h2 id="styling-with-vanilla-css"><a class="hash" href="#styling-with-vanilla-css" aria-label="Link to heading"></a>Styling with vanilla CSS</h2>
    <p>This works great for rendering the nested lists, but we still need to style them. Ideally nested comments have the correct border and spacing to make it obvious which parent they are replies to.</p>
<p>This isn&#39;t too hard with vanilla CSS:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.List</span> <span class="token class">.List</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
  <span class="token property">border-left</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">px</span> solid<span class="token punctuation">;</span>
  <span class="token property">padding-left</span><span class="token punctuation">:</span> <span class="token number">1.5</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>CSS selectors work left-to-right. So the selector <code>.List .List</code> means &quot;find all elements with the classname &quot;List&quot;, then check if they&#39;re inside an element with the classname &quot;List&quot;. This is exactly what our UI needs: top-level comments won&#39;t get any extra spacing or border, but <em>all</em> nested comments will.</p>

      <h2 id="the-big-refactor"><a class="hash" href="#the-big-refactor" aria-label="Link to heading"></a>The big refactor</h2>
    <p>Once I had a functioning prototype I decided to refactor the styling to use the Tailwind library. I had a vague justification that it was getting a little bit unwieldy just raw-dogging CSS, but really I was just bored. What else are side-projects for? I did also feel like I owed Tailwind a fair try since I&#39;ve been pretty vocally critical of it in the past. I&#39;m working on a full write-up of my thoughts, but here&#39;s a sneak preview: Tailwind is pretty good now!</p>
<p>Most of the styles were easy to port over to Tailwind&#39;s &quot;just bung it all in the classname and never think about it again&quot; approach. However a few <em>CSS tricks</em> like the nested comments had me stumped for a while.</p>
<p>Tailwind only lets us apply classes to an element directly. There are some special-cased things for parent/sibling relationships, but nothing for something nested within itself. I was tempted to just hack this with JS by passing down a prop indicating the nesting level of the recursion, but no way was I letting a utility-CSS library beat me.</p>
<p>After a little experimentation (and reading all the Tailwind release blog posts), I found the answer.</p>

      <h2 id="arbitrary-variants"><a class="hash" href="#arbitrary-variants" aria-label="Link to heading"></a>Arbitrary variants</h2>
    <p>This feature really needs a more exciting name, because it&#39;s really cool. Tailwind has supported arbitrary <em>values</em> since <a href="https://tailwindcss.com/blog/tailwindcss-2-2#extended-arbitrary-value-support">version 2.2</a>. This is where you put any value you like in square brackets, and Tailwind just injects it into the generated CSS class. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mt-[476px]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre>
    </div><p>That will generate this class in your CSS:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.mt-</span>\<span class="token attribute"><span class="token punctuation">[</span><span class="token attr-name">476px</span>\<span class="token punctuation">]</span></span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token number">476</span><span class="token unit">px</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This is great for one off things that don&#39;t fit into your wider design system.</p>
<p>However in <a href="https://tailwindcss.com/blog/tailwindcss-v3-1#arbitrary-values-but-for-variants">version 3.1</a> Tailwind added arbitrary <em>variants</em>, and they&#39;re fantastic. Quick recap: variants are how you express things like hover states and media queries within a classname. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">&lt;button class=<span class="token string">"hover:bg-red-100 xl:text-lg"</span>>Click me&lt;/button></code></pre>
    </div><p>Arbitrary variants let you put <em>anything you like</em> as the modifier. You can basically put whatever regular CSS you want inside the square brackets to create your own variants on the fly. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">&lt;p class=<span class="token string">"[&amp;:nth-child(3):font-bold]"</span>>Hello&lt;/p></code></pre>
    </div><p>This will make the text bold only if the element is the third child of its parent.</p>
<p>So the <code>&amp;</code> (ampersand) character refers to the class itself, which is pretty mind-bending. This is a similar concept to how its used in <a href="https://www.w3.org/TR/css-nesting-1/">CSS Nesting</a> (and its inspirations in Sass/Less).</p>
<p>This means you can do fun stuff like:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[&amp;>h2]:mt-4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><p>This will apply margin above any <code>h2</code> elements within the div.</p>

      <h2 id="bringing-it-all-together"><a class="hash" href="#bringing-it-all-together" aria-label="Link to heading"></a>Bringing it all together</h2>
    <p>Now we have everything we need to adapt the nested list styles. We can use <code>&amp;</code> as a reference to the current class (and therefore the element). This means we can use it <em>twice</em> to indicate the current class nested within the current class 🤯. Behold Gill, the inside-himself variant: <code>[&amp;_&amp;]</code>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>[&amp;_&amp;]:mt-4 [&amp;_&amp;]:border-l [&amp;_&amp;]:pl-5<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
    </div><p>The underscore represents a space, as you can&#39;t use spaces inside variants (the pitfalls of writing all your styles inside a single attribute).</p>
<p>This generates the CSS we&#39;re looking for (with a lot of backslashes to escape the special characters):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector">.\<span class="token attribute"><span class="token punctuation">[</span>\&amp;_\&amp;\<span class="token punctuation">]</span></span>\<span class="token pseudo-class">:mt-4</span> .\<span class="token attribute"><span class="token punctuation">[</span>\&amp;_\&amp;\<span class="token punctuation">]</span></span>\<span class="token pseudo-class">:mt-4</span></span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.\<span class="token attribute"><span class="token punctuation">[</span>\&amp;_\&amp;\<span class="token punctuation">]</span></span>\<span class="token pseudo-class">:border-l</span> .\<span class="token attribute"><span class="token punctuation">[</span>\&amp;_\&amp;\<span class="token punctuation">]</span></span>\<span class="token pseudo-class">:border-l</span></span> <span class="token punctuation">{</span>
  <span class="token property">border-left-width</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">px</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.\<span class="token attribute"><span class="token punctuation">[</span>\&amp;_\&amp;\<span class="token punctuation">]</span></span>\<span class="token pseudo-class">:pl-5</span> .\<span class="token attribute"><span class="token punctuation">[</span>\&amp;_\&amp;\<span class="token punctuation">]</span></span>\<span class="token pseudo-class">:pl-5</span></span> <span class="token punctuation">{</span>
  <span class="token property">padding-left</span><span class="token punctuation">:</span> <span class="token number">1.25</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>I only needed a few rules in a single place, so I was fine leaving it like this. If you were going to need this variant again you could create a custom variant using a plugin in your Tailwind config:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> plugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"tailwindcss/plugin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token function">plugin</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> addVariant <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">addVariant</span><span class="token punctuation">(</span><span class="token string">"inside-self"</span><span class="token punctuation">,</span> <span class="token string">"&amp;_&amp;"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Using this would technically be more typing, but it&#39;s more explicit and saves characters compared to linking to this blog post in a comment every time you use <code>[&amp;_&amp;]</code>.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Redirect your log output to files for easier debugging</title>
    <link href="https://oliverjam.com/articles/redirect-logs"/>
    <updated>2023-02-27T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/redirect-logs</id>
    <content type="html"><![CDATA[<p>I was recently scraping hundreds of URLs at once (backing up my saved Reddit posts). This was a bit annoying to debug as I worked on the code, as logging each success/failure meant a <em>ton</em> of output in my terminal. Sometimes a network failure was buried way back in the logs, making it easy to miss.</p>

      <h2 id="terminal-problems"><a class="hash" href="#terminal-problems" aria-label="Link to heading"></a>Terminal problems</h2>
    <p>Most terminal emulators limit the number of lines you can scroll back (my iTerm2 appears to be set to 1000 lines). This is annoying when you are logging a lot—you literally cannot scroll back to view earlier logs.</p>
<p>You could bump up the limit, but unless you make it unlimited you&#39;ll hit this issue eventually. Also the limits are there for a reason—to stop your terminal sucking up all the memory with an ever-increasing scrollback buffer.</p>
<p>Terminals are not a particularly nice environment for browsing through logs, especially when you&#39;re logging structured data. They often don&#39;t support search, line-wrapping, syntax-highlighting etc. All of these are things you take for granted in a text editor.</p>

      <h2 id="redirecting-log-output"><a class="hash" href="#redirecting-log-output" aria-label="Link to heading"></a>Redirecting log output</h2>
    <p>Here&#39;s the fun trick: you can redirect the output of a program to a file with a single shell operator: <code>&gt;</code>. You may have used this to quickly populate a file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">echo</span> <span class="token string">"hello world"</span> <span class="token operator">></span> hello.txt</code></pre>
    </div><p>However this works just as well for the output of a Node program:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        index.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;=</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The number is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax">$ <span class="token function">node</span> index.js <span class="token operator">></span> output.log</code></pre>
    </div><div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        output.log
      </p>
      <pre><code class="CodeSyntax">The number is 0
The number is 1
The number is 2
...</code></pre>
    </div>
      <h2 id="capturing-different-types-of-log"><a class="hash" href="#capturing-different-types-of-log" aria-label="Link to heading"></a>Capturing different types of log</h2>
    <p>Programs have three <a href="https://en.wikipedia.org/wiki/Standard_streams">input/output connections</a>: &quot;stdin&quot; (standard input), &quot;stdout&quot; (standard output), and &quot;stderr&quot; (standard error). Having two different outputs (one for normal logs and one for errors) can be helpful in cases where you want to only see one or the other.</p>
<p>By default the <code>&gt;</code> operator only redirects stdout. This means that if our Node program logs an error using <code>console.error</code> (which outputs to &quot;stderr&quot;) it will still show up in the terminal.</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        index.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;=</span> <span class="token number">100</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">===</span> <span class="token number">23</span><span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is not allowed</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">else</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The number is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>i<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax">$ <span class="token function">node</span> index.js <span class="token operator">></span> output.log
Error: <span class="token number">23</span> is not allowed
    at Object.<span class="token operator">&lt;</span>anonymous<span class="token operator">></span> <span class="token punctuation">(</span>/Users/oli/Code/node-pipe-logs/index.js:12:31<span class="token punctuation">)</span>
    <span class="token punctuation">..</span>.</code></pre>
    </div><p>We can <em>also</em> redirect stderr to a file by using <code>2&gt;</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ <span class="token function">node</span> index.js <span class="token operator">></span> output.log <span class="token operator"><span class="token file-descriptor important">2</span>></span> errors.log</code></pre>
    </div><div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        errors.log
      </p>
      <pre><code class="CodeSyntax">Error: 23 is not allowed
    at Object.<anonymous> (/Users/oli/Code/node-pipe-logs/index.js:12:31)
    ...</code></pre>
    </div><p>This is super helpful for debugging: if the errors file is empty you know everything worked fine; if not you have a nice list of everything that went wrong to peruse at your leisure.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Custom site search with DuckDuckGo</title>
    <link href="https://oliverjam.com/articles/site-search-ddg"/>
    <updated>2023-02-22T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/site-search-ddg</id>
    <content type="html"><![CDATA[<p>My site&#39;s new design has a searchbar front-and-centre. I don&#39;t have a <em>ton</em> of articles published, but as I start to add more shortform notes and bookmarks it will get harder to track down specific blog posts, so a search feature felt helpful.</p>
<p>I didn&#39;t want to spend much time on this, and I definitely didn&#39;t want to change my site&#39;s architecture or goals (fully static HTML/CSS with as little JS as humanly possible). Luckily the DuckDuckGo search engine made it super easy to add custom site search.</p>

      <h2 id="summary"><a class="hash" href="#summary" aria-label="Link to heading"></a>Summary</h2>
    <p>This article goes into a lot of detail about how I built this feature. If you just want the code you can <a href="https://github.com/oliverjam/oliverjames-v4/blob/a6e8ba868981fb9cb99f3c15fad212f903a73ad5/components/search.jsx">see it on GitHub</a>.</p>

      <h2 id="long-live-the-url"><a class="hash" href="#long-live-the-url" aria-label="Link to heading"></a>Long live the URL</h2>
    <p>Most search engines (including Google) take search queries as part of the URL. More specifically they extract them from the <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams">search parameters</a> (the bit after a <code>?</code>). For example if you search for <code>css</code> on google.com the browser sends a <code>GET</code> request to <code>google.com/search?q=css&amp;abunchoftrackingjunk</code> (this is how form submissions work). The cool thing about this is that by default <em>any form</em> can submit to this URL (this is also how <a href="https://owasp.org/www-community/attacks/csrf">CSRF attacks</a> happen unfortunately).</p>
<p>We can craft a form that submits a <code>GET</code> request to Google like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://google.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Search<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>q<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>If a visitor to my site enters &quot;css&quot; into this form they&#39;ll be sent off to Google to see the results, exactly as if they&#39;d clicked a link to <code>google.com?q=css</code>.</p>
<p>This is great, but there were two big reasons I couldn&#39;t use Google in the end. The first is that I respect my visitors&#39; privacy. Google does a lot of tracking that many people wish to avoid—I&#39;m uncomfortable semi-tricking people into using a Google service. The second is that Google just wouldn&#39;t work.</p>

      <h2 id="searching-a-single-site"><a class="hash" href="#searching-a-single-site" aria-label="Link to heading"></a>Searching a single site</h2>
    <p>You may be aware that the only way to get decent results out of Google nowadays is to add <code>site:reddit.com</code> to your search. This relies on Google&#39;s ability to search a single site rather than the whole web.</p>
<p>This seemed perfect for my use-case. I could limit the results to <code>site:oliverjam.com</code> so visitors would only see my articles. Unfortunately as far as I can tell there&#39;s no way to configure this without adding it to the search query itself. I could have used JS to append it to the query on submit, but that goes against my &quot;no JS unless absolutely necessary&quot; goal.</p>
<p>This is when I discovered that DuckDuckGo has a way more robust set of search parameters for configuring results. They also use the <code>q</code> param for setting the query, but also support a <code>sites</code> param for specifying the domain to search.</p>
<p>Here&#39;s a form that searches this site on DuckDuckGo:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://duckduckgo.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Search<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>q<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sites<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>oliverjam.com<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h2 id="customising-the-results-page"><a class="hash" href="#customising-the-results-page" aria-label="Link to heading"></a>Customising the results page</h2>
    <p>It seems like DuckDuckGo actually <em>want</em> people to use this feature (shocking). They provide a <a href="https://duckduckgo.com/params">plethora of parameters</a> for making the search results page fit your brand better.</p>
<ol>
<li>You can remove the branded DDG header from the top by setting <code>k0=-2</code></li>
<li>You can remove all the adverts (!!!) by setting <code>k1=-1</code></li>
<li>You can remove &quot;related searches&quot; with <code>kz=-1</code></li>
<li>You can center the results with <code>km=m</code></li>
<li>You can set a background colour with <code>k7=#000</code></li>
</ol>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://duckduckgo.com<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Search<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>q<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sites<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>oliverjam.com<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ko<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-2<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>k1<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>kz<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>km<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>m<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>k7<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#fafef5<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>It honestly blew me away how far DuckDuckGo have gone in making this feature user-friendly.</p>

      <h2 id="matching-my-sites-theme"><a class="hash" href="#matching-my-sites-theme" aria-label="Link to heading"></a>Matching my site&#39;s theme</h2>
    <p>Although I could set a custom background colour, this wouldn&#39;t necessarily match my site. The param had to be hard-coded into the HTML for the form, which meant I had to pick either the light or dark background. It was quite a jarring experience going from dark-mode site to bright search results.</p>
<p>This was a scenario where I was willing to add a tiny bit of JS to improve the user-experience of this feature, since I couldn&#39;t think of any other way to have the value of a hidden input match the current document background.</p>
<p>I added a single line of JS to run when the form was submitted:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span>
  <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://duckduckgo.com<span class="token punctuation">"</span></span>
  <span class="token special-attr"><span class="token attr-name">onsubmit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>k7<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token function">getComputedStyle</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>documentElement<span class="token punctuation">)</span><span class="token punctuation">.</span>backgroundColor</span><span class="token punctuation">"</span></span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>This sets the value of the hidden input to whatever the <code>&lt;html&gt;</code> element&#39;s background currently is. Since it happens on submit it should always match the user&#39;s theme preference, even if this changed as they were searching.</p>

      <h2 id="opening-results-in-a-new-tab"><a class="hash" href="#opening-results-in-a-new-tab" aria-label="Link to heading"></a>Opening results in a new tab</h2>
    <p>I&#39;m still on the fence about this feature. I generally dislike links that forcibly open in a new tab (sometimes I don&#39;t want this! let me choose!), but for search results on another domain entirely I felt like a new tab was a sensible choice.</p>
<p>This blew my mind when I learnt it—you can make a form submit to a new tab using the exact same attributes as a link. It makes sense when you think about how links and forms are both just ways to navigate.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://duckduckgo.com<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>noopener<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h2 id="conclusion"><a class="hash" href="#conclusion" aria-label="Link to heading"></a>Conclusion</h2>
    <p>I wrapped all this code up into a reusable component with comments so I wouldn&#39;t forget what the inscrutable search parameters did in the future (they came in handy writing this post). You can also see the source <a href="https://github.com/oliverjam/oliverjames-v4/blob/a6e8ba868981fb9cb99f3c15fad212f903a73ad5/components/search.jsx">on GitHub</a>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">/**
 * DuckDuckGo offers a lot of customisation via URL params
 * https://duckduckgo.com/params
 * ko=-2 Remove header
 * k1=-1 Remove adverts
 * kz=-1 Remove instant answers/related searches
 * km=m  Center results
 * k7=#  Set background colour
 */</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">Search</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span>
        <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Search<span class="token punctuation">"</span></span>
        <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://duckduckgo.com<span class="token punctuation">"</span></span>
        <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span>
        <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>noopener<span class="token punctuation">"</span></span>
        <span class="token special-attr"><span class="token attr-name">onsubmit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value javascript language-javascript"><span class="token keyword">this</span><span class="token punctuation">.</span>k7<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token function">getComputedStyle</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>documentElement<span class="token punctuation">)</span><span class="token punctuation">.</span>backgroundColor</span><span class="token punctuation">"</span></span></span>
      <span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ko<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-2<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>k1<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>kz<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>-1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>km<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>m<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>k7<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#fafef5<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hidden<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sites<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>oliverjam.com<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid pile items-center<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
            <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span>
            <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>q<span class="token punctuation">"</span></span>
            <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Search via DuckDuckGo<span class="token punctuation">"</span></span>
            <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Search<span class="token punctuation">"</span></span>
            <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SearchInput<span class="token punctuation">"</span></span>
          <span class="token punctuation">/></span></span><span class="token plain-text">
          </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Icon</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>search<span class="token punctuation">"</span></span> <span class="token attr-name">size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>]]></content>
  </entry>
      
  <entry>
    <title>Simple icon systems using SVG sprites</title>
    <link href="https://oliverjam.com/articles/svg-sprites"/>
    <updated>2023-01-17T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/svg-sprites</id>
    <content type="html"><![CDATA[<p>I recently rebuilt both my own site and my designer buddy <a href="https://jaredhill.co">Jared&#39;s</a>. Both required a few icons, which meant I had to decide how to handle lots of small images. There are quite a few options, but I think SVG sprites are the best solution for most projects.</p>
<p>I&#39;ll start with the solution, then talk about alternatives afterwards.</p>

      <h2 id="building-a-sprite-sheet"><a class="hash" href="#building-a-sprite-sheet" aria-label="Link to heading"></a>Building a sprite sheet</h2>
    <p>Historically a &quot;sprite sheet&quot; was a single file containing lots of images, often for use in videogames. Storing all the images in one file helped with performance on under-powered systems. To display a specific image the program would crop the coordinates for that part, hiding the rest of the file.</p>
<p>SVG has this capability built in via the <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use"><code>&lt;use&gt;</code></a> element. This takes a node from within an SVG and duplicates it for display. Usually this is used <em>within</em> the same SVG as the source node, but crucially it doesn&#39;t have to be.</p>
<p>You can use the <code>href</code> attribute to copy a node from <em>any</em> SVG, even one loaded as a separate file. For example:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        index.html
      </p>
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>use</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/icons.svg#circle<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span></code></pre>
    </div><p>This will load <code>/icons.svg</code>, then find the node with ID &quot;circle&quot; and duplicate that here. The other half of the puzzle is to ensure that file contains an SVG with each icon specified as a <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/symbol"><code>&lt;symbol&gt;</code></a>.</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        /assets/icons.svg
      </p>
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>symbol</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>circle<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>circle</span> <span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>symbol</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>symbol</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>square<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>rect</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>symbol</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span></code></pre>
    </div><p>The SVG file can contain as many icons as you like as long as you give each symbol a unique ID.</p>
<p>That&#39;s it! My process for adding a new icon is:</p>
<ol>
<li>Find an SVG (usually on <a href="https://heroicons.com">Heroicons</a>)</li>
<li>Copy/paste it into my <code>icons.svg</code> file</li>
<li>Change the <code>&lt;svg&gt;</code> tag to <code>&lt;symbol&gt;</code> and add an ID</li>
</ol>
<p>The advantage of this technique is that you can cache the sprite sheet so each visitor to your site only has to download it once. The <em>downside</em> is that they must download every icon even if the page they view only uses a single SVG. Unless you have a <em>ton</em> of icons I don&#39;t think this is a big deal (my entire sprite sheet is 2.67KB gzipped).</p>

      <h2 id="alternatives"><a class="hash" href="#alternatives" aria-label="Link to heading"></a>Alternatives</h2>
    <p>There are only really two viable ways to use SVGs:</p>
<ol>
<li>Reference the SVG file with an image element (<code>&lt;img src=&quot;circle.svg&quot;&gt;</code>)</li>
<li>Put the SVG markup directly in your HTML (<code>&lt;svg&gt;&lt;circle .../&gt;&lt;/svg&gt;</code>)</li>
</ol>
<p>Storing each SVG as a separate file and just using image elements is relatively simple, but loses you one of the best benefits of SVGs: styling them with CSS. Icons usually want to inherit their colour from the surrounding text, which doesn&#39;t work with a self-contained image file. The colour is just whatever is hard-coded inside the file, and that&#39;s it.</p>
<p>Putting the SVG markup in your HTML works great. If you only need to use an icon once or twice I highly recommend just pasting it in there. However you will eventually feel the pain of duplication. Also larger icons look messy taking up a bunch of space in your HTML with all their random path data:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>Some nice neat HTML<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>
    Published at
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>clock<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>path</span>
        <span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zM12.75 6a.75.75 0 00-1.5 0v6c0 .414.336.75.75.75h4.5a.75.75 0 000-1.5h-3.75V6z<span class="token punctuation">"</span></span>
      <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></code></pre>
    </div><p>In this case you either need to use a sprite sheet as above, or a component system as below.</p>

      <h3 id="react-components"><a class="hash" href="#react-components" aria-label="Link to heading"></a>React components</h3>
    <p>If you&#39;re using a component/templating system (like React) you may have solved this duplication problem by making each icon a separate component. For example:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        components/icons/circle.jsx
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">CircleIcon</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 20 20<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>circle</span> <span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Some framework/bundler setups even support importing SVG files directly (like <a href="https://create-react-app.dev/docs/adding-images-fonts-and-files/#adding-svgs">Create React App does</a>) to get a component.</p>
<p>There are downsides to this. First, JSX is different to HTML and so requires you to camelCase SVG attributes. This is annoying enough that Heroicons offers icons in either standard SVG or JSX format.</p>
<p>Second if you server-render and hydrate your HTML (as frameworks like Next.js and Remix do by default), you will end up with your icons duplicated in both the HTML page <em>and</em> your JavaScript bundle.</p>
<p>This is true of <em>all</em> your markup, not only the icons, as it&#39;s a currently unavoidable side-effect of hydration. It&#39;s just more annoying here since icons are almost always static markup with no interactivity. If there are no event handlers or state attached to the icon then there&#39;s no need for it to be embedded in your JS.</p>
<blockquote>
<p>“Please don&#39;t import SVGs as JSX. It&#39;s the most expensive form of sprite sheet: costs a minimum of 3x more than other techniques, and hurts both runtime (rendering) performance and memory usage.</p>
<p>This bundle from a popular site is almost 50% SVG icons (250kb), and most are unused.”</p>
<p><cite><a href="https://twitter.com/_developit/status/1382838799420514317">Jason Miller (@_developit)</a></cite></p>
</blockquote>

      <h3 id="best-of-both"><a class="hash" href="#best-of-both" aria-label="Link to heading"></a>Best of both</h3>
    <p>If you&#39;re working with a component system you can build an abstraction for rendering the <code>&lt;use href=&quot;&quot;&gt;</code> elements, but let the browser handle actually rendering the SVG. Here&#39;s the one I wrote for this site:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        components/icon.jsx
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">Icon</span><span class="token punctuation">(</span><span class="token punctuation">{</span> size <span class="token operator">=</span> <span class="token string">"20"</span><span class="token punctuation">,</span> name<span class="token punctuation">,</span> <span class="token operator">...</span>rest <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token spread"><span class="token punctuation">{</span><span class="token operator">...</span>rest<span class="token punctuation">}</span></span> <span class="token attr-name">width</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>size<span class="token punctuation">}</span></span> <span class="token attr-name">height</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>size<span class="token punctuation">}</span></span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>use</span> <span class="token attr-name">href</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/assets/icons.svg#</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now I don&#39;t have to worry about typing out the width/height etc every time I use an icon, I can just do <code>&lt;Icon name=&quot;article&quot; /&gt;</code>.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Deploying web apps to Fly.io</title>
    <link href="https://oliverjam.com/articles/deploying-to-fly"/>
    <updated>2022-10-19T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/deploying-to-fly</id>
    <content type="html"><![CDATA[
      <h2 id="key-features"><a class="hash" href="#key-features" aria-label="Link to heading"></a>Key features</h2>
    <p>I&#39;m looking for something quick and easy to setup, that doesn&#39;t require my code to be written a certain way, and <a href="https://help.heroku.com/RSBRUH58/removal-of-heroku-free-product-plans-faq">has a free tier</a>. That last one has gotten harder to find (probably <a href="https://drewdevault.com/2021/04/26/Cryptocurrency-is-a-disaster.html">blame cryptocurrency shenanigans</a>). It&#39;s important to me because most of my random side-projects average less than one user a month—paying a nominal $5 or something for that is pretty silly.</p>

      <h2 id="what-is-fly"><a class="hash" href="#what-is-fly" aria-label="Link to heading"></a>What is Fly?</h2>
    <p>Fly is a &quot;Platform-as-a-service&quot; provider (PaaS), sort of like Heroku. You give them your app&#39;s code and they provision the server to run it on.</p>
<p>They require a payment method even if you&#39;re staying within the free tier to prevent abuse, but limits are pretty generous. You get three shared-CPU 256MB RAM virtual machines to play with, and everything scales with usage beyond that. Each additional machine costs $1.94, which is a lot better than some services where crossing the threshold from &quot;basic&quot; to &quot;pro&quot; plan can triple your spend.</p>

      <h2 id="how-do-you-deploy"><a class="hash" href="#how-do-you-deploy" aria-label="Link to heading"></a>How do you deploy?</h2>
    <p>You have to install and use Fly&#39;s command-line tool to deploy, which is a bit annoying. It would be nice if they had an HTTP service or something (<a href="https://devcenter.heroku.com/articles/build-and-release-using-the-api">Heroku do</a>). However it seems to be the norm nowadays to have a CLI client for every service you use.</p>
<p>The canonical way to deploy appears to be:</p>
<ol>
<li><a href="https://fly.io/docs/flyctl/installing/">Install the Fly CLI</a></li>
<li>Authenticate the CLI with <a href="https://fly.io/docs/flyctl/auth-login/"><code>flyctl auth login</code></a></li>
<li>Detect config and deploy with <a href="https://fly.io/docs/flyctl/launch/"><code>flyctl launch</code></a></li>
</ol>
<p>Fly does some magic to figure out how to build your code (e.g. &quot;this is a Next.js app so it needs Node etc&quot;), provisions a machine in the region of your choice, then builds and deploys your code. After you&#39;ve run <code>launch</code> once you can re-deploy with <code>flyctl deploy</code>.</p>
<p>This process also generates a bunch of config and dumps it into your project, which is a little weird the first time. You&#39;ll end up with a <code>fly.toml</code>, <code>Dockerfile</code> and <code>.dockerignore</code>. Although Fly magically figures out how your app works it insists on writing it down for next time. This is sort of nice as you can see the assumptions it made and tweak them if you need to.</p>

      <h3 id="flytoml"><a class="hash" href="#flytoml" aria-label="Link to heading"></a><code>fly.toml</code></h3>
    <p>The <code>fly.toml</code> file is how you configure the machine your app runs on. I <em>think</em> this is about as minimal as you can go:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token key property">app</span> <span class="token punctuation">=</span> <span class="token string">"next-cookie-session"</span>

<span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token table class-name">services</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
  <span class="token key property">internal_port</span> <span class="token punctuation">=</span> <span class="token number">8080</span>

  <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token table class-name">services.ports</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
    <span class="token key property">handlers</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">"tls"</span><span class="token punctuation">,</span> <span class="token string">"http"</span><span class="token punctuation">]</span>
    <span class="token key property">port</span> <span class="token punctuation">=</span> <span class="token number">443</span></code></pre>
    </div><p>Your app needs a name and at least one &quot;service&quot;. Services have internal ports they listen on and can have outside internet traffic routed to them. In this case we&#39;re having Fly forward all HTTPS traffic from port 443 to our app on port 8080.</p>
<p>You can add a <em>lot</em> more config in here to control how your machine restarts or handles errors, health check requests, load balancing and concurrency etc.</p>

      <h3 id="dockerfile"><a class="hash" href="#dockerfile" aria-label="Link to heading"></a><code>Dockerfile</code></h3>
    <p>It&#39;s a bit weird to have a <code>Dockerfile</code> generated when you weren&#39;t planning on using Docker. Fly uses these as a universal &quot;describe what your app needs&quot; language. Here&#39;s a minimal <code>Dockerfile</code> for a Node.js app:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">FROM node:16-alpine
WORKDIR /app
COPY . .
CMD ["npm", "start"]</code></pre>
    </div><p>This effectively tells Fly: &quot;I&#39;m going to need a machine with Node version 16 installed, copy my files into the <code>/app</code> directory, then run <code>npm start</code> to get the server going&quot;. But this could just as easily describe something different, like a Go app.</p>
<p>It&#39;s important to note that you don&#39;t have to use Docker yourself—if you don&#39;t have Docker installed Fly will provision a free &quot;builder&quot; machine in your account, and use that to build all your apps in the cloud.</p>

      <h2 id="persistent-volumes"><a class="hash" href="#persistent-volumes" aria-label="Link to heading"></a>Persistent volumes</h2>
    <p>Almost all PaaS services nowadays are &quot;ephemeral&quot;. This means they recreate your app from scratch every time you deploy (and sometimes more often), because it&#39;s simpler to treat the Git repo as the source of truth.</p>
<p>Unfortunately this means you cannot rely on anything in the machine&#39;s filesystem sticking around. This makes it hard to use a simple database like SQLite, since that relies on writing files.</p>
<p>Fantastically Fly avoids this problem with their <a href="https://fly.io/docs/reference/volumes/">Volumes</a> feature. This lets you specify a chunk of storage on the machine that should be kept around permanently.</p>
<p>You create a volume using the CLI:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">flyctl volumes create myapp_data --region lhr --size <span class="token number">1</span></code></pre>
    </div><p>This will create a 1GB volume for the app whose <code>fly.toml</code> is in the current directory. You can <em>use</em> this volume in your app by adding it to the <code>fly.toml</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">[</span><span class="token table class-name">mounts</span><span class="token punctuation">]</span>
  <span class="token key property">source</span><span class="token punctuation">=</span><span class="token string">"myapp_data"</span>
  <span class="token key property">destination</span><span class="token punctuation">=</span><span class="token string">"/data"</span></code></pre>
    </div><p>This maps the volume to the <code>/data</code> directory in your app. You would then configure your database to store files in here.</p>

      <h2 id="frustrations"><a class="hash" href="#frustrations" aria-label="Link to heading"></a>Frustrations</h2>
    <p>Coming from Heroku I would like a slightly simpler experience for beginners or devs deploying very simple apps. Maybe Heroku is <em>too</em> magical, but I kind of miss not really needing any configuration at all to get started.</p>
<p>You <em>can</em> use <a href="https://fly.io/docs/reference/builders/#buildpacks">Heroku-like buildpacks</a> rather than Dockerfiles, but I found the docs on this a bit confusing (and lacking examples). It seems like Fly have been moving pretty quickly and iterating on this stuff, so example config in the wild often doesn&#39;t match up. My experiment with a buildpack didn&#39;t end well (deploying was way slower than with a Dockerfile, and it broke a lot).</p>
<p>The default <code>fly.toml</code> and <code>Dockerfile</code> have <em>a lot</em> in them, and this could be offputting or confusing to beginners. I had a frustrating time trying to figure out exactly what was <em>required</em> and what was a nice-to-have.</p>
<p>It turned out quite a lot of both files could be deleted without breaking my app. The docs are partly to blame here—the section on <code>fly.toml</code> don&#39;t really specify what default values it uses, or what config is absolutely necessary.</p>

      <h2 id="conclusion"><a class="hash" href="#conclusion" aria-label="Link to heading"></a>Conclusion</h2>
    <p>I&#39;m a fullstack dev who mostly writes JS, with a bias towards UX/UI. I don&#39;t want to spend a lot of time or energy dealing with low-level primitives—I just want to make apps. I&#39;ve gone through so much frustration in the past dealing with the complexities of AWS, so it&#39;s incredibly heartening to see a new player in this space focused on a better experience for devs like me.</p>
<p>I&#39;ll probably be putting anything I need a server for on Fly for the foreseeable future.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Frontend testing in Node with jsdom</title>
    <link href="https://oliverjam.com/articles/frontend-testing-node-jsdom"/>
    <updated>2022-05-18T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/frontend-testing-node-jsdom</id>
    <content type="html"><![CDATA[
      <h2 id="the-problem"><a class="hash" href="#the-problem" aria-label="Link to heading"></a>The problem</h2>
    <p>The browser and Node might share the JavaScript language, but they are very different environments. This means it can be awkward to wrangle things when you have some code written for the browser (accessing browser APIs like <code>document.querySelector</code>), but you want to <em>execute</em> that code in a more convenient Node environment (e.g. to run some tests in your terminal).</p>
<p>You cannot simply import browser-JS into Node, since it will rely on a bunch of missing global variables like <code>document</code> or <code>window</code>. If you want to write anything but a simple unit test you will probably need the accompanying HTML too—the elements the JS manipulates.</p>

      <h2 id="testing-in-the-browser"><a class="hash" href="#testing-in-the-browser" aria-label="Link to heading"></a>Testing in the browser</h2>
    <p>You can get around this problem by sacrificing some convenience and running your tests <em>in the browser</em>. This means including your test files as <code>&lt;script&gt;</code> tags in your HTML, and using the <em>browser</em> console as the place to view test results. The QUnit testing library <a href="https://qunitjs.com/intro/#in-the-browser">can be used this way</a>.</p>
<p>This isn&#39;t ideal though, since your tests aren&#39;t really <em>automated</em> anymore. You have to manually open the HTML file in a browser, then open the console to view the results. This precludes for example running the tests as part of a continuous integration pipeline to automatically catch any bugs you&#39;ve introduced.</p>

      <h2 id="testing-in-node"><a class="hash" href="#testing-in-node" aria-label="Link to heading"></a>Testing in Node</h2>
    <p>The <a href="https://github.com/jsdom/jsdom">jsdom Node library</a> is a huge, complex piece of magic. It effectively reimplements swathes of the browser APIs purely in Node. This means we can give it some browser-code, have it run that code, then query the resulting document <em>from inside Node</em> without ever involving a real browser.</p>
<p>There are of course some complications to setting this up, which I have documented here. Let&#39;s try and write a test for a simple DOM app that converts a string to uppercase. Here&#39;s the brief source code:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        index.html
      </p>
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span><span class="token punctuation">></span></span>
    Text to uppercase
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>input<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>Convert<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>output</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>output<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>output</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"hello from the browser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>index.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        index.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> form <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"form"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> input <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>input<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  <span class="token keyword">let</span> output <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>output<span class="token punctuation">;</span>
  output<span class="token punctuation">.</span>textContent <span class="token operator">=</span> input<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>The code examples will assume you&#39;re using Node 18 and writing ES Modules rather than CommonJS (i.e. using <code>import/export</code>, not <code>require</code>).</p>

      <h3 id="loading-an-html-file"><a class="hash" href="#loading-an-html-file" aria-label="Link to heading"></a>Loading an HTML file</h3>
    <p>jsdom&#39;s primary API is to load a string of JS. In our case we would like to load an HTML file, since that&#39;s how our app is structured. Luckily jsdom provides a method for this:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        test.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">JSDOM</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"jsdom"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> dom <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token constant">JSDOM</span><span class="token punctuation">.</span><span class="token function">fromFile</span><span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>dom<span class="token punctuation">.</span>window<span class="token punctuation">.</span>document<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Running this code in your terminal with <code>node test.js</code> will log an actual document object for the HTML file you loaded. Magic!</p>

      <h3 id="getting-scripts-to-run"><a class="hash" href="#getting-scripts-to-run" aria-label="Link to heading"></a>Getting scripts to run</h3>
    <p>Unfortunately we <em>don&#39;t</em> see our &quot;hello from the browser&quot; message logged. This is because by default jsdom won&#39;t execute any scripts inside the HTML file. This is because that JS will technically execute in your Node environment, which is more privileged than the browser sandbox. It would be dangerous to run untrusted input here, since some malicious code could execute directly on your computer (e.g. potentially with access to the file system).</p>
<p>Since we know we&#39;ll only be running scripts that we wrote we can tell jsdom that it&#39;s safe:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        test.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">JSDOM</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"jsdom"</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> dom <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token constant">JSDOM</span><span class="token punctuation">.</span><span class="token function">fromFile</span><span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">runScripts</span><span class="token operator">:</span> <span class="token string">"dangerously"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Now re-running our test should show our browser-side log in the terminal too.</p>

      <h3 id="writing-the-test"><a class="hash" href="#writing-the-test" aria-label="Link to heading"></a>Writing the test</h3>
    <p>Let&#39;s try and write a simple test for our app. It should use jsdom to load the HTML, grab the input element, fill in a value, click the submit button, then check the output contains the right value.</p>
<p>To keep things simple and avoid any new dependencies we&#39;ll use <a href="https://nodejs.org/en/blog/announcements/v18-release-announce/#test-runner-module-experimental">the new testing API in Node 18</a>. This is similar to the <a href="https://github.com/substack/tape">Tape</a> testing library.</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        test.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> test <span class="token keyword">from</span> <span class="token string">"node:test"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> assert <span class="token keyword">from</span> <span class="token string">"node:assert"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">JSDOM</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"jsdom"</span><span class="token punctuation">;</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"app converts lowercase to uppercase"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> dom <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token constant">JSDOM</span><span class="token punctuation">.</span><span class="token function">fromFile</span><span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">runScripts</span><span class="token operator">:</span> <span class="token string">"dangerously"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> document <span class="token operator">=</span> dom<span class="token punctuation">.</span>window<span class="token punctuation">.</span>document<span class="token punctuation">;</span>

  <span class="token keyword">let</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  input<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">"hello world"</span><span class="token punctuation">;</span>

  <span class="token keyword">let</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  button<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">let</span> output <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"output"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  assert<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span>output<span class="token punctuation">.</span>textContent<span class="token punctuation">,</span> <span class="token string">"HELLO WORLD"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>If we run this our test fails and logs a jsdom error:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Error: Not implemented: HTMLFormElement.prototype.requestSubmit</code></pre>
    </div>
      <h3 id="loading-external-resources"><a class="hash" href="#loading-external-resources" aria-label="Link to heading"></a>Loading external resources</h3>
    <p>There are a few layers to this problem. First jsdom <a href="https://github.com/jsdom/jsdom#unimplemented-parts-of-the-web-platform">does not implement <em>every</em> browser feature</a>, since implementing an entire browser in Node is an enormous undertaking. One of the main things they leave out is <em>navigation</em>. This includes not only link clicks, but also form submissions (since they navigate to a new page by default).</p>
<p>So we are seeing this error because the form submission is trying to navigate. This should not be happening though, because our submit handler includes this line:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This should stop the default navigation and allow our submit handler to run. It seems like jsdom is not actually running our JS code. We can verify this by adding a log inside <code>index.js</code>—it won&#39;t show up.</p>
<p>It turns out jsdom does not load external resources by default. This means linked CSS or JS files will not be loaded. We can change this with the <code>resources</code> option:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        test.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> dom <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token constant">JSDOM</span><span class="token punctuation">.</span><span class="token function">fromFile</span><span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">runScripts</span><span class="token operator">:</span> <span class="token string">"dangerously"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">resources</span><span class="token operator">:</span> <span class="token string">"usable"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="waiting-for-external-resources"><a class="hash" href="#waiting-for-external-resources" aria-label="Link to heading"></a>Waiting for external resources</h3>
    <p>Running the test again will still fail with the same error. There is another problem—jsdom acts like a real browser, in that it returns the document to you before it has finished loading everything. The promise it returns resolves with the DOM before all the external CSS/JS files load. This means our test code runs <em>before</em> our <code>index.js</code> code, so our form submit handler is not listening yet.</p>
<p>We can fix this by waiting for the <code>load</code> event to fire on the DOM&#39;s <code>window</code> before running our test:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        test.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> dom <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token constant">JSDOM</span><span class="token punctuation">.</span><span class="token function">fromFile</span><span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">runScripts</span><span class="token operator">:</span> <span class="token string">"dangerously"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">resources</span><span class="token operator">:</span> <span class="token string">"usable"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token operator">=></span> dom<span class="token punctuation">.</span>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"load"</span><span class="token punctuation">,</span> resolve<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ... test code here</span></code></pre>
    </div><p>This promise will not resolve until the <code>load</code> event fires, which signifies that our <code>index.js</code> script tag has finished loading.</p>
<p>Running this test should work!</p>

      <h3 id="abstracting-jsdom"><a class="hash" href="#abstracting-jsdom" aria-label="Link to heading"></a>Abstracting jsdom</h3>
    <p>We&#39;re likely to want to write more than one test, and it would be annoying to copy this code for each one. It&#39;s a good idea to load the app fresh each time to ensure the tests are fully isolated from each other, so lets abstract the jsdom setup into a <code>load</code> function that just needs a filename:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        helpers.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> dom <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token constant">JSDOM</span><span class="token punctuation">.</span><span class="token function">fromFile</span><span class="token punctuation">(</span>file<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">runScripts</span><span class="token operator">:</span> <span class="token string">"dangerously"</span><span class="token punctuation">,</span>
    <span class="token literal-property property">resources</span><span class="token operator">:</span> <span class="token string">"usable"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    dom<span class="token punctuation">.</span>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"load"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">window</span><span class="token operator">:</span> dom<span class="token punctuation">.</span>window<span class="token punctuation">,</span>
        <span class="token literal-property property">document</span><span class="token operator">:</span> dom<span class="token punctuation">.</span>window<span class="token punctuation">.</span>document<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now we can use this in any test we need to access the DOM:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        test.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> load <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./helpers.js"</span><span class="token punctuation">;</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"app converts lowercase to uppercase"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> <span class="token punctuation">{</span> document <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token string">"index.html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> input <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  input<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">"hello world"</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  button<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> output <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"output"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  assert<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span>output<span class="token punctuation">.</span>textContent<span class="token punctuation">,</span> <span class="token string">"HELLO WORLD"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>You can see the full example in <a href="https://github.com/oliverjam/frontend-testing-jsdom">the GitHub repo</a>.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Using JSDoc to check your code</title>
    <link href="https://oliverjam.com/articles/jsdoc-type-checking"/>
    <updated>2022-01-28T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/jsdoc-type-checking</id>
    <content type="html"><![CDATA[
      <h2 id="documenting-your-functions"><a class="hash" href="#documenting-your-functions" aria-label="Link to heading"></a>Documenting your functions</h2>
    <p>It&#39;s often useful to document what our functions do. For example, if we had a function that created a new task object (for an imaginary to-do list app):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">createTask</span><span class="token punctuation">(</span><span class="token parameter">title<span class="token punctuation">,</span> owner_id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> created_at <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> title<span class="token punctuation">,</span> owner_id<span class="token punctuation">,</span> created_at <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>It&#39;s easy to accidentally mix up the arguments, especially working in a different file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> task <span class="token operator">=</span> <span class="token function">createTask</span><span class="token punctuation">(</span><span class="token number">17</span><span class="token punctuation">,</span> <span class="token string">"Learn JavaScript"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We <em>could</em> document the function with a general comment, like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// Creates a new todo object with the title, owner_id and created_at date</span>
<span class="token keyword">function</span> <span class="token function">createTask</span><span class="token punctuation">(</span><span class="token parameter">title<span class="token punctuation">,</span> owner_id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> created_at <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> title<span class="token punctuation">,</span> owner_id<span class="token punctuation">,</span> created_at <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>However this isn&#39;t super useful, since it requires anyone calling this from another file to open this file and read the function definition. It would be nice if our editor could automatically provide that info when we are typing the function call.</p>

      <h2 id="using-jsdoc"><a class="hash" href="#using-jsdoc" aria-label="Link to heading"></a>Using JSDoc</h2>
    <p>We can instead structure our comment according to the <a href="https://en.wikipedia.org/wiki/JSDoc">JSDoc</a> format, like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">/**
 * @param {string} title
 * @param {number} owner_id
 * @returns {{ title: string, owner_id: number, created_at: number }}
 */</span>
<span class="token keyword">function</span> <span class="token function">createTask</span><span class="token punctuation">(</span><span class="token parameter">title<span class="token punctuation">,</span> owner_id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> created_at <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> title<span class="token punctuation">,</span> owner_id<span class="token punctuation">,</span> created_at <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This comment defines all our parameters and the return value, including what <em>types</em> of values they should be. Since this information is structured our editor can use it to give us hints.</p>

      <h2 id="configuring-your-editor"><a class="hash" href="#configuring-your-editor" aria-label="Link to heading"></a>Configuring your editor</h2>
    <p>To get VS Code to use the JSDoc information as you&#39;re typing you have to enable the &quot;Implicit project config: Check JS&quot; setting. This will cause it to parse JSDoc comments as TypeScript types, even if you aren&#39;t using TypeScript. You can enable this globally (&quot;User&quot;) or just for the current project (&quot;Workspace&quot;).</p>
<p>Now you should get warnings if you misuse this function. For example if you forget an argument:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> task <span class="token operator">=</span> <span class="token function">createTask</span><span class="token punctuation">(</span><span class="token string">"Learn JavaScript"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>you should see the function underlined red, with an error like:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Expected 2 arguments, but got 1
  An argument for 'owner_id' was not provided.</code></pre>
    </div><p>If you pass an invalid type for an argument:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">let</span> task <span class="token operator">=</span> <span class="token function">createTask</span><span class="token punctuation">(</span><span class="token number">17</span><span class="token punctuation">,</span> <span class="token string">"Learn JavaScript"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>you should see the incorrect argument underlined red, with an error like:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">Argument of type 'number' is not assignable to parameter of type 'string'.</code></pre>
    </div><p>You should even get autocompletion and suggestions as you&#39;re typing, or if you hover the function name.</p>
<p>You can check <a href="https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html">Typescript&#39;s JSDoc reference</a> for more information about the different things you can check with this syntax.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Making Git push a bit friendlier</title>
    <link href="https://oliverjam.com/articles/git-push-friendlier"/>
    <updated>2022-01-11T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/git-push-friendlier</id>
    <content type="html"><![CDATA[<p>Here&#39;s an approximation of what happens when a beginner tries to use Git branches for the first time. After committing some changes on the local branch they try to push to GitHub:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git switch --create example
Switched to a new branch 'example'
$ git push
fatal: The current branch example has no upstream branch.
To push the current branch and set the remote as upstream, use

  git push --set-upstream origin example</code></pre>
    </div><p>Great. The problem is that Git doesn&#39;t know what branch to push to on our remote repository (i.e. GitHub). We need to specify the name of the remote repository (usually &quot;origin&quot;) and the remote branch (&quot;example&quot;, same as our local branch).</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git push origin example
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'example' on GitHub by visiting:
remote:      https://github.com/user/repo/pull/new/example
remote:
To github.com:user/repo.git
 * [new branch]      example -> example</code></pre>
    </div><p>We can replace the branch name with <code>HEAD</code> to get a consistent command that works for <em>any</em> branch:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git push origin HEAD
Everything up-to-date</code></pre>
    </div>
      <h2 id="setting-the-upstream-branch"><a class="hash" href="#setting-the-upstream-branch" aria-label="Link to heading"></a>Setting the upstream branch</h2>
    <p>If we include the <code>---set-upstream</code> option Git will remember this so we don&#39;t have to specify it in future.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git push --set-upstream origin example
Branch 'example' set up to track remote branch 'example' from 'origin'.
Everything up-to-date</code></pre>
    </div><p>Now we can just push directly:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git push
Everything up-to-date</code></pre>
    </div><p>Having to set the upstream on the first push is a little annoying though. On simple projects I often only ever push a branch once, when I&#39;m ready to make a pull request. So setting the upstream doesn&#39;t save me any time or typing.</p>
<p>The exception would be my default branch (usually <code>main</code>). Since this effectively lives forever I end up pushing to it a lot, so I always make sure to set the upstream for it.</p>

      <h2 id="changing-the-default"><a class="hash" href="#changing-the-default" aria-label="Link to heading"></a>Changing the default</h2>
    <p>The default config changed in Git 2.0 (released in 2014). The default value for the <code>push.default</code> option is now <code>simple</code>, which means &quot;push to the branch with the same name on the remote&quot;.</p>
<p>At first this confused me, because I assumed this change meant I wouldn&#39;t have to specify the upstream branch. However the <code>simple</code> option is designed to be a safe default, and so won&#39;t magically match a remote branch you haven&#39;t set as the upstream (since this might overwrite a different remote branch that coincidentally has the same name as your local one).</p>
<p>If you&#39;re happy with that potential downside you can set <code>push.default</code> to <code>current</code>. This will do what I expected: always push to the remote branch with the same name as your local branch, even if you haven&#39;t set it as the upstream branch.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git config --global push.default current</code></pre>
    </div><p>Now we can push a new branch straight away without specifying the remote or branch name, or setting the upstream:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">$ git switch --create example2
Switched to a new branch 'example2'
$ git push
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'example2' on GitHub by visiting:
remote:      https://github.com/user/repo/pull/new/example2
remote:
To github.com:user/repo.git
 * [new branch]      example2 -> example2</code></pre>
    </div>]]></content>
  </entry>
      
  <entry>
    <title>Building boring websites with Next.js</title>
    <link href="https://oliverjam.com/articles/simple-next-sites"/>
    <updated>2021-07-24T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/simple-next-sites</id>
    <content type="html"><![CDATA[<p>If you&#39;re just interested in how to use Next.js for simple forms you can <a href="#a-better-way">jump to that section</a>. First I&#39;m going to rant a little about the current state of web development.</p>
<p>If you want a recap on how forms work you should check out my <a href="https://learn.foundersandcoders.com/workshops/html-forms/">HTML forms intro workshop</a>.</p>

      <h2 id="what-are-we-doing"><a class="hash" href="#what-are-we-doing" aria-label="Link to heading"></a>What are we doing</h2>
    <p>A significant percentage of websites are effectively forms connected to a database. This architecture is what the web was made for, and it is conceptually quite simple:</p>
<ol>
<li>The user&#39;s browser requests a page</li>
<li>Your server responds with some HTML containing a <code>&lt;form action=&quot;/submit&quot;&gt;</code></li>
<li>The user fills in the form and submits</li>
<li>The browser sends a request containing all the form fields that have <code>name</code>s to your server</li>
<li>The server receives that data and puts it in the database</li>
</ol>
<p>Here&#39;s a basic Express server that accomplishes this:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        server.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> server <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
    &lt;form action="/submit" method="post">
      &lt;label htmlFor="message">Message&lt;/label>
      &lt;input id="message" name="message" />
      &lt;button type="submit">Save&lt;/button>
    &lt;/form>
  </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">"/submit"</span><span class="token punctuation">,</span> express<span class="token punctuation">.</span><span class="token function">urlencoded</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  db<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// this part will be unique to your own DB setup</span>
  res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">"/success"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// or wherever you want to go next</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

server<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Unfortunately the React ecosystem tends to prefer solving problems with client-side JavaScript. This means a much more convoluted architecture:</p>
<ol>
<li>The user&#39;s browser requests a page</li>
<li>Your server responds with some HTML containing a <code>&lt;form&gt;</code> (hopefully)</li>
<li>and a load of JavaScript files containing the same React components used to render the HTML (and all of the React and Next.js runtimes)</li>
<li>The JS &quot;hydrates&quot; (re-rendering all those components to the same HTML)</li>
<li>and attaches event listeners and other client-side behaviour</li>
<li>The user fills in the form</li>
<li>Your <code>onChange</code> listeners update React state for every input</li>
<li>The user submits the form</li>
<li>Your <code>onSubmit</code> listener prevents the default form submission</li>
<li>and takes all the state values, turns them into JSON and uses <code>fetch</code> to send them to the server</li>
<li>Your server receives the JSON and puts it in the database</li>
</ol>
<p>Here&#39;s a basic example of this in Next.js. You can also <a href="https://stackblitz.com/edit/nextjs-7ei8fp?file=pages%2Findex.js">load the full working example</a>.</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        pages/index.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> useRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"next/router"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">Index</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">useRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>message<span class="token punctuation">,</span> setMessage<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&lt;</span>form
      onSubmit<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/submit"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
          <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">"/success"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// or wherever you want to go next</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">}</span>
    <span class="token operator">></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Message</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
        <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span>
        <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span>
        <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>message<span class="token punctuation">}</span></span>
        <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setMessage</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
      <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Save</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        pages/api/submit.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">handler</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    db<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// this part will be unique to your own DB setup</span>
    res<span class="token punctuation">.</span><span class="token function">status</span><span class="token punctuation">(</span><span class="token number">201</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Not only is the second architecture worse for performance (downloading and executing tons of JS to replicate features the browser already has) it&#39;s a worse <em>developer experience</em>. You have to write a lot more code, which adds complexity that you&#39;ll have to maintain forever.</p>
<p>There&#39;s way more potential for things to break—if JS fails to load, or throws an error, or contains a bug, your form is totally useless. The more fields you add to your form the more complex the React state management will get. You also need a more complex server setup, since it has to transpile and bundle your React components at build time and generate all the static assets.</p>
<p>I am aware I&#39;m glossing over all the reasons people do use a framework like Next.js. There are scenarios where the more complex architecture makes sense. However those are usually for much larger apps built by huge companies with big teams and a good understanding of why they&#39;re opting in to that complexity.</p>
<p>It just frustrates me that the habits of tech giants have taken over the industry in such a way that junior devs building simple projects get sucked into all this complexity. They&#39;re using tools that are overkill for the task at hand mostly because they need to have React projects in their portfolio to get a job.</p>
<p>I&#39;m probably going to write an opinion piece on the state of the modern frontend ecosystem at some point. Until then Tom MacWright&#39;s post <a href="https://macwright.com/2020/05/10/spa-fatigue.html">&quot;Second guessing the modern web&quot;</a> is a great summary of the problems.</p>

      <h2 id="a-better-way"><a class="hash" href="#a-better-way" aria-label="Link to heading"></a>A better way</h2>
    <p>There&#39;s no reason you can&#39;t use the simple server-rendered forms architecture with Next.js. React components are a decent way to break up your UI, and I recognise how valuable it is for people to get experience with projects using it. Luckily we can have the best of both worlds: React components for rendering HTML on our server, and zero JS sent to the browser.</p>

      <h3 id="step-1-render-a-form"><a class="hash" href="#step-1-render-a-form" aria-label="Link to heading"></a>Step 1: render a form</h3>
    <p>We need a basic form that can submit data. We&#39;ll put it on the homepage to keep the example simple. Create a <code>pages/index.jsx</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Index</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Message</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>message<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">Save</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> Index<span class="token punctuation">;</span></code></pre>
    </div><p>Don&#39;t forget that form fields need labels that are associated with them by <code>htmlFor</code>/<code>id</code>!</p>

      <h3 id="step-2-no-more-js"><a class="hash" href="#step-2-no-more-js" aria-label="Link to heading"></a>Step 2: no more JS</h3>
    <p>We&#39;re using built-in browser features rather than replicating them with client-side JS. That means there&#39;s no point sending a whole React app&#39;s worth of JS to the browser.</p>
<p>Next.js has supported <a href="https://piccalil.li/quick-tip/disable-client-side-react-with-next-js/">disabling client-side JS</a> for a while (although the option is still marked as &quot;unstable&quot;). You have to do this per-page—as far as I can tell there&#39;s no global option.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// pages/index.js</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">unstable_runtimeJS</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Now Next.js will just send the initial HTML your components render, and nothing more. This means you can&#39;t use event listeners or other client-side code. If you&#39;re building a simple static site with some forms then that should be fine.</p>
<p>Note: you don&#39;t have to disable all client-side JS to use regular HTML forms. If you have other pages with lots of interaction then feel free to leave it on for those.</p>

      <h3 id="step-3-submit-the-form"><a class="hash" href="#step-3-submit-the-form" aria-label="Link to heading"></a>Step 3: submit the form</h3>
    <p>Currently this form won&#39;t submit anywhere. We need to give it an <code>action</code> attribute to tell the browser what URL it should send the data to. This will be a <a href="https://nextjs.org/docs/api-routes/introduction">Next.js API route</a>, since that will execute server-side, receive our POST request, and can access the database.</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        pages/api/submit.js
      </p>
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">handler</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span>method <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    db<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>body<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// this part will be unique to your own DB setup</span>
    res<span class="token punctuation">.</span><span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string">"/success"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We can then update our form with the correct <code>action</code> and <code>method</code> attributes:</p>
<div class="Code">
      <p class="CodeFile">
        <svg width="12" height="12" aria-hidden="true">
          <use href="/assets/sprite.703997ca.svg#file" />
        </svg>
        pages/index.js
      </p>
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">action</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/api/submit<span class="token punctuation">"</span></span> <span class="token attr-name">method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>post<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><p>That&#39;s it! It&#39;s not actually so different from the &quot;standard&quot; Next.js example—it just removes all the faffing about with React state/fetch. The main difference is that a form element submits data encoded as the <code>x-www-form-urlencoded</code> content-type by default, whereas we were sending <code>application/json</code> beforehand. Next.js&#39; body-parsing middleware should handle both fine, so <code>req.body</code> will always be the right thing.</p>
<p>Here&#39;s the <a href="https://stackblitz.com/edit/nextjs-pslvf9?file=pages%2Findex.js">final running example</a> to play with.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Avoiding 404 errors with Single-Page Apps</title>
    <link href="https://oliverjam.com/articles/avoid-spa-404"/>
    <updated>2021-06-11T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/avoid-spa-404</id>
    <content type="html"><![CDATA[
      <h2 id="client-side-routing"><a class="hash" href="#client-side-routing" aria-label="Link to heading"></a>Client-side routing</h2>
    <p>Single-Page Apps differ from traditional server-rendered applications in that they only ever load one &quot;page&quot; from the server. This means your server only knows about a single route: the home <code>index.html</code>. The server is just there to deliver your client-side JS to the browser.</p>
<p>Routing is usually handled client-side—when a user clicks a link some JavaScript intercepts it, prevents the normal request to the server, updates the content of the page and changes the URL. In a React app this might be handled by the React Router library.</p>

      <h2 id="the-problem"><a class="hash" href="#the-problem" aria-label="Link to heading"></a>The problem</h2>
    <p>In order for the client-side routing to work the home page needs to load, along with all the JavaScript code. Unfortunately this means if a user goes <em>directly</em> to another route in their browser—i.e. clicks a link to &quot;/about&quot;, or refreshes—they will see a 404 error.</p>
<p>This is because your server doesn&#39;t know about any routes like &quot;/about&quot;. From its perspective there&#39;s only a single page—the home <code>index.html</code>. So when the server receives a request for &quot;/about&quot; it correctly responds with a 404.</p>
<p><strong>Note</strong>: you generally don&#39;t catch this issue during local development since most dev servers redirect all requests to the home <code>index.html</code>.</p>

      <h2 id="the-solution"><a class="hash" href="#the-solution" aria-label="Link to heading"></a>The solution</h2>
    <p>The solution is to tell your server to respond with the <code>index.html</code> for <em>any</em> route. Since that page contains all the client-side JS to render any other pages the user will still end up seeing the correct page.</p>
<p>You can configure most static hosts to redirect all requests to the home route. I&#39;ll demonstrate how to do it with Netlify here, since I&#39;m most comfortable with it. For other platforms you&#39;ll have to search their docs for something like &quot;SPA routing fallback&quot;.</p>

      <h3 id="netlify"><a class="hash" href="#netlify" aria-label="Link to heading"></a>Netlify</h3>
    <p>Netlify supports <a href="https://docs.netlify.com/routing/redirects/">configuring redirects</a> in two ways: either a standalone file named <code>_redirects</code>, or as part of your whole <code>netlify.toml</code> config file.</p>
<p>Using the <code>_redirects</code> file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">/* /index.html 200</code></pre>
    </div><p><strong>Important</strong>: this file must end up in the final folder that gets deployed. If you have any kind of build-step to generate the folder you should ensure <code>_redirects</code> gets copied over. E.g. using Create React App you can put it inside your <code>public/</code> directory.</p>
<p>Using the <code>netlify.toml</code> file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token table class-name">redirects</span><span class="token punctuation">]</span><span class="token punctuation">]</span>
  <span class="token key property">from</span> <span class="token punctuation">=</span> <span class="token string">"/*"</span>
  <span class="token key property">to</span> <span class="token punctuation">=</span> <span class="token string">"/index.html"</span>
  <span class="token key property">status</span> <span class="token punctuation">=</span> <span class="token number">200</span></code></pre>
    </div><p>This file generally lives at the root of your project, and you don&#39;t have to worry about it being deployed along with your site.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Better dev environments with npm workspaces</title>
    <link href="https://oliverjam.com/articles/npm-workspaces"/>
    <updated>2021-06-10T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/npm-workspaces</id>
    <content type="html"><![CDATA[<p>For example you may have a React frontend and an Express backend for your app that you want to manage as a single repository on GitHub. However this makes development awkward, as you constantly have to <code>cd</code> into the right directory to install dependencies or run npm scripts.</p>

      <h2 id="npm-setup"><a class="hash" href="#npm-setup" aria-label="Link to heading"></a>npm setup</h2>
    <p>To use workspaces you need to be on the latest version of npm. Although the feature was added in npm 7 some of the best parts weren&#39;t available until later (e.g. installing dependencies came in v7.14.0).</p>
<p>If you originally installed Node and npm with a management tool like <a href="https://volta.sh/">Volta</a> then you can get the latest version of npm by running <code>volta install npm</code> in your terminal. If not you can use npm to upgrade npm (🤯) by running <code>npm install -g npm</code>.</p>

      <h2 id="project-setup"><a class="hash" href="#project-setup" aria-label="Link to heading"></a>Project setup</h2>
    <p>Let&#39;s imagine you have a minimal project set up with two sub-directories for your <code>client</code> and <code>server</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">my-project/
  client/
    index.js
    package.json
  server/
    index.js
    package.json</code></pre>
    </div><p>To use workspaces you need to create a <code>package.json</code> at the root of your project with the <code>&quot;workspaces&quot;</code> config:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"my-project"</span><span class="token punctuation">,</span>
  <span class="token property">"workspaces"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"client"</span><span class="token punctuation">,</span> <span class="token string">"server"</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This tells npm that the <code>client</code> and <code>server</code> directories should be managed as workspaces.</p>

      <h2 id="using-workspaces"><a class="hash" href="#using-workspaces" aria-label="Link to heading"></a>Using workspaces</h2>
    <p>Most npm commands can now have workspace-related options added to make them run against just one (or all) of your workspaces. To run a command against a single workspace you can append <code>--workspace=client</code>. To run a command against all workspaces you can append <code>--workspaces</code> (note the <code>s</code>).</p>
<p>All the following commands are run from the root directory. No <code>cd</code>ing around required!</p>

      <h3 id="installing-packages"><a class="hash" href="#installing-packages" aria-label="Link to heading"></a>Installing packages</h3>
    <p>To install <em>all</em> packages for all workspaces you can run:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> <span class="token function">install</span> --workspaces</code></pre>
    </div><p>This is very useful when you first clone a project, to immediately get all the dependencies installed so you can run everything.</p>
<p><strong>Note</strong>: npm will create a single <code>package-lock.json</code> and <code>node_modules</code> at the root of your repo containing all the dependencies. This can be more efficient as one combined <code>node_modules</code> is smaller (because there&#39;s less duplication).</p>
<p>To install a package into a single workspace you can run:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> <span class="token function">install</span> express --workspace<span class="token operator">=</span>server</code></pre>
    </div>
      <h3 id="running-scripts"><a class="hash" href="#running-scripts" aria-label="Link to heading"></a>Running scripts</h3>
    <p>You can run npm scripts defined in your workspaces&#39; <code>package.json</code> files. Read more in the <a href="https://docs.npmjs.com/cli/v7/commands/npm-run-script#workspaces-support">npm <code>run-script</code> docs</a>.</p>
<p>To run a script from a single workspace:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> run <span class="token builtin class-name">test</span> --workspace<span class="token operator">=</span>client</code></pre>
    </div><p>Note this requires that <code>client</code> has a script named &quot;test&quot; defined in its <code>package.json</code>.</p>
<p>To run the same script in <em>all</em> workspaces:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> run <span class="token builtin class-name">test</span> --workspaces</code></pre>
    </div>
      <h4 id="missing-scripts"><a class="hash" href="#missing-scripts" aria-label="Link to heading"></a>Missing scripts</h4>
    <p>If any workspace is missing a script you&#39;ll get an error trying to use <code>--workspaces</code>. Sometimes you just want to run all the scripts if they exist, and you don&#39;t care if they don&#39;t. There&#39;s <a href="https://docs.npmjs.com/cli/v7/commands/npm-run-script#if-present">an option for this</a>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> run <span class="token builtin class-name">test</span> --workspaces --if-present</code></pre>
    </div><p>Now only those test scripts that actually exist will be run.</p>

      <h4 id="running-in-parallel"><a class="hash" href="#running-in-parallel" aria-label="Link to heading"></a>Running in parallel</h4>
    <p>Unfortunately npm runs the scripts in series, in the order the workspaces were defined in the top-level <code>package.json</code> (as far as I can tell, this isn&#39;t documented). This means you can&#39;t use it for long-running processes like dev servers, since the first script will never finish (and so the second script will never run).</p>
<p>Until npm implements something like Yarn workspaces&#39;s <a href="https://yarnpkg.com/cli/workspaces/foreach"><code>foreach --parallel</code></a> you&#39;ll have to workaround this by writing your own script.</p>
<p>In Mac/Linux environments you can run tasks in parallel using the <code>&amp;</code> operator. So you could make an npm script in your top-level <code>package.json</code> to run multiple workspace-level scripts:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"dev"</span><span class="token operator">:</span> <span class="token string">"npm run dev --workspace=client &amp; npm run dev --workspace=server"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This will run both scripts in the same terminal, which means all your logs will be mixed together. I also have no idea if it will work with tools that hijack the whole terminal (like Create React App). So in these cases you probably still want to just open two separate terminal tabs/windows.</p>
]]></content>
  </entry>
      
  <entry>
    <title>How to make your own Git hooks</title>
    <link href="https://oliverjam.com/articles/how-make-git-hooks"/>
    <updated>2021-02-15T00:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/how-make-git-hooks</id>
    <content type="html"><![CDATA[
      <h2 id="what-is-a-git-hook"><a class="hash" href="#what-is-a-git-hook" aria-label="Link to heading"></a>What is a Git hook?</h2>
    <p>Git hooks are programs that automatically run at different points in the lifecycle of a Git repository. The most common one I see in JavaScript projects is the &quot;pre-commit&quot; hook. As the name suggests this runs right before a commit is made (i.e. after a developer runs <code>git commit</code> in the repo).</p>
<p>This allows you to &quot;hook&quot; into the Git process to run your own code, and potentially prevent the commit. For example you may want to run a linter and tests to make sure the code is correct. If the tests fail you would want to prevent the commit and ask the developer to fix them first.</p>

      <h2 id="how-are-hooks-made"><a class="hash" href="#how-are-hooks-made" aria-label="Link to heading"></a>How are hooks made?</h2>
    <p>Until recently I&#39;d only ever used <a href="https://typicode.github.io/husky/">Husky</a> to create Git hooks. Don&#39;t get me wrong, it&#39;s a great tool, but it felt a little unwieldy at times.</p>
<p>It turns out all you need to make a Git hook is an executable script in the Git hooks directory. By default (assuming you are in a Git repo) this is <code>.git/hooks</code>. There are even some example ones in there.</p>
<p>The name of the file determines when in the Git lifecycle it runs. E.g. to make a pre-commit hook you can create a file at <code>.git/hooks/pre-commit</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token shebang important">#! /bin/sh</span>

<span class="token builtin class-name">echo</span> <span class="token string">"This runs before your commits!"</span></code></pre>
    </div><p>Finally you have to change the permissions of this file so it is executable (since Git needs to be able to execute it):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">chmod</span> +x .git/hooks/pre-commit</code></pre>
    </div><p>That&#39;s it—now whenever you <code>git commit</code> you&#39;ll see <code>&quot;This runs before your commits!&quot;</code> printed in your terminal.</p>
<p>For more useful/complex stuff you&#39;ll probably want to defer to an npm script. E.g. your <code>pre-commit</code> file can just contain:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token shebang important">#! /bin/sh</span>

<span class="token function">npm</span> run pre-commit</code></pre>
    </div><p>Now you can configure that script in your <code>package.json</code> to do anything you like (e.g. run tests, linter, etc).</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"lint"</span><span class="token operator">:</span> <span class="token string">"eslint ."</span><span class="token punctuation">,</span>
    <span class="token property">"test"</span><span class="token operator">:</span> <span class="token string">"jest"</span><span class="token punctuation">,</span>
    <span class="token property">"pre-commit"</span><span class="token operator">:</span> <span class="token string">"npm run lint &amp;&amp; npm run test"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>If your script exits with a non-zero (i.e. error) code then the hook will stop the commit from finishing.</p>

      <h2 id="how-can-you-share-hooks"><a class="hash" href="#how-can-you-share-hooks" aria-label="Link to heading"></a>How can you share hooks?</h2>
    <p>Unfortunately the <code>.git/hooks</code> folder isn&#39;t shared by other people cloning your repository. Since the main reason for a pre-commit hook is to make sure every contributor&#39;s code is consistent and correct this isn&#39;t ideal.</p>
<p>Conveniently you can tell Git to use a <em>different</em> directory to look for hooks:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">git</span> config core.hooksPath .githooks</code></pre>
    </div><p>This command sets the hooks directory to <code>.githooks/</code>. You can add hook files to this directory instead and Git will run them from there. Since this directory will get committed everyone who clones the repo will have access to them.</p>
<p>The final step is to make sure this config is changed for everyone who is running your project. You can do this with an npm <code>postinstall</code> script in your <code>package.json</code>. This is a special npm script that will run right after somebody runs <code>npm install</code>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"postinstall"</span><span class="token operator">:</span> <span class="token string">"git config core.hooksPath .githooks"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now anyone who clones your repo and runs <code>npm install</code> will get the correct hooks path set for this repo.</p>

      <h2 id="bonus-round-formatting-changes-with-prettier"><a class="hash" href="#bonus-round-formatting-changes-with-prettier" aria-label="Link to heading"></a>Bonus round: formatting changes with Prettier</h2>
    <p>By far my biggest use for pre-commit hooks is to format the changed files with Prettier. This ensures that contributors can write code however they like, and have it it auto-formatted into the style the project prefers. This keeps everything consistent and easy to read.</p>
<p>You <em>could</em> just run <code>prettier --write .</code> before every commit. This would format the entire project. Prettier isn&#39;t super slow, but it&#39;s still inefficient to format 1000 files every time you change 1.</p>
<p>You&#39;d also have to manually ensure the formatted files were staged for commit afterwards. Otherwise you&#39;d end up committing the unformatted version that you had previously staged.</p>
<p>Instead you should use <a href="https://github.com/okonet/lint-staged">lint-staged</a> to run commands only against changed files, and auto-stage the updated version afterwards.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> i -D prettier lint-staged</code></pre>
    </div><p>You need a <code>lint-staged</code> field in your <code>package.json</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"lint-staged"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"*.{md,html,css,js}"</span><span class="token operator">:</span> <span class="token string">"prettier --write"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This tells lint-staged to look for changes to <code>.md</code>, <code>.html</code>, <code>.css</code> and <code>.js</code> files, and run Prettier on each one.</p>
<p>To set up the Git hooks first change your Git hooks directory with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">git</span> config core.hooksPath .githooks</code></pre>
    </div><p>Now we can create a pre-commit hook at <code>.githooks/pre-commit</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token shebang important">#! /bin/sh</span>

<span class="token function">npm</span> run pre-commit</code></pre>
    </div><p>Then make the hook executable with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">chmod</span> +x .githooks/pre-commit</code></pre>
    </div><p>and finally add <code>postinstall</code> and <code>pre-commit</code> scripts to your npm scripts in <code>package.json</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"postinstall"</span><span class="token operator">:</span> <span class="token string">"git config core.hooksPath .githooks"</span><span class="token punctuation">,</span>
    <span class="token property">"pre-commit"</span><span class="token operator">:</span> <span class="token string">"lint-staged"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now when a new contributor clones your repo and runs <code>npm install</code> their Git hooks directory will be changed to <code>.githooks</code>. Whenever they commit changes the <code>.githooks/pre-commit</code> hook will run, which runs the <code>pre-commit</code> npm script. This script runs <code>lint-staged</code>, which checks the changed files to see if they match the file extensions specified. If they do it will format them with Prettier, then re-add those changes to be committed. Finally (assuming nothing went wrong) the commit will complete.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Responsive CSS For Beginners</title>
    <link href="https://oliverjam.com/articles/responsive-css-for-beginners"/>
    <updated>2020-12-06T21:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/responsive-css-for-beginners</id>
    <content type="html"><![CDATA[
      <h2 id="responsive-design-history"><a class="hash" href="#responsive-design-history" aria-label="Link to heading"></a>Responsive Design history</h2>
    <p>In the early days of the web layouts were mostly single columns. CSS didn&#39;t have any way to control where things went on the page. Eventually people began abusing the <code>&lt;table&gt;</code> element to achieve complex layouts. This let them control exactly where things went on the page.</p>
<p>However tables had a big downside: they required hard-coding everything with absolute pixel values. This meant sites tended to be laid out to a fixed width design. Fixed width pages were okay when everybody browsed the web on pretty much the same size screen (768px wide) desktop monitors. However this became a big problem when people started browsing the web on their phones.</p>
<p>Early smartphone screens were <em>tiny</em> in comparison (the original iPhone screen was 320px wide). To cope with this developers began creating &quot;mobile sites&quot;. These were entirely separate pages served from a separate URL (e.g. m.facebook.com). Creating a totally separate site/layout for mobile was a lot of overhead, especially for small teams.</p>
<p>In 2010 (three years after the original iPhone was released) <a href="https://ethanmarcotte.com/">Ethan Marcotte</a> wrote <a href="https://alistapart.com/article/responsive-web-design/">an article titled &quot;Responsive Web Design&quot;</a>. It explained a new technique for building web pages with <em>flexible</em> layouts by using &quot;media queries&quot; to apply certain styles at different screen widths.</p>

      <h2 id="modern-responsive-design"><a class="hash" href="#modern-responsive-design" aria-label="Link to heading"></a>Modern responsive design</h2>
    <p>Back then CSS had almost no features dedicated to layout. Luckily now we have access to flexbox, CSS grid and other things designed for creating flexible layouts that work across any screen size.</p>
<p>People often think of &quot;responsive design&quot; as a special extra task they have to do after creating a web page. I would suggest designing with a flexible, responsive mindset from the very beginning. This way you often don&#39;t have to do anything &quot;extra&quot;.</p>

      <h2 id="start-with-html"><a class="hash" href="#start-with-html" aria-label="Link to heading"></a>Start with HTML</h2>
    <p>HTML is responsive by default. It&#39;s designed to never hide, cut-off or otherwise obscure content. If you never added any CSS your content would always be &quot;responsive&quot; (although it wouldn&#39;t look so pretty).</p>
<p>So we&#39;ll start by writing our HTML and making sure we have all the correct semantic elements in place. This will give us a base to enhance with CSS.</p>

      <h3 id="document-structure"><a class="hash" href="#document-structure" aria-label="Link to heading"></a>Document structure</h3>
    <p>First we need to define the structure of our HTML document. If you want to learn more about what each of these tags does you can read my <a href="complete-guide-to-making-web-pages">&quot;complete guide to making web-pages&quot;</a> post.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token comment">&lt;!-- content goes here --></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><p>Then we can add some content inside the <code>&lt;body&gt;</code>. Let&#39;s add some headings, paragraphs and a couple of images.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>main</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Lorem, ipsum.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fugit aliquam
      iste suscipit sunt officiis deserunt corrupti in ipsa, veritatis vitae?
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://source.unsplash.com/600x350?x=1<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://source.unsplash.com/600x350?x=2<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>
      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Inventore ab
      alias quisquam nam assumenda, maxime ipsam similique ducimus sed in
      obcaecati quod maiores dolores repudiandae dolore hic incidunt, aliquam
      unde?
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>Lorem, ipsum dolor.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>
      Lorem ipsum dolor sit adipisicing elit. Quo ipsa eaque doloremque, tempora
      quidem laudantium magni aliquam! Maxime reprehenderit cumque maiores
      ducimus a doloremque natus?
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>main</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span></code></pre>
    </div><p>If we open this in a browser we should see the content.</p>
<img src="responsive-css-1.png" alt="">

<p>We can use our browser&#39;s developer tools to simulate a mobile device, to see how this would look on a smaller screen. In Firefox this button is at the top right of devtools (in Chrome it&#39;s at the top left).</p>
<img src="responsive-css-2.png" alt="">

<p>This shows us that our content still fits on a small screen (we&#39;ve selected the iPhone XS size here).</p>

      <h3 id="viewport-meta-tag"><a class="hash" href="#viewport-meta-tag" aria-label="Link to heading"></a>Viewport meta tag</h3>
    <p>There&#39;s a problem: everything is very zoomed out. This is because when mobile browsers were first created most sites were not optimised for the smaller screen. So browsers had to compensate by zooming out to fit everything on screen.</p>
<p>You can opt-out of this behaviour by adding a meta tag to the <code>&lt;head&gt;</code> of your document:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
    </div><p>This tells the browser that your site should scale down to smaller screens, so don&#39;t zoom out.</p>
<p>Our site now looks the same on the narrower screen:</p>
<img src="responsive-css-3.png" alt="">


      <h2 id="sprinkle-on-css"><a class="hash" href="#sprinkle-on-css" aria-label="Link to heading"></a>Sprinkle on CSS</h2>
    <p>Now that we have our document structure in place we can start adding CSS. Let&#39;s add a style tag to the head of our document:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
    <span class="token comment">/* css goes in here */</span>
  </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h3 id="image-sizing"><a class="hash" href="#image-sizing" aria-label="Link to heading"></a>Image sizing</h3>
    <p>Our images are overflowing horizontally. They are too wide for the viewport and so make the page wider, which means users have to scroll sideways to see the rest of the image.</p>
<img src="responsive-css-4.png" alt="">

<p>This happens because images are displayed at their real size by default. In this case the images are 600px wide, but the iPhone viewport is only 375px wide.</p>
<p>Ideally we want the images to scale down to fill whatever container they are inside. They should never overflow like this. We can use CSS to tell all images that they should never be wider than their container:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector">img</span> <span class="token punctuation">{</span>
  <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This is all we need to get the images to fit the mobile viewport:</p>
<img src="responsive-css-5.png" alt="">


      <h3 id="mobile-first"><a class="hash" href="#mobile-first" aria-label="Link to heading"></a>Mobile-first</h3>
    <p>We now have our mobile layout looking pretty good, with almost no CSS required. Obviously it&#39;s not pretty yet, but all the content is present and fits on the screen.</p>
<p>&quot;Mobile-first&quot; design means ensuring your page looks correct on a smaller screen before moving on to larger ones. Mobile layouts are usually the simplest, since they&#39;re mostly just one column of content.</p>
<p>We should make our screen a little bigger and write some more CSS to handle cases where the page doesn&#39;t look right.</p>

      <h3 id="line-length"><a class="hash" href="#line-length" aria-label="Link to heading"></a>Line length</h3>
    <img src="page-too-wide.png" alt="">

<p>At a medium viewport size we can see that the content is getting a bit wide. It&#39;s hard for users to read long lines of text, since their eyes have to move so far from left to right. Generally it&#39;s best to keep line length <a href="https://www.smashingmagazine.com/2014/09/balancing-line-length-font-size-responsive-web-design/">between 45 and 75 characters</a>.</p>
<p>We can achieve this with a <code>max-width</code> on the <code>main</code> element to ensure it never gets wider than a certain size.</p>
<p>Since we care about how many characters fit on a line we can use the <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Relative_length_units"><code>ch</code> unit</a>. This unit refers to the width of the <code>0</code> character in the current font.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector">main</span> <span class="token punctuation">{</span>
  <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">60</span><span class="token unit">ch</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This rule tells the browser to prevent the <code>&lt;main&gt;</code> from growing larger than 60 characters wide.</p>
<p>We can see that the content now doesn&#39;t get too long to read on wider viewports:</p>
<img src="main-max-width.png" alt="">

<p>Since we set a <em>max</em> width this won&#39;t affect anything on smaller viewports. The content will fill the width of the screen until it hits 60 characters wide, then it will stop growing.</p>

      <h3 id="centre-layout"><a class="hash" href="#centre-layout" aria-label="Link to heading"></a>Centre layout</h3>
    <p>Our page content is stuck over on the left side of the viewport. This isn&#39;t <em>bad</em>, but it&#39;s common for websites to put their main content in the centre of the page.</p>
<p>We can use <code>margin</code> to achieve this. An <code>auto</code> value for margin tells the browser to make that margin as big as possible to fill the space.</p>
<p>For example <code>margin-left: auto</code> on this box pushes it all the way to the right side (the left margin takes up all available space):</p>
<div style="background: var(--bg); border: 2px solid var(--primaryShadow)">
  <div style="width: 150px; height: 150px; background: var(--primary); margin-left: auto"></div>
</div>

<p>Setting both left <em>and</em> right margin to <code>auto</code> creates an equal amount of space on either side, pushing the element into the middle:</p>
<div style="background: var(--bg); border: 2px solid var(--primaryShadow)">
  <div style="width: 150px; height: 150px; background: var(--primary); margin-left: auto; margin-right: auto"></div>
</div>

<p>We can use this technique to force our <code>main</code> element to always be centred in the page:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector">main</span> <span class="token punctuation">{</span>
  <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">60</span><span class="token unit">ch</span><span class="token punctuation">;</span>
  <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
  <span class="token property">margin-right</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><img src="main-centre.png" alt="">


      <h2 id="image-layout"><a class="hash" href="#image-layout" aria-label="Link to heading"></a>Image layout</h2>
    <p>Our images are kind of huge on wider viewports. Since they fill the entire 60-character-wide container they end up really tall, which pushes the rest of the content off the screen.</p>
<p>Since we have more space it would be nice to put the images next to each other in a row. We <em>could</em> use a media query for this, which would let us specify some CSS rules that only applied above a certain viewport width.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> <span class="token number">40</span><span class="token unit">em</span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">img</span> <span class="token punctuation">{</span>
    <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">50</span><span class="token unit">%</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This says &quot;when the viewport is above 40em wide (i.e. bigger than a phone) make the images half the width of their container&quot;. This works okay, but it requires us to hard-code the viewport size where the images switch.</p>
<p>It would be nicer if we could tell the browser that we want to fit images all in a row, as long as they don&#39;t shrink below some minimum size. We can achieve this using CSS grid. First we need to wrap the images in a container element:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>grid<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://...<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://...<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><p>We set the container&#39;s display property to <code>grid</code>. This tells it to lay all its children out within a grid that we can specify.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Then we tell the grid container how many columns it should have. We could hard-code these, e.g.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">fr</span> <span class="token number">1</span><span class="token unit">fr</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><div style="background: var(--bg); border: 2px solid var(--primaryShadow); display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; padding: 0.5rem; color: var(--text-code)">
  <div style="width: 100%; height: 150px; background: var(--primary); margin-left: auto; display: grid; place-content: center">1fr</div>
  <div style="width: 100%; height: 150px; background: var(--primary); margin-left: auto; display: grid; place-content: center">1fr</div>
</div>

<p>This creates two equal size columns, since the <code>fr</code> unit means &quot;fraction of the available space&quot;. However this only works if there are two images. It also won&#39;t work on mobile since the two columns will be too small when the viewport is narrow.</p>
<div style="max-width: 200px; background: var(--bg); border: 2px solid var(--primaryShadow); display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; padding: 0.5rem; color: var(--text-code)">
  <div style="width: 100%; height: 150px; background: var(--primary); margin-left: auto; display: grid; place-content: center">1fr</div>
  <div style="width: 100%; height: 150px; background: var(--primary); margin-left: auto; display: grid; place-content: center">1fr</div>
</div>

<p>Ideally our layout should be flexible so we can change the content without it breaking. The <code>repeat</code> function lets us create multiple columns of the same size, e.g.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token unit">fr</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This reduces the duplication in our code but we still have to hard-code the number of columns. Luckily repeat can take the <code>auto-fit</code> keyword instead of a number. This tells the grid to create as many columns of a given size as it can fit. E.g.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>auto-fit<span class="token punctuation">,</span> <span class="token number">200</span><span class="token unit">px</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>However now we must hard-code the <em>size</em> of the columns (since <code>repeat</code> needs an absolute value so it knows how many columns it can fit). If we want to automatically add new columns with <em>flexible</em> sizes we must use the <code>minmax</code> function. This takes a minimum and maximum size, and picks a value in between.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>auto-fit<span class="token punctuation">,</span> <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token unit">px</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token unit">fr</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This tells the grid container to create as many columns as it can with a minimum size of 200px. If there are too many children to fit then it will create extra rows for them underneath.</p>
<img src="grid-minmax.png" alt="">

<p>The final step is to add some space between the images. We can create gaps between grid rows/columns:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">grid-column-gap</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
  <span class="token property">grid-row-gap</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>If the space between columns and rows is the same this can be simplified:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><img src="grid-gap.png" alt="">

<img src="grid-mobile.png" alt="">

<p>We&#39;ve achieved a grid layout without even using any media queries. This means it&#39;s more flexible and will change fluidly as the viewport size changes. It&#39;s always a good idea to constrain your layout based on the size of the <em>content</em>, rather than the size of the viewport.</p>

      <h2 id="in-summary"><a class="hash" href="#in-summary" aria-label="Link to heading"></a>In summary</h2>
    <p>We&#39;ve taken our strong HTML base and built a robust layout that adapts to any screen size with only a few CSS rules. Working &quot;mobile-first&quot;, starting with the narrowest size and adding rules as needed when the viewport grows, lets us write relatively simple code to create solid layouts.</p>
<p>Here&#39;s the final CSS all together:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector">img</span> <span class="token punctuation">{</span>
  <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">main</span> <span class="token punctuation">{</span>
  <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token number">60</span><span class="token unit">ch</span><span class="token punctuation">;</span>
  <span class="token property">margin-left</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
  <span class="token property">margin-right</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.grid</span></span> <span class="token punctuation">{</span>
  <span class="token property">grid-column-gap</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
  <span class="token property">grid-row-gap</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token unit">rem</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This is obviously not <em>all</em> the CSS you&#39;d want on your own page, as you&#39;ll have specific elements that need styling differently. This is not meant to be a series of &quot;CSS tricks&quot; you can copy to your own project but instead a <em>mindset</em> you can apply when writing your own layouts.</p>
]]></content>
  </entry>
      
  <entry>
    <title>How to make your terminal nicer to use</title>
    <link href="https://oliverjam.com/articles/make-your-terminal-nicer"/>
    <updated>2020-08-13T13:30:00.000Z</updated>
    <id>https://oliverjam.com/articles/make-your-terminal-nicer</id>
    <content type="html"><![CDATA[<img alt="A comparison of the default terminal with my customised one. Mine has larger font, nicer colour scheme and extra useful information" src="/assets/media/terminal-comparison.png">

<p>It can be overwhelming looking at power users&#39; configurations since they tend to have years of accumulated stuff, and little explanation for what everything does. This guide will keep things as minimal as possible—just setting up a few useful things. If you dump 200 cool aliases and plugins into your setup you won&#39;t even remember most of them are there and they&#39;ll never get used.</p>

      <h2 id="a-little-computing-history"><a class="hash" href="#a-little-computing-history" aria-label="Link to heading"></a>A little computing history</h2>
    <p>I got a little carried away here so feel free to <a href="#what-is-a-shell">skip this section</a> if you&#39;d rather get straight to the configuration.</p>
<p>Using a terminal to control your computer feels unnatural and different at first. This is because to a certain extent they are relics from the past.</p>

      <h3 id="what-is-the-terminal"><a class="hash" href="#what-is-the-terminal" aria-label="Link to heading"></a>What is the terminal?</h3>
    <p>Way back before Graphical User Interfaces (or GUIs) were invented a <a href="https://en.wikipedia.org/wiki/Computer_terminal">terminal</a> was a separate piece of hardware that let an operator interact with a computer that probably filled an entire separate room.</p>
<p>Operators would use a textual interface to enter commands and interact with programs and files on the computer. These are known as Command-Line Interfaces (or CLIs).</p>
<p>Eventually computers were small enough to fit under a desk, and came with GUIs. However although graphical interfaces were good at letting new users discover features, they were slower for experienced operators. If you know exactly what you want to do and the right commands to do it a text-based interface can be faster and more powerful.</p>
<p>So computers came with &quot;terminal emulator&quot; programs that allowed the use of CLIs. The default Terminal.app that comes with a Mac is an example of a terminal emulator.</p>

      <h3 id="what-is-a-shell"><a class="hash" href="#what-is-a-shell" aria-label="Link to heading"></a>What is a shell?</h3>
    <p>Operating systems have what&#39;s called a &quot;shell&quot; (often more than one). This is the bit at the edges of the system that the user interacts with. For example you can think of Mac&#39;s Finder &amp; Dock or Windows&#39; Explorer &amp; Start Menu as the graphical shell.</p>
<p>Terminals also have a shell—this is the set of commands and language features you can type to interact with the computer. Nowadays most <a href="https://en.wikipedia.org/wiki/Unix-like">Unix-like</a> operating systems use Bash or Zsh as their command-line shell (this includes Mac, Linux, and Windows if you&#39;re using WSL).</p>
<p>The shell is what you interact with when you type commands into a terminal. When you enter <code>ls</code> the shell interprets the command as &quot;list the files in the current directory&quot;, accesses the storage drive to read all the file names, then prints them to the terminal.</p>
<p>All popular shells descend from a common ancestor, which is why most commands and syntax work whether you&#39;re using Bash, Zsh or Fish.</p>

      <h2 id="configuring-your-terminal"><a class="hash" href="#configuring-your-terminal" aria-label="Link to heading"></a>Configuring your terminal</h2>
    <p>Enough history, let&#39;s make our terminal useful. Most of the shell configuration applies to any operating system (since the shell is the same). However the terminal stuff is specific to Macs since that&#39;s what I use (sorry).</p>
<p>First I recommend installing a better terminal emulator than the default. macOS&#39;s Terminal.app is perfectly adequate, but it&#39;s less configurable and modern than some alternatives. <a href="">iTerm</a> is the most popular—it&#39;s super configurable and has great performance. You may also like <a href="">Hyper</a>, which is built with web technologies and therefore easy to customise with JS.</p>

      <h3 id="iterm"><a class="hash" href="#iterm" aria-label="Link to heading"></a>iTerm</h3>
    <p>I use iTerm, with a few customisations. The most important is switching to &quot;natural&quot; text editing. This makes all the normal keyboard shortcuts work in the terminal (e.g. <code>cmd-left</code> to jump your cursor to the start of a line, <code>option-delete</code> to clear a single word etc). Otherwise you&#39;re stuck with whatever ancient keyboard shortcuts were used for text editing in the 1980s. You can change this by going to <code>Preferences &gt; Profiles &gt; Keys &gt; Presets... &gt; Natural Text Editing</code>.</p>
<p>You probably also want to bump up the font size considerably, since most terminals assume you have a 480p CRT monitor instead of a retina display. You can change this in <code>Preferences &gt; Profiles &gt; Text</code>.</p>
<p>I&#39;d also recommend installing a nice colour scheme. You can find these online: they&#39;re files with a <code>.itermcolors</code> extension. I&#39;m currently using <a href="https://draculatheme.com/iterm/">Dracula</a>. Install them by navigating to <code>Preferences &gt; Profiles &gt; Colors &gt; Color Presets... &gt; Import</code>.</p>

      <h2 id="configuring-your-shell"><a class="hash" href="#configuring-your-shell" aria-label="Link to heading"></a>Configuring your shell</h2>
    <p>This is where things get really interesting. The shell is responsible for pretty much everything you see and everything you can do, so it&#39;s worth making it your own.</p>

      <h3 id="using-a-modern-shell"><a class="hash" href="#using-a-modern-shell" aria-label="Link to heading"></a>Using a modern shell</h3>
    <p>I highly recommend you use Zsh as your shell. It&#39;s the default on Macs as of macOS Catalina, and it has a lot of nice features over something like Bash (which you may be using). Check which shell you&#39;re using with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token environment constant">$SHELL</span>"</span></code></pre>
    </div><p>This should print something like <code>/bin/zsh</code> or <code>/bin/bash</code>. If you&#39;re not using Zsh you should install it and switch. On a Mac <a href="https://brew.sh/">Homebrew</a> is the easiest way to do this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">brew <span class="token function">install</span> <span class="token function">zsh</span></code></pre>
    </div><p>This should automatically switch your shell over (you can check with the same command above). If it doesn&#39;t switch (or you install Zsh another way) you can change your shell using <code>chsh</code> and the path to your Zsh install:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">chsh -s /bin/zsh</code></pre>
    </div>
      <h3 id="zsh-settings"><a class="hash" href="#zsh-settings" aria-label="Link to heading"></a>Zsh settings</h3>
    <p>You can configure your shell with a config file, which usually lives in your home directory. Bash is configured with a <code>.bashrc</code> file and Zsh with a <code>.zshrc</code> file. These are &quot;dotfiles&quot;, which are hidden by default on most systems. Check if you have an existing config file by listing everything in your home directory:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">ls</span> -a ~</code></pre>
    </div><p>The <code>-a</code> makes it list all files (including hidden ones). If you don&#39;t see a <code>.zshrc</code> file listed create one with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">touch</span> ~/.zshrc</code></pre>
    </div><p>Open the file using the text editor of your choice. I use VS Code, so I can open it with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">code ~/.zshrc</code></pre>
    </div><p>If you already had a config file it might have some settings in it. Feel free to ignore this and append stuff to the bottom—you probably won&#39;t break anything. If you&#39;re really worried make a copy of this file to your desktop before you change it:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">cp</span> ~/.zshrc ~/Desktop/zshrc-backup</code></pre>
    </div><p>Now we can start configuring our shell.</p>

      <h3 id="changing-your-prompt"><a class="hash" href="#changing-your-prompt" aria-label="Link to heading"></a>Changing your prompt</h3>
    <p>The &quot;prompt&quot; is what shows up on the line where you&#39;re entering commands. It &quot;prompts&quot; you to enter a new command. Bash shows a <code>$</code> by default; I think Zsh shows a <code>%</code>. You can include much more useful information here however.</p>
<img alt="My shell prompt, listing the current working directory, the current git branch and an asterix indicating that I have changes to commit" src="/assets/media/pure-prompt.png">

<p>You can see my prompt shows the current directory, the current git branch and whether I have un-committed changes (the asterix). I&#39;m using <a href="https://github.com/sindresorhus/pure">Pure Prompt</a>. The easiest way to install this is with npm:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> <span class="token function">install</span> --global pure-prompt</code></pre>
    </div><p>You can then enable the prompt by adding these lines to your config file (<code>.zshrc</code> or <code>.bashrc</code> etc):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">autoload -U promptinit<span class="token punctuation">;</span> promptinit
prompt pure</code></pre>
    </div><p>There are other <a href="https://www.youtube.com/watch?v=XSeO6nnlWHw">more elaborate prompts</a> online if you&#39;d like something more intense.</p>

      <h3 id="auto-cd"><a class="hash" href="#auto-cd" aria-label="Link to heading"></a>Auto cd</h3>
    <p>Zsh has some cool features that you have to enable. The first is &quot;auto cd&quot;, which allows you to change into a directory by just typing its name. E.g. instead of <code>cd my-code</code> you can just type <code>my-code</code>. This also allows you to move up a directory by entering just <code>..</code>.</p>
<p>Add this line to your <code>~/.zshrc</code> and save the change:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">setopt AUTO_CD</code></pre>
    </div><p>For this to take affect you have to either restart your terminal or run this command:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">source</span> ~/.zshrc</code></pre>
    </div><p>This will run the settings file and pickup any new additions.</p>

      <h3 id="set-your-default-editor"><a class="hash" href="#set-your-default-editor" aria-label="Link to heading"></a>Set your default editor</h3>
    <p>Lots of programs force you into a text editor at certain times. For example when git needs you to write a commit message it automatically opens your default editor. This is usually Vim or Nano, neither of which are intuitive. It&#39;s nicer to stick to your usual editor, which for me is VS Code. You can change the default by adding this line to your <code>~/.zshrc</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">export</span> <span class="token assign-left variable">EDITOR</span><span class="token operator">=</span><span class="token string">"code -w"</span></code></pre>
    </div><p>Substitute whichever editor program you prefer on the right-hand side.</p>

      <h3 id="autocompletions"><a class="hash" href="#autocompletions" aria-label="Link to heading"></a>Autocompletions</h3>
    <p>Zsh has really nice built-in tab-completion. For example if you type the start of a directory name and hit the tab key it&#39;ll show you the possible matches and let you hit tab to move between them.</p>
<img alt="My shell highlighting a suggested directory from all available directories after I entered `cd` and hit tab" src="/assets/media/zsh-autocomp.png">

<p>To get a nicer visual selection menu you need a bit of config. Add the following lines to your <code>~/.zshrc</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment"># initialise nice autocompletion</span>
autoload -U compinit <span class="token operator">&amp;&amp;</span> compinit

<span class="token comment"># do not autoselect the first completion entry</span>
unsetopt MENU_COMPLETE
unsetopt FLOW_CONTROL
<span class="token comment"># show completion menu on successive tab press</span>
setopt AUTO_MENU
setopt COMPLETE_IN_WORD
setopt ALWAYS_TO_END

<span class="token comment"># use a pretty menu to select options</span>
zstyle <span class="token string">':completion:*:*:*:*:*'</span> menu <span class="token keyword">select</span></code></pre>
    </div>
      <h3 id="aliases"><a class="hash" href="#aliases" aria-label="Link to heading"></a>Aliases</h3>
    <p>Aliases let you create shortcuts for stuff you do often. For example I often work on this website, so I have an alias configured to quickly switch to that directory:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">jam</span><span class="token operator">=</span><span class="token string">'cd ~/Code/oliverjames-v3'</span></code></pre>
    </div><p>You can add as many of these as you like to your <code>~/.zshrc</code>. I have a whole bunch of git ones for common tasks:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">ga</span><span class="token operator">=</span><span class="token string">'git add'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gst</span><span class="token operator">=</span><span class="token string">'git status'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gl</span><span class="token operator">=</span><span class="token string">'git pull'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gp</span><span class="token operator">=</span><span class="token string">'git push'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gc</span><span class="token operator">=</span><span class="token string">'git commit -v'</span>
<span class="token comment"># and many more</span></code></pre>
    </div><p>You can even use aliases to override default commands, for example to make <code>ls</code> always show a coloured output:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">ls</span><span class="token operator">=</span><span class="token string">'command ls -G'</span></code></pre>
    </div><p>My favourite aliases are for quickly moving up a directory:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token builtin class-name">alias</span> <span class="token punctuation">..</span>.<span class="token operator">=</span><span class="token string">"../.."</span>
<span class="token builtin class-name">alias</span> <span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token operator">=</span><span class="token string">"../../.."</span>
<span class="token builtin class-name">alias</span> <span class="token punctuation">..</span><span class="token punctuation">..</span>.<span class="token operator">=</span><span class="token string">"../../../.."</span></code></pre>
    </div><p>This lets me enter <code>...</code> to move up a two directories, <code>....</code> to move up three etc (assuming you have auto cd enabled).</p>

      <h3 id="functions"><a class="hash" href="#functions" aria-label="Link to heading"></a>Functions</h3>
    <p>Zsh also lets you create custom functions. By far my most used is <code>mkcd</code>. This lets me create a new directory, then immediately move into it:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function-name function">mkcd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">mkdir</span> -p <span class="token string">"<span class="token variable">$@</span>"</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> <span class="token string">"<span class="token variable">$_</span>"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>I also have a function for quickly setting up a new JS project:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function-name function">newjs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  mkcd <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">npm</span> init -y <span class="token operator">&amp;&amp;</span> <span class="token function">git</span> init <span class="token operator">&amp;&amp;</span> npx gitignore <span class="token function">node</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This will create a new directory, create a <code>package.json</code>, initialise git and add a gitignore.</p>

      <h2 id="summary"><a class="hash" href="#summary" aria-label="Link to heading"></a>Summary</h2>
    <p>Here&#39;s everything we added to the <code>~/.zshrc</code> again all together:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">setop AUTO_CD

<span class="token builtin class-name">export</span> <span class="token assign-left variable">EDITOR</span><span class="token operator">=</span><span class="token string">"code -w"</span>

autoload -U compinit <span class="token operator">&amp;&amp;</span> compinit

unsetopt MENU_COMPLETE
unsetopt FLOW_CONTROL
setopt AUTO_MENU
setopt COMPLETE_IN_WORD
setopt ALWAYS_TO_END

zstyle <span class="token string">':completion:*:*:*:*:*'</span> menu <span class="token keyword">select</span>

<span class="token builtin class-name">alias</span> <span class="token assign-left variable">ga</span><span class="token operator">=</span><span class="token string">'git add'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gst</span><span class="token operator">=</span><span class="token string">'git status'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gl</span><span class="token operator">=</span><span class="token string">'git pull'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gp</span><span class="token operator">=</span><span class="token string">'git push'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">gc</span><span class="token operator">=</span><span class="token string">'git commit -v'</span>

<span class="token builtin class-name">alias</span> <span class="token assign-left variable">ls</span><span class="token operator">=</span><span class="token string">'command ls -G'</span>

<span class="token builtin class-name">alias</span> <span class="token punctuation">..</span>.<span class="token operator">=</span><span class="token string">"../.."</span>
<span class="token builtin class-name">alias</span> <span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token operator">=</span><span class="token string">"../../.."</span>
<span class="token builtin class-name">alias</span> <span class="token punctuation">..</span><span class="token punctuation">..</span>.<span class="token operator">=</span><span class="token string">"../../../.."</span>

<span class="token keyword">function</span> <span class="token function-name function">mkcd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">mkdir</span> -p <span class="token string">"<span class="token variable">$@</span>"</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> <span class="token string">"<span class="token variable">$_</span>"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function-name function">newjs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  mkcd <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">&amp;&amp;</span> <span class="token function">npm</span> init -y <span class="token operator">&amp;&amp;</span> <span class="token function">git</span> init <span class="token operator">&amp;&amp;</span> npx gitignore <span class="token function">node</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Hopefully this has helped you make your terminal a little more useful. If you want a little more inspiration you can see how my setup is configured in my <a href="https://github.com/oliverjam/dotfiles/">dotfiles repo</a> on GitHub.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Better native form validation</title>
    <link href="https://oliverjam.com/articles/better-native-form-validation"/>
    <updated>2020-05-04T12:50:00.000Z</updated>
    <id>https://oliverjam.com/articles/better-native-form-validation</id>
    <content type="html"><![CDATA[
      <h2 id="quick-summary"><a class="hash" href="#quick-summary" aria-label="Link to heading"></a>Quick summary</h2>
    <p>If you just want the code here&#39;s <a href="https://codepen.io/oliverjam/pen/eYpGwEG">the final CodePen</a>. I turn off default validation with the form&#39;s <code>novalidate</code> attribute, then manually validate all fields with <code>form.checkValidity()</code>. This triggers an <code>invalid</code> event on each field, allowing me to mark each field as invalid and show the default browser validation message in a div.</p>

      <h2 id="native-isnt-always-better"><a class="hash" href="#native-isnt-always-better" aria-label="Link to heading"></a>Native isn&#39;t always better</h2>
    <p>I sometimes catch myself assuming that if the browser implemented it a feature must be usable/accessible/performant etc. Unfortunately this is not always the case. Whilst defaulting to built-in semantic HTML elements is usually a good idea, there are plenty of cases where this will let you down.</p>
<p>Dave Rupert recently <a href="https://daverupert.com/2020/02/html-the-inaccessible-parts/">documented lots of cases of innaccessible HTML</a>. This is heartbreaking as someone who cares about and advocates for accessibility.</p>
<p>The same problem applies to native form validation. Adrian Roselli <a href="https://adrianroselli.com/2019/02/avoid-default-field-validation.html">highlights several WCAG violations</a> with the default browser behaviour.</p>
<p>Here is an incomplete list of problems:</p>
<ol>
<li>Some screen reader + browser combinations do not read out the validation message.</li>
<li><code>required</code> inputs are immediately announced as &quot;invalid&quot; before the user has tried to enter information.</li>
<li>Default error indicators generally rely only on a coloured outline.</li>
<li>We cannot style the validation message &quot;bubble&quot;.</li>
</ol>
<p>Let&#39;s see if we can do better.</p>

      <h2 id="validation-goals"><a class="hash" href="#validation-goals" aria-label="Link to heading"></a>Validation goals</h2>
    <p>I set out with a specific set of goals:</p>
<ol>
<li>Keep using HTML5 validation attributes (<code>required</code>, <code>minLength</code>, <code>pattern</code> etc).</li>
<li>Don&#39;t re-implement stuff HTML5 attributes can do for us (no unnecessary JS).</li>
<li>Default to using the browser&#39;s validation messages, but override with my own where needed.</li>
<li>Add my own DOM elements containing validation messages so I can style them and expose them to assistive tech.</li>
</ol>
<p>It turns out the <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation">Constraint Validation API</a> provides all the tools we need.</p>

      <h2 id="constraint-validation"><a class="hash" href="#constraint-validation" aria-label="Link to heading"></a>Constraint Validation</h2>
    <p>This API provides access to and control of all the native validation features, but via JavaScript.</p>

      <h3 id="validity-state"><a class="hash" href="#validity-state" aria-label="Link to heading"></a>Validity state</h3>
    <p>The browser exposes the &quot;validity state&quot; of an input via the <code>inputElement.validity</code> property. The <a href="https://developer.mozilla.org/en-US/docs/Web/API/ValidityState">ValidityState interface</a> has properties for each possible native validation error. It looks like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">ValidityState <span class="token punctuation">{</span>
  <span class="token literal-property property">badInput</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">customError</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">patternMismatch</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">rangeOverflow</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">rangeUnderflow</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">stepMismatch</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">tooLong</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">tooShort</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">typeMismatch</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token literal-property property">valid</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token literal-property property">valueMissing</span><span class="token operator">:</span> <span class="token boolean">false</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Only one of these properties can be true at a time. When the browser validates a field it will flip the property for the first constraint failure to <code>true</code>. If the input has no constraint failures the <code>valid</code> property will be set to true.</p>
<p>I&#39;m not sure where the order comes from, but <code>valueMissing</code> appears to always come first. I guess there&#39;s no point validating more specific constraints when the user hasn&#39;t typed anything yet.</p>

      <h3 id="preventing-default-validation"><a class="hash" href="#preventing-default-validation" aria-label="Link to heading"></a>Preventing default validation</h3>
    <p>If we&#39;re going to implement our own validation we should stop the browser defaults showing up. We can do this by adding the <code>novalidate</code> attribute to the form element.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> form <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"form"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
form<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"novalidate"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// boolean attributes don't need a value</span></code></pre>
    </div><p>Now the browser will allow a form containing invalid values to be submitted, so we need to stop that happening.</p>

      <h3 id="triggering-validation"><a class="hash" href="#triggering-validation" aria-label="Link to heading"></a>Triggering validation</h3>
    <p>By default the browser validates all fields within a form when that form is submitted. We can mimic that behaviour with an onsubmit handler that calls <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement#Methods"><code>formElement.checkValidity</code></a>. This method will validate each field within the form and return <code>true</code> if there were no failures or <code>false</code> if any input is invalid.</p>
<p>Since the form should not submit with invalid values we can call <code>event.preventDefault</code> if we receive a false value.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> allValid <span class="token operator">=</span> form<span class="token punctuation">.</span><span class="token function">checkValidity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>allValid<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="detecting-invalid-fields"><a class="hash" href="#detecting-invalid-fields" aria-label="Link to heading"></a>Detecting invalid fields</h3>
    <p>This is my favourite part. I always assumed I had to manually loop through all the fields and figure out which ones were invalid. I recently discovered that&#39;s not the case: the browser fires <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/invalid_event">&quot;invalid&quot; events</a> on each input that is validated and has a constraint failure.</p>
<p>We can add access each field in our form using <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements"><code>form.elements</code></a>, then attach an oninvalid listener to each.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> fields <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>form<span class="token punctuation">.</span>elements<span class="token punctuation">)</span><span class="token punctuation">;</span>
fields<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"invalid"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>field<span class="token punctuation">.</span>validity<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Now when we submit our form and call <code>checkValidity</code> all invalid fields should log their validity state.</p>

      <h3 id="validation-messages"><a class="hash" href="#validation-messages" aria-label="Link to heading"></a>Validation messages</h3>
    <p>We want to put an element in the DOM containing a validation message for each invalid field. This element should be associated with the input so that its content is part of the input&#39;s <a href="https://developer.paciellogroup.com/blog/2017/04/what-is-an-accessible-name/">accessible name</a>.</p>
<p>That way when an assitive tech user focuses the input the validation message will be read out after the label. Scott O&#39;Hara has a great guide on <a href="https://developer.paciellogroup.com/blog/2018/09/describing-aria-describedby/">using the <code>aria-describedby</code> attribute</a> to provide additional information about form fields.</p>
<p>Our final markup should look something like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  Email
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">aria-hidden</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">aria-describedby</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>emailError<span class="token punctuation">"</span></span> <span class="token attr-name">required</span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>emailError<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><p>Since we&#39;re currently just replicating the built-in validation we should re-use the message the browser provides. We can get this from the <code>inputElement.validationMessage</code> property.</p>
<p>We&#39;re <em>enhancing</em> the native browser validation here, so we should add the message element with JS. That way any user whose JS doesn&#39;t run will just get the normal slightly-less-good HTML5 validation.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">fields<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> errorBox <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> errorId <span class="token operator">=</span> field<span class="token punctuation">.</span>id <span class="token operator">+</span> <span class="token string">"Error"</span><span class="token punctuation">;</span>
  errorBox<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"id"</span><span class="token punctuation">,</span> errorId<span class="token punctuation">)</span><span class="token punctuation">;</span>
  field<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-describedby"</span><span class="token punctuation">,</span> errorId<span class="token punctuation">)</span><span class="token punctuation">;</span>
  field<span class="token punctuation">.</span><span class="token function">insertAdjacentElement</span><span class="token punctuation">(</span><span class="token string">"afterend"</span><span class="token punctuation">,</span> errorBox<span class="token punctuation">)</span><span class="token punctuation">;</span>

  field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"invalid"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    errorBox<span class="token punctuation">.</span>textContent <span class="token operator">=</span> field<span class="token punctuation">.</span>validationMessage<span class="token punctuation">;</span>
    <span class="token comment">// e.g. "Please fill out this field"</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="communicating-validity"><a class="hash" href="#communicating-validity" aria-label="Link to heading"></a>Communicating validity</h3>
    <p>We now have a functioning replica of the default validation. However there&#39;s no indication that a given field is invalid (other than the message appearing). We need to communicate this both visually and programmatically. It&#39;s usually a good idea to tie these things together so that the visual styles depend on the right programmatic attributes being set.</p>
<p>In this case we should set <code>aria-invalid=&quot;true&quot;</code> for any field that fails validation. We should <em>also</em> set <code>aria-invalid=&quot;false&quot;</code> on all the fields before they are validated. That way fields aren&#39;t invalid before the user has had a chance to enter any information.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">fields<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  field<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-invalid"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// ...</span>

  field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"invalid"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// ...</span>
    field<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-invalid"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can now use this ARIA attribute as a styling hook:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token attribute"><span class="token punctuation">[</span><span class="token attr-name">aria-invalid</span><span class="token operator">=</span><span class="token attr-value">"true"</span><span class="token punctuation">]</span></span></span> <span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token color">firebrick</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>You&#39;ll probably want more complex styles than this to make sure all types of field are correctly highlighted as invalid. E.g. it might be nice to show some kind of warning icon next to the field.</p>

      <h3 id="fixing-errors"><a class="hash" href="#fixing-errors" aria-label="Link to heading"></a>Fixing errors</h3>
    <p>Currently the field will never be marked as valid again. Even if the user fixes their entry the field will still have <code>aria-invalid=&quot;true&#39;</code> and a visible error message. We can handle this in two ways: either re-validate as they type, or mark the field as valid as soon as the user changes it.</p>

      <h4 id="clear-errors"><a class="hash" href="#clear-errors" aria-label="Link to heading"></a>Clear errors</h4>
    <p>We can add an <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event">oninput</a> handler that marks the field as valid again whenever the user changes the value.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">fields<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">//...</span>
  field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    field<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-invalid"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    errorBox<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Now as soon as the user edits the field it is marked as valid. It will get re-validated when the form is submitted, as before.</p>

      <h4 id="re-validating"><a class="hash" href="#re-validating" aria-label="Link to heading"></a>Re-validating</h4>
    <p>The browser re-validates invalid fields when the user types into them. This gives the user immediate feedback when they&#39;re trying to correct an invalid field. However I tend to think a constantly updating error beneath an input is distracting, so this might be something that you need to user test.</p>
<p>Form fields also have a <code>checkValidity</code> method. This behaves just like the form element&#39;s method, except it only triggers validation for this single field.</p>
<p>We check its validity, which will trigger an <code>invalid</code> event that updates the message if the field is invalid. If the field <em>is</em> valid we mark the input as valid and remove the error message.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">fields<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">//...</span>
  field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"input"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> valid <span class="token operator">=</span> field<span class="token punctuation">.</span><span class="token function">checkValidity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>valid<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      field<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"aria-invalid"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      errorBox<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="validating-before-submit"><a class="hash" href="#validating-before-submit" aria-label="Link to heading"></a>Validating before submit</h3>
    <p>This is optional but it can be helpful to validate a field as soon as the user is done filling it in. That way the user can immediately fix the error rather than filling out the entire form and attempting to submit before they know they made a mistake.</p>
<p>We can add an <a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event">onblur</a> listener that will fire when the user&#39;s focus leaves the field.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">fields<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">//...</span>
  field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"blur"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    field<span class="token punctuation">.</span><span class="token function">checkValidity</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="custom-messages"><a class="hash" href="#custom-messages" aria-label="Link to heading"></a>Custom messages</h3>
    <p>Some of the built-in browser validation messages are unhelpful or confusing. It would be nice if we could override this for certain fields/validation states. We can write a <code>getMessage</code> function that checks the field&#39;s <code>validity</code> property and returns custom message string.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">field<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"invalid"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> message <span class="token operator">=</span> <span class="token function">getMessage</span><span class="token punctuation">(</span>field<span class="token punctuation">)</span><span class="token punctuation">;</span>
  errorBox<span class="token punctuation">.</span>textContent <span class="token operator">=</span> message <span class="token operator">||</span> field<span class="token punctuation">.</span>validationMessage<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token parameter">field</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> validity <span class="token operator">=</span> field<span class="token punctuation">.</span>validity<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>validity<span class="token punctuation">.</span>valueMissing<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Please enter your </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>field<span class="token punctuation">.</span>id<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>validity<span class="token punctuation">.</span>typeMismatch<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Please enter a valid </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>field<span class="token punctuation">.</span>type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>You can create the messages however you like: dynamically using the element properties like this, or look them up in a big object where you define every single possible error for every input.</p>
<p>It&#39;s worth highlighting that the browser&#39;s default messages are translated, so make sure yours are too if you have a localised application.</p>
<!-- ### Custom validation

So far we've relied entirely on validation that can be achieved using HTML5 validation attributes. Sometimes these aren't enough, however, and we need to write custom JS logic to determine if a field is invalid.

Fortunately since we've hooked into the native Constraint Validation API we don't have to do anything special here. Form fields have a `setCustomValidity` method that takes a string argument. If the string is empty the field is marked valid, otherwise the field is marked invalid and the string is used as the validation message.

Here's a simple attempt to validate that the user entered a date:

```html
<label for="dateOfBirth">Date of birth</label>
<input type="text" id="dateOfBirth" placeholder="dd/mm/yyyy" required />

<script>
  dateOfBirth.addEventListener("blur", () => {
    const date = new Date(dateOfBirth.value);
    if (date.toString() === "Invalid Date") {
      dateOfBirth.setCustomValidity("Please enter a valid date");
    } else {
      dateOfBirth.setCustomValidity("");
    }
  });
</script>
```

Your logic can get as complex as you like here, all that matters is that you call `setCustomValidity`. The constraint validation code we already wrote will handle all the rest. -->


      <h2 id="conclusion"><a class="hash" href="#conclusion" aria-label="Link to heading"></a>Conclusion</h2>
    <p>You can play around with the final version in <a href="https://codepen.io/oliverjam/pen/eYpGwEG">my CodePen example</a>. It&#39;s not <em>too</em> much code, and since it&#39;s pretty generic you can copy/paste it for any form you like. Hopefully you&#39;ll go forth and write more usable and accessible forms 🚀.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Build your own analytics with Netlify Functions</title>
    <link href="https://oliverjam.com/articles/diy-analytics-netlify-functions"/>
    <updated>2020-05-02T16:10:00.000Z</updated>
    <id>https://oliverjam.com/articles/diy-analytics-netlify-functions</id>
    <content type="html"><![CDATA[
      <h2 id="diy-not-google"><a class="hash" href="#diy-not-google" aria-label="Link to heading"></a>DIY, not Google</h2>
    <p>It would however be hypocritical of me to have privacy-violating user tracking (like Google Analytics) on my own site when I block all tracking scripts in my personal web browser.</p>
<p>Instead I figured I could create my own basic analytics without handing my users&#39; data over to Google. A bare minimum analytics implementation counts each request to the server, records what page was requested, and <em>maybe</em> some information to tell different users&#39; requests apart.</p>

      <h2 id="no-js-required"><a class="hash" href="#no-js-required" aria-label="Link to heading"></a>No JS required</h2>
    <p>I also wanted this to work without client-side JS (since the rest of my site does). It turns out the old ways are the best here—a &quot;tracking pixel&quot; image on every page will work as long as the user hasn&#39;t disabled image loading.</p>
<p>Here&#39;s roughly how a tracking pixel works: there&#39;s an <code>&lt;img&gt;</code> tag at the bottom of every page. This image&#39;s <code>src</code> attribute points to a server. When this server receives the request it records the <code>referer</code> header somewhere. This header is sent by the browser and contains the URL of the page the request came from.</p>

      <h2 id="serverless-aka-a-server"><a class="hash" href="#serverless-aka-a-server" aria-label="Link to heading"></a>Serverless (AKA a server)</h2>
    <p>There was one downside to this plan: my blog doesn&#39;t have a server. It&#39;s a static website served from Netlify&#39;s CDN. Luckily Netlify has a feature called <a href="https://www.netlify.com/products/functions/">Functions</a> that allows you to deploy &quot;serverless functions&quot; alongside your otherwise static site. I have written a full <a href="we-dont-need-servers/">guide to Netlify Functions</a> if you&#39;re curious.</p>
<p>So the solution was to create a <code>functions/counter.js</code> Function. The tracking image&#39;s <code>src</code> would point at <code>/.netlify/counter</code> so the Function would receive a request for every page view. The Function itself grabs the <code>referer</code> header to save the page view, then responds with a 1px transparent GIF.</p>
<p>Here&#39;s a simplified implementation:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">exports<span class="token punctuation">.</span><span class="token function-variable function">handler</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> headers <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>headers<span class="token punctuation">.</span>referer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// e.g. "https://oliverjam.es/blog"</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">statusCode</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span>
    <span class="token comment">// a Base64 encoded 1px transparent gif</span>
    <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token string">"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"</span><span class="token punctuation">,</span>
    <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"image/gif"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">isBase64Encoded</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Note we have to tell Netlify that we&#39;re returning a Base64-encoded body.</p>

      <h2 id="persisting-data"><a class="hash" href="#persisting-data" aria-label="Link to heading"></a>Persisting data</h2>
    <p>Unfortunately Netlify doesn&#39;t yet have a data storage solution. This means I needed to find somewhere else to chuck the page view each time an image was requested.I started looking at some Google Cloud storage product but got overwhelmed with dashboards and regions and confusing price calculators.</p>
<p>Luckily there are a bunch of simple free JSON storage services like <a href="https://jsonbin.io/">JSONbin.io</a> and <a href="https://jsonbox.io/">jsonbox.io</a>. I ended up going with jsonbox because I liked the API a bit better.</p>
<p>It&#39;s pretty much an array of objects stored in MongoDB and exposed via a REST API. So whenever my Function receives a request it sends a <code>POST</code> request with a JSON object containing the URL the image was loaded on (from the <code>referer</code> header):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> body <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">url</span><span class="token operator">:</span> referer <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token constant">ANALYTICS_URL</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span> body <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>It&#39;s actually a bit more complicated because referers are full URLs, whereas I only cared about the pathname.</p>

      <h2 id="unique-visits-and-browser-fingerpints"><a class="hash" href="#unique-visits-and-browser-fingerpints" aria-label="Link to heading"></a>Unique visits and browser fingerpints</h2>
    <p>Most analytics services allow you to distinguish a single viewer browsing multiple pages from multiple viewers. Since I&#39;m only tracking anonymous requests I can&#39;t do this. It turns out reliably tracking unique visits anonymously is <em>hard</em>.</p>
<p>Fathom (a privacy-focused analytics service) <a href="https://usefathom.com/blog/anonymization">came up with a cool solution</a>, but it&#39;s overkill for my needs. Since I hardly get any visitors I compromised by recording the user-agent string for each request.</p>
<p>This is a string that identifies the browser that made the request. E.g. my current version of Firefox sends this user-agent header: <code>&quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:76.0) Gecko/20100101 Firefox/76.0&quot;</code>. I added this to the JSON I stored, so each visit has a pathname and user-agent.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">exports<span class="token punctuation">.</span><span class="token function-variable function">handler</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> headers <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">url</span><span class="token operator">:</span> headers<span class="token punctuation">.</span>referer<span class="token punctuation">,</span> <span class="token literal-property property">ua</span><span class="token operator">:</span> headers<span class="token punctuation">[</span><span class="token string">"user-agent"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> body <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token constant">ANALYTICS_URL</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span> body <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">//...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>The user-agent is unique enough that I&#39;m comfortable using it to identify unique visits, but it can&#39;t really identify a specific individual. <a href="https://www.amiunique.org/">When <em>combined</em> with other info</a> like IP address, language and timezone this could identify an individual, which is why I didn&#39;t include anything else.</p>

      <h2 id="conclusion"><a class="hash" href="#conclusion" aria-label="Link to heading"></a>Conclusion</h2>
    <p>That&#39;s it. You can see the full implementation in <a href="https://github.com/oliverjam/oliverjames-v3/blob/master/functions/counter/counter.js">this site&#39;s GitHub repo</a>. It&#39;s surprisingly simple to build something like this with modern tooling. I had never really considered returning anything but JSON from a Netlify Function, but my mind is spinning with possibilities for serverless functions returning HTML, images and other cool stuff.</p>
<p>I would love to see more developers move away from including Google Analytics by default and consider either a simple DIY solution like this, or paying for a privacy-focused service like <a href="https://usefathom.com/">Fathom</a>.</p>
<p>My next project will be to turn this data into some nice looking graphs, so I can actually try and glean insights from it. I&#39;ll probably make that publicly available on this site, since the data is anonymous-ish.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Pitfalls of async functions</title>
    <link href="https://oliverjam.com/articles/pitfalls-of-async-functions"/>
    <updated>2020-03-13T18:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/pitfalls-of-async-functions</id>
    <content type="html"><![CDATA[
      <h2 id="async-functions"><a class="hash" href="#async-functions" aria-label="Link to heading"></a>Async functions</h2>
    <p>An async function is defined with the <code>async</code> keyword at the start. It works for function declarations and arrow functions:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">fetchData</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>This keyword makes the function always return a promise, even if all the code inside of it is synchronous:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">one</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">one</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Promise &lt;pending></span>
result<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span></code></pre>
    </div><p>The advantage of <code>async</code> functions is that you can use the <code>await</code> keyword within them. This allows you to treat asynchronous code as if it were synchronous. Awaiting a promise will pause the execution of your <code>async</code> function until that promise resolves.</p>
<p>Here are two examples that fetch data from the <a href="https://pokeapi.co">PokeAPI</a>, one with promises and one using an async function:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Lots of people prefer the async function version because it reads almost the same as synchronous code. You don&#39;t have to deal with chaining <code>.then()</code>s together and nesting callbacks.</p>
<p>However it&#39;s important to remember that JS is asynchronous for a reason.</p>

      <h2 id="possible-performance-problems"><a class="hash" href="#possible-performance-problems" aria-label="Link to heading"></a>Possible performance problems</h2>
    <p>Here are the same two examples, with one extra line of code added after the fetch request:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"unrelated stuff"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"unrelated stuff"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>In the first promise example we fire off the network request and then keep executing the rest of our function. This means we see &quot;unrelated stuff&quot; logged immediately, <em>then</em> (after some delay) the fetch request will resolve.</p>
<p>In the second async function example we fire off the network request, then block the rest of the function until it resolves. This means the response data will log <em>before</em> &quot;unrelated stuff&quot;.</p>
<p>This seems obvious here, but this is a common issue when coordinating multiple requests. It&#39;s easy to <code>await</code> them both and unintentionally make the requests synchronous instead of parallel:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pikaResponse <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveeResponse <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/eevee"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> pikaData <span class="token operator">=</span> <span class="token keyword">await</span> pikaResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveData <span class="token operator">=</span> <span class="token keyword">await</span> eeveeResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>pikaData<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>eeveeData<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Here we don&#39;t even start fetching the second request until the first resolves, even though they are unrelated and could easily be fetched in parallel.</p>

      <h3 id="parallel-async-requests"><a class="hash" href="#parallel-async-requests" aria-label="Link to heading"></a>Parallel async requests</h3>
    <p>We can work around this problem by only using the <code>await</code> keyword when we actually need to use a value.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pikaPromise <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveePromise <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/eevee"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> pikaResponse <span class="token operator">=</span> <span class="token keyword">await</span> pikaPromise<span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveeResponse <span class="token operator">=</span> <span class="token keyword">await</span> eeveePromise<span class="token punctuation">;</span>
  <span class="token keyword">const</span> pikaData <span class="token operator">=</span> <span class="token keyword">await</span> pikaResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveData <span class="token operator">=</span> <span class="token keyword">await</span> eeveeResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>pikaData<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>eeveeData<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now both requests are fired off, then we wait for the first response, then the second. This is still not 100% parallel though. For that we can use <code>Promise.all</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pikaPromise <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveePromise <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/eevee"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>pikaResponse<span class="token punctuation">,</span> eeveeResponse<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    pikaPromise<span class="token punctuation">,</span>
    eeveePromise<span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>pikaData<span class="token punctuation">,</span> eeveeData<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    pikaResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    eeveeResponse<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>pikaData<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>eeveeData<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p><code>Promise.all</code> takes an array of promises and resolves with an array of results once they all finish. We can <code>await</code> <code>Promise.all</code> to get hold of the resolved array of results, then destructure the data we need.</p>
<p>In my opinion the cleanest way to achieve this actually mixes promises with <code>await</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pikaPromise <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> eeveePromise <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/eevee"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>pikaData<span class="token punctuation">,</span> eeveeData<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    pikaPromise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    eeveePromise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>pikaData<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>eeveeData<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="its-promises-all-the-way-down"><a class="hash" href="#its-promises-all-the-way-down" aria-label="Link to heading"></a>It&#39;s promises all the way down</h2>
    <p>One other thing I&#39;ve seen developers new to async functions struggle with is that the return value is always a promise. This means you can&#39;t just call the function and use the return value directly, you either have to <code>await</code> the function itself or add a <code>.then()</code>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokeapi.co/api/v2/pokemon/pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// { id: "25", name: "pikachu" }</span>
  <span class="token keyword">return</span> data<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Promise &lt;pending></span></code></pre>
    </div><p>It does seem counterintuitive that you can have access to the <code>data</code> value <em>inside</em> the async function, log it fine, but when you return it suddenly it&#39;s not there?</p>
<p>This makes more sense when you remember that the async function effectively pauses its execution while waiting for the request to resolve. This can&#39;t happen outside the function though: JS will move on to the rest of your code and try to run that straight away. So the return value isn&#39;t ready yet, we need to wait for that to resolve before trying to access it.</p>

      <h2 id="the-future"><a class="hash" href="#the-future" aria-label="Link to heading"></a>The future</h2>
    <p>Async functions are becoming super popular, and with good reason. They make thinking about async code more natural and remove some of JavaScript&#39;s confusing parts. I&#39;m sure they&#39;ll become more and more prevalent. Hopefully you&#39;re now slightly better equipped to spot their potential pitfalls.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Schedule Netlify deploys using GitHub Actions</title>
    <link href="https://oliverjam.com/articles/schedule-netlify-github-actions"/>
    <updated>2020-02-19T10:15:06.000Z</updated>
    <id>https://oliverjam.com/articles/schedule-netlify-github-actions</id>
    <content type="html"><![CDATA[
      <h2 id="scheduling-netlify-deploys"><a class="hash" href="#scheduling-netlify-deploys" aria-label="Link to heading"></a>Scheduling Netlify deploys</h2>
    <p>Netlify is a fantastic place to deploy static sites, but they have no built-in way to schedule a deploy. They do however provide &quot;build hooks&quot;. These are URLs that trigger a build when they receive a POST request.</p>
<p>Previously I had played with <a href="https://zapier.com">Zapier</a>, setting up a scheduled task that hit the Netlify build hook. This never felt right to me though: this one (crucial!) part of the site&#39;s config lived on a totally separate platform with a different login. It&#39;s easy to imagine someone else taking over maintenance of the site and not knowing the Zapier task was there.</p>
<p>Ideally I wanted a way to have the schedule config live in the GitHub repo where the code is.</p>

      <h2 id="github-actions"><a class="hash" href="#github-actions" aria-label="Link to heading"></a>GitHub Actions</h2>
    <p>Recently GitHub launched their <a href="https://github.com/features/actions">Actions</a> platform. This is a Continuous Integration service (like Travis), allowing you to run tests, deploy packages and all the other stuff CI is used for.</p>
<p>The best part is you can <em>schedule</em> an Action using <a href="https://crontab.guru">CRON</a> syntax. Rather than running (for example) on every push to the repo, the Action will run at the time and date you specify.</p>
<p>This is exactly what I needed. GitHub Actions are configured with a yaml file in the repo itself, alongside all the code.</p>

      <h3 id="configuring"><a class="hash" href="#configuring" aria-label="Link to heading"></a>Configuring</h3>
    <p>The easiest way to create an Action is to click the &quot;Actions&quot; tab on your repo on GitHub.</p>
<img src="/assets/media/actions-1.png" alt="" width="1200" height="761">

<p>Then click the &quot;Set up a workflow yourself&quot; button. It will give you a boilerplate yaml file in a nice UI that&#39;s part text editor and part GUI, with the docs visible on the right.</p>
<img src="/assets/media/actions-2.png" alt="" width="1200" height="761">

<p>The default file looks like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token key atrule">name</span><span class="token punctuation">:</span> CI

<span class="token key atrule">on</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>push<span class="token punctuation">]</span>

<span class="token key atrule">jobs</span><span class="token punctuation">:</span>
  <span class="token key atrule">build</span><span class="token punctuation">:</span>
    <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest

    <span class="token key atrule">steps</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> <span class="token key atrule">uses</span><span class="token punctuation">:</span> actions/checkout@v2
      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Run a one<span class="token punctuation">-</span>line script
        <span class="token key atrule">run</span><span class="token punctuation">:</span> echo Hello<span class="token punctuation">,</span> world<span class="token tag">!</span>
      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Run a multi<span class="token punctuation">-</span>line script
        <span class="token key atrule">run</span><span class="token punctuation">:</span> <span class="token punctuation">|</span><span class="token scalar string">
          echo Add other actions to build,
          echo test, and deploy your project.</span></code></pre>
    </div><p>This creates an Action that runs whenever someone pushes to the repo. It will start an Ubuntu machine, load the pre-existing &quot;checkout&quot; Action (which allows this Action to access repo files), then run two tasks, both of which just echo some text.</p>
<p>We don&#39;t need access to the repo files, so we can remove the <code>- uses</code> line. We also only need a single step, so we can delete the second.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token key atrule">name</span><span class="token punctuation">:</span> CI

<span class="token key atrule">on</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>push<span class="token punctuation">]</span>

<span class="token key atrule">jobs</span><span class="token punctuation">:</span>
  <span class="token key atrule">build</span><span class="token punctuation">:</span>
    <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest

    <span class="token key atrule">steps</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Run a one<span class="token punctuation">-</span>line script
        <span class="token key atrule">run</span><span class="token punctuation">:</span> echo Hello<span class="token punctuation">,</span> world<span class="token tag">!</span></code></pre>
    </div><p>We want to change the <code>on</code> section to use a schedule instead:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token key atrule">name</span><span class="token punctuation">:</span> CI

<span class="token key atrule">on</span><span class="token punctuation">:</span>
  <span class="token key atrule">schedule</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">cron</span><span class="token punctuation">:</span> <span class="token string">"0 0 * * *"</span>

<span class="token key atrule">jobs</span><span class="token punctuation">:</span>
  <span class="token key atrule">build</span><span class="token punctuation">:</span>
    <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest

    <span class="token key atrule">steps</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Run a one<span class="token punctuation">-</span>line script
        <span class="token key atrule">run</span><span class="token punctuation">:</span> echo Hello<span class="token punctuation">,</span> world<span class="token tag">!</span></code></pre>
    </div><p>The GitHub Action editor is nice enough to show you what time your confusing CRON syntax refers to when you hover, which is very helpful. So this Action will now run every day at midnight (UTC). By default scheduled Actions run against the default or base branch of the repo (here Master), which is what we want to deploy.</p>
<img src="/assets/media/actions-3.png" alt="" width="1200" height="761">

<p>The final step is changing the <code>run</code> line so the Action actually hits our Netlify deploy webhook.</p>
<p>First we create the hook in our Netlify admin UI (in <code>Settings &gt; Build &amp; deploy &gt; Build hooks</code>. Click the &quot;Add build hook&quot; button, then name your hook. Save the hook and Netlify will show you the webhook URL.</p>
<img src="/assets/media/actions-4.png" alt="" width="1200" height="761">

<p>If you click the URL it will also give you an example <code>curl</code> command, which is what we want for our Action. Go back to your Action file and replace the <code>echo Hello, world!</code> with the <code>curl</code> command. We can also give it a more descriptive name.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token key atrule">name</span><span class="token punctuation">:</span> CI

<span class="token key atrule">on</span><span class="token punctuation">:</span>
  <span class="token key atrule">schedule</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">cron</span><span class="token punctuation">:</span> <span class="token string">"0 0 * * *"</span>

<span class="token key atrule">jobs</span><span class="token punctuation">:</span>
  <span class="token key atrule">build</span><span class="token punctuation">:</span>
    <span class="token key atrule">runs-on</span><span class="token punctuation">:</span> ubuntu<span class="token punctuation">-</span>latest

    <span class="token key atrule">steps</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Nightly deploy
        <span class="token key atrule">run</span><span class="token punctuation">:</span> curl <span class="token punctuation">-</span>X POST <span class="token punctuation">-</span>d <span class="token punctuation">{</span><span class="token punctuation">}</span> https<span class="token punctuation">:</span>//api.netlify.com/build_hooks/1234</code></pre>
    </div><p>That&#39;s it! Commit the Action file and wait for the scheduled time to hit. I&#39;ve found they usually run between 2 and 5 minutes after the scheduled time, so bear that in mind.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Where we're going, we don't need servers</title>
    <link href="https://oliverjam.com/articles/we-dont-need-servers"/>
    <updated>2020-01-23T12:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/we-dont-need-servers</id>
    <content type="html"><![CDATA[
      <h2 id="maybe-we-do-need-a-server"><a class="hash" href="#maybe-we-do-need-a-server" aria-label="Link to heading"></a>Maybe we do need a server</h2>
    <p>However you&#39;ll quickly hit a point where you need just a <em>tiny taste</em> of a server. This usually happens when you have an API secret that you don&#39;t want to leak—if all your code is client-side there&#39;s no way to hide anything.</p>
<p>Have we lost all the nice benefits of our static app? Do we have to maintain and deploy a separate backend repo (or try and deploy both from one repo)? It seems like overkill to have to build an entire Express app when all you want is a single endpoint that takes your request, attaches an API secret and forwards it on.</p>

      <h2 id="enter-netlify-functions"><a class="hash" href="#enter-netlify-functions" aria-label="Link to heading"></a>Enter Netlify Functions</h2>
    <p>As usual Netlify is out there making my job easier. Their &quot;Functions&quot; service allows you to write and deploy backend code from within the same repo as your frontend. These are technically &quot;serverless functions&quot; (or &quot;lambdas&quot; in Amazon-speak), but what that really means is a backend endpoint that runs a function whenever it gets a request. It&#39;s like on-demand Express routes.</p>

      <h3 id="netlify-dev"><a class="hash" href="#netlify-dev" aria-label="Link to heading"></a>Netlify Dev</h3>
    <p>Before we begin we should install the <a href="https://docs.netlify.com/cli/get-started/#installation">Netlify CLI</a>. It allows you to run the entire Netlify production environment locally on your machine. This lets you test Functions, redirects and other config you may have set up.</p>
<p>You can <code>npm install -g netlify-cli</code> to give you access to the <code>netlify</code> command anywhere. You can now run <code>netlify dev</code> inside a project and it should detect the project type and start up a dev server automatically.</p>

      <h3 id="getting-started-with-functions"><a class="hash" href="#getting-started-with-functions" aria-label="Link to heading"></a>Getting started with Functions</h3>
    <p>First we need to tell Netlify where our Functions will live. Create a <code>netlify.toml</code> file at the root of your project. This allows us to configure all of Netlify&#39;s features within our repo.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">[</span><span class="token table class-name">build</span><span class="token punctuation">]</span>
  <span class="token key property">functions</span> <span class="token punctuation">=</span> <span class="token string">"functions"</span></code></pre>
    </div><p>Now Netlify knows where to put them we can use the CLI to create one for us. Run <code>netlify functions:create</code>. It should ask you to choose a template—for now pick the basic hello world example.</p>
<p>You should see a new file at <code>functions/hello/hello.js</code> that contains this code:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">exports<span class="token punctuation">.</span><span class="token function-variable function">handler</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">event<span class="token punctuation">,</span> context</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> subject <span class="token operator">=</span> event<span class="token punctuation">.</span>queryStringParameters<span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token string">"World"</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">statusCode</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span>
      <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Hello </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>subject<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">statusCode</span><span class="token operator">:</span> <span class="token number">500</span><span class="token punctuation">,</span> <span class="token literal-property property">body</span><span class="token operator">:</span> err<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Important: the export <em>must</em> be named &quot;handler&quot; for this to work.</p>

      <h3 id="anatomy-of-a-function"><a class="hash" href="#anatomy-of-a-function" aria-label="Link to heading"></a>Anatomy of a Function</h3>
    <p>Each Function is passed two arguments: the request object (commonly named <code>event</code>) and the <code>context</code> object (containing info about e.g. authentication).</p>
<p><code>event</code> has properties like the request querystring and body ready for you to use.</p>
<p>When you&#39;re ready to respond to the client you return an object with at least <code>statusCode</code> and <code>body</code> properties.</p>

      <h3 id="async-vs-callback"><a class="hash" href="#async-vs-callback" aria-label="Link to heading"></a>Async vs callback</h3>
    <p>The example above uses an <code>async</code> JS function. This allows you to simply return an object for the response. Async functions always return promises, so Netlify will wait for the promise to resolve before sending the response.</p>
<p>If you don&#39;t like <code>async</code> you can also use callbacks: the handler function receives a third callback argument that you can call with the response object:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">exports<span class="token punctuation">.</span><span class="token function-variable function">handler</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">event<span class="token punctuation">,</span> context<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token function">callback</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">statusCode</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span>
    <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token string">"hello"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="sending-requests"><a class="hash" href="#sending-requests" aria-label="Link to heading"></a>Sending requests</h3>
    <p>The endpoint is defined by the filesystem. Since our file is named <code>hello.js</code> it&#39;ll be the <code>/hello</code> route.</p>
<p>This means a request sent to <code>/.netlify/functions/hello?message=everyone</code> would receive a response of <code>{ &quot;message&quot;: &quot;Hello everyone&quot; }</code>.</p>
<p>Note the <code>.netlify/</code> part—this namespaces Netlify stuff so it doesn&#39;t clash with routes your actual app might be using.</p>

      <h3 id="using-environment-variables"><a class="hash" href="#using-environment-variables" aria-label="Link to heading"></a>Using environment variables</h3>
    <p>If you&#39;re using <code>netlify dev</code> to run your site locally it will automatically have access to environment variables you have set in the Netlify UI. So if you&#39;ve created an environment variable in the UI named &quot;API_SECRET&quot; you should be able to access it in your Functions with <code>process.env.API_SECRET</code>.</p>
<p>First you will have to authorize the Netlify CLI by running <code>netlify login</code>.</p>
<p>If you have already deployed this repo to Netlify you can run <code>netlify link</code> to link the Netlify CLI with the deployed site.</p>
<p>If you haven&#39;t deployed it yet you can run <code>netlify init</code> to link and deploy right from the command line.</p>
<p>Once you&#39;ve linked the site you should see a <code>.netlify/state.json</code> file created, which contains the <code>&quot;siteID&quot;</code> referring to your deployed site.</p>

      <h4 id="multiple-users"><a class="hash" href="#multiple-users" aria-label="Link to heading"></a>Multiple users</h4>
    <p>There is a downside here: you have to log in to the Netlify account that owns the site in order to link them and access the API secrets. The easiest way to work around this if you have multiple people working on the project is to create a shared account you can all log in to.</p>
<p>Alternatively you can pay for Netlify, which allows you to have multiple users in your team.</p>

      <h2 id="using-with-create-react-app"><a class="hash" href="#using-with-create-react-app" aria-label="Link to heading"></a>Using with Create React App</h2>
    <p>If you use <code>netlify dev</code> to run your local environment you don&#39;t need any special config. Running that command will start both the CRA server (on port <code>3000</code> by default) and the Functions server (on a random port). It will also start your entire combined app on port <code>8888</code>. This is where the magic happens: your React code can now make requests to <code>/.netlify/functions/hello</code>.</p>
<p>Important note: the React app on port <code>3000</code> <em>won&#39;t work</em> as it won&#39;t be able to reach the Functions. Make sure you&#39;re using the Netlify-Dev-served version on <code>8888</code>.</p>

      <h3 id="without-netlify-dev"><a class="hash" href="#without-netlify-dev" aria-label="Link to heading"></a>Without Netlify Dev</h3>
    <p>If you can&#39;t or don&#39;t want to use Netlify Dev it&#39;s a little more complicated. You&#39;ll need to run your Functions server manually (say on port <code>9000</code>), then <a href="https://create-react-app.dev/docs/proxying-api-requests-in-development">set up a proxy</a> in your React app so that requests get forwarded to that port. Netlify have a good <a href="https://github.com/netlify/create-react-app-lambda">example project</a> with this set up (but Netlify Dev really is a lot easier).</p>
]]></content>
  </entry>
      
  <entry>
    <title>Setting up a project from scratch</title>
    <link href="https://oliverjam.com/articles/setting-up-a-project"/>
    <updated>2019-12-15T15:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/setting-up-a-project</id>
    <content type="html"><![CDATA[<p>I&#39;m going to assume you aren&#39;t using a project-generator like <a href="https://create-react-app.dev/">Create React App</a> or <a href="https://cli.vuejs.org/">Vue CLI</a> and are starting totally from scratch.</p>
<p>I&#39;ll also be doing everything from the command line since that&#39;s how I typically work. I find it&#39;s faster and easier (after a bit of practice) than fiddling with Finder and other GUIs.</p>

      <h2 id="creating-the-directory"><a class="hash" href="#creating-the-directory" aria-label="Link to heading"></a>Creating the directory</h2>
    <p>First I create a new directory for the project. I keep all my projects in a <code>~/Web</code> directory, so lets make it there. I like to use a short function that lives in my shell config (e.g. <code>.bashrc</code> or <code>.zshrc</code>) to both create and move into a directory at once:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function-name function">mkcd</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">mkdir</span> <span class="token string">"<span class="token variable">$1</span>"</span>
  <span class="token builtin class-name">cd</span> <span class="token string">"<span class="token variable">$1</span>"</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>So I can run <code>mkcd ~/Web/my-project</code> and end up where I want to be. You could of course manually <code>mkdir</code> and then <code>cd</code> yourself.</p>

      <h2 id="initialising-stuff"><a class="hash" href="#initialising-stuff" aria-label="Link to heading"></a>Initialising stuff</h2>
    <p>Since I want to be able to share this project on Github (and generally track any changes I make) I need to tell git to keep track of the directory:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">git</span> init</code></pre>
    </div><p>This is a web project, and I&#39;m probably going to have to install some dependencies, so I&#39;ll also create a <code>package.json</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> init</code></pre>
    </div><p>You can either answer the questions it asks or just add a <code>-y</code> flag to the command to automatically skip them. It&#39;s easy enough to manually edit the <code>package.json</code> later.</p>
<p>An even smoother solution is to customise the default values, since they probably won&#39;t change much from project to project:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> config <span class="token builtin class-name">set</span> init-author-name <span class="token string">"Oliver Phillips"</span> -g
<span class="token function">npm</span> config <span class="token builtin class-name">set</span> init-author-email <span class="token string">"hello@oliverjam.com"</span> -g</code></pre>
    </div><p>This will populate my name and email whenever I run <code>npm init -y</code>.</p>
<p>Since I&#39;m using npm to install dependencies I want a <code>.gitignore</code> file. This will stop me committing 100 trillion nested node modules and creating a black hole at the centre of the Earth (or just crashing the VS Code git integration).</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">npx gitignore <span class="token function">node</span></code></pre>
    </div><p>This will temporarily install the <a href="https://www.npmjs.com/package/gitignore">gitignore</a> package from npm, then use it to generate a boilerplate <code>.gitignore</code> file for node projects.</p>

      <h2 id="linting"><a class="hash" href="#linting" aria-label="Link to heading"></a>Linting</h2>
    <p>Linters are a good idea no matter what type of project you&#39;re building. A linter will <em>statically analyse</em> your code and report any mistakes it finds. This means it just looks at the code, without running it, so it won&#39;t find certain types of errors. It will catch annoying hard to spot stuff like this though:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">doStuff</span><span class="token punctuation">(</span><span class="token parameter">fileInput</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// many lines</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>fileinput<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// undefined 😱</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>I would <em>strongly</em> recommend only linting for actual errors. There are lots of rulesets that let you specify exact formatting or styles of code, but these usually get in the way more than they help. A better way to enforce consistency across a team is to format all your files <a href="#formatting">with Prettier</a>.</p>

      <h3 id="eslint"><a class="hash" href="#eslint" aria-label="Link to heading"></a>ESLint</h3>
    <p>ESLint is a great JavaScript linter that integrates with most text editors to highlight problems as you type.</p>
<p>I install and configure it by running the ESLint wizard and answering some questions:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">npx eslint --init</code></pre>
    </div><p>The CLI will ask you a few questions about the code you&#39;re writing and then create a basic config file. It will ask if it should automatically install ESLint and other required dependencies too.</p>
<p>You should now have a config file that looks something like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"env"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"browser"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"commonjs"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">"es6"</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"extends"</span><span class="token operator">:</span> <span class="token string">"eslint:recommended"</span><span class="token punctuation">,</span>
  <span class="token property">"parserOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"ecmaVersion"</span><span class="token operator">:</span> <span class="token number">2018</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"rules"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>You can <a href="https://eslint.org/docs/user-guide/getting-started#configuration">configure specific rules</a> by adding to the <code>&quot;rules&quot;</code> object.</p>
<p>I can now lint everything in the directory with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">npx eslint <span class="token builtin class-name">.</span></code></pre>
    </div><p>Make sure you have an editor plugin so that errors are also highlighted as you type.</p>

      <h4 id="linting-react"><a class="hash" href="#linting-react" aria-label="Link to heading"></a>Linting React</h4>
    <p>ESLint can be very useful for writing React code, especially the <a href="">Rules of hooks</a> plugin.</p>
<p>If you&#39;re using Create React App it will come with <a href="https://www.npmjs.com/package/eslint-config-react-app">its ESLint config</a> pre-configured. I highly recommend using the same config on non-CRA React projects, as it is a great selection of rules that will catch real errors. Other configs like the Airbnb preset have a lot of very opinionated rules that will get in your way.</p>
<p>Unfortunately due to the way ESLint configs work you&#39;ll have to install all of the CRA config&#39;s dependencies yourself:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> <span class="token function">install</span> -D eslint-config-react-app @typescript-eslint/eslint-plugin@2.x @typescript-eslint/parser@2.x babel-eslint@10.x eslint@6.x eslint-plugin-flowtype@3.x eslint-plugin-import@2.x eslint-plugin-jsx-a11y@6.x eslint-plugin-react@7.x eslint-plugin-react-hooks@1.x</code></pre>
    </div><p>You can then configure this in your <code>.eslintrc.json</code> file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"extends"</span><span class="token operator">:</span> <span class="token string">"react-app"</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="stylelint"><a class="hash" href="#stylelint" aria-label="Link to heading"></a>Stylelint</h3>
    <p>Stylelint is the CSS equivalent of ESLint. I don&#39;t know if I just make more JS mistakes, but I find myself using this less. It is useful if you would like to check your CSS to ensure you haven&#39;t mistyped any properties or made other mistakes.</p>
<p>Install Stylelint and the basic config with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> i -D stylelint stylelint-config-recommended</code></pre>
    </div><p>Then configure it by creating a <code>.stylelintrc</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"extends"</span><span class="token operator">:</span> <span class="token string">"stylelint-config-recommended"</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This will turn on only rules designed to catch actual errors. If there are stylistic or opinionated rules you&#39;d like to enable you can do <a href="https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#the-configuration-object">turn them on manually</a>.</p>
<p>I can lint from the command line:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">npx stylelint <span class="token string">"**/*.css"</span></code></pre>
    </div><p>This will lint all CSS files in all directories.</p>

      <h2 id="formatting"><a class="hash" href="#formatting" aria-label="Link to heading"></a>Formatting</h2>
    <p>Prettier is a life-changing tool for auto-formatting your code. It&#39;s a good idea to have this set up from the very beginning so that all your code is always consistently formatted no matter who writes it.</p>
<p>I install it with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> i -D prettier</code></pre>
    </div><p>I can now format files from the command line with:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">npx prettier --write <span class="token string">'**/*.{js,css,html,md}'</span></code></pre>
    </div><p>Prettier can format lots of different file types, so I specify the file extensions I&#39;m using. You can check you&#39;ve got the command right by replacing <code>--write</code> with <code>--check</code>. Prettier will list all the files with problems but will not change them.</p>
<p>It&#39;s nice to have an editor plugin that will auto-format my file when I save. This frees me to write code with abandon, shoving entire functions onto a single line and letting Prettier instantly format it.</p>
<p>You don&#39;t <em>need</em> to configure Prettier as it is designed to have sensible defaults. However you can get inconsistencies if different team members have different personal editor configurations. Create a <code>.prettierrc</code> file with no rules:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
    </div><p>This should override the local plugin config and make it use the Prettier defaults. Of course you can add project-specific rules there if you don&#39;t like the defaults. For example I prefer trailing commas, so I always enable that rule.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"trailingComma"</span><span class="token operator">:</span> <span class="token string">"es5"</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="git-hooks"><a class="hash" href="#git-hooks" aria-label="Link to heading"></a>Git hooks</h2>
    <p>Having all these development niceties is great, but it&#39;s easy to forget to run them, which would allow unformatted or error-riddled code to be committed. You can use git hooks to run the checks whenever somebody commits to the codebase.</p>
<p>I&#39;ll be using Husky to configure the hooks and lint-staged to run my tasks against only changed files.</p>
<p>I install both dependencies:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> i -D husky lint-staged</code></pre>
    </div><p>Then configure lint-staged in the <code>package.json</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"lint-staged"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"*.css"</span><span class="token operator">:</span> <span class="token string">"stylelint"</span><span class="token punctuation">,</span>
    <span class="token property">"*.js"</span><span class="token operator">:</span> <span class="token string">"eslint"</span><span class="token punctuation">,</span>
    <span class="token property">"*.{js,css,html,md}"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"prettier --write"</span><span class="token punctuation">,</span> <span class="token string">"git add"</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Since Prettier <em>changes</em> the files I&#39;ve already staged I need to pass two commands to lint-staged—the Prettier one and then <code>git add</code>, to ensure the formatting changes get staged as part of the current commit.</p>
<p>Finally I need to tell git to run lint-staged before every commit, by configuring Husky in my <code>package.json</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"husky"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"pre-commit"</span><span class="token operator">:</span> <span class="token string">"lint-staged"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Now whenever I try to commit any staged files will be linted, then formatted with Prettier. If any of those tasks find an error the commit will be prevented so I can fix it.</p>

      <h2 id="development-environment"><a class="hash" href="#development-environment" aria-label="Link to heading"></a>Development environment</h2>
    <p>This is usually where I&#39;d install the relevant dependencies for the libraries I needed, then set up my <code>&quot;start&quot;</code> and <code>&quot;dev&quot;</code> scripts in the <code>package.json</code>. This is totally different depending on the type of project though, so I&#39;ll just cover &quot;vanilla&quot; options.</p>

      <h3 id="vanilla-static-website"><a class="hash" href="#vanilla-static-website" aria-label="Link to heading"></a>Vanilla static website</h3>
    <p>If I&#39;m building a simple HTML page then I don&#39;t need any libraries or frameworks. It&#39;s nice to have a dev server that will auto-reload when I save changes though. I tend to reach for <a href="https://www.browsersync.io/docs/command-line">browser-sync</a> for this.</p>
<p>First I install it:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> i -D browser-sync</code></pre>
    </div><p>The command line API is easy to use with npm scripts. This script will start a dev server, open it in your browser and watch your files for changes:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"dev"</span><span class="token operator">:</span> <span class="token string">"browser-sync start --server --watch"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>You can <a href="https://www.browsersync.io/docs/command-line">configure it further</a> to only watch certain file types (or ignore files).</p>

      <h4 id="on-device-testing"><a class="hash" href="#on-device-testing" aria-label="Link to heading"></a>On-device testing</h4>
    <p>One really cool browser-sync feature is testing your dev site on real devices. When the server starts it&#39;ll log both a &quot;Local&quot; and &quot;External&quot; URL. You can visit the external one on any device connected to the same wi-fi as this machine, so you can see your changes in real-time on a mobile phone.</p>

      <h3 id="node-server"><a class="hash" href="#node-server" aria-label="Link to heading"></a>Node server</h3>
    <p>If I&#39;m developing a server I usually reach for <a href="https://nodemon.io/">nodemon</a>. It&#39;s similar to browser-sync in that it will watch your files and automatically restart your server when you save changes.</p>
<p>Where you would normally run <code>node myfile.js</code> you use <code>nodemon myfile.js</code>.</p>
<p>I need to install it:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">npm</span> i -D nodemon</code></pre>
    </div><p>Then set up my npm scripts:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"node index.js"</span><span class="token punctuation">,</span>
    <span class="token property">"dev"</span><span class="token operator">:</span> <span class="token string">"nodemon index.js"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="finally-leaving-my-machine"><a class="hash" href="#finally-leaving-my-machine" aria-label="Link to heading"></a>Finally, leaving my machine</h2>
    <p>I generally sync all of my projects to GitHub. It&#39;s free, convenient, and where the whole open-source community lives. This may change in the future given their current <a href="https://github.com/drop-ice/dear-github-2.0">unrepentant support for US Immigrations and Customs Enforcement (ICE)</a>, but for now there aren&#39;t really better options.</p>
<p>I like to use <a href="https://github.com/github/hub">Hub</a>, which allows you to do GitHub stuff (like creating repos) from your terminal. You can install this with <a href="https://brew.sh">Brew</a>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">brew <span class="token function">install</span> hub</code></pre>
    </div><p>I create a repository on GitHub:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">hub create</code></pre>
    </div><p>You can specify a name here—it will default to the directory name.</p>
<p>Hub will automatically set up the remote URL so you can push your code up and set the default remote:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">git</span> push origin master -u</code></pre>
    </div><p>I then open the GitHub repo to check everything worked:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">hub browse</code></pre>
    </div><p>This should open your shiny new repo on GitHub in your web browser. Make sure you write a <code>README.md</code> so people know what your project is for!</p>
]]></content>
  </entry>
      
  <entry>
    <title>First-class functions in JavaScript</title>
    <link href="https://oliverjam.com/articles/first-class-functions"/>
    <updated>2019-12-11T13:15:00.000Z</updated>
    <id>https://oliverjam.com/articles/first-class-functions</id>
    <content type="html"><![CDATA[
      <h2 id="functions-are-variables"><a class="hash" href="#functions-are-variables" aria-label="Link to heading"></a>Functions are variables</h2>
    <p>When you create a function in JS you are creating a normal variable:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">returnsOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// we now have a variable named returnsOne</span></code></pre>
    </div><p>This is still true (and perhaps more obvious) for arrow functions:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">returnsOne</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">;</span></code></pre>
    </div><p>You can reference this variable the same way you would any other:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>returnsOne<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// function returnsOne()</span></code></pre>
    </div><p>You can pass this function to other functions as arguments:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">logger</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">logger</span><span class="token punctuation">(</span>returnsOne<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// function returnsOne()</span></code></pre>
    </div>
      <h2 id="functions-are-callable"><a class="hash" href="#functions-are-callable" aria-label="Link to heading"></a>Functions are <em>callable</em></h2>
    <p>The main distinction between a function and other types of variable is that you can <em>call</em> a function. You call a function by putting parens (normal brackets) after it:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">returnsOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Calling a function will run the lines of code inside of it. If you try to reference the <em>called</em> function as a value you&#39;ll get whatever the function returns:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> myValue <span class="token operator">=</span> <span class="token function">returnsOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myValue<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span></code></pre>
    </div><p>If the function returns nothing you&#39;ll get <code>undefined</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">returnsNothing</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// doesn't have a return statement</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> myValue <span class="token operator">=</span> <span class="token function">returnsNothing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myValue<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// undefined</span></code></pre>
    </div><p>This is often a source of confusion when passing functions as arguments. It&#39;s easy to accidentally call your function as you reference it, which means you&#39;re actually passing its return value:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">logger</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">logger</span><span class="token punctuation">(</span>returnsOne<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// function returnsOne()</span>

<span class="token function">logger</span><span class="token punctuation">(</span><span class="token function">returnsOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 1</span></code></pre>
    </div><p>This is clear if we log the <em>type</em> of the value:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> returnsOne<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// function</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token function">returnsOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// number</span></code></pre>
    </div>
      <h2 id="inline-functions"><a class="hash" href="#inline-functions" aria-label="Link to heading"></a>Inline functions</h2>
    <p>Another source of confusion is functions defined inline. This is a common pattern for passing functions as arguments to other functions (for example as event listeners):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">// do stuff</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can extract this inline function and assign it to a variable:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">handleSubmit</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">// do stuff</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This can be <em>even simpler</em> if we realise that all our inline function is doing now is taking an argument and passing it on to <code>handleSubmit</code>. We don&#39;t need the intermediary wrapper function at all:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">handleSubmit</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">// do stuff</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> handleSubmit<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>It&#39;s important to note that we don&#39;t want to <em>call</em> our function when we pass it here. This won&#39;t work as we need to pass a function, not its return value:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">handleSubmit</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token comment">// do stuff</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// this is equivalent to:</span>
<span class="token comment">// form.addEventListener("submit", undefined);</span>
<span class="token comment">// since handleSubmit doesn't return anything</span></code></pre>
    </div>
      <h2 id="built-in-functions"><a class="hash" href="#built-in-functions" aria-label="Link to heading"></a>Built-in functions</h2>
    <p>These rules apply to any functions, not just those you define yourself. For example if you wanted to log the result of a promise:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">getAsyncData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>The <code>.then</code> method expects to be passed a function as an argument. It will call whatever function we pass it with the resolved data. In this case our inline arrow function will be called with <code>data</code>, which we then pass on to the <code>console.log</code> function.</p>
<p>It&#39;s important to note that we are <em>defining</em> a function here, which means we can call the argument anything:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">getAsyncData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">whateverWeLike</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>whateverWeLike<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>The actual value that gets passed to our function comes from inside the <code>.then</code>—we never have control of it.</p>
<p>Next lets extract the inline function to a named variable, then reference it inside the <code>.then</code>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">logData</span><span class="token punctuation">(</span><span class="token parameter">whateverWeLike</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>whateverWeLike<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">getAsyncData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>logData<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This works, but there&#39;s an even simpler way. We can get rid of our wrapper function entirely, since all it does is forward whatever argument it receives on to <code>console.log</code>. Since <code>console.log</code> is already a function we can use it as-is:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">getAsyncData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h2 id="further-reading"><a class="hash" href="#further-reading" aria-label="Link to heading"></a>Further reading</h2>
    <p>You can learn more about first-class functions in <a href="https://mostly-adequate.gitbooks.io/mostly-adequate-guide/ch02.html">Chapter 2</a> of the <a href="https://mostly-adequate.gitbooks.io/mostly-adequate-guide/">Mostly Adequate Guide To Functional Programming</a>. I highly recommend reading at least the first few chapters, as they will improve your JavaScript whether you become a hardcore functional programmer or not.</p>
]]></content>
  </entry>
      
  <entry>
    <title>A complete guide to making web pages from scratch</title>
    <link href="https://oliverjam.com/articles/complete-guide-to-making-web-pages"/>
    <updated>2019-11-07T12:15:00.000Z</updated>
    <id>https://oliverjam.com/articles/complete-guide-to-making-web-pages</id>
    <content type="html"><![CDATA[<p>I&#39;m going to explain all the required bits you need to get a functioning page, using nothing but a text editor.</p>

      <h2 id="before-you-start"><a class="hash" href="#before-you-start" aria-label="Link to heading"></a>Before you start</h2>
    <p>I&#39;m assuming you&#39;re working on a desktop computer or laptop. Whilst it is possible to code on a smartphone or tablet it will be much more difficult to set up.</p>
<p>You&#39;ll need a program for editing text (ideally one designed for writing code). I&#39;d recommend <a href="https://code.visualstudio.com/">VS Code</a> from Microsoft. It&#39;s free, cross-platform and has good defaults.</p>
<p>In order to view your web page you&#39;ll also need a web browser. <a href="https://www.mozilla.org/en-GB/firefox/new/">Firefox</a> and <a href="https://www.google.com/chrome/">Chrome</a> are both great, and have good developer tools built in.</p>

      <h2 id="how-the-web-works"><a class="hash" href="#how-the-web-works" aria-label="Link to heading"></a>How the web works</h2>
    <p>Imagine you click a link to google.com. Your browser connects to Google&#39;s remote computer (usually called a server). It knows where to go using a system called DNS (like an address book for domains).</p>
<p>Your browser asks the server for a response to show. The server sends back an HTML file representing the Google homepage. Since your browser understands HTML it can display the text, images and other elements that make up the web page.</p>
<p>This is a very simplified explanation; if you want to know more detail try <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/How_the_Web_works">this MDN article about the web</a>.</p>

      <h2 id="the-language-of-the-web"><a class="hash" href="#the-language-of-the-web" aria-label="Link to heading"></a>The language of the web</h2>
    <p>HTML, or <em>HyperText Markup Language</em>, is the language of the web. An HTML file is the entrypoint for all web pages—no other type of file will work. For example if you click a link to a <code>.js</code> file the browser will just display the raw text content rather than actually running any code.</p>
<p>So we need to create an HTML file that our browser understands. If you want to follow along create a folder called <code>my-webpage</code> anywhere on your computer (the Desktop is fine). Then create a file called <code>index.html</code> inside the folder and open it in your text editor. This file can be called whatever you like, but <code>index</code> is the convention for the homepage of a website.</p>

      <h2 id="a-minimal-html-page"><a class="hash" href="#a-minimal-html-page" aria-label="Link to heading"></a>A minimal HTML page</h2>
    <p>Let&#39;s create a &quot;minimum viable&quot; HTML page—just the stuff we need to get it to load in a browser.</p>
<p>An HTML file has a specific structure that you have to follow.</p>

      <h3 id="the-doctype"><a class="hash" href="#the-doctype" aria-label="Link to heading"></a>The doctype</h3>
    <p>First you have to tell the browser that this file is actually HTML (and what version of the HTML syntax it&#39;s using).</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span></code></pre>
    </div><p>This tells the browser that this is a modern HTML5 document and should always appear at the top of the file.</p>

      <h3 id="the-root-element"><a class="hash" href="#the-root-element" aria-label="Link to heading"></a>The root element</h3>
    <p>Next we should have a root element. This contains everything else in the HTML document—there should be nothing outside this except the doctype.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h3 id="the-head-element"><a class="hash" href="#the-head-element" aria-label="Link to heading"></a>The head element</h3>
    <p>The <code>&lt;head&gt;</code> contains stuff that should be included in the document but won&#39;t show up on the page. This means metadata about the page, external assets like CSS files etc.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h4 id="mandatory-head-elements"><a class="hash" href="#mandatory-head-elements" aria-label="Link to heading"></a>Mandatory head elements</h4>
    <p>There are a couple of things that should always be inside the head.</p>

      <h5 id="document-encoding"><a class="hash" href="#document-encoding" aria-label="Link to heading"></a>Document encoding</h5>
    <p>There are lots of different ways computers can display human text, so we need to specify which one we want this page to use. The most useful is <a href="https://en.wikipedia.org/wiki/UTF-8">utf-8</a>, which includes pretty much all characters you&#39;ll ever use.</p>
<p>We can set this using the <code>&lt;meta&gt;</code> tag. This is a general purpose tag for describing information <em>about</em> the page. You&#39;ll see it used for a few other things later too.</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->


      <h5 id="the-page-title"><a class="hash" href="#the-page-title" aria-label="Link to heading"></a>The page title</h5>
    <p>Every web page should have a unique title. This is displayed in the tab in your browser, shown in search results and also read out by screenreaders to identify the page. We can use the <code>&lt;title&gt;</code> element for this.</p>
<p>Remember nothing in the head is shown on the page itself—this is only used outside the page.</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->


      <h3 id="the-body-element"><a class="hash" href="#the-body-element" aria-label="Link to heading"></a>The body element</h3>
    <p>The <code>&lt;body&gt;</code> element contains everything you want to appear on the page.</p>
<p>Let&#39;s put an <code>&lt;h1&gt;</code> inside it so we have a heading we can see.</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-wns -->

<p>That&#39;s it—if you save the above text in your HTML file you should be able to double-click it to open in your default web browser.</p>
<p>This is how it looks for me in Firefox:</p>
<img src="/assets/media/web-page-basics.png" alt="" width="1060" height="649">

<p>You can keep adding HTML elements inside the <code>&lt;body&gt;</code>, saving your file and refreshing the browser to see updates.</p>

      <h2 id="browser-developer-tools"><a class="hash" href="#browser-developer-tools" aria-label="Link to heading"></a>Browser developer tools</h2>
    <p>Most browsers have good developer tools to help you work on a web page. You can usually open them by pressing <kbd>command</kbd> + <kbd>option</kbd> + <kbd>i</kbd> (on a Mac) or <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>i</kbd> (on Windows). There should be an &quot;Elements&quot; panel where you can see all the HTML in your page, as well as any associated styles.</p>
<p>This is what our page so far looks like in Firefox dev tools:</p>
<img src="/assets/media/web-page-devtools.png" alt="" width="1060" height="649">


      <h2 id="adding-styles"><a class="hash" href="#adding-styles" aria-label="Link to heading"></a>Adding styles</h2>
    <p>We can now use CSS to style the elements on our page. HTML is an interesting language because it can actually include CSS and JS inside it. There are two ways to add styles.</p>

      <h3 id="inline-styles"><a class="hash" href="#inline-styles" aria-label="Link to heading"></a>Inline styles</h3>
    <p>The simplest way to add some styles is with the <code>&lt;style&gt;</code> element. This usually goes inside the head.</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
      <span class="token selector">h1</span> <span class="token punctuation">{</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token color">firebrick</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->

<p>If you add the style tag, save and refresh your browser you should see the heading turn dark red.</p>
<p>Open the developer tools again and select our <code>&lt;h1&gt;</code> in the &quot;Elements tab&quot;. You should see the CSS rule applied. You can edit, add or remove CSS here temporarily to play around with things before adding code to your actual file.</p>
<img src="/assets/media/web-page-devtools-styles.png" alt="" width="1060" height="649">


      <h3 id="external-css-files"><a class="hash" href="#external-css-files" aria-label="Link to heading"></a>External CSS files</h3>
    <p>We can also include a separate <code>.css</code> file. You may want to do this if you have lots of styles that are making your HTML file too big. You can also share a separate CSS file across multiple pages.</p>
<p>Create a new file called <code>my-styles.css</code> and copy the inline styles from above into it.</p>
<p>The <code>&lt;link&gt;</code> tag lets us include other resources in our page. We need to specify the type of resource and its URL:</p>
<!-- prettier-ignore -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/my-styles.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
    </div><p>Replace the style tag in your document&#39;s head with that link tag, then save and refresh. Your styles should still be applied.</p>

      <h2 id="adding-interaction"><a class="hash" href="#adding-interaction" aria-label="Link to heading"></a>Adding interaction</h2>
    <p>HTML supports a limited amount of interactivity, mostly via form elements. If we want our page to have more complex behaviour we need to add JavaScript. There are also two ways to do this.</p>

      <h3 id="inline-js"><a class="hash" href="#inline-js" aria-label="Link to heading"></a>Inline JS</h3>
    <p>We can use the <code>&lt;script&gt;</code> tag to add inline JavaScript to our page. This tag can contain JS-language code within our HTML in the same way the <code>&lt;style&gt;</code> tag contains CSS-language code.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"JavaScript is working!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
    </div><p>You <em>can</em> put this in the <code>&lt;head&gt;</code>, but unlike CSS it&#39;s usually a good idea to put JS at the bottom of the <code>&lt;body&gt;</code>. This way all the rest of your content is loaded before you try to run any JS.</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/my-styles.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"JavaScript is working!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->

<p>Open the developer tools, then click the &quot;Console&quot; tab and you should see our &quot;JavaScript is working!&quot; message.</p>
<img src="/assets/media/web-page-devtools-js.png" alt="" width="1060" height="649">


      <h3 id="external-js-files"><a class="hash" href="#external-js-files" aria-label="Link to heading"></a>External JS files</h3>
    <p>We might want to move our JS to an external file for the same reasons we would move our CSS. Create a new file called <code>my-script.js</code> and copy in our <code>console.log</code> line from above.</p>
<p>Confusingly we <em>don&#39;t</em> use the link tag for this—we use the same script tag, but with the <code>src</code> attribute to point to the URL of our JS file:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/my-script.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
    </div><p>Note that you need the closing <code>&lt;/script&gt;</code> tag even though there&#39;s nothing inside it.</p>
<p>Replace the script tag in your html with the new one, save and refresh. You should still see the message logged to your browser console.</p>

      <h2 id="nice-extras"><a class="hash" href="#nice-extras" aria-label="Link to heading"></a>Nice extras</h2>
    <p>That&#39;s pretty much everything that&#39;s absolutely needed to make a functioning web page. However there are a few extra things that most web pages have that aren&#39;t <em>required</em>, but make the experience better for users.</p>

      <h3 id="specify-a-language"><a class="hash" href="#specify-a-language" aria-label="Link to heading"></a>Specify a language</h3>
    <p>It&#39;s a good idea to tell the browser what language the page content is in. This helps your page appear in language-specific search results, allows browser translation tools to offer translation for users with a different language set, and sets the correct voice/accent for screenreaders.</p>
<p>Generally we set the language once on the root element:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><p>If you have parts of your site in another language you can set the attribute there too, and it will override the site-level language for just that element:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>blockquote</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>de<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Ich bin ein Berliner<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>cite</span><span class="token punctuation">></span></span>President John F. Kennedy<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>cite</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>blockquote</span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h3 id="the-viewport-meta-tag"><a class="hash" href="#the-viewport-meta-tag" aria-label="Link to heading"></a>The viewport meta tag</h3>
    <p>The <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport meta tag</a> is used to tell mobile browsers that your page is mobile-optimised.</p>
<p>In the early days of the mobile web most sites were built exclusively for big screens, so mobile browsers would zoom the page out to let the user see everything at once. Nowadays a <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Responsive_Design">responsive site</a> should display correctly on a small screen, so we can use this viewport meta tag to opt-out of the default zooming behaviour.</p>
<!-- prettier-ignore -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
    </div>
      <h3 id="a-favicon"><a class="hash" href="#a-favicon" aria-label="Link to heading"></a>A favicon</h3>
    <p>A favicon is the little icon that appears in the tab next to the site title (and in some other places). This helps users identify your site and can add a nice design touch.</p>
<p>You&#39;ll need a <code>favicon.ico</code> file. If you don&#39;t want to make your own you can <a href="/favicon.ico">download mine here</a> (right click the link and save), then copy it into your website folder.</p>
<p>We include this file with a link tag in the <code>&lt;head&gt;</code>, just like CSS files.</p>
<!-- prettier-ignore -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/favicon.ico<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
    </div><p>Some browsers will automatically request and use a file named <code>favicon.ico</code> if they find one, but it&#39;s best to be explicit. There are lots of different formats for larger icons and different platforms, so it&#39;s best to use <a href="https://realfavicongenerator.net">a favicon generator</a> to create all the files you might need.</p>

      <h3 id="the-meta-description-tag"><a class="hash" href="#the-meta-description-tag" aria-label="Link to heading"></a>The meta description tag</h3>
    <p>It&#39;s useful to provide a description of your page and its content. This will be shown by search engines along with the page title, so users have an idea of what the page is about before they visit it.</p>
<!-- prettier-ignore -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>description<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>My web page is a playground for me to learn about web concepts<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
    </div><p>The description should be 120-150 characters to avoid being cut-off in Google search results.</p>

      <h2 id="wrapping-up"><a class="hash" href="#wrapping-up" aria-label="Link to heading"></a>Wrapping up</h2>
    <p>For completeness here&#39;s a full code sample of everything a web page needs to get started:</p>
<!-- prettier-ignore-start -->
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/favicon.ico<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/my-styles.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>description<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>My web page is a playground for me to learn about web concepts<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>My web page<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/my-script.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
    </div><!-- prettier-ignore-end -->

<p>Hopefully now you have some understanding of what each of these tags does, and why we should include them.</p>
<p>If you feel comfortable building static web pages and want to learn how to add interactivity with JavaScript I&#39;d recommend my <a href="/blog/dom-intro/">Introduction to the DOM</a> article next.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Minimum viable GraphQL: the client</title>
    <link href="https://oliverjam.com/articles/minimum-viable-graphql-client"/>
    <updated>2019-11-06T15:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/minimum-viable-graphql-client</id>
    <content type="html"><![CDATA[<p>I&#39;m going to demonstrate how to make basic GraphQL queries directly from the browser using vanilla JavaScript. If you know how to make <code>POST</code> requests using <code>fetch</code> then you&#39;re 90% of the way there already.</p>
<p>If you&#39;ve never encountered GraphQL before or you&#39;re confused by any of the terminology take a look at <a href="/blog/minimum-viable-graphql-concepts">my previous post on GraphQL concepts</a>.</p>

      <h2 id="the-query"><a class="hash" href="#the-query" aria-label="Link to heading"></a>The query</h2>
    <p>GraphQL queries can be represented as strings in JavaScript. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">Template literals</a> (backticks) are handy for writing multiline strings. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> myQuery <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
{
  allPokemon {
    name
  }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre>
    </div>
      <h2 id="the-request"><a class="hash" href="#the-request" aria-label="Link to heading"></a>The request</h2>
    <p>We&#39;ll be sending our query as a <code>POST</code> request, with a JSON body. The GraphQL spec also allows <code>GET</code> requests using a URL-encoded query, but sending JSON is usually easier.</p>
<p>The body will be an object with a <code>query</code> property containing (surprisingly) our query.</p>

      <h2 id="a-basic-query"><a class="hash" href="#a-basic-query" aria-label="Link to heading"></a>A basic query</h2>
    <p>We need to make a <code>fetch</code> call, setting the method to <code>POST</code> and passing a JSON body containing our query:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
{
  allPokemon {
    name
  }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokemon-gql.now.sh/api"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"application/json"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can then do the standard <code>fetch</code> promise/error handling to see the result of our request:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
{
  allPokemon {
    name
  }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokemon-gql.now.sh/api"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"application/json"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Request failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">json</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>If successful this should log:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"allPokemon"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"bulbasaur"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"ivysaur"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"venusaur"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"charmander"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"charmeleon"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"charizard"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      ...
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="a-query-with-variables"><a class="hash" href="#a-query-with-variables" aria-label="Link to heading"></a>A query with variables</h2>
    <p>We can update our query to take an argument (see <a href="/blog/minimum-viable-graphql-concepts/#dynamic-argument-variables">this section of the previous post</a> for more details).</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
query Pikachu($name: String!) {
  pokemon(name: $name) {
    id
    name
    weight
  }
}
</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre>
    </div><p>We need to add a <code>variables</code> key to our body object to pass in dynamic values. The query itself should always be a static string (like SQL queries).</p>
<p><code>variables</code> should be an object containing all the arguments your query requires. In this case we only need one: the <code>name</code>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> variables <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"pikachu"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokemon-gql.now.sh/api"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
  <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"application/json"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> query<span class="token punctuation">,</span> variables <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token comment">// ... standard promise stuff</span>
  <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>If successful this should log:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"pokemon"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"25"</span><span class="token punctuation">,</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"pikachu"</span><span class="token punctuation">,</span>
      <span class="token property">"weight"</span><span class="token operator">:</span> <span class="token number">60</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="dynamic-variables"><a class="hash" href="#dynamic-variables" aria-label="Link to heading"></a>Dynamic variables</h3>
    <p>If we want our variables to be dynamic (maybe taken from user input) we can create a reusable fetching function that takes the variables as arguments.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">fetchPokemon</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://pokemon-gql.now.sh/api"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
    <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"content-type"</span><span class="token operator">:</span> <span class="token string">"application/json"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> query<span class="token punctuation">,</span> <span class="token literal-property property">variables</span><span class="token operator">:</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Request failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">fetchPokemon</span><span class="token punctuation">(</span><span class="token string">"pikachu"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>log<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We could then call <code>fetchPokemon</code> inside an event handler where we have a user&#39;s chosen name.</p>

      <h2 id="a-complete-example"><a class="hash" href="#a-complete-example" aria-label="Link to heading"></a>A complete example</h2>
    <p>Here&#39;s <a href="https://codepen.io/oliverjam/pen/wvwQGXd?editors=1111">a small demo app</a> that let&#39;s you search for Pokémon by name.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Minimum viable GraphQL: the concepts</title>
    <link href="https://oliverjam.com/articles/minimum-viable-graphql-concepts"/>
    <updated>2019-11-05T12:30:00.000Z</updated>
    <id>https://oliverjam.com/articles/minimum-viable-graphql-concepts</id>
    <content type="html"><![CDATA[
      <h2 id="unique-selling-points"><a class="hash" href="#unique-selling-points" aria-label="Link to heading"></a>Unique selling points</h2>
    <p>GraphQL&#39;s main selling points are (in my opinion):</p>
<ol>
<li>Clients can query exactly the data they need (less over-fetching)</li>
<li>The data and queries are strongly typed via a schema (fewer typos)</li>
<li>There&#39;s a well-defined &quot;right way to do it&quot; (fewer opinions)</li>
</ol>

      <h2 id="tooling"><a class="hash" href="#tooling" aria-label="Link to heading"></a>Tooling</h2>
    <p>GraphQL&#39;s strictly spec&#39;d and strongly typed nature lends itself to nice automated tooling. For example most APIs using GraphQL expose a <a href="https://github.com/graphql/graphiql">Graphiql</a> explorer. This is a graphical interface that exposes the API schema and lets you make queries. You can see an example of this for the <a href="https://pokemon-gql.now.sh/api">demo Pokémon API</a> we&#39;ll be using.</p>

      <h2 id="fetching-data"><a class="hash" href="#fetching-data" aria-label="Link to heading"></a>Fetching data</h2>
    <p>GraphQL&#39;s query syntax is designed to be similar to JSON. This means the query ends up looking a lot like the resulting data. For example, sending this query to my <a href="https://pokemon-gql.now.sh/api?query=%7B%0A%20%20allPokemon%7B%0A%20%20%20%20name%0A%20%20%7D%0A%7D">Pokémon GraphQL API</a>:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">{
  allPokemon {
    name
  }
}</code></pre>
    </div><p>results in a JSON response that looks like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"allPokemon"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"bulbasaur"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"ivysaur"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"venusaur"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"charmander"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"charmeleon"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"charizard"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      ...
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>If we realise we also need the ID of each pokémon we can adjust our query like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">{
  allPokemon {
    name
    id
  }
}</code></pre>
    </div><p>Now our pokémon objects will also contain the <code>&quot;id&quot;</code> property.</p>
<p>Hopefully you can see how it&#39;s easier for a client to fetch exactly the data it needs, in the shape it needs. In a typical REST API the client might have to hit multiple endpoints, fetching lots of JSON it doesn&#39;t need, and then reformat it to the right shape.</p>

      <h3 id="query-arguments"><a class="hash" href="#query-arguments" aria-label="Link to heading"></a>Query arguments</h3>
    <p>GraphQL queries can also accept arguments to allow filtering and sorting data, and fetching dynamically. For example we can get a specific pokémon with this query:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">{
  pokemon(name: "pikachu") {
    name
    id
    weight
  }
}</code></pre>
    </div><p>Here&#39;s the result:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"pokemon"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"25"</span><span class="token punctuation">,</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"pikachu"</span><span class="token punctuation">,</span>
      <span class="token property">"weight"</span><span class="token operator">:</span> <span class="token number">60</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="operation-type-and-name"><a class="hash" href="#operation-type-and-name" aria-label="Link to heading"></a>Operation type and name</h3>
    <p>Until now we&#39;ve been relying on a shorthand: without specifying the type of operation we&#39;re performing (or giving it a name) GraphQL assumes we&#39;re just querying data. The name is only required if you&#39;re performing multiple operations. Here&#39;s how our first query looks with the operation type and name specified:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">query Pokemons {
  allPokemon {
    name
  }
}</code></pre>
    </div>
      <h3 id="dynamic-argument-variables"><a class="hash" href="#dynamic-argument-variables" aria-label="Link to heading"></a>Dynamic argument variables</h3>
    <p>Hard-coded arguments are not very useful. If we want to pass dynamic values in as arguments we need to use &quot;variables&quot;. Variables must be declared (including their type) as part of the named query. They can then be referenced in the query arguments:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">query Pikachu($myName: String!) {
  pokemon(name: $myName) {
    name
    id
    weight
  }
}</code></pre>
    </div><p>The client must then send a separate <code>&quot;variables&quot;</code> object as part of the request. GraphQL will match the properties from this object to the variables declared in the query. We&#39;ll see how exactly this works when we talk about using GraphQL on the client in the next post.</p>
<p>The exclamation mark makes this a <em>required</em> variable: the client <em>must</em> pass a variable called <code>&quot;name&quot;</code> with a string value or it will receive an error.</p>

      <h2 id="sending-data"><a class="hash" href="#sending-data" aria-label="Link to heading"></a>Sending data</h2>
    <p>So far we have only discussed fetching data. APIs usually also need a way to create or update data. GraphQL uses &quot;mutations&quot; to achieve this.</p>
<p>Mutations look similar to queries, but with the operation type set to &quot;mutation&quot; instead of &quot;query&quot; (the operation name is still optional). They usually also need some kind of input argument.</p>
<p>Our Pokémon API supports a <code>createPokemon</code> mutation that takes a new pokémon object as an argument:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">mutation MyNewPokemon {
  createPokemon(
    input: {
      name: "test"
      height: 1
      species_id: 10
      weight: 100
      base_experience: 5
      order: 1000
    }
  ) {
    id
    name
  }
}</code></pre>
    </div><p>You can <a href="https://pokemon-gql.now.sh/api?query=mutation%20create%20%7B%0A%09createPokemon(input%3A%20%7B%0A%20%20%20%20name%3A%20%22test%22%2C%0A%20%20%20%20height%3A%201%2C%0A%20%20%20%20species_id%3A%2010%2C%0A%20%20%20%20weight%3A%20100%2C%0A%20%20%20%20base_experience%3A%205%2C%0A%20%20%20%20order%3A%201000%0A%20%20%7D)%20%7B%0A%20%20%20%20name%0A%20%20%20%20id%0A%20%20%20%20order%0A%20%20%7D%0A%7D&amp;operationName=create">try this in GraphiQL</a>.</p>
<p>Mutations should return what they just created so that you can immediately query for fields on it. Here we&#39;re asking for the ID and name of the created pokémon. Our response looks like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"createPokemon"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"0"</span><span class="token punctuation">,</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"test"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="actually-sending-queries"><a class="hash" href="#actually-sending-queries" aria-label="Link to heading"></a>Actually sending queries</h2>
    <p>You may be wondering how you actually send these nice queries to a GraphQL API. That will depend on the client you&#39;re using as GraphQL is an intentionally client-agnostic spec. Read <a href="/blog/minimum-viable-graphql-client/">Part Two of this series</a> for an introduction to making GraphQL requests from the browser using <code>fetch</code>.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Testing your UI with React Testing Library</title>
    <link href="https://oliverjam.com/articles/react-ui-testing"/>
    <updated>2019-08-22T17:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/react-ui-testing</id>
    <content type="html"><![CDATA[
      <h2 id="philosophy"><a class="hash" href="#philosophy" aria-label="Link to heading"></a>Philosophy</h2>
    <p>We&#39;re aiming to test our components like a real user using <a href="https://testing-library.com">React Testing Library</a>]. That means rendering a React component to a real DOM, rather than shallow rendering. We should also avoid calling event handler methods directly—all interactions should happen via actual DOM events as they would when a user browses the site.</p>

      <h3 id="vanilla-example"><a class="hash" href="#vanilla-example" aria-label="Link to heading"></a>Vanilla example</h3>
    <p>Here&#39;s a simple test for a React component (assuming you&#39;re using Jest and have access to a JSDom environment):</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">Hello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"It should render hello"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Hello</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> el <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"h1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>el<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Hello world"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This works fine, but requires some boilerplate before rendering anything. It would also be nice to have some helpers to find things in the DOM. This is where React Testing Library (RTL) comes in.</p>

      <h2 id="react-testing-library"><a class="hash" href="#react-testing-library" aria-label="Link to heading"></a>React Testing Library</h2>
    <p>You&#39;ll need to install the library with <code>npm install -D @testing-library/react</code>.</p>

      <h3 id="basic-testing"><a class="hash" href="#basic-testing" aria-label="Link to heading"></a>Basic testing</h3>
    <p>Here&#39;s our basic test from above, re-written:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@testing-library/react"</span><span class="token punctuation">;</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"It should render hello"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Hello</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  screen<span class="token punctuation">.</span><span class="token function">getByText</span><span class="token punctuation">(</span><span class="token string">"Hello world"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>RTL&#39;s <code>render</code> method creates a container and renders our component into it. The <code>screen</code> import contains useful methods for querying the rendered DOM.</p>
<p>In this case we&#39;re using <code>getByText()</code> to search the DOM for an element matching a certain string. Any query method starting with <code>getBy</code> will throw an error if it doesn&#39;t find a match. This will fail the test, which means we don&#39;t even have to write an assertion!</p>
<p>These functions can take a regular expression instead of a string, which is useful for case-insensitive matching: <code>getByText(/hello world/i)</code>.</p>

      <h3 id="testing-interaction"><a class="hash" href="#testing-interaction" aria-label="Link to heading"></a>Testing interaction</h3>
    <p>RTL provides <code>fireEvent</code> to simplify triggering DOM events. This is handy for testing user interaction:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen<span class="token punctuation">,</span> fireEvent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@testing-library/react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Toggle <span class="token keyword">from</span> <span class="token string">"./Toggle"</span><span class="token punctuation">;</span> <span class="token comment">// renders "off" or "on" after click</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"It should toggle on/off"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Toggle</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> button <span class="token operator">=</span> screen<span class="token punctuation">.</span><span class="token function">getByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">off</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  fireEvent<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">;</span>
  screen<span class="token punctuation">.</span><span class="token function">getByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">on</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This test checks the DOM contains an element with text content &quot;off&quot;, then fires a click event on that element and checks its text content is now &quot;on&quot;.</p>

      <h3 id="testing-input"><a class="hash" href="#testing-input" aria-label="Link to heading"></a>Testing input</h3>
    <p>We can also use <code>fireEvent</code> to test user input. Since we&#39;re dispatching real DOM events here we need to pass in an event object with the properties we expect:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen<span class="token punctuation">,</span> fireEvent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@testing-library/react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Shouter <span class="token keyword">from</span> <span class="token string">"./Shouter"</span><span class="token punctuation">;</span> <span class="token comment">// takes user input and renders it in all-caps</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"It should make user input all-caps"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Shouter</span></span> <span class="token attr-name">label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Enter text to shout<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> input <span class="token operator">=</span> screen<span class="token punctuation">.</span><span class="token function">getByLabelText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">enter text to shout</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  fireEvent<span class="token punctuation">.</span><span class="token function">change</span><span class="token punctuation">(</span>input<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">target</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">"hello world"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  screen<span class="token punctuation">.</span><span class="token function">getByText</span><span class="token punctuation">(</span><span class="token string">"HELLO WORLD"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We&#39;re using <code>getByLabelText</code> to find the input with a specific label. This is nice because it also enforces accessibility best-practices—inputs should always have an associated label, so our test should fail if it doesn&#39;t.</p>

      <h3 id="testing-async"><a class="hash" href="#testing-async" aria-label="Link to heading"></a>Testing async</h3>
    <p>RTL can help testing asynchronous UI updates too. All <code>getBy</code> methods have an equivalent <code>findBy</code> that will wait for a matching element to appear. It returns a promise that either resolves with the element or rejects after a default timeout of 4500ms.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> screen<span class="token punctuation">,</span> fireEvent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"@testing-library/react"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Info <span class="token keyword">from</span> <span class="token string">"./Info"</span><span class="token punctuation">;</span> <span class="token comment">// loads more info on click</span>

<span class="token function">test</span><span class="token punctuation">(</span><span class="token string">"It should load more info"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">LoadMore</span></span><span class="token punctuation">></span></span><span class="token plain-text">Some async info</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">LoadMore</span></span><span class="token punctuation">></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> children <span class="token operator">=</span> screen<span class="token punctuation">.</span><span class="token function">queryByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">some async info</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">expect</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeFalsy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// should not exist until we click</span>

  <span class="token keyword">const</span> button <span class="token operator">=</span> screen<span class="token punctuation">.</span><span class="token function">getByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">more info</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  fireEvent<span class="token punctuation">.</span><span class="token function">click</span><span class="token punctuation">(</span>button<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">await</span> <span class="token function">findByText</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">some async info</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We&#39;re also using the <code>queryBy</code> variant here. This will <em>not</em> throw an error if it can&#39;t find the element. This is useful for asserting that something has <em>not</em> been rendered yet.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Stop exporting things, I'm begging you</title>
    <link href="https://oliverjam.com/articles/stop-exporting-things"/>
    <updated>2019-08-22T15:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/stop-exporting-things</id>
    <content type="html"><![CDATA[<p>Even if you aren&#39;t using <a href="https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md">this rule</a> yourself it seems to have spread its sinister tentacles out into the brains of the community. In my experience most people default to creating a new file whenever they need a new component.</p>
<p>I think this is a bad default.</p>

      <h2 id="modules-are-modules-not-organisers"><a class="hash" href="#modules-are-modules-not-organisers" aria-label="Link to heading"></a>Modules are modules, not organisers</h2>
    <p>Most people seem to think of ES Modules as a mechanism for modularising and organising their code. Whilst they <em>are</em> useful for this, I&#39;d argue that the clue is in the name: they&#39;re <em>modules</em>. They&#39;re designed to divide your code up into isolated scopes. Importing and exporting allow things to cross that boundary.</p>
<p>This means you can consider anything exported from a module part of the &quot;public API&quot; for that file.</p>

      <h2 id="big-render-methods-are-fine"><a class="hash" href="#big-render-methods-are-fine" aria-label="Link to heading"></a>Big render methods are fine</h2>
    <p>JSX is pretty readable. The closing tags make large trees easier to follow (unlike nested function calls/objects that just have anonymous closing brackets).</p>
<p>Try only splitting an element out into a new component when there&#39;s complex conditional rendering logic or lots of stuff that needs to be defined outside of the JSX (e.g. hooks).</p>

      <h3 id="say-no-to-weird-render-functions"><a class="hash" href="#say-no-to-weird-render-functions" aria-label="Link to heading"></a>Say no to weird render functions</h3>
    <p>A weird common pattern that has presumably emerged to counter the over-zealous ESLint rule is the <code>renderThing()</code> method. Someone will decide their JSX is getting a bit long and create a helper function that returns a chunk of it.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token class-name">BigThing</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span>
  <span class="token function">renderSomeStuff</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">Imagine this was longer</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">renderSomeStuff</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>This is like a bastardised pseudo-component. It&#39;s a function that returns a React element, but it doesn&#39;t take props and can&#39;t be rendered using JSX. It&#39;s also usually defined <em>before</em> the render method, so you end up reading some random child elements out of context before you know where they go in the parent.</p>
<p>I honestly can&#39;t see any reason to use this pattern over a simple function component. A component can use hooks, can be memoised, is more idiomatic React—the framework gives you a specific way for modularising your render, so why not use it?</p>

      <h2 id="keep-related-components-in-the-same-file"><a class="hash" href="#keep-related-components-in-the-same-file" aria-label="Link to heading"></a>Keep related components in the same file</h2>
    <p>If you do need to split a chunk of your render out into another component, start out with it in the same file. This is less effort than creating a whole new file and means the new component already has access to everything in scope in the current module.</p>
<p>If you&#39;ve got a few &quot;child&quot; components in one file I find it can be useful to define them below the &quot;main&quot; exported component and rely on hoisting to ensure they&#39;re available at the top. That way someone opening the file sees the most important thing first, and can go read the smaller components when they encounter them in the main render method.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">BigThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">SmallPart</span></span> <span class="token punctuation">/></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">SmallPart</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">Imagine this was longer</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="share-when-you-need-to"><a class="hash" href="#share-when-you-need-to" aria-label="Link to heading"></a>Share when you need to</h2>
    <p>Sharing code always comes with overhead. Once something is in its own file and exported you have to maintain that. Who knows what other dark corners of the codebase are depending on it after some time passes. Are you sure it&#39;s safe to tweak, or refactor, or even delete?</p>
<p>If you definitely need a component in another place then it might be time to extract it to a new file. I would resist this until it&#39;s really obvious that you need it though.</p>
<p>If the component needs to be a bit different in the second place just copy/paste it and tweak the copied version. Making reusable components that fit lots of use-cases is <em>hard</em> - most of the time you just end up with a franken-component that takes forty props and renders a totally different set of JSX for each one.</p>
<p>If you definitely, truly, need the exact same component in another place then sure, move it to its own file and export it. Just be aware that you&#39;ve now committed to maintaining this as something that could hypothetically be used all over the codebase.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Gatsby is the future</title>
    <link href="https://oliverjam.com/articles/gatsby-future"/>
    <updated>2019-07-03T12:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/gatsby-future</id>
    <content type="html"><![CDATA[
      <h2 id="why-wordpress-was-so-successful"><a class="hash" href="#why-wordpress-was-so-successful" aria-label="Link to heading"></a>Why WordPress was so successful</h2>
    <p>I think WordPress has dominated the web for a few reasons.</p>

      <h3 id="free-and-open-source"><a class="hash" href="#free-and-open-source" aria-label="Link to heading"></a>Free and open-source</h3>
    <p>WordPress is free and open-source, but backed by a private company called Automattic. This makes it an obvious default to build on, especially for small to mid-sized sites with limited budgets. If you&#39;re an agency charging under £10k for a basic marketing site plus blog you can&#39;t really afford to splash a decent chunk of that on a framework or content management system.</p>

      <h3 id="easy-hosting"><a class="hash" href="#easy-hosting" aria-label="Link to heading"></a>Easy hosting</h3>
    <p>The proliferation of cheap shared PHP hosting that sprang up in the 2000s made it easy to throw a WordPress site somewhere. There are also lots of well-established (slightly more expensive) dedicated WordPress hosts who manage the installation and upgrade process. This is great for peace of mind after handing a site off to a non-technical client.</p>

      <h3 id="huge-community"><a class="hash" href="#huge-community" aria-label="Link to heading"></a>Huge community</h3>
    <p>There are a lot of developers and businesses contributing themes, plugins and code to WordPress. This makes it easy to install new functionality without writing code yourself.</p>

      <h3 id="great-content-experience"><a class="hash" href="#great-content-experience" aria-label="Link to heading"></a>Great content experience</h3>
    <p>The WordPress CMS makes it easy for non-technical users to log in and update the site. I think developers sometimes underestimate just how important this is—even something as &quot;simple&quot; to us as editing a Markdown file on Github is too much for someone at a small business already doing three jobs who just wants to edit a blog post.</p>

      <h2 id="gatsby-overview"><a class="hash" href="#gatsby-overview" aria-label="Link to heading"></a>Gatsby overview</h2>
    <p>Gatsby started life as a React-based static-site generator. It takes various data sources and uses React components as templates to generate HTML files. The big difference between Gatsby and most static-site generators is that Gatsby also creates a client-side JavaScript app. This best-of-both-worlds approach means your site renders the initial view very quickly, then continues to &quot;boot up&quot; into a full-blown single-page app while the user is browsing. Once enough of the &quot;app&quot; has been loaded navigation becomes instant and doesn&#39;t require server round-trips.</p>

      <h2 id="gatsby-vs-wordpress"><a class="hash" href="#gatsby-vs-wordpress" aria-label="Link to heading"></a>Gatsby vs WordPress</h2>
    <p>Lets revisit the four things that helped WordPress succeed and see how Gatsby matches up.</p>

      <h3 id="free-and-open-source-1"><a class="hash" href="#free-and-open-source-1" aria-label="Link to heading"></a>Free and open-source</h3>
    <p>Gatbsy is also free and open source. There&#39;s a VC-backed company behind the software (<a href="https://www.gatsbyjs.com/">Gatsby Inc</a>) just like Automattic. Gatsby Inc is a <em>little</em> bit smaller than Automattic, but it&#39;s very new. They&#39;ve assembled a <a href="https://www.gatsbyjs.com/about">team of great people</a> who clearly care deeply about building a fantastic tool.</p>

      <h3 id="easy-shared-hosting"><a class="hash" href="#easy-shared-hosting" aria-label="Link to heading"></a>Easy shared hosting</h3>
    <p>Since Gatsby sites are entirely static (everything is either pre-rendered at build time or rendered on the client) you don&#39;t even need your own server. There&#39;s been a boom in cheap (or free!) static hosts with great developer experiences (e.g. Netlify, Now) and Gatsby is positioned to take advantage. You can even throw a Gatsby site on Github Pages if you like.</p>

      <h3 id="huge-community-1"><a class="hash" href="#huge-community-1" aria-label="Link to heading"></a>Huge community</h3>
    <p>The community isn&#39;t as big as WordPress&#39; but it&#39;s growing quickly. The Gatsby ecosystem is built on plugins, and the core Gatsby APIs make it easy to create your own if you can&#39;t find what you&#39;re looking for.</p>

      <h3 id="great-content-experience-1"><a class="hash" href="#great-content-experience-1" aria-label="Link to heading"></a>Great content experience</h3>
    <p>This is where Gatsby is still lacking. A static site is great for many reasons, but it does make content editing more complicated. You&#39;ve got to store the assets somewhere, and without a server and database that means you&#39;re reliant on 3rd party services like <a href="https://www.contentful.com/">Contentful</a> and <a href="https://www.netlifycms.org/">Netlify CMS</a>. Lots of Gatsby sites are developer-focused and store content in Github, but this isn&#39;t as feasible for non-technical editors.</p>

      <h2 id="new-gatsby-features"><a class="hash" href="#new-gatsby-features" aria-label="Link to heading"></a>New Gatsby features</h2>
    
      <h3 id="themes"><a class="hash" href="#themes" aria-label="Link to heading"></a>Themes</h3>
    <p>Gatsby&#39;s new <a href="https://www.gatsbyjs.org/blog/2018-11-11-introducing-gatsby-themes/">Themes</a> are a huge step in the right direction for developers building client sites. Themes allow you to hide all the complexity and setup of big sites that need lots of plugins behind a single dependency. All of the config files and base components/styling can live somewhere else, an <code>npm install</code> away. They&#39;re also quite easy to override using <a href="https://www.christopherbiscardi.com/post/component-shadowing-in-gatsby-child-themes">component shadowing</a>.</p>

      <h3 id="mdx"><a class="hash" href="#mdx" aria-label="Link to heading"></a>MDX</h3>
    <p><a href="https://mdxjs.com/">MDX</a> is a new superset of markdown that also allows JSX (to render React components). Writing in it is a pretty amazing experience, and it will get even better with good CMS support. It&#39;s still fairly new (most Gatsby sites still use Remark Markdown rather than MDX), but it&#39;s getting more and more mature. This very blog is written in MDX if you&#39;d like to see <a href="https://github.com/oliverjam/oliverjam.es/blob/master/content/blog/flicker-avatar-animation/index.mdx">an example</a>.</p>
<p>I find using JSX in MDX is nicer than <a href="https://www.christopherbiscardi.com/post/towards-shortcodes-for-gatsby-sites">shortcodes</a> in WordPress. You can achieve the same functionality, but the syntax for content editors is closer to HTML (a standard). Creating React components is a nicer experience than registering custom shortcodes. You can also leverage any of the pre-existing React components on npm/Github. MDX makes creating custom content very accessible to non-technical users:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token title important"><span class="token punctuation">#</span> My blog post</span>

Hello world

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Youtube</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dQw4w9WgXcQ<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
    </div>
      <h2 id="where-gatsby-outshines-wordpress"><a class="hash" href="#where-gatsby-outshines-wordpress" aria-label="Link to heading"></a>Where Gatsby outshines WordPress</h2>
    
      <h3 id="performance"><a class="hash" href="#performance" aria-label="Link to heading"></a>Performance</h3>
    <p>Gatsby is super fast by default. It&#39;s possible to make a slow Gatsby site, but out of the box it generally gets perfect scores on performance tests. In contrast whilst it is possible to make a super fast WordPress site the default isn&#39;t great. The plugin model means it&#39;s common to come across sites with tons of injected blocking resources, three different copies of JQuery and a generally slower experience.</p>

      <h3 id="data-sourcing"><a class="hash" href="#data-sourcing" aria-label="Link to heading"></a>Data-sourcing</h3>
    <p>WordPress has an opinionated data model. You store everything in the MySQL database and adapt everything to fit how WordPress wants it to work. Gatsby is much more data-agnostic. The plugin system makes it simple to combine different sources of data. You can have markdown files in a Github repo, a Google Sheet and a CMS like Contentful all piping content in to the site at build time.</p>

      <h3 id="developer-experience"><a class="hash" href="#developer-experience" aria-label="Link to heading"></a>Developer experience</h3>
    <p>React has <a href="https://wptavern.com/npms-2019-javascript-ecosystem-survey-shows-63-of-respondents-are-using-react">taken over the JavaScript world</a>. Developers want to use it for everything, but on its own React isn&#39;t well-suited to static sites. Gatsby enabled devs to use the powerful framework they already know to create great static sites as well as apps. The dev experience of Gatsby is pretty incredible too. It&#39;s very quick and easy to get started, especially since you don&#39;t have to worry about getting some LAMP/MAMP setup going and running your own MySQL database locally.</p>

      <h3 id="javascript-all-the-things"><a class="hash" href="#javascript-all-the-things" aria-label="Link to heading"></a>JavaScript all the things</h3>
    <p>For better or worse PHP has <a href="https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages">fallen out of favour</a>, which makes it a bit off-putting to do WordPress development nowadays. It&#39;s kind of nice to be able to use JavaScript for everything. I&#39;ve built a few <a href="https://github.com/oliverjam/workstream-jekyll">Jekyll sites</a> in my time, and as a primarily frontend/JS developer it was awkward having to context switch into Ruby-land to <code>gem install</code> or <code>bundler</code> something. A totally JavaScript API also opens up the world of compile-to-JS languages like <a href="https://www.typescriptlang.org/">TypeScript</a> and <a href="https://reasonml.github.io/">Reason</a>.</p>

      <h3 id="performance-1"><a class="hash" href="#performance-1" aria-label="Link to heading"></a>Performance</h3>
    <p>There&#39;s no other way to say it: Gatsby sites are blazing fast. There are lots of modern best-practices included by default. Pre-rendered static HTML pages are obviously faster than a server hitting a database and rendering on the fly, but Gatsby goes even further. It will automatically split your JavaScript bundle into chunks for each route, so users don&#39;t load more code than they have to. It also smartly preloads assets, and even pages. Since it uses the React runtime once the JS loads it can &quot;boot up&quot; into a single-page app that pre-caches new routes so page navigation becomes instant.</p>

      <h3 id="modern-interaction-paradigm"><a class="hash" href="#modern-interaction-paradigm" aria-label="Link to heading"></a>Modern interaction paradigm</h3>
    <p>WordPress sites usually still rely on JQuery to sprinkle interactivity on top of server rendered pages. When sites require a lot of dynamic interactions this can get pretty gnarly to manage. Gatsby is nice because it&#39;s both a platform for static sites <em>and</em> client-side apps. Since you always have React available it&#39;s pretty trivial to quickly throw a more dynamic &quot;app-like&quot; experience onto certain parts of a site.</p>

      <h2 id="problems-gatsby-needs-to-solve"><a class="hash" href="#problems-gatsby-needs-to-solve" aria-label="Link to heading"></a>Problems Gatsby needs to solve</h2>
    
      <h3 id="content-management"><a class="hash" href="#content-management" aria-label="Link to heading"></a>Content management</h3>
    <p>I think the content management problem is a big one for Gatsby. Until there&#39;s a good (probably included) solution for this I can&#39;t imagine the long tail of agencies building marketing sites for mid-tier companies will jump on board. Third party CMSs are great but they&#39;re usually an extra load of setup (and another thing to break during upgrades down the line) <em>and</em> usually another monthly bill for the client.</p>
<p>This is obviously a difficult challenge for a framework designed to run without a server or database. One possible solution could be a (probably paid) product offering from Gatsby Inc (the company rather than the OSS project) that adds CMS functionality on top for those who need it and want an &quot;integrated&quot; solution. Gatsby Inc are already experimenting with associated products like <a href="https://www.gatsbyjs.com/preview">Gatsby Preview</a> so this isn&#39;t entirely unfeasible.</p>

      <h3 id="authentication"><a class="hash" href="#authentication" aria-label="Link to heading"></a>Authentication</h3>
    <p>This is related to content management—if you want people to be able to update the site you need to be able to authenticate users. Without a server this is pretty difficult. Again there are third-party solutions like <a href="https://authy.com/">Authy</a> and <a href="https://www.netlify.com/docs/identity/">Netlify Identity</a> but this won&#39;t work for everyone.</p>

      <h3 id="mindshare"><a class="hash" href="#mindshare" aria-label="Link to heading"></a>Mindshare</h3>
    <p>There are still huge numbers of developers out there comfortable with their WordPress LAMP stack. If they&#39;re happy and productive then that&#39;s great, but Gatsby needs to find a way to reach them and communicate that there could be something even better. Gatsby also needs to win mindshare amongst clients, as there&#39;s not much an agency can do if a business insists on a WordPress site because that&#39;s what they know.</p>

      <h2 id="final-thoughts"><a class="hash" href="#final-thoughts" aria-label="Link to heading"></a>Final thoughts</h2>
    <p>I love creating Gatsby sites as a developer, and I love browsing Gatsby sites as a user (you can usually tell it&#39;s a Gatsby site when everything is loading <em>instantly</em>). I&#39;ve built WordPress sites in the past and I have a lot of love for what it&#39;s done for the web and open source, but I think the time has come for a new default that really pushes the web forward.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Static typing in JavaScript with Flow</title>
    <link href="https://oliverjam.com/articles/flow-intro"/>
    <updated>2019-06-12T13:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/flow-intro</id>
    <content type="html"><![CDATA[<div style="padding: 2rem; background-color: var(--bg-contrast); grid-column: md-breakout">

<p><strong>Disclaimer</strong></p>
<p>This was written a year ago as an introduction to static typing and the Flow library to help onboard new developers into my team at Ticketmaster. It&#39;s very likely Flow has published new major versions with new features since then; I apologise in advance for any out-of-date information.</p>
</div>


      <h2 id="what-are-types"><a class="hash" href="#what-are-types" aria-label="Link to heading"></a>What are types?</h2>
    <p>A type is something that tells the language what a piece of data is and how it&#39;s intended to be used. For example JavaScript has 6 &quot;primitive&quot; types:</p>
<ol>
<li>Boolean</li>
<li>Null</li>
<li>Undefined</li>
<li>Number</li>
<li>String</li>
<li>Symbol (new in ES6)</li>
</ol>
<p>and a 7th type: Object. Functions are technically also objects that happen to be callable.</p>
<p>You don&#39;t really need to understand JS types in detail to use Flow, but if you&#39;re interested there&#39;s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures">more info on MDN</a>.</p>

      <h2 id="what-is-static-typing"><a class="hash" href="#what-is-static-typing" aria-label="Link to heading"></a>What is static typing?</h2>
    <p>JavaScript is a <em>dynamically</em> typed language. This means the language figures out what a piece of data should be when your program is running.</p>
<p>There are benefits to this: the language doesn&#39;t have to be compiled before you can run your code, and it&#39;s friendlier to beginners because you don&#39;t have to think about types yourself.</p>
<p>There are also downsides: it&#39;s easy to mix up your types and try to do something like <code>4 + &#39;20&#39;</code>, which often results in strange bugs. You also don&#39;t get lots of helpful editor features as you write your code, like smart auto-completion and error highlighting when you try to do things you shouldn&#39;t.</p>
<p><em>Statically</em> typed languages on the other hand either require you to explicitly state what type a data structure is when you create/use it, or will <em>infer</em> the type for you.</p>
<p>This results in slightly more work up-front: thinking about what types your data should be and recording them, but often results in better, more resilient code.</p>

      <h2 id="what-is-flow"><a class="hash" href="#what-is-flow" aria-label="Link to heading"></a>What is Flow?</h2>
    <p>Flow gives us a way to add static types to our JavaScript. You add type annotations to your normal JS code, and the Flow library will check your codebase and ensure everything is correct. There are also editor integrations that can check your code as you write and highlight errors for you.</p>

      <h3 id="how-do-i-get-it"><a class="hash" href="#how-do-i-get-it" aria-label="Link to heading"></a>How do I get it?</h3>
    <p>Install Flow with <code>npm i -D flow-bin</code>. Run <code>npx flow init</code> to generate a <code>.flowconfig</code> file at the root of your project. It&#39;s fine for this to be empty, it just tells Flow where to start. If you need to configure Flow later you&#39;ll use this file.</p>
<p>You can run Flow on your project with <code>npx flow</code>. You might notice this doesn&#39;t do anything. That&#39;s because Flow is designed to be adopted incrementally: you need to opt files in to Flow checking by adding <code>// @flow</code> to the top.</p>

      <h4 id="removing-types"><a class="hash" href="#removing-types" aria-label="Link to heading"></a>Removing types</h4>
    <p>Since Flow isn&#39;t valid JavaScript you need to strip the types out of your code before it runs in a browser. You can do this with the Flow Babel preset.</p>
<p>If aren&#39;t already using Babel install it and the preset with <code>npm i -D babel-cli babel-preset-flow</code>.</p>
<p>Add the preset to a <code>.babelrc</code> file at your project&#39;s root:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token punctuation">{</span>
  <span class="token property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"flow"</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>If you didn&#39;t have a build step before add an npm script for running Babel: <code>&quot;build&quot;: &quot;babel my-src my-output&quot;</code></p>

      <h2 id="using-flow"><a class="hash" href="#using-flow" aria-label="Link to heading"></a>Using Flow</h2>
    
      <h3 id="type-inference"><a class="hash" href="#type-inference" aria-label="Link to heading"></a>Type inference</h3>
    <p>Flow will infer types from your code, so you don&#39;t <em>technically</em> need to write type annotations. For example this function:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">add</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span></code></pre>
    </div><p>won&#39;t cause any Flow errors. You could call it with <code>add(1, 2); // 3</code> or <code>add(&#39;Hello&#39;, &#39; world&#39;); // &#39;Hello world&#39;</code> without problem. However Flow doesn&#39;t know what your <em>intent</em> for this function is, so it also won&#39;t error if you call it with <code>add(1, &#39;2&#39;); // &#39;12&#39;</code>.</p>
<p>This isn&#39;t really making full use of the power of Flow. If your intent for this function is to add two numbers together then you need to communicate that to Flow.</p>

      <h3 id="basic-type-annotation"><a class="hash" href="#basic-type-annotation" aria-label="Link to heading"></a>Basic type annotation</h3>
    <p>We can tell Flow what types our function parameters should be like so:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">add</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">a</span><span class="token operator">:</span> number<span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> number</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span></code></pre>
    </div><p>This tells Flow that <code>a</code> and <code>b</code> should always be numbers.</p>
<p>We can also annotate the return value of the function, to ensure that we always get back what we expect:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> add <span class="token operator">=</span> <span class="token punctuation">(</span>a<span class="token operator">:</span> number<span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> number<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">number</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span></code></pre>
    </div><p>Now Flow will error if we call the function with <code>add(1, &#39;2&#39;); // Cannot call &#39;add&#39; with &#39;2&#39; bound to &#39;b&#39; because string is incompatible with number</code></p>
<p>You can see this yourself and play around with it in the <a href="https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVBjOA7AzgFzAEMATEsAXjAAoiAuMbAVwFsAjAUwCcAaMNhs3bcAlINaculAHzEwAan7pSJagEY+AcgBMmkUA">Flow Repl online</a></p>

      <h3 id="flow-types"><a class="hash" href="#flow-types" aria-label="Link to heading"></a>Flow types</h3>
    
      <h4 id="primitive-types"><a class="hash" href="#primitive-types" aria-label="Link to heading"></a>Primitive types</h4>
    <p>Flow supports all the JS primitive types listed above. Arrays and objects are handled slightly differently because they can <em>contain</em> other types.</p>

      <h5 id="array-types"><a class="hash" href="#array-types" aria-label="Link to heading"></a>Array types</h5>
    <p>You specify an array type with <code>Array&lt;type&gt;</code>. So an array of numbers would be <code>Array&lt;number&gt;</code>. You can put any other Flow type inside an array. If your array contains values of different types you can use the <a href="#Mixed-types"><code>mixed</code> type</a> explained below (<code>Array&lt;mixed&gt;</code>).</p>
<p>These can be made even more specific by using a &quot;tuple&quot; type. This is like an array but with a specific length and specific type per &quot;slot&quot;. These are defined using square brackets: <code>[string, number, string]</code>. This tuple must contain 3 things: a string, a number and another string, in that order.</p>

      <h5 id="object-types"><a class="hash" href="#object-types" aria-label="Link to heading"></a>Object types</h5>
    <p>You can create object types with a similar syntax to JS objects:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">Component</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">props</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> string <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">Hello </span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">;</span></code></pre>
    </div><p>Object types can have optional properties marked with a question mark:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">Component</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">props</span><span class="token operator">:</span> <span class="token punctuation">{</span> name<span class="token operator">?</span><span class="token operator">:</span> string <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">Hello </span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token string">"world"</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This can get confusing when combined with object destructuring:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">Component</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> name <span class="token punctuation">}</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> string <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">Hello </span><span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">;</span></code></pre>
    </div><p>In these cases using <a href="#Type-aliases">type aliases</a> can be more readable (especially as the number of object properties grows).</p>
<p>It&#39;s also possible to type objects that aren&#39;t static (e.g. they may have dynamically added or removed properties). You can use square brackets to specify a type for the object&#39;s keys:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">takesObject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">x</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span>string<span class="token punctuation">]</span><span class="token operator">:</span> number <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator">...</span><span class="token punctuation">;</span></code></pre>
    </div><p>This means <code>x</code> is an object that always has string keys and number values, but may have any number of properties.</p>

      <h4 id="literal-types"><a class="hash" href="#literal-types" aria-label="Link to heading"></a>Literal types</h4>
    <p>You can also use literal values as types. For example if a string should always be <code>&#39;open&#39;</code> you can set the type as <code>&#39;open&#39;</code> instead of <code>string</code>.</p>

      <h4 id="union-types"><a class="hash" href="#union-types" aria-label="Link to heading"></a>Union types</h4>
    <p>&quot;union&quot; types allow a value to be more than one type. For example we could allow our <code>add</code> function to accept numbers <em>or</em> strings:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> add <span class="token operator">=</span> <span class="token punctuation">(</span>a<span class="token operator">:</span> number <span class="token operator">|</span> string<span class="token punctuation">,</span> <span class="token literal-property property">a</span><span class="token operator">:</span> number <span class="token operator">|</span> string<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">number</span> <span class="token operator">=></span>
  <span class="token function">Number</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">Number</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>Note that you must ensure you&#39;re returning the correct type (here by converting the arguments to numbers before adding them).</p>
<p>Union types can be powerful when combined with literal types:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> getColour <span class="token operator">=</span> <span class="token punctuation">(</span>status<span class="token operator">:</span> <span class="token string">'success'</span> <span class="token operator">|</span> <span class="token string">'warning'</span> <span class="token operator">|</span> <span class="token string">'danger'</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span><span class="token punctuation">(</span>status<span class="token punctuation">)</span><span class="token operator">:</span>
    <span class="token keyword">case</span> <span class="token string">'success'</span><span class="token operator">:</span> <span class="token keyword">return</span> <span class="token string">'green'</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token string">'warning'</span><span class="token operator">:</span> <span class="token keyword">return</span> <span class="token string">'orange'</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token string">'danger'</span><span class="token operator">:</span> <span class="token keyword">return</span> <span class="token string">'red'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Now Flow knows that <code>getColour</code> should only ever be passed &#39;success&#39;, &#39;warning&#39; or &#39;danger&#39; and will error if anyone ever tries to pass something different.</p>
<p>This makes using strings in this way (known as &quot;enums&quot;) much safer and more powerful (see <a href="https://twitter.com/DavidKPiano/status/972620672743673856">this Tweet on using enums instead of booleans for state values</a>).</p>

      <h4 id="mixed-types"><a class="hash" href="#mixed-types" aria-label="Link to heading"></a>Mixed types</h4>
    <p>Sometimes you want to allow any type of input to a function because you know you&#39;re going to handle it in the code. You can use the <code>mixed</code> type for this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> stringify <span class="token operator">=</span> <span class="token punctuation">(</span>a<span class="token operator">:</span> mixed<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">string</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> a <span class="token operator">===</span> <span class="token string">"string"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> a<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> a <span class="token operator">===</span> <span class="token string">"null"</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> a <span class="token operator">===</span> <span class="token string">"undefined"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">""</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> a <span class="token operator">===</span> <span class="token string">"number"</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> a <span class="token operator">===</span> <span class="token string">"boolean"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> a<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> a<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">" "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> a <span class="token operator">===</span> <span class="token string">"object"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">turnObjectIntoString</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>This is a bit contrived but you get the idea. You can pass anything in to the function, but because the return value should be a string you need to handle all the different possible argument types inside the function.</p>

      <h4 id="maybe-types"><a class="hash" href="#maybe-types" aria-label="Link to heading"></a>Maybe types</h4>
    <p>You can mark an argument as a <code>maybe</code> type with a question mark:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token function-variable function">exponentize</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">value</span><span class="token operator">:</span> number<span class="token punctuation">,</span> <span class="token literal-property property">exponent</span><span class="token operator">:</span> <span class="token operator">?</span>number</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>exponent<span class="token punctuation">)</span> <span class="token keyword">return</span> value <span class="token operator">**</span> exponent<span class="token punctuation">;</span>
  <span class="token keyword">return</span> value <span class="token operator">**</span> <span class="token number">2</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Flow will allow this argument to be missing, <code>null</code> or explicitly set to <code>undefined</code>.</p>
<p>You will need to check the value is available in your code before you use it otherwise Flow can&#39;t guarantee that you won&#39;t hit a null/undefined error at runtime.</p>

      <h4 id="danger-any-type"><a class="hash" href="#danger-any-type" aria-label="Link to heading"></a>Danger: any type</h4>
    <p>Flow offers an escape hatch for code that you might want to be checked, but you don&#39;t have to time to add proper types to right now. You can use <code>any</code> as a type to completely opt out of Flow checking for that value.</p>
<p>Be careful with this as <code>any</code> can leak through your code as you use the value in other places.</p>

      <h3 id="type-aliases"><a class="hash" href="#type-aliases" aria-label="Link to heading"></a>Type aliases</h3>
    <p>Sometimes you want to split out a long or complex type so it doesn&#39;t pollute a function declaration. It&#39;s also helpful to be able to reuse common types. You can create type aliases for this using the <code>type</code> keyword:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">type ViewportType <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">small</span><span class="token operator">:</span> <span class="token number">320</span><span class="token punctuation">,</span>
  <span class="token literal-property property">medium</span><span class="token operator">:</span> <span class="token number">480</span><span class="token punctuation">,</span>
  <span class="token literal-property property">large</span><span class="token operator">:</span> <span class="token number">768</span><span class="token punctuation">,</span>
  <span class="token literal-property property">xlarge</span><span class="token operator">:</span> <span class="token number">1200</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token function-variable function">MediaQueries</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">viewports</span><span class="token operator">:</span> ViewportType</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator">...</span><span class="token punctuation">;</span></code></pre>
    </div><p>These can be imported and exported just like normal JS objects.</p>

      <h3 id="sharing-types"><a class="hash" href="#sharing-types" aria-label="Link to heading"></a>Sharing types</h3>
    <p>The simplest way to share types is to create type aliases. These can be used throughout a file, or exported to import in another file.</p>
<p>If you find yourself using lots of aliases it might be useful to make them available globally. The simplest way to do this is to create a folder called <code>flow-typed</code> at the root of your project. Anything in here will automatically be picked up by Flow.</p>

      <h3 id="third-party-code"><a class="hash" href="#third-party-code" aria-label="Link to heading"></a>Third-party code</h3>
    <p>It wouldn&#39;t be a JavaScript project without some <code>node_modules</code>. Flow needs type definitions for any third party code that you&#39;re relying on in order to work effectively.</p>
<p>Some libraries export untranspiled copies of all their JS files (with Flow types intact) as <code>.js.flow</code> files. In this case Flow will automatically find the types and work without you doing anything.</p>
<p>The <a href="https://github.com/flowtype/flow-typed"><code>flow-typed</code></a> project exists for libraries that don&#39;t have their own Flow type definitions. It&#39;s a repository of user-submitted typings for popular libraries. You can run <code>npx flow-typed install package@version</code> to generate type definitions for a package in your <code>flow-typed</code> directory.</p>
<p>If <code>flow-typed</code> doesn&#39;t have definitions for a library it can optionally create a &quot;stub&quot; of empty types, which will at least stop Flow generating errors for the library.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Introduction to the DOM</title>
    <link href="https://oliverjam.com/articles/dom-intro"/>
    <updated>2019-03-03T16:30:00.000Z</updated>
    <id>https://oliverjam.com/articles/dom-intro</id>
    <content type="html"><![CDATA[<p>This is my attempt to bridge the gap between JavaScript <em>the language</em> and the bits of it you need to know to make things happen on a web page. It will assume you have a basic understanding of HTML and JS, but are new to actually using JS on a web page.</p>

      <h2 id="what-is-the-document-object-model"><a class="hash" href="#what-is-the-document-object-model" aria-label="Link to heading"></a>What is the Document Object Model?</h2>
    <p>The Document Object Model (DOM) is the JavaScript representation of the elements on a webpage.</p>
<p>It&#39;s implemented by web browsers, rather than the JavaScript language itself. It&#39;s important to recognise this distinction—JavaScript is a general purpose programming language (although it originated on the web), but browsers implement specific <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs">Web APIs</a> within the language.</p>
<p>A browser&#39;s DOM APIs are how you access and manipulate elements within the page—for example to read the value of an input, or add another item into a list.</p>

      <h2 id="using-the-dom"><a class="hash" href="#using-the-dom" aria-label="Link to heading"></a>Using the DOM</h2>
    
      <h3 id="accessing-elements"><a class="hash" href="#accessing-elements" aria-label="Link to heading"></a>Accessing elements</h3>
    <p>There are a few useful methods for accessing elements on a webpage. Almost all DOM methods live on the global <code>document</code> object, which means you access them like this: <code>document.someMethod()</code>.</p>

      <h4 id="documentqueryselector"><a class="hash" href="#documentqueryselector" aria-label="Link to heading"></a><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector"><code>document.querySelector()</code></a></h4>
    <p>This allows you to select an element on the page using a <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors">CSS selector</a>.</p>
<p>For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>will find the first <code>&lt;button&gt;</code> element on the page.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> para <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">".container > p.text-large"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>will find the first <code>&lt;p&gt;</code> element that has a classname of <code>&quot;text-large&quot;</code> and is a direct child of an element with a classname of <code>&quot;container&quot;</code>.</p>

      <h4 id="documentqueryselectorall"><a class="hash" href="#documentqueryselectorall" aria-label="Link to heading"></a><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll"><code>document.querySelectorAll()</code></a></h4>
    <p>This is used to select multiple elements that match the same CSS selector. It returns a <a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeList">NodeList</a> of the matching elements.</p>
<p>It&#39;s important to note that a NodeList is <em>not</em> the same as an array. This means you can&#39;t use most array methods (like <code>map</code> or <code>reduce</code>). NodeLists do have a <code>forEach</code> method if you need to do something with each element. Alternatively you can use <code>Array.from(nodeList)</code> to turn it into an array with no limitations.</p>
<p>For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button-1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button-2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button-3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btns <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
btns<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">btn</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"ID is: "</span> <span class="token operator">+</span> btn<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ID is button-1</span>
<span class="token comment">// ID is button-2</span>
<span class="token comment">// ID is button-3</span></code></pre>
    </div>
      <h4 id="element"><a class="hash" href="#element" aria-label="Link to heading"></a><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element"><code>Element</code></a></h4>
    <p>This is the JS representation of an element on the page. It&#39;s what you&#39;ll be dealing with once you&#39;ve used <code>querySelector</code> to assign an element to a variable.</p>

      <h5 id="element-properties"><a class="hash" href="#element-properties" aria-label="Link to heading"></a>Element properties</h5>
    <p>A DOM element is an object with various properties. These will include attributes you may have set (e.g. <code>id</code> or <code>className</code>) as well as inherent properties like <code>clientWidth</code> and <code>clientHeight</code>.</p>
<p>You can access these just like any other object properties:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn--primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>btn<span class="token punctuation">.</span>className<span class="token punctuation">,</span> btn<span class="token punctuation">.</span>textContent<span class="token punctuation">,</span> btn<span class="token punctuation">.</span>clientHeight<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// "btn--primary", "Hello", 44</span></code></pre>
    </div><p>Different properties will be available depending on the type of element. For example an <code>HTMLInputElement</code> like an <code>input</code> or <code>select</code> will have a <code>.value</code> property, but a basic <code>HTMLElement</code> (like a <code>div</code>) will not.</p>

      <h3 id="user-input"><a class="hash" href="#user-input" aria-label="Link to heading"></a>User input</h3>
    <p>Being able to access elements on the page isn&#39;t very useful if you can&#39;t react to user actions. To do this we add an &quot;event listener&quot; using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener"><code>element.addEventListener()</code></a>.</p>
<p><code>addEventListener</code> has two required arguments:</p>
<ol>
<li><strong>Type</strong>: The type of event to listen for (e.g. <code>&quot;click&quot;</code>, <code>&quot;submit&quot;</code> etc)</li>
<li><strong>Listener</strong>: A function to run when that event happens</li>
</ol>
<p>For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#my-button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// select the first element with an ID of "my-button"</span>
btn<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> handleClick<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>would run the <code>handleClick</code> function whenever someone clicked on that button.</p>
<p>We need to define the <code>handleClick</code> function for this to work. The function will be called with the event that triggered this listener as its argument:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleClick</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// MouseEvent {</span>
<span class="token comment">//   ...</span>
<span class="token comment">//   clientX: 479</span>
<span class="token comment">//   clientY: 238</span>
<span class="token comment">//   target: button#my-button</span>
<span class="token comment">//   type: "click"</span>
<span class="token comment">//   x: 479</span>
<span class="token comment">//   y: 238</span>
<span class="token comment">//   ...</span>
<span class="token comment">// }</span></code></pre>
    </div><p>There are <a href="https://developer.mozilla.org/en-US/docs/Web/Events">a lot of different events</a>, although you&#39;ll usually only use a few:</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/Events/click">Click</a>: usually to make a button trigger something</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/Events/keydown">Keydown</a>: to add keyboard controls</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/Events/change">Change</a>: for reacting to updates in an input</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/Events/submit">Submit</a>: to get the result of a submitted form</li>
</ul>

      <h3 id="updating-the-dom"><a class="hash" href="#updating-the-dom" aria-label="Link to heading"></a>Updating the DOM</h3>
    <p>You usually need to change something on the page after receiving user input. This may mean toggling an element&#39;s visibility or colour, or adding a totally new element.</p>

      <h4 id="reading-and-writing-attributes"><a class="hash" href="#reading-and-writing-attributes" aria-label="Link to heading"></a>Reading and writing attributes</h4>
    <p>Most element attributes can be set directly as object properties:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
btn<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">"set-from-js"</span><span class="token punctuation">;</span></code></pre>
    </div><p>This will override any previous value, so be careful.</p>

      <h4 id="adding-and-removing-class-names"><a class="hash" href="#adding-and-removing-class-names" aria-label="Link to heading"></a>Adding and removing class names</h4>
    <p>Since setting a property directly only allows a single value, it can be difficult to work with multiple class names. You can use the <code>element.classList</code> API to make this easier.</p>

      <h5 id="adding-class-names"><a class="hash" href="#adding-class-names" aria-label="Link to heading"></a>Adding class names</h5>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

btn<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"btn--primary"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>btn<span class="token punctuation">.</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "btn btn--primary"</span></code></pre>
    </div><p>This will add a class without overwriting any that already exist.</p>

      <h5 id="removing-class-names"><a class="hash" href="#removing-class-names" aria-label="Link to heading"></a>Removing class names</h5>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

btn<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"btn--primary"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>btn<span class="token punctuation">.</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "btn"</span></code></pre>
    </div>
      <h5 id="toggling-a-class-name"><a class="hash" href="#toggling-a-class-name" aria-label="Link to heading"></a>Toggling a class name</h5>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> btn <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

btn<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span><span class="token string">"btn--primary"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>btn<span class="token punctuation">.</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "btn"</span>

btn<span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span><span class="token string">"btn--primary"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>btn<span class="token punctuation">.</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "btn btn--primary"</span></code></pre>
    </div><p>This will check if a class name already exists. If so it will remove the class, otherwise it will add it.</p>

      <h4 id="toggling-element-visibility"><a class="hash" href="#toggling-element-visibility" aria-label="Link to heading"></a>Toggling element visibility</h4>
    <p>HTML5 introduced the <code>hidden</code> property. This determines whether the browser should show it. Note that this doesn&#39;t just mean visually: a hidden element will also be removed from screenreader output. It can be set like any other attribute:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
button<span class="token punctuation">.</span>hidden <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h4 id="creating-elements"><a class="hash" href="#creating-elements" aria-label="Link to heading"></a>Creating elements</h4>
    <p>You can create totally new elements in JavaScript:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> myButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

button<span class="token punctuation">.</span>id <span class="token operator">=</span> <span class="token string">"myBtn"</span><span class="token punctuation">;</span>
button<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Submit"</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myButton<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;button id="myBtn">Submit&lt;/button></span></code></pre>
    </div><p>However this element will not exist within the DOM (on the actual page) until you put it there.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#container"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> myButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"button"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
button<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token string">"Submit"</span><span class="token punctuation">;</span>

container<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>myButton<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;div id="container">&lt;button>Submit&lt;/button>&lt;/div></span></code></pre>
    </div>
      <h2 id="putting-it-all-together"><a class="hash" href="#putting-it-all-together" aria-label="Link to heading"></a>Putting it all together</h2>
    <p>Let&#39;s build a to-do list to see all these concepts work together.</p>

      <h3 id="step-1-structure"><a class="hash" href="#step-1-structure" aria-label="Link to heading"></a>Step 1: structure</h3>
    <p>We need to take user input (new to-do items), which means we&#39;ll need a <code>form</code> with some inputs. We also need to display the list of to-do items, which probably means a <code>ul</code>.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>newTodo<span class="token punctuation">"</span></span> <span class="token attr-name">required</span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Add +<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
    </div><p>We&#39;ll need references to some of these elements in our JavaScript.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> form <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"form"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> list <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"ul"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="step-2-user-input"><a class="hash" href="#step-2-user-input" aria-label="Link to heading"></a>Step 2: user input</h3>
    <p>When the user submits the form with a new to-do we want to capture this. We&#39;ll do so by adding an event listener for the form&#39;s <code>&quot;submit&quot;</code> event.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> handleSubmit<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We then need to write the <code>handleSubmit</code> function that will be run when the user submits the form.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;form></span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We call the <code>preventDefault()</code> method on the event to stop the form&#39;s default behaviour from happening. This would attempt to send the submission to a server and reload the page. Since we&#39;re handling the submission entirely within JS on the page we don&#39;t want this default behaviour.</p>
<p>The <code>event.target</code> property refers to the element the event came from (in this case the <code>&lt;form&gt;</code>). This will allow us to access the elements inside the form:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p><code>event.target.elements</code> is an <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormControlsCollection"><code>HTMLFormControlsCollection</code></a> containing the elements within the form.</p>
<p>Since we gave our <code>input</code> a name attribute of &quot;newTodo&quot; it will be available here as <code>event.target.elements.newTodo</code>. This will give us a full reference to the input element and all its properties.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>newTodo<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;input type="text" name="newTodo" required /></span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We need the value of this input to create our new to-do:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> value <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>newTodo<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "write blog post" (whatever the user entered)</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="step-3-updating-the-dom"><a class="hash" href="#step-3-updating-the-dom" aria-label="Link to heading"></a>Step 3: updating the DOM</h3>
    <p>Now that we have enough information to add a new to-do entry we can update the DOM.</p>
<p>First we need to create a new list element and set its text content:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> value <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>newTodo<span class="token punctuation">.</span>value<span class="token punctuation">;</span>

  <span class="token keyword">const</span> newItem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"li"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  newItem<span class="token punctuation">.</span>textContent <span class="token operator">=</span> value<span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newItem<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;li>write blog post&lt;/li></span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Then we can put the new item into the DOM:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> value <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>newTodo<span class="token punctuation">.</span>value<span class="token punctuation">;</span>

  <span class="token keyword">const</span> newItem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"li"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  newItem<span class="token punctuation">.</span>textContent <span class="token operator">=</span> value<span class="token punctuation">;</span>
  list<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>newItem<span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;ul>&lt;li>write blog post&lt;/li>&lt;/ul></span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="final-code"><a class="hash" href="#final-code" aria-label="Link to heading"></a>Final code</h3>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>newTodo<span class="token punctuation">"</span></span> <span class="token attr-name">required</span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Add +<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> form <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"form"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> list <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"ul"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> handleSubmit<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">handleSubmit</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> value <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>newTodo<span class="token punctuation">.</span>value<span class="token punctuation">;</span>

  <span class="token keyword">const</span> newItem <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"li"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  newItem<span class="token punctuation">.</span>textContent <span class="token operator">=</span> value<span class="token punctuation">;</span>
  list<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>newItem<span class="token punctuation">)</span><span class="token punctuation">;</span>

  form<span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// reset inputs so user can enter another to-do</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Here&#39;s <a href="https://codepen.io/oliverjam/pen/zbBxOz">a working Codepen</a> if you want to play around. If you want some practice try adding a delete button to the to-do items.</p>
<video autoPlay muted loop>
  <source src="/assets/media/basic-todo.mp4" type="video/mp4" />
</video>
]]></content>
  </entry>
      
  <entry>
    <title>Introduction to Redux</title>
    <link href="https://oliverjam.com/articles/redux-intro"/>
    <updated>2019-02-22T12:00:00.000Z</updated>
    <id>https://oliverjam.com/articles/redux-intro</id>
    <content type="html"><![CDATA[
      <h2 id="principles"><a class="hash" href="#principles" aria-label="Link to heading"></a>Principles</h2>
    <p>Redux has three <a href="https://redux.js.org/introduction/three-principles">Principles</a>:</p>
<ol>
<li>Your state has a single source of truth (one top-level object)</li>
<li>Your state is read-only (can only be updated by dispatching actions)</li>
<li>Your state is only altered by pure functions</li>
</ol>
<p>These principles are designed to help state management remain predictable even as an app or team grows much larger.</p>

      <h2 id="core-concepts"><a class="hash" href="#core-concepts" aria-label="Link to heading"></a>Core Concepts</h2>
    
      <h3 id="state"><a class="hash" href="#state" aria-label="Link to heading"></a>State</h3>
    <p>Your single source of truth for state is by convention called the &quot;store&quot;. This store is usually structured as an object.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">todos</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1234</span><span class="token punctuation">,</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"Do a thing"</span><span class="token punctuation">,</span> <span class="token literal-property property">done</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1235</span><span class="token punctuation">,</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"Do another thing"</span><span class="token punctuation">,</span> <span class="token literal-property property">done</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">showDone</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="actions"><a class="hash" href="#actions" aria-label="Link to heading"></a>Actions</h3>
    <p>You describe updates to this store using &quot;actions&quot;. An action is an object with a <code>type</code> property that describes what kind of update it is.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token constant">ADD_TODO</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"ADD_TODO"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Actions can optionally contain other properties with data necessary for the update:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> <span class="token constant">ADD_TODO</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"ADD_TODO"</span><span class="token punctuation">,</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"Do a third thing"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
    </div><p>Your application can fire these actions using the <code>dispatch</code> function. This is provided by Redux, as we&#39;ll see shortly.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"ADD_TODO"</span><span class="token punctuation">,</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"Do a third thing"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="reducers"><a class="hash" href="#reducers" aria-label="Link to heading"></a>Reducers</h3>
    <p>A reducer is a function that is called every time an action is dispatched. It receives the current state and the dispatched action as arguments, and returns the updated state.</p>
<p>The simplest possible reducer would receive no actions and always return the state unchanged:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> initialState <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">todos</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">showDone</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span><span class="token parameter">state <span class="token operator">=</span> initialState<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> state<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We default the <code>state</code> argument to whatever we want our initial state to be so that the first time the reducer runs it returns the state in the shape we want.</p>
<p>Reducers are the only way to alter your state in Redux, which means all possible state updates are in one place.</p>
<p>By convention reducers usually use <code>switch</code> statements to handle different action types.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span><span class="token parameter">state <span class="token operator">=</span> initialState<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">switch</span> <span class="token punctuation">(</span>action<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token string">"ADD_TODO"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> newTodo <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">text</span><span class="token operator">:</span> action<span class="token punctuation">.</span>text<span class="token punctuation">,</span> <span class="token literal-property property">done</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> newTodos <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>state<span class="token punctuation">.</span>todos<span class="token punctuation">,</span> newTodo<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">todos</span><span class="token operator">:</span> newTodos <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">case</span> <span class="token string">"CLEAR_TODOS"</span><span class="token operator">:</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>state<span class="token punctuation">,</span> <span class="token literal-property property">todos</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token keyword">default</span><span class="token operator">:</span>
      <span class="token keyword">return</span> state<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Since the reducer is supposed to be pure you should always return a <em>new copy</em> of the state, rather than mutating the old value. The spread operator helps a lot with this.</p>
<p>Reducers should also return the state unchanged if no valid action type is dispatched (the default case).</p>

      <h2 id="usage"><a class="hash" href="#usage" aria-label="Link to heading"></a>Usage</h2>
    <p>These concepts come together with a a helper method from Redux: <code>createStore()</code>. We pass this our reducer and it returns our store.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"redux"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> initialState <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token comment">//...</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">reducer</span><span class="token punctuation">(</span><span class="token parameter">state <span class="token operator">=</span> initialState<span class="token punctuation">,</span> action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">//...</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>reducer<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>We can now dispatch actions from the store to update our state:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax">store<span class="token punctuation">.</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"ADD_TODO"</span><span class="token punctuation">,</span> <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token string">"Do a thing"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
store<span class="token punctuation">.</span><span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// {</span>
<span class="token comment">//   todos: [</span>
<span class="token comment">//     { id: 123, text: "Do a thing", done: false }</span>
<span class="token comment">//   ],</span>
<span class="token comment">//   showDone: true</span>
<span class="token comment">// }</span></code></pre>
    </div><p>It&#39;s important to note that we&#39;ve only used one method from the base Redux package. This store can be used with any UI code you like. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>add-todo<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>add<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Add todo<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>add<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>todoText<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">></span></span>Add +<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">//...</span>
<span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>reducer<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> form <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#add-todo"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
form<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> text <span class="token operator">=</span> event<span class="token punctuation">.</span>target<span class="token punctuation">.</span>elements<span class="token punctuation">.</span>addTodo<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"ADD_TODO"</span><span class="token punctuation">,</span> text <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="vanilla-js-example"><a class="hash" href="#vanilla-js-example" aria-label="Link to heading"></a>Vanilla JS Example</h3>
    <p>Putting together the examples gives us a relatively functional todo app: <a href="https://codesandbox.io/s/qq293xpvx4">https://codesandbox.io/s/qq293xpvx4</a></p>

      <h2 id="complexity"><a class="hash" href="#complexity" aria-label="Link to heading"></a>Complexity</h2>
    <p>You may be thinking that the Redux code you&#39;ve seen in the wild is much more complex than this. This is because there are some common patterns (or boilerplate) that are used to ensure consistency in larger apps. These aren&#39;t required to use Redux and may even make an app unnecessarily complex if embraced too quickly.</p>

      <h3 id="type-constants"><a class="hash" href="#type-constants" aria-label="Link to heading"></a>Type Constants</h3>
    <p>Since action types are just strings it&#39;s easy to mistype them or use the wrong value. It&#39;s common to use variables to represent these types so they can be shared across different files.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token constant">ADD_TODO</span> <span class="token operator">=</span> <span class="token string">"ADD_TODO"</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="action-creators"><a class="hash" href="#action-creators" aria-label="Link to heading"></a>Action Creators</h3>
    <p>It&#39;s quite common to create your actions using small functions, rather than constructing the objects manually. Similar to using type constants, this centralises this logic and prevents mistakes.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token constant">ADD_TODO</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./constants"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">addTodo</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token constant">ADD_TODO</span><span class="token punctuation">,</span> text <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

store<span class="token punctuation">.</span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token function">addTodo</span><span class="token punctuation">(</span><span class="token string">"Do a thing"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h3 id="multiple-reducers"><a class="hash" href="#multiple-reducers" aria-label="Link to heading"></a>Multiple Reducers</h3>
    <p>As an app gets more complex you may find it difficult to manage all of your state in one huge object. Your reducer might be doing a lot of unnecessary work just ensuring that it duplicates every field when returning state (<code>return {...state, todos: [...state.todos], other: {...state.other, nested: ...state.other.nested }}</code> etc).</p>
<p>Redux gives you the ability to break your state up into logical chunks, with a reducer for each one. Since <code>createStore()</code> expects a single reducer argument we must combine our separate reducer with <code>combineReducers()</code> before creating our store:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> combineReducers<span class="token punctuation">,</span> createStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"redux"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> reducer1<span class="token punctuation">,</span> reducer2 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./reducers"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> reducer <span class="token operator">=</span> <span class="token function">combineReducers</span><span class="token punctuation">(</span><span class="token punctuation">{</span> reducer1<span class="token punctuation">,</span> reducer2 <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>reducer<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h2 id="usage-with-react"><a class="hash" href="#usage-with-react" aria-label="Link to heading"></a>Usage with React</h2>
    <p>The <code>react-redux</code> package provides some useful abstractions for managing your Redux store and connecting your components to it so they can access the state (and re-render when it changes).</p>
<p>Using Redux with React requires understanding a few extra React-specific concepts.</p>

      <h3 id="concepts"><a class="hash" href="#concepts" aria-label="Link to heading"></a>Concepts</h3>
    
      <h4 id="context"><a class="hash" href="#context" aria-label="Link to heading"></a>Context</h4>
    <p>Usually React app data (state and props) flows down through the component tree, passed to children as props. React provides a way to bypass this &quot;prop-drilling&quot; and make data available anywhere in the tree: <a href="https://reactjs.org/docs/context.html">context</a>.</p>
<p>Having a global single source of truth for your state is a core principle of Redux. So it makes sense to provide this state to your components via context.</p>

      <h5 id="context-provider"><a class="hash" href="#context-provider" aria-label="Link to heading"></a>Context Provider</h5>
    <p>The <code>&lt;Provider&gt;</code> component wraps your entire component tree and &quot;provides&quot; the store via context.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> createStore <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"redux"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> Provider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-redux"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> reducer <span class="token keyword">from</span> <span class="token string">"./reducer"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> store <span class="token operator">=</span> <span class="token function">createStore</span><span class="token punctuation">(</span>reducer<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Provider</span></span> <span class="token attr-name">store</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>store<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">Hello world</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span><span class="token class-name">Provider</span></span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h3 id="accessing-state"><a class="hash" href="#accessing-state" aria-label="Link to heading"></a>Accessing State</h3>
    <p>Your state is now available anywhere in your component tree—but how do you access it? <code>react-redux</code> provides a higher-order component that lets your component grab just the bits of state it needs.</p>

      <h4 id="higher-order-components"><a class="hash" href="#higher-order-components" aria-label="Link to heading"></a>Higher-order Components</h4>
    <p>An HoC is a function that wraps a component and returns a new copy of that component with some extra props added. For example:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// add.js</span>
<span class="token keyword">function</span> <span class="token function">withAdd</span><span class="token punctuation">(</span><span class="token parameter">Component</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token function-variable function">add</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token keyword">class</span> <span class="token class-name">extends</span> React<span class="token punctuation">.</span>Component <span class="token punctuation">{</span>
    <span class="token function-variable function">add</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span>
    <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Component</span></span> <span class="token spread"><span class="token punctuation">{</span><span class="token operator">...</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">}</span></span> <span class="token attr-name">add</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>add<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">Test</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>props<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">withAdd</span><span class="token punctuation">(</span>Test<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token comment">// index.js</span>
<span class="token keyword">import</span> Add <span class="token keyword">from</span> <span class="token string">""</span><span class="token punctuation">.</span><span class="token operator">/</span>add"<span class="token punctuation">;</span>

ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token class-name">Add</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> root<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// &lt;div>5&lt;/div></span></code></pre>
    </div><p>Since we have exported the <em>wrapped</em> version of <code>Test</code> it will have access to the additional <code>add</code> prop from <code>withAdd</code> whenever we use it, without having to pass the prop ourselves. This isn&#39;t very useful here as we could just import <code>add</code>, but when combined with context it allows us to have up-to-date access to dynamic values.</p>

      <h4 id="connect-hoc"><a class="hash" href="#connect-hoc" aria-label="Link to heading"></a>Connect HoC</h4>
    <p><code>react-redux</code> provides an HoC called <code>connect</code>. This wraps your component, grabs some state from the Redux store context and then passes that state as extra props onto your wrapped component.</p>

      <h4 id="accessing-state-with-connect"><a class="hash" href="#accessing-state-with-connect" aria-label="Link to heading"></a>Accessing State with <code>connect</code></h4>
    <p>You choose which state you want by passing a function to <code>connect</code>. It will call your function with the current state from the store, and expects you to return an object of the props to pass to your component.</p>
<p>This function is usually called <code>mapStateToProps</code>. Calling <code>connect</code> with <code>mapStateToProps</code> returns another function, which you call with your component to inject the state as props.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> connect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-redux"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">Todos</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> todos <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span>todos<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">todo</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>id<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
      <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token function-variable function">mapStateToProps</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">state</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">todos</span><span class="token operator">:</span> state<span class="token punctuation">.</span>todos<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">connect</span><span class="token punctuation">(</span>mapStateToProps<span class="token punctuation">)</span><span class="token punctuation">(</span>Todos<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p><a href="https://react-redux.js.org/using-react-redux/connect-mapstate">Read more about accessing state in the docs.</a></p>

      <h4 id="updating-state-with-connect"><a class="hash" href="#updating-state-with-connect" aria-label="Link to heading"></a>Updating State with <code>connect</code></h4>
    <p>React components only access the Redux store via <code>connect</code>. This means we cannot dispatch actions with <code>store.dispatch()</code> as we did before. <code>connect</code> will pass <code>dispatch</code> to your wrapped component as a prop.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> connect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-redux"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">ClearTodos</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dispatch <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token function-variable function">clear</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"CLEAR_TODOS"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>clear<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text">Clear all todos</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">(</span>Todos<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div>
      <h5 id="mapdispatchtoprops"><a class="hash" href="#mapdispatchtoprops" aria-label="Link to heading"></a><code>mapDispatchToProps</code></h5>
    <p>You can avoid having to manually dispatch actions like this by providing a second argument to <code>connect</code>. This should be a function that takes <code>dispatch</code> and returns an object of state updating functions to be passed to your component as props.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> connect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-redux"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">ClearTodos</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> clear <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>clear<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text">Clear all todos</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> <span class="token function-variable function">mapDispatchToProps</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">dispatch</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token function-variable function">clear</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"CLEAR_TODOS"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> mapDispatchToProps<span class="token punctuation">)</span><span class="token punctuation">(</span>Todos<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// note we explicitly pass nothing as the first argument (mapStateToProps)</span>
<span class="token comment">// since we don't need to access state</span></code></pre>
    </div><p>If you&#39;re using <a href="#Action-Creators">action creator functions</a> you can pass an object of action creators here, which will automatically have <code>dispatch</code> bound to them:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">import</span> <span class="token punctuation">{</span> connect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-redux"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> clearTodos <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"./actions"</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">ClearTodos</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> clear <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>clear<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text">Clear all todos</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token function">connect</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">clear</span><span class="token operator">:</span> clearTodos <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span>Todos<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p><a href="https://react-redux.js.org/using-react-redux/connect-mapdispatch">Read more about updating state in the docs.</a></p>
<p>If you&#39;re curious you can also check out Dan Abramov&#39;s <a href="https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e">simplified implementation of <code>connect</code></a> to see roughly what it&#39;s doing.</p>

      <h3 id="full-react-example"><a class="hash" href="#full-react-example" aria-label="Link to heading"></a>Full React Example</h3>
    <p>Putting together all our little examples from above gives us a fully functional todo app: <a href="https://codesandbox.io/s/qp3l3zvo6">https://codesandbox.io/s/qp3l3zvo6</a></p>
]]></content>
  </entry>
      
  <entry>
    <title>Create a flickering image effect using CSS sprites</title>
    <link href="https://oliverjam.com/articles/flicker-avatar-animation"/>
    <updated>2016-12-01T22:40:32.169Z</updated>
    <id>https://oliverjam.com/articles/flicker-avatar-animation</id>
    <content type="html"><![CDATA[<p><a href="%22https://github.com/fogleman/primitive%22">Primitive</a> came to my attention a while ago as a nice tool for creating vectorised images. I was enamoured with the flickering effect achieved by animating between multiple versions of the same photo (Primitive produces different versions each time it is run).</p>

      <h2 id="animation"><a class="hash" href="#animation" aria-label="Link to heading"></a>Animation</h2>
    <p>There are a few different ways to achieve this effect — the Primitive pencil example uses JavaScript to repeatedly switch each image from <code>display: none</code> to <code>display: block</code> in order. I felt like this would be a perfect case to experiment with <abbr title="cascading style sheets">CSS</abbr> sprite animation.</p>
<p>Sprite animation is similar to a flipbook: you create a &#39;sprite&#39; (a long image containing each frame of your animation) and then use <abbr>CSS</abbr> keyframes to animate along this image.</p>
<p>The tricks to get it working are putting the sprite in a container the size of a single frame (so only one frame is visible at a time), and using <code>steps()</code> as your <code>animation-timing-function</code>.</p>

      <h2 id="steps"><a class="hash" href="#steps" aria-label="Link to heading"></a>Steps</h2>
    <p>By default keyframe animations tween between each frame to create smooth motion. In this case however this ruins the effect:</p>
<style>
@keyframes slide {
  to {
    transform: translateX(-100%);
  }
}

.stage__image {
  animation-name: slide;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
  margin: 0;
  max-width: none;
}

.steps {
  animation-timing-function: steps(3);
}

.final {
  animation-duration: 0.25s;
}

.stage {
  margin-left: auto;
  margin-right: auto;
  width: 256px;
  height: 256px;
  border: 0.25rem solid;
  transform: translate3D(0, 0, 0);
}

.stage--final {
  border-radius: 50%;
  overflow: hidden;
}

</style>

<div class="stage">
  <img
    class="stage__image"
    src="/assets/media/profile-pic.jpg"
    alt=""
  >
</div>

<p>We want the animation to jump from frame to frame, giving the illusion of animation. The <code>steps()</code> function can be confusing (especially if you don&#39;t know that it takes an optional second value of &#39;start&#39; or &#39;end&#39;). <a href="%22https://designmodo.com/steps-css-animations/%22">This article</a> explains better than I could how it works, but for this particular purpose we can just set set the same number of steps as frames in our sprite.</p>
<div class="stage">
  <img
    class="stage__image steps"
    src="/assets/media/profile-pic.jpg"
    alt=""
  >
</div>


      <h2 id="the-sprite"><a class="hash" href="#the-sprite" aria-label="Link to heading"></a>The sprite</h2>
    <p>I generated three different versions of the same image using the <a href="%22https://ondras.github.io/primitive.js/%22">JavaScript fork of Primitive</a> and then stitched them together in Preview. This in itself was a bit of a hassle as you can&#39;t change the canvas size without also resizing the image. You need to select all, cut the image, adjust image size to 300% width, then re-paste the first image and move to the left edge. You can then cut and paste the next two images alongside the first to fill the remaining space.</p>
<p><img src="undefined" alt="three slightly different versions of my face"></p>

      <h2 id="the-code"><a class="hash" href="#the-code" aria-label="Link to heading"></a>The code</h2>
    <p>Once you&#39;ve got your sprite you can start writing code. We need a container to hide the extra frames. One downside to this technique is that it requires a specific size to be set on the container — the size of a single frame of your sprite.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sprite<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span>
    <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sprite__img<span class="token punctuation">"</span></span>
    <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/assets/media/sprite.png<span class="token punctuation">"</span></span>
    <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>An animated avatar of Oli<span class="token punctuation">"</span></span>
  <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.sprite</span></span> <span class="token punctuation">{</span>
  <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">256</span><span class="token unit">px</span><span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">256</span><span class="token unit">px</span><span class="token punctuation">;</span>
  <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>We then need to animate the image within the container. The below code will move the sprite its full length to the left every 0.3s, but in 3 discrete steps (moving 33% of its length each step). This means each frame of the sprite is displayed for 0.1s before jumping to the next one.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.sprite__img</span></span> <span class="token punctuation">{</span>
  <span class="token property">animation</span><span class="token punctuation">:</span> flicker <span class="token number">0.25</span><span class="token unit">s</span> <span class="token function">steps</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> infinite<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> flicker</span> <span class="token punctuation">{</span>
  <span class="token selector">to</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token number">-100</span><span class="token unit">%</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div>
      <h2 id="border-radius-bug"><a class="hash" href="#border-radius-bug" aria-label="Link to heading"></a>Border-radius bug</h2>
    <p>I wanted my avatar to be circular rather than square, so I put <code>border-radius: 50%</code> on the containing <code>div</code>. This was fine until I added the animation, which apparently triggered a <a href="%22https://bugs.chromium.org/p/chromium/issues/detail?id=157218%22">long-standing bug in Chrome</a> causing animated children to overflow their containers (something to do with Chrome promoting the animated element to a new layer for performance).</p>
<p>You can solve this by also promoting the parent element to a new layer with <code>transform: translate3D(0, 0, 0)</code>. So the final <abbr>CSS</abbr> looks like this:</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.sprite</span></span> <span class="token punctuation">{</span>
  <span class="token property">width</span><span class="token punctuation">:</span> <span class="token number">256</span><span class="token unit">px</span><span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> <span class="token number">256</span><span class="token unit">px</span><span class="token punctuation">;</span>
  <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token number">50</span><span class="token unit">%</span><span class="token punctuation">;</span>
  <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translate3D</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.sprite__img</span></span> <span class="token punctuation">{</span>
  <span class="token property">animation</span><span class="token punctuation">:</span> flicker <span class="token number">0.25</span><span class="token unit">s</span> <span class="token function">steps</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> infinite<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> flicker</span> <span class="token punctuation">{</span>
  <span class="token selector">to</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span><span class="token number">-100</span><span class="token unit">%</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>And here&#39;s the end result:</p>
<div class="stage stage--final">
  <img
    class="stage__image steps final"
    src="/assets/media/sprite.png"
    alt=""
  >
</div>

]]></content>
  </entry>
      
  <entry>
    <title>How to create a Ken Burns hero image effect</title>
    <link href="https://oliverjam.com/articles/ken-burns-hero-image"/>
    <updated>2016-11-16T22:40:32.169Z</updated>
    <id>https://oliverjam.com/articles/ken-burns-hero-image</id>
    <content type="html"><![CDATA[
      <h2 id="the-design-process"><a class="hash" href="#the-design-process" aria-label="Link to heading"></a>The design process</h2>
    <p>The first iteration of this hero area featured several looping videos, but we quickly ran into performance issues. There was no way to get multiple videos at a high enough quality to do justice to Lick&#39;s work without forcing users to download unfeasibly large files. We also struggled to provide a good user experience for mobile browsers that either refused to autoplay video or forced the video to display inline.</p>
<p>I suggested we instead try using still images with a <a href="http://en.wikipedia.org/wiki/Ken_Burns_effect">Ken Burns</a> style pan and zoom animation using <abbr title="cascading style sheets">css</abbr>. Using optimised jpegs allowed file sizes to stay manageable and <abbr>CSS</abbr> transforms gave a nice sense of motion without stressing the browser too much. As a bonus this even worked perfectly on mobile.</p>
<p>We deliberately chose stock imagery as we found that showing actual work on the frontpage of the previous site needed updating constantly to stop the page from looking stale. Using high quality stock imagery that subtly referred to some of Lick&#39;s clients (grass for Spurs, paint for Wilko etc).</p>

      <h2 id="the-code"><a class="hash" href="#the-code" aria-label="Link to heading"></a>The code</h2>
    <p>The basic idea here is to absolutely position a &#39;stack&#39; of images within a container, animate the image to zoom in and move across, then fade out the top image and move it to the bottom of the stack and repeat.</p>

      <h3 id="html"><a class="hash" href="#html" aria-label="Link to heading"></a>HTML</h3>
    <p>We need a full viewport container with some images.</p>
<div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hero<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>js-hero<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hero__image js-animating<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image1.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hero__image<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image2.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hero__image<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image3.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
    </div><p>The <code>js-hero</code> <abbr title="identifier">ID</abbr> will be used to target the container later. The <code>js-animating</code> class will be used to apply the <abbr>CSS</abbr> animations. The first image starts with this class applied to ensure it animates as soon as it loads, without waiting for the javascript to download and execute. This also provides a graceful degradation for users without JavaScript — they still see a single image animate.</p>

      <h3 id="css"><a class="hash" href="#css" aria-label="Link to heading"></a>CSS</h3>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.hero</span></span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
  <span class="token property">min-height</span><span class="token punctuation">:</span> <span class="token number">600</span><span class="token unit">px</span><span class="token punctuation">;</span>
  <span class="token property">min-height</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">vh</span><span class="token punctuation">;</span>
  <span class="token property">overflow</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.hero__image</span></span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  <span class="token property">min-width</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span>
  <span class="token property">min-height</span><span class="token punctuation">:</span> <span class="token number">100</span><span class="token unit">%</span><span class="token punctuation">;</span>
  <span class="token property">transform-origin</span><span class="token punctuation">:</span> top left<span class="token punctuation">;</span>
  <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token property">will-change</span><span class="token punctuation">:</span> opacity<span class="token punctuation">,</span> transform<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.hero__image</span><span class="token pseudo-class">:nth-child</span><span class="token punctuation">(</span><span class="token n-th"><span class="token number">2n</span></span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token property">transform-origin</span><span class="token punctuation">:</span> top right<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.hero__image</span><span class="token pseudo-class">:nth-child</span><span class="token punctuation">(</span><span class="token n-th"><span class="token number">3n</span></span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token property">transform-origin</span><span class="token punctuation">:</span> bottom right<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>The container is set to be at least as tall as the viewport (with a fallback for browsers that <a href="http://caniuse.com/#feat=viewport-units">don&#39;t support viewport units</a>), and has its overflow hidden so the images within don&#39;t spill out when zoomed by the animation.</p>
<p>The images are positioned absolutely within the container with a minimum width and height of 100%, ensuring they fill the container at any aspect ratio. This means the image will crop when the window is resized, so consider using the <a href="https://developer.mozilla.org/en/docs/Web/HTML/Element/picture">picture element</a> to specify different image files at different window widths.</p>
<p>Each image has a different corner set as its transform-origin. This is so we can apply the same <abbr>CSS</abbr> animation later on but have each image look as if it&#39;s moving in a different direction.</p>
<p>We also set the opacity to 0, allowing our animation to fade the pictures in, and we tell the browser to expect these elements to change opacity and transform (using the new <a href="https://developer.mozilla.org/en/docs/Web/CSS/will-change">will-change</a> property). This can help with performance and is an official version of the old transform3d hack to force <abbr title="graphics processing unit">GPU</abbr> rendering.</p>

      <h3 id="animation"><a class="hash" href="#animation" aria-label="Link to heading"></a>Animation</h3>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token selector"><span class="token class">.js-animating</span></span> <span class="token punctuation">{</span>
  <span class="token property">animation</span><span class="token punctuation">:</span> fade <span class="token number">3</span><span class="token unit">s</span> forwards<span class="token punctuation">,</span> zoom <span class="token number">15</span><span class="token unit">s</span> linear forwards<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector"><span class="token class">.js-animating</span><span class="token pseudo-class">:first-child</span> <span class="token combinator">+</span> img <span class="token combinator">~</span> img</span> <span class="token punctuation">{</span>
  <span class="token property">z-index</span><span class="token punctuation">:</span> <span class="token number">-1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> fade</span> <span class="token punctuation">{</span>
  <span class="token selector">100%</span> <span class="token punctuation">{</span>
    <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> zoom</span> <span class="token punctuation">{</span>
  <span class="token selector">100%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span><span class="token number">1.2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
    </div><p>Here we describe two animations, &#39;fade&#39; and &#39;zoom&#39;. The first will fade an image in and the second will increase an image to 120% of its original size.</p>
<p>The <code>js-animating</code> class sets both of these animations (using the <a href="https://css-tricks.com/snippets/css/keyframe-animation-syntax/">animation shorthand</a>). The fade is relatively short, as we want the new image to fade in and be visible for most of the animation, whilst the zoom is long so the image keeps slowly moving throughout.</p>
<p>Zoom has its <code>animation-timing-function</code> set to linear as I found any easing here looks strange (Ken Burns effects tend to have a consistent pan speed). Finally both have their <code>animation-direction</code> set to forwards to ensure they stay in their final frame state (rather than snapping back to how they started).</p>

      <h3 id="javascript"><a class="hash" href="#javascript" aria-label="Link to heading"></a>Javascript</h3>
    <div class="Code">
      
      <pre><code class="CodeSyntax"><span class="token keyword">const</span> hero <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"js-hero"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> heroImages <span class="token operator">=</span> hero<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">".hero__image"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> numberOfImages <span class="token operator">=</span> heroImages<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
<span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">kenBurns</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">===</span> numberOfImages<span class="token punctuation">)</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  heroImages<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"js-animating"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> heroImages<span class="token punctuation">[</span>numberOfImages <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"js-animating"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> heroImages<span class="token punctuation">[</span>numberOfImages <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"js-animating"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>i <span class="token operator">></span> <span class="token number">1</span><span class="token punctuation">)</span> heroImages<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">.</span>classList<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token string">"js-animating"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  i<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
window<span class="token punctuation">.</span><span class="token function">setInterval</span><span class="token punctuation">(</span>kenBurns<span class="token punctuation">,</span> <span class="token number">6000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
    </div><p>This is where the magic happens. We first select our container, then our nodelist of images. We also need the total number of images, <code>numberOfImages</code> and a counter variable <code>i</code>, which is initially 1.</p>
<p>The <code>kenBurns()</code> function does the actual work. It checks whether the counter is equal to the total number of images, and resets the counter to zero if so. This is so the first image is shown again after the loop has finished.</p>
<p>The function then adds the <code>js-animating</code> class to the second image (at index 1 in the nodelist). We then need to make sure the animating class is removed from not the previous image but the one before that. Otherwise we wouldn&#39;t get the nice fade out to the next image.</p>
<p>The next three lines of code make this happen — when the counter is at zero <code>js-animating</code> is removed from the second last image in the stack, which lets the final image fade out as the first image fades back in. When the counter is equal to one the animating class is removed from the final image in the stack, and for any other value of the counter the class is removed from the image before the previous one.</p>
<p>(I&#39;m aware this logic is convoluted, but I can&#39;t think of a way of improving on this. As long as it works…)</p>
<p>We then increment the counter variable by one so that the next image is shown each time the function runs.</p>
<p>The function is run by setting an interval. The time in milliseconds here determines how long each iteration of the function will last (and therefore how long each image will get to animate). This takes a little playing with to get the exact effect you&#39;re looking for.</p>
]]></content>
  </entry>
      
  <entry>
    <title>Why I donate 10% of my income to charity</title>
    <link href="https://oliverjam.com/articles/why-i-donate-to-charity"/>
    <updated>2016-07-11T22:40:32.169Z</updated>
    <id>https://oliverjam.com/articles/why-i-donate-to-charity</id>
    <content type="html"><![CDATA[<p>Imagine you’re crossing a bridge on your way to work. As you reach the middle you hear splashing and a cry for help. There’s a young child in the water!</p>
<p>Glancing around you realise that you can’t see anybody else — if you don’t jump in and pull the child out they’ll drown for sure. This is going to inconvenience you, as you’ll have to go home and change your wet clothes. As soon as this thought crosses your mind you dismiss it of course. What kind of person would let a kid drown to avoid being late to work?</p>
<p><strong>Inconvenience is not an excuse for letting a child die.</strong></p>
<p>You pull the kid out, go home, change clothes and get to work slightly late but feeling fantastic.</p>
<p>The following week you are on the bridge again when you hear splashing. No way, you think, how unlikely. But sure enough there’s a child struggling in the water, calling for help. This time they’re further away though, too far for you to swim in your business shoes and suit.</p>
<p>You are carrying a briefcase though. You realise that the briefcase floats, so throwing it to the child will help them stay above the water and paddle to shore. Glancing down at the case you think for a second about the cost of replacing it and the papers inside. It’s not a really nice briefcase, but along with the contents it’s worth about £50 to you.</p>
<p>Again you shake your head and dismiss the thought — who would let a child die to save £50? You toss the child your briefcase and they make it to the shore.</p>
<p><strong>Cost is not an excuse for letting a child die.</strong></p>
<p>Another week goes by before you find yourself on the bridge again. This time you’re walking with a few of your friends. You’ve been telling them about your strange experiences on the bridge when, sure enough, you hear splashing and cries for help. This time there are five children scattered around the river! You jump straight in and pull one of the kids to shore.</p>
<p>Feeling good about your lack of indecision and moral fortitude you glance up to find your friends still standing on the bridge. They look appropriately concerned and are talking to each other about how awful it is that children drown in rivers, but they aren’t doing anything to help.</p>
<p>You feel frustrated for a moment. Why should I keep saving these drowning children when nobody else is helping? It’s not fair! You don’t mean it though, so you dive back in to pull as many children as you can from the river.</p>
<p><strong>Lack of popular support is not an excuse for letting a child die.</strong></p>
<p>I earn just under the average London salary. Giving What We Can’s <a href="https://www.givingwhatwecan.org/get-involved/how-rich-am-i/">‘How Rich Am I?’</a> calculator tells me that donating 10% of my income would move me from the richest 1.7% of people in the world to the richest 2.1%. I would barely notice the change, but that money could cure over 4000 children of parasitic worms per year (statistically saving two children&#39;s live).</p>
<p>If you would save a child drowning in a river you need to at least think about how you justify not saving at least some of the thousands of children living in poverty around the world.</p>
<p>I’ll write about the best ways to distribute your resources in Part 2, but if you want to learn more about Effective Altruism right now I recommend <a href="https://www.ted.com/talks/peter_singer_the_why_and_how_of_effective_altruism">Peter Singer’s TED Talk</a> and either <a href="USA">GiveWell</a> or <a href="UK">Giving What We Can</a>.</p>
]]></content>
  </entry>
      
  <entry>
    <title>A readable guide to writing more readable content</title>
    <link href="https://oliverjam.com/articles/readable-guide-to-readable-content"/>
    <updated>2016-07-08T22:40:32.169Z</updated>
    <id>https://oliverjam.com/articles/readable-guide-to-readable-content</id>
    <content type="html"><![CDATA[<p>Writing informative articles for the web is not like writing for other mediums. People read differently online — they open lots of links at once and flick from tab to tab, scanning up and down each page to find the information they want as quickly as possible. The easier to read and absorb your writing is, the more people you will reach.</p>

      <h2 id="sentences-and-paragraphs"><a class="hash" href="#sentences-and-paragraphs" aria-label="Link to heading"></a>Sentences and paragraphs</h2>
    
      <h3 id="line-length"><a class="hash" href="#line-length" aria-label="Link to heading"></a>Line Length</h3>
    <p>Limit your sentences to under 25 words. This limit is a compromise between easy reading and expressing complicated ideas. <a href="http://webcache.googleusercontent.com/search?q=cache:dGEifPIq0gIJ:prsay.prsa.org/2009/01/14/how-to-make-your-copy-more-readable-make-sentences-shorter/">Research suggests</a> readers understand 90% of a 14 word sentence, but only 10% of a 43 word sentence.</p>
<blockquote>
<p>More people fear snakes than full stops, so they recoil when a long sentence comes hissing across the page.</p>
<p>— <cite>Martin Cutts, Oxford Guide To Plain English</cite></p>
</blockquote>
<p>People tend to scan websites rather than read the whole page in order. They only fully read <a href="https://www.nngroup.com/articles/how-little-do-users-read/">about 25%</a> of the text, so it’s important to get your meaning across quickly.</p>
<p>Following a long sentence requires more concentration, which means the reader has to hold several ideas in their head at once. This makes it harder to actually take in the meaning of a sentence.</p>
<p>Shorter sentences also force you to be more concise as a writer. This helps you express clear ideas that everyone immediately understands.</p>

      <h3 id="paragraph-length"><a class="hash" href="#paragraph-length" aria-label="Link to heading"></a>Paragraph Length</h3>
    <p>This also applies to <a href="https://www.prsa.org/Intelligence/Tactics/Articles/view/10215/1078/Cut_it_down_Readers_skip_long_paragraphs">paragraph length</a>. Most paragraphs should have no more than three or four 25-word sentences. Each sentence should support the same point, so the paragraph argues for a single idea. If you find a paragraph growing longer than this, consider breaking it out into two separate points.
Breaking your content into smaller chunks also helps people scan the page for the relevant bits of information they need.</p>
<p>Don’t be scared of very short paragraphs!</p>

      <h2 id="language-use"><a class="hash" href="#language-use" aria-label="Link to heading"></a>Language use</h2>
    
      <h3 id="write-in-plain-english"><a class="hash" href="#write-in-plain-english" aria-label="Link to heading"></a>Write in plain English</h3>
    <p>Your writing should be suitable for everyone. Use simple alternatives to complex or formal words. Try ‘help’ instead of ‘assist’ and ‘about’ instead of ‘approximately’. If you need to use technical terms then do, just make sure you explain them the first time they appear.</p>
<p>This even applies to highly educated readers. <a href="https://gds.blog.gov.uk/2014/02/17/guest-post-clarity-is-king-the-evidence-that-reveals-the-desperate-need-to-re-think-the-way-we-write/">The more educated a person is the simpler they prefer their text.</a></p>

      <h3 id="use-direct-language"><a class="hash" href="#use-direct-language" aria-label="Link to heading"></a>Use direct language</h3>
    <p>Use concrete language to make your ideas easier to visualise.</p>
<p>Write literally. Figurative writing can be harder to understand and often doesn’t say what you mean.</p>

      <h3 id="use-the-active-voice"><a class="hash" href="#use-the-active-voice" aria-label="Link to heading"></a>Use the ‘active voice’</h3>
    <p>The subject of your sentence should be performing the action. If the subject is sitting passively, unrelated to the verb, then you might be using the passive voice. An easy way to tell is to <a href="https://www.grammarly.com/blog/a-scary-easy-way-to-help-you-find-passive-voice/">try inserting “by zombies”</a> after the verb. If the result makes sense then you should re-work the sentence to use the active voice.</p>
<p>The passive voice is okay to use in <a href="https://www.grammarly.com/blog/how-to-use-the-passive-voice-correctly-2/">certain situations</a>, like describing a general truth, or an action with an unknown subject, or for focusing attention on the object being acted upon. In most situations the active voice will be more appropriate.</p>

      <h2 id="page-structure"><a class="hash" href="#page-structure" aria-label="Link to heading"></a>Page structure</h2>
    
      <h3 id="use-subheadings"><a class="hash" href="#use-subheadings" aria-label="Link to heading"></a>Use subheadings</h3>
    <p>Dividing your content into subheadings lets readers scan the page to find what they need. As people tend to only read 25% of a page it’s good to give them obvious clues to the content of each section.</p>
<p>Use a subheading summarising the following content every few paragraphs. This also makes the page more inviting, as the reader never sees a long mass of text that they’ll have to work through to find what they want.</p>

      <h3 id="summarise"><a class="hash" href="#summarise" aria-label="Link to heading"></a>Summarise</h3>
    <p>Make sure your reader knows at all times what your point is. Tell them what you’re going to say at the beginning, then say it, and finally recap what you just told them. You’re trying to get people to understand information — keeping them in suspense is not helpful here.</p>
<p>This structure can lead to boring writing (which will cause your reader to disengage), so make sure you fill the middle with interesting content.</p>

      <h2 id="conclusion"><a class="hash" href="#conclusion" aria-label="Link to heading"></a>Conclusion</h2>
    <p>You’re not writing a beautiful novel. If you want people to stay on your article, find the information they need and actually take it all in, then you should:</p>
<ol>
<li>Write less</li>
<li>Write simply</li>
<li>Break up your content</li>
</ol>
]]></content>
  </entry>
      
</feed>