<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jim Burbridge</title>
    <description>The latest articles on DEV Community by Jim Burbridge (@jhechtf).</description>
    <link>https://dev.to/jhechtf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F213243%2F452ddc8f-bd4c-4143-8259-4981b3af7f63.jpg</url>
      <title>DEV Community: Jim Burbridge</title>
      <link>https://dev.to/jhechtf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jhechtf"/>
    <language>en</language>
    <item>
      <title>Into the Fray: A Dive into Deno</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Mon, 27 Jun 2022 07:55:00 +0000</pubDate>
      <link>https://dev.to/jhechtf/into-the-fray-a-dive-into-deno-4h9j</link>
      <guid>https://dev.to/jhechtf/into-the-fray-a-dive-into-deno-4h9j</guid>
      <description>&lt;p&gt;Tl;Dr: I just wanted to build a simple CLI in Deno, and now I've made at least 5 repositories related to Deno in the search to flush out the ecosystem. I'm not done yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;I've been following Deno since stumbling across Ryan Dahl's talk about things he wishes he'd have done different with Node JS(embedded below). &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/M3BM9TB-8yA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;When 1.0 came out I was itching to try and do something with the runtime. Recently, I got a chance to try something.&lt;/p&gt;

&lt;p&gt;Previously where I worked we had a &lt;a href="https://spectrum.adobe.com/page/design-tokens/"&gt;Design Token&lt;/a&gt; library. I wasn't entirely sure how it worked, but in thinking about it I thought it should be easy to make something that would generate tokens for my own projects. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Well, I made it.&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jhechtf"&gt;
        jhechtf
      &lt;/a&gt; / &lt;a href="https://github.com/jhechtf/design-tokens"&gt;
        design-tokens
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Design token generator written in Deno + TS
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Raven (Design Token Generator)&lt;/h1&gt;
&lt;p&gt;Trying to create design tokens that can be used in CSS, SCSS, and
Javascript/Typescript?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Yeah, me too.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
Notes&lt;/h2&gt;
&lt;p&gt;In the end I hope that there will be two ways that users can use this library:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In code, by importing the relevant items / functions and building it
themselves or&lt;/li&gt;
&lt;li&gt;By using a CLI tool with a config file (aiming for it to be TS, but
considering JSON) to generate it the necessary files in one shot.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;Currently the code can be used with the following examples.&lt;/p&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-smi"&gt;MediaQuery&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-smi"&gt;Stylesheet&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-smi"&gt;Token&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'./mod.ts'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-c"&gt;// Creates a new stylesheet&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;stylesheet&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;Stylesheet&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-c"&gt;// create the tokens.&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;primaryToken&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;Token&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'primary-color'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;'#fecc99'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;spacingToken&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;Token&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'gap'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;'4px'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s"&gt;'size'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;blueToken&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-smi"&gt;Token&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'blue-100'&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jhechtf/design-tokens"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;As Deno (in particular deno.land/x/) works with GitHub when a tag is pushed to the repository I had wanted to do something like NodeJS' "Standard Version." I asked on the Github page if there was a plan to port Standard Version over to Deno, and after not receiving a response I started on &lt;a href="https://github.com/jhechtf/version-bump"&gt;Version Bump&lt;/a&gt;(aren't I the greatest at names?).&lt;/p&gt;

&lt;p&gt;This portion took quite a bit of time, and went through at least 2 system overhauls that I can remember. My goal was to make Version Bump much more pluggable than Standard Version was, and in doing that I had to be very careful with how I worked with things. I could honestly write a whole post about Version Bump, but I had wanted to hit a 1.0 release but wanted to ensure I had hit a code coverage target before going forward.&lt;/p&gt;

&lt;p&gt;Well, turns out there's built in code coverage in Deno's testing, and even a way to get it into a format that isn't totally weird. Downside though, is that there wasn't a way I found to get this information into a report table like I was accustomed to (thanks Jest).&lt;/p&gt;

&lt;p&gt;Can you guess what I did next?&lt;/p&gt;

&lt;p&gt;That's right, &lt;em&gt;built my own!&lt;/em&gt;. &lt;a href="https://github.com/jhechtf/code-coverage"&gt;Code Coverage&lt;/a&gt; Takes an LCOV file generated through test data and the &lt;code&gt;deno coverage&lt;/code&gt; command and outputs a nice little table for you.&lt;/p&gt;

&lt;p&gt;Except the table breaks the viewport when you have a larger file that has many missing blocks of text. &lt;/p&gt;

&lt;p&gt;I had to build &lt;a href="https://github.com/jhechtf/deno-terminal-size"&gt;Terminal Size&lt;/a&gt;, using a combination of a very nice Rust package and Deno's Foreign Function Interface in order to get this to work. However, this meant that I had to use a different table library because the one I was using wouldn't be work with the terminal size out of the box. &lt;em&gt;Yup, another package.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jhechtf/ascii-table"&gt;ASCII Table&lt;/a&gt; Uses the terminal size library to get the terminal size if requested. Unfortunately this requires a lot of permission from Deno's sandbox, and the use of the &lt;code&gt;--unstable&lt;/code&gt; flag so I doubt people will use it until it no longer requires that flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Impressions
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;What have you learned?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A couple of things: &lt;/p&gt;

&lt;h3&gt;
  
  
  I really enjoy Deno.
&lt;/h3&gt;

&lt;p&gt;Direct TS? No fiddling with TS-Node or having to declare TS as a package? I love it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Since it is newer, it's ecosystem is not as flushed out.
&lt;/h3&gt;

&lt;p&gt;This ends up showing up in weird places; you know, like trying to get your code coverage into a quick and precise format. I'm going to see about contributing back to the deno project's coverage command, but I feel like I should know more about Rust before doing that. I don't want for the Code Coverage tool to be a necessary third-party tool in the Deno ecosystem going forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sometimes the permissions thing feels a little like it gets in the way.
&lt;/h3&gt;

&lt;p&gt;Especially for CLI libraries such Raven, Version Bump, or Code Coverage. On the one hand being able to run and install a library only in the current directory could be great, but on the other it feels more like a hurdle than anything else. One thing I &lt;em&gt;wish&lt;/em&gt; I could've done was determine if the current script was being run with the &lt;code&gt;--unstable&lt;/code&gt; flag to dynamically load my terminal library, allowing people who aren't using the full-width feature to scope down their permissions. &lt;/p&gt;

&lt;p&gt;Please feel free to try out any of the tools I've made, and any ideas for improvements please go ahead and create an issue on the given Github. Any PRs are welcomed!&lt;/p&gt;

</description>
      <category>deno</category>
      <category>typescript</category>
      <category>rust</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The World's Worst Todo App</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sat, 23 Oct 2021 03:37:42 +0000</pubDate>
      <link>https://dev.to/jhechtf/the-worlds-worst-todo-app-15g9</link>
      <guid>https://dev.to/jhechtf/the-worlds-worst-todo-app-15g9</guid>
      <description>&lt;p&gt;There's plenty of great todo list applications out there. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://vicci.dev"&gt;Vicci&lt;/a&gt; is definitely not one of them.&lt;/p&gt;

&lt;p&gt;However, that's not what its aim is.&lt;/p&gt;

&lt;p&gt;You see, Vicci started life as what was meant to be a front-end only project to show some architecture examples to a friend of mine. We call him "Vinny", and every time I was writing something to help him the old latin phrase "veni, vidi, vici" ("I came, I saw, I conquered"). The last bit of that, "vici", is where I drew the name for the project. It means "I conquered," and I think that's pretty uplifting of a motto for a list of things that needs to get done.&lt;/p&gt;

&lt;p&gt;Once I started to go really hard into the code I realized that it would be nice if there was some kind of user system, so I thought "well I'll just add a Cognito, and that way the user can login and out" but after that I thought "I mean, if the user system is out of the way, what's stopping me from building a simple API?" So... I did.&lt;/p&gt;

&lt;p&gt;The result is a project far removed from the "quick and dirty" app that I wanted to start with, and is instead an app in a weird state as of writing this. &lt;/p&gt;

&lt;p&gt;The UI is... let's say &lt;em&gt;rough&lt;/em&gt;. It wasn't meant to be, but this all started as a way to show off the architecture more than the view. As such, the API is also pretty rough. &lt;/p&gt;

&lt;p&gt;That's fine though. It's more a chance to talk about the tech and architecture used in it, specially in the context of a "Serverless" app on AWS. &lt;/p&gt;

&lt;p&gt;That all said, let's talk about the tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React + TypeScript&lt;/li&gt;
&lt;li&gt;TailwindCss&lt;/li&gt;
&lt;li&gt;Webpack&lt;/li&gt;
&lt;li&gt;AWS SAM, includes AWS Lambda and API Gateway&lt;/li&gt;
&lt;li&gt;AWS CloudFront&lt;/li&gt;
&lt;li&gt;AWS S3&lt;/li&gt;
&lt;li&gt;AWS CDK&lt;/li&gt;
&lt;li&gt;Route53&lt;/li&gt;
&lt;li&gt;AWS Certificate Manager (for the SSL certs in prod)&lt;/li&gt;
&lt;li&gt;GitHub as source control version host.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice, nothing too outrageous, odds are if you already work in the web right now most of these are things you have at least &lt;em&gt;some&lt;/em&gt; experience with. I will (eventually) get to the point where tag pushes to any of the github repos will also trigger a deployment of said resource, but was running into issues and wanted to get this published before my job got busy.&lt;/p&gt;

&lt;p&gt;I'm open to feedback from other engineers, and questions from people new to programming in this space. Please create an issue on the corresponding Github repo and I'll address it as soon as I can.&lt;/p&gt;

&lt;p&gt;Til then, welcome to the world's worst todo app.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>A(nother) Todo List: Version 1.2</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sun, 07 Mar 2021 04:25:48 +0000</pubDate>
      <link>https://dev.to/jhechtf/a-nother-todo-list-version-1-2-4hlo</link>
      <guid>https://dev.to/jhechtf/a-nother-todo-list-version-1-2-4hlo</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This post refers to &lt;a href="https://gitlab.com/jhechtf/vanilla-todo/-/tree/version-1.2"&gt;this branch&lt;/a&gt;, and is a part of an ongoing series.&lt;/p&gt;

&lt;p&gt;Version 1.2 looks a little different, yet again. As the README states in the repo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This branch is the version of the application where the developer has started more work into finding a solution where directly modifying the todo values links those changes to the DOM.&lt;/p&gt;

&lt;p&gt;For this version of the project I've chosen a very rough implementation of the Observer pattern, as I think that of the ways that frameworks and updates function currently that this is probably the easiest to understand; there's not a lot of magic that goes on, like you would have to make the jump to understand with things like Proxies (which I believe Vue uses, though I could be wrong) or the magic that comes from the Svelte compiler. You create a store, and in one particular place that we subscribe to it we set the render function.&lt;/p&gt;

&lt;p&gt;This is also nice because it's a relatively simple pattern to follow and extend, meaning that if we should want to create other "components" there really isn't a lot we would need to add. It's also nice because decoupling the store (or "state") from the rendering process means that we could just subscribe to the todos state in other locations to make some additional functionality, such as adding in a "yet to be done" section in an entirely different part of the page (like the navbar).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's take a look at the world's roughest Observable implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//observableStore.class.js&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * @template T
 * @description A very rough observable-store class. In real-life, you would probably use a library like RxJS
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ObservableStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * @param {T} initial The initial value for the store. Defaults to null.
   */&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_fns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   *
   * @param {T | (cur: T) =&amp;gt; T} v the new value that will be updated to the store. A rough typecheck is done.
   * Could also be function that will be passed the current value of the store and will return the new value.
   */&lt;/span&gt;
  &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Rough type check.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Typeof updated data is not the same as the initial data.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// update the store&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// run the subscribed functions for each. In a real implementation it might be worth it to check if making this async would cut times on observables with many subscribers.&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_fns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   *
   * @param {(data: T) =&amp;gt; void} fn A function to run everytime the store is updated.
   */&lt;/span&gt;
  &lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_fns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_fns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_fns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * @description This function is only included as it allows for some quick moment-in-time debugging and has some
   * use cases
   * @returns {T}
   */&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This effectively creates a class that takes an initial value for the store, and whenever someone updates the value using the &lt;code&gt;ObservableStore.prototype.update&lt;/code&gt; function, any listener functions are run. Note that these listeners could be functions that tie into anything, anywhere. There's nothing stopping you from subscribing to the store with a function that simply counts how many things there are. Absolutely nothing!&lt;/p&gt;

&lt;p&gt;Most of the changes here are for the fact that the Store + Subscription now deal with most of the rendering. The rest is reworking the add/remove/toggle functions to deal with the todos store.&lt;/p&gt;

&lt;p&gt;All of the code I think is fairly well documented, but please give drop a comment if you think I could expand upon something.&lt;/p&gt;

&lt;p&gt;The next branch will be "the big rewrite" -- it will be the move to TypeScript and creating a very rough React-like Component. The WIP/version-2.0 branch on the repo is there and visible if you want to check it out. It will be removed once I finalize the items and iron out some bugs. I'll be honest, I haven't been working on it for awhile now due to my day job 😅.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A(nother) todo: Version 1.1</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sat, 06 Mar 2021 23:43:36 +0000</pubDate>
      <link>https://dev.to/jhechtf/a-nother-todo-version-1-1-1laj</link>
      <guid>https://dev.to/jhechtf/a-nother-todo-version-1-1-1laj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; This post refers to &lt;a href="https://gitlab.com/jhechtf/vanilla-todo/-/tree/version-1.1" rel="noopener noreferrer"&gt;this branch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our initial version of the project works, but things are kind of ugly. &lt;/p&gt;

&lt;p&gt;For one thing, the entirety of the application lives inside the &lt;code&gt;main.js&lt;/code&gt; file, and while that may not be an issue &lt;em&gt;now&lt;/em&gt;, when the app is relatively simple, it's going to end up being a &lt;strong&gt;&lt;em&gt;nightmare&lt;/em&gt;&lt;/strong&gt; later on down the line as we add more and more features. I've kept a good summary in the &lt;a href="https://gitlab.com/jhechtf/vanilla-todo/-/blob/version-1.1/README.md" rel="noopener noreferrer"&gt;README.md&lt;/a&gt;, but I'll copy/paste it over so we can talk about what is going on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This branch is meant to be "I've been working in this project for awhile now, and I would like to refactor it to do some things differently."&lt;/p&gt;

&lt;p&gt;The things that are different here&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The application now does not all live inside the &lt;code&gt;main.js&lt;/code&gt; file. Instead all of the functionality has been put into it's own files, with the main.js file simply serving as the aggregator of those events.&lt;/li&gt;
&lt;li&gt;The renderer and the store have been largely separated. The render function here is what would be called a "Pure" function -- it keeps no track of state and will render the todos based solely off their values into the DOM.&lt;/li&gt;
&lt;li&gt;Largely there are no direct interactions with the &lt;code&gt;todo&lt;/code&gt; variable outside of the &lt;code&gt;todo.store.js&lt;/code&gt; file with 1 exception. I could imagine that a slightly more knowledgeable engineer would  want to persist information between browser refreshes, and as such takes advantage of the &lt;code&gt;localStorage&lt;/code&gt;. However, trying to pull this data from storage and use our todos store API was likely a bit more complex. I imagine someone having had a bit of time to fiddle around with adding the items in a loop, but "this way was faster and just worked" is definitely something I could see myself in my earlier years saying.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, this definitely has some downsides. The largest thing is that since we are no longer doing this all in the &lt;code&gt;main.js&lt;/code&gt; file there are multiple places where we need to call &lt;code&gt;document.querySelector('#todo-list-container')&lt;/code&gt;, which even for a relatively small app was rather annoying to write. &lt;/p&gt;

&lt;p&gt;The question then is: how do we make it so that we only have to call the query selector once? There are a few ways, if you are starting off with Javascript and ESM think of a few and test them out.&lt;/p&gt;

&lt;p&gt;Beyond that, I think a lot of developers after looking at this code will say something like "I just &lt;em&gt;feel&lt;/em&gt; like there should be a way to get the rendering function to run when the data updates... there has to be &lt;strong&gt;some&lt;/strong&gt; way to do that, right?"&lt;/p&gt;

&lt;p&gt;Also at this point many people are probably feeling the itch of wanting to make the UI a bit prettier, with a navbar and things...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's look at what our &lt;code&gt;src/&lt;/code&gt; directory looks like now&lt;/p&gt;

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

&lt;p&gt;Well, there's definitely more files!&lt;/p&gt;

&lt;p&gt;Notice that each one of the files is a bit more specific. There are two files that start with &lt;code&gt;todos&lt;/code&gt;, but one very clearly says it is the "store"(&lt;code&gt;todos.store.js&lt;/code&gt;) while the other is the "render" (&lt;code&gt;todos.render.js&lt;/code&gt;). The store now handles actions related to the actual array of todos. This means adding, removing, and marking todos as done is all stored in one logical place.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// todos.store.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;itemCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./todos.render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/** @type {import('./todos.render').todo[]} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="c1"&gt;// Get an item from local storage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos__visited&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// if we do not have a value from our localStorage, add an example to the array.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;stored&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Extra details you may want the user to know.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// make sure to set the storage so that other people do not see it again.&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos__visited&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * 
 * @param {string} title
 * @param {stirng} description
 * @returns {boolean} true if added / false if not.
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="c1"&gt;// render tick&lt;/span&gt;
    &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#todo-list-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * 
 * @param {number} todo the index of the todo
 * @returns {-1 | 0 | 1} 1 for success, 0 for failure, -1 if the item could not be found. Helpful for debugging and not much else.
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;removeTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// if we do not have this todo, don't try anything further&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// try to do this&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#todo-list-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// re-render&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * 
 * @param {number} index 
 * @returns {boolean} True if toggled, false if there was an error.
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toggleTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#todo-list-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.render.&lt;/code&gt; file focuses solely on taking the data and rendering it out to the provided &lt;code&gt;&amp;lt;dl&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;Other than that, there isn't really a whole lot different about this branch. It was just meant to serve as a logical thing, going from the "but it works!" to the "well, now things are a bit sectioned out and we've separated out concerns."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// todos.render.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * @typedef todo
 * @property {string} title
 * @property {boolean} done
 * @property {string} description
 */&lt;/span&gt;

&lt;span class="cm"&gt;/** @type {Map&amp;lt;todo, [HTMLElement, HTMLElement]} */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @param {HTMLDListElement} todo
 * @param {todo[]} todos 
 * @returns {void} 
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;els&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// either we can grab this item from the cache OR we create a new one.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// set the innerHTML, along with creating the delete span.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// Very generic close button&lt;/span&gt;
      &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;times;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;span&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Add necessary classes.&lt;/span&gt;
      &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;//update description element if we have a description&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// store the data so that it persists between sessions.&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos__data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// append the items to the list.&lt;/span&gt;
  &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;els&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Please do view the gitlab repository. I am working on getting a live preview of the "app" up and going but the workflow here is a bit weird.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A(nother) Todo List: The Mainline Branch</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sun, 10 Jan 2021 06:38:37 +0000</pubDate>
      <link>https://dev.to/jhechtf/a-nother-todo-list-the-mainline-branch-49jn</link>
      <guid>https://dev.to/jhechtf/a-nother-todo-list-the-mainline-branch-49jn</guid>
      <description>&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; This article refers to &lt;a href="https://gitlab.com/jhechtf/vanilla-todo/-/tree/mainline" rel="noopener noreferrer"&gt;this branch&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp1aair5xo4yfd3mqfmsh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp1aair5xo4yfd3mqfmsh.PNG" alt="Repository Layout, Mainline branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mainline branch is pretty straight forward: it is a Node package that has a source directory, a static directory, a gitignore file, our README.md, the requisite package.json file, our pnpm lock file, and our Snowpack config file.&lt;/p&gt;

&lt;p&gt;The source directory has only two files, &lt;code&gt;main.js&lt;/code&gt; and &lt;code&gt;styles.module.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;the static directory also has just two files, &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;styles.main.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's look at each of those in a bit more depth; we'll save the &lt;code&gt;main.js&lt;/code&gt; file for last as it's arguably the biggest file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// snowpack.config.js&lt;/span&gt;
&lt;span class="c1"&gt;// Snowpack Configuration File&lt;/span&gt;
&lt;span class="c1"&gt;// See all supported options: https://www.snowpack.dev/#configuration&lt;/span&gt;

&lt;span class="cm"&gt;/** @type {import("snowpack").SnowpackUserConfig } */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;static&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/_dist_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// plugins: [],&lt;/span&gt;
  &lt;span class="c1"&gt;// installOptions: {},&lt;/span&gt;
  &lt;span class="na"&gt;devOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// buildOptions: {},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The Snowpack config is pretty straight forward, if you know how to read Snowpack configs. The &lt;code&gt;mount&lt;/code&gt; object takes key-value pairs, with the key being the directory on your file system and the value is where it will be mounted to in the Snowpack dev server. Notice &lt;code&gt;static&lt;/code&gt; mounts to &lt;code&gt;/&lt;/code&gt;, so you can directly access our items in the &lt;code&gt;static&lt;/code&gt; folder. The &lt;code&gt;src&lt;/code&gt; directory mounts to &lt;code&gt;/_dist_&lt;/code&gt; meaning any files we include have to be relative to that base.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Todo List&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/styles.main.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Todos&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"todo-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"add-input"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Add a todo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"description-input"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Add extra details"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dl&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"todo-list-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/dl&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/_dist_/main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty standard HTML file, right? The things to notice are the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags I have. The &lt;code&gt;link&lt;/code&gt; is pulling the styles from &lt;code&gt;/styles.main.css&lt;/code&gt;, &lt;em&gt;because&lt;/em&gt; the &lt;code&gt;static&lt;/code&gt; directory was mounted to the root of our development server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* styles.main.css */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Segoe UI'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tahoma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Geneva&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Verdana&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;lightgray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"text"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;.block&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;It's some pretty straight forward CSS, just to modify the elements not created by Javascript.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; directory first we'll talk about the &lt;code&gt;styles.module.css&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* styles.module.css */&lt;/span&gt;
&lt;span class="nt"&gt;dd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.todo-list-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.todo-list-item&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"delete"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;pink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"delete"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.todo-list-item.todo-list-complete&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.todo-list-item.todo-list-complete&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;dd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;line-through&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#989898&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There isn't anything spectacular here because honestly the UI isn't spectacular; it is functional, which is where a lot of people start ("make it work, then make it pretty"). As a base style we are removing the left margin from our &lt;code&gt;&amp;lt;dd&amp;gt;&lt;/code&gt; tags, and setting our &lt;code&gt;dt&lt;/code&gt; tag to be sort-of bold. We add some margin to our delete indicator, and we add some styles to visually differentiate completed vs. in progress todos.&lt;/p&gt;

&lt;p&gt;Now, I would post the entirety of the &lt;code&gt;main.js&lt;/code&gt; file, but it's &lt;strong&gt;&lt;em&gt;137&lt;/em&gt;&lt;/strong&gt; lines, and honestly in one go that would be too much. So, let's look at it a few lines at a time so that we can discuss what is occurring.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.js, lines 1 thru 28&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./styles.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * @typedef todo
 * @property {string} title
 * @property {boolean} done
 * @property {string} description
 */&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @type {todo[]}
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example Todo, no details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Example todo, with details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Many details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Completed Todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;with details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Alright, so if you are brand new you'll likely notice something weird almost immediately. There's this long comment with weird notations such as "&lt;a class="mentioned-user" href="https://dev.to/typedef"&gt;@typedef&lt;/a&gt;" and "@property." It's a notation system called &lt;a href="https://jsdoc.app/" rel="noopener noreferrer"&gt;JSDoc&lt;/a&gt; and when you are using raw JS it's very helpful if you have a code editor (or a plugin) that uses it to help give you information about the code in question.&lt;/p&gt;

&lt;p&gt;That long comment is just me declaring a type that I will use throughout the rest of the code in this file called "todo." A todo will have 3 properties: title, description, and done. A todo's title and description are strings, and "done" is boolean (true/false).&lt;/p&gt;

&lt;p&gt;With that out of the way let's talk about the actual Javascript seen here.&lt;/p&gt;

&lt;p&gt;Line 1 is importing the styles from our CSS module. That's all it does so far.&lt;/p&gt;

&lt;p&gt;the line that starts with &lt;code&gt;const todos ...&lt;/code&gt; is just assigning an array of todos with some initial data. Remember, the point of this branch is to reflect the workstate of "I got this done in a hurry and it works." Some todos are done, some are not.&lt;/p&gt;

&lt;p&gt;Now let's talk about the next bit of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {Map&amp;lt;todo, Element | Element[]} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itemCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is utilizing our &lt;code&gt;todo&lt;/code&gt; type that we defined previously in that big comment from the first section we talked about. The notation here is a bit weird, especially if you've never worked with a language that uses generics. The basics of it is that the &lt;code&gt;Map&lt;/code&gt; object in JS takes one type to use as a key, and stores another type. the line &lt;code&gt;Map&amp;lt;todo, Element | Element[]&amp;gt;&lt;/code&gt; in words says "We have a Map, using the type 'todo' as the key, which will store either a single Element object or an array of Element objects."&lt;/p&gt;

&lt;p&gt;Now, I'm going to introduce this next bit of code out of order, just because it is needed to make sense of some of the event listeners we have setup. This code is the function that actually renders our todos, and it starts on line 102 and ends on line 137. The JSDoc dictates that the function has two parameters, the first is an HTMLDListElement and the second is an array of todo elements. It also handedly notes that this function doesn't return anything -- it just runs the code inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {HTMLDListElement} todo
 * @param {todo[]} todos 
 * @returns {void} 
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;els&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// either we can grab this item from the cache OR we create a new one.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// set the innerHTML, along with creating the delete span.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;times;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTextNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;span&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Add necessary classes.&lt;/span&gt;
      &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;//update description element if we have a description&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;els&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think the easiest way to show what this does is to show what HTML results from it. Assume you call the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#someDLElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello DevTo!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Remember to hit the heart button!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and subsequently check the HTML in your browser, you'd get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dl&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"someDLElement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dt&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"_todo-list-item_8dbky_7"&lt;/span&gt; &lt;span class="na"&gt;data-key=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello DevTo!&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"delete"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;×&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/dt&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dd&lt;/span&gt; &lt;span class="na"&gt;data-key=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Remember to his the heart button!&lt;span class="nt"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dl&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, some notes about this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It creates a &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; element, and a text node for the actual text of the given todo.&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; element there is a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; element that has a &lt;code&gt;role&lt;/code&gt; attribute on it, signifying that it deletes the current element.&lt;/li&gt;
&lt;li&gt;it adds in &lt;code&gt;data-key&lt;/code&gt; attributes equal to the current todo's index in the todos array on both the &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; and matching &lt;code&gt;&amp;lt;dd&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are important things to remember going forward, as the remaining portion of the "app" will assume this HTML structure when calling for events.&lt;/p&gt;

&lt;p&gt;The next bit of code is quite long so I will attempt to break it up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todoList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#todo-list-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Whole mess of stuff here.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function wraps the rest of the code in an event listener. the "DOMContentLoaded" event will fire after the DOM has finished parsing and you can call things like &lt;code&gt;document.getElementById()&lt;/code&gt; without worrying. &lt;/p&gt;

&lt;p&gt;The next thing we are doing is querying the document in search of an element that has an id of "todo-list-container", which if we look back at our HTML is a &lt;code&gt;&amp;lt;dl&amp;gt;&lt;/code&gt; element that will hold our todos.&lt;/p&gt;

&lt;p&gt;Now we get onto the meat of the project. The first up is going to be a lot to take in all at once, but I think it's better that we talk about it as one item, and not in parts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// if our target matches a delete element&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span[role="delete"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// grab the key&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// grab the element&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="c1"&gt;// grab the elements from our cahce&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;els&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// sanity check&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;els&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// for each element associated with this todo, delete it.&lt;/span&gt;
        &lt;span class="nx"&gt;els&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="c1"&gt;// remove the todo from our cache&lt;/span&gt;
        &lt;span class="nx"&gt;itemCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// remove the todo from the array&lt;/span&gt;
        &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// re-render, mostly to fix key-indexes&lt;/span&gt;
        &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// if our target matches just the regular dt element&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dt.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todo-list-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopPropagation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// get the key&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// if the todos does not have this key, stop execution.&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// invert the value&lt;/span&gt;
      &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// re-render&lt;/span&gt;
      &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This event listener is added on to our &lt;code&gt;todoList&lt;/code&gt;, since the child elements will come/go quite frequently adding an event onto them doesn't particularly make a lot of sense. Instead, we add the events onto the container, which will not go away. Here we have two things to check&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Was the delete span that we created clicked?&lt;/li&gt;
&lt;li&gt;Was the actual &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; element clicked?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first scenario is handled by the first &lt;code&gt;if()&lt;/code&gt; statement, which I think is commented quite well, but I will go through the steps &lt;em&gt;after&lt;/em&gt; we go into the &lt;code&gt;if()&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;The first thing we do is stop the propagation of this click. In a real application with pure JS we have no idea what could be listening on click in the ancestor elements, so we stop the propagation upwards.&lt;/p&gt;

&lt;p&gt;Next is that we grab a key out of the &lt;strong&gt;parent node's&lt;/strong&gt; dataset. Remember, in this scenario the item being clicked is the &lt;code&gt;&amp;lt;span role="delete"&amp;gt;&lt;/code&gt; element, and not the actual &lt;code&gt;&amp;lt;dt&amp;gt;&lt;/code&gt; element. The &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; element doesn't have the &lt;code&gt;data-key&lt;/code&gt; property on it, so we look for the parent instead. If the todos array does not have an element at that index, we stop execution. Otherwise, we grab the corresponding elements from our cache variable, remove each of them, delete the key from our cache, remove the todo from our array (using &lt;code&gt;.splice()&lt;/code&gt;), and finally re-render the todos in the todos container.&lt;/p&gt;

&lt;p&gt;The next &lt;code&gt;if()&lt;/code&gt; block is for toggling the "done" status of the clicked todo. Like the first one, it stops the propagation of the event; then we grab the key from the dataset. The same check is done to make sure we have the given key value in our todos, and then we toggle it to the opposite of whatever the current state is (i.e. if the current state is false, then we toggle it to true and vice versa). We then re-render the list.&lt;/p&gt;

&lt;p&gt;The next section deals with handling the submission of new todos through the form on the HTML page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.js, lines 74 to 95&lt;/span&gt;
&lt;span class="c1"&gt;// add an event handler to the form to prevent default stuff.&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#todo-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// prevent the default&lt;/span&gt;
      &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// get the elements from this form.&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add-input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;addInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description-input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;descriptionInput&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// break execution if we do not have strings.&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;descriptionInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// push the results&lt;/span&gt;
      &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;addInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;descriptionInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="c1"&gt;// Reset the values&lt;/span&gt;
      &lt;span class="nx"&gt;addInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;descriptionInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Render the todos&lt;/span&gt;
      &lt;span class="nf"&gt;renderTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Discussion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Why didn't you use TypeScript?&lt;br&gt;
&lt;em&gt;A:&lt;/em&gt; I imagine someone coming into Javascript not particularly feeling the need of TypeScript -- If people would like I can create a TypeScript branch of each version, but unless someone asks I'm not likely to do so until a larger version difference.&lt;/p&gt;

&lt;p&gt;Now, as I said in the original post, this is meant to be an exercise to show people why things like React have gotten popular. While this is definitely not the &lt;em&gt;best&lt;/em&gt; way to setup an app, it's definitely a way that many people will do for their first few (speaking from past experience here).&lt;/p&gt;

&lt;p&gt;The next branch we will talk about is the Version 1.1 branch, which changes the structure a bit so that we don't need one large file. Keep an eye out for that post!&lt;/p&gt;

&lt;p&gt;Feel free to comment any questions / clarifications!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A(nother) Todo List</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sun, 27 Dec 2020 23:09:55 +0000</pubDate>
      <link>https://dev.to/jhechtf/a-nother-todo-list-20h5</link>
      <guid>https://dev.to/jhechtf/a-nother-todo-list-20h5</guid>
      <description>&lt;p&gt;I've been working on the web since 2001, when I first got in to HTML, CSS, and Javascript. The internet of 2001 is not the same internet that we have today, and that is in no small part to the updates of all three of the web's technologies. However, with this growth has come some changes in how people actually develop for the web: frameworks.&lt;/p&gt;

&lt;p&gt;When I started there was nothing fancy-- If you wanted to do things in Javascript you needed to learn how to use Javascript and the Document Object Model (DOM). This was ... well quite honestly it was awful, and honestly it's still not &lt;em&gt;great&lt;/em&gt; -- but it is doable.&lt;/p&gt;

&lt;p&gt;Normally, I don't tend to think about this anymore. I trust that the teams responsible for the frameworks I use put much more time in caring how they deal with the DOM on a webpage than I ever will. However, I am active in places like StackOverflow and Quora. Recently, on Quora I saw a question that I've seen many times, and that I've ignored just as many times:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why should I learn (React / Angular / Vue / another framework or library)?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The other day when I read the first thing I said internally was "because most people don't want to have to deal with the DOM themselves." While that statement might be broadly correct, it occurs to me that I know plenty of people who can work in React or Vue or Angular, but who would absolutely have no idea how to build the same functionality in a framework-less world.&lt;/p&gt;

&lt;p&gt;I had started writing a response when an idea hit me: "Instead of just telling them about how dealing with the DOM is annoying, just make a quick app that doesn't use anything outside of pure JS."&lt;/p&gt;

&lt;p&gt;So, I did. I call the project "Vanilla Todo" and in it I have attempted to imagine myself as someone who is a recent entry into the world of web development, and that they are somehow unaware of the many frameworks and libraries that now live on the front end.&lt;/p&gt;

&lt;p&gt;Each branch of Vanilla Todo will progress through stages that I myself can remember hitting when I was new to the web. The first branch is "version 1" or "I put this together in a craze and it works!". Each branch from there will modify the repository, both in code structure and in implementation, until such time that I (hope) a new user will understand why people have flocked to front-end frameworks.&lt;/p&gt;

&lt;p&gt;The repository is still in it's earlier stages, with two branches being overall done, and I am working on others as we speak.&lt;/p&gt;

&lt;p&gt;The link for the repository is &lt;a href="https://gitlab.com/jhechtf/vanilla-todo"&gt;gitlab.com/jhechtf/vanilla-todo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will be making posts to talk about each branch in a bit more detail, and possible things that people could do to try out different ways of dealing with the DOM.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>noframework</category>
    </item>
    <item>
      <title>[Request For Post] Your solution for auto publishing NPM packages?</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sat, 14 Mar 2020 00:14:10 +0000</pubDate>
      <link>https://dev.to/jhechtf/request-for-post-your-solution-for-auto-publishing-npm-packages-2k0j</link>
      <guid>https://dev.to/jhechtf/request-for-post-your-solution-for-auto-publishing-npm-packages-2k0j</guid>
      <description>&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;I recently created an NPM module that while it's not hugely popular, has more downloads than I thought it would. I have a CI/CD setup on my gitlab to lint, test, generate a changelog, and publish. &lt;/p&gt;

&lt;p&gt;Three of those jobs work. Take a guess at which 3? That's right, linting, testing, and changelog-ing all work. &lt;/p&gt;

&lt;p&gt;All of the places I've found mention of CI/CD with Gitlab and NPM boils down to the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Either run &lt;code&gt;npm config set registry //registry.npmjs.org/:_authToken ${NPM_TOKEN}&lt;/code&gt; and then running &lt;code&gt;npm publish&lt;/code&gt; OR&lt;/li&gt;
&lt;li&gt;doing basically the same thing, but instead adding the &lt;code&gt;//registry.npmjs.org/:_authToken=${NPM_TOKEN}&lt;/code&gt; to a local &lt;code&gt;.npmrc&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've tried both of these on my WSL Ubuntu install. Neither has worked. &lt;/p&gt;

&lt;p&gt;I found &lt;a href="https://stackoverflow.com/questions/54665511/how-do-i-publish-a-private-npm-package-with-gitlab-ci"&gt;this Stack Overflow post&lt;/a&gt;, and in digging through some links found someone who recommended setting &lt;code&gt;strict-ssl&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;. I can't say I'm comfortable with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do &lt;em&gt;YOU&lt;/em&gt; do it?
&lt;/h2&gt;

&lt;p&gt;Most of the time my CI/CD stuff pertains to servers, not necessarily NPM modules, so I'm a little out of flavor here. I figure there has to be some way to do this &lt;em&gt;without&lt;/em&gt; turning off SSL? I'm holding off on updating my pipeline in the hopes that maybe there's something I missed in all my searching.&lt;/p&gt;

</description>
      <category>requestforpost</category>
      <category>continousdeployment</category>
    </item>
    <item>
      <title>Opinion: PUT should be the HTTP method for new data</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Wed, 11 Mar 2020 21:33:59 +0000</pubDate>
      <link>https://dev.to/jhechtf/opinion-put-should-be-the-http-method-for-new-data-2pop</link>
      <guid>https://dev.to/jhechtf/opinion-put-should-be-the-http-method-for-new-data-2pop</guid>
      <description>&lt;p&gt;I said what I said, and I mean every word of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rewind
&lt;/h2&gt;

&lt;p&gt;For those a little confused, let's back up.&lt;/p&gt;

&lt;p&gt;REST (REpresentation State Transfer) APIs are still very common, and honestly I don't have an issue with them for most projects. REST APIs work by using HTTP verbs to denote the purpose of a request, i.e. a &lt;code&gt;GET&lt;/code&gt; request on a given endpoint (say "comments") means that the user is trying to get a list of (or perhaps a specific) comment value(s). &lt;code&gt;DELETE&lt;/code&gt; along with an identifier of some type does just what you think it would: removes the resource given by the identifier. The last two main HTTP methods utilized with REST are &lt;code&gt;POST&lt;/code&gt; and &lt;code&gt;PUT&lt;/code&gt;, and this is where I seem to break with most API designers / REST routing libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schism
&lt;/h2&gt;

&lt;p&gt;The last two, in English, are very close to one another due to some extra uses of the word "post", as in to "post a job listing" (i.e. put up, create). For a long time many back-end languages didn't have good support for requests outside of GET or POST (for reasons I honestly don't know), so POST sort of fell as the default for anything that needed more security in sending data (i.e. not transmissible through the URL). &lt;/p&gt;

&lt;p&gt;With the growth of AJAX (i.e. XMLHttpRequests) REST APIs became the flavor-of-the-month and with it developers &lt;em&gt;should&lt;/em&gt; have thought about our default to using POST requests for creating data / records. Not many did, unfortunately, and many places that use REST APIs have, in my opinion, mixed up PUT and POST.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Argument
&lt;/h2&gt;

&lt;p&gt;I read an article some years ago (if I can find it I will link it, but so far have been unsuccessful) stating that the four big verbs (&lt;code&gt;GET&lt;/code&gt;,&lt;code&gt;DELETE&lt;/code&gt;,&lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;) are really the only verbs you'd need for a large majority of use cases. In that post the author made a point: &lt;code&gt;POST&lt;/code&gt; requests are (in his opinion) for resources that are being &lt;em&gt;modified&lt;/em&gt;, not &lt;em&gt;created&lt;/em&gt;, because they are &lt;strong&gt;POST&lt;/strong&gt; creation. To create new values, you would &lt;strong&gt;PUT&lt;/strong&gt; data to the server (database).&lt;/p&gt;

&lt;p&gt;I think &lt;code&gt;PUT&lt;/code&gt; has always made more sense as the verb for adding new data, but please give me any reasons you may have for thinking that &lt;code&gt;POST&lt;/code&gt; is the preferred method.&lt;/p&gt;

</description>
      <category>api</category>
      <category>rest</category>
      <category>opinion</category>
    </item>
    <item>
      <title>Automating VSCode Extension Publishing and Changelog Generation with Gitlab-CI</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Mon, 26 Aug 2019 05:26:28 +0000</pubDate>
      <link>https://dev.to/jhechtf/automating-vscode-extension-publishing-and-changelog-generation-with-gitlab-ci-3pep</link>
      <guid>https://dev.to/jhechtf/automating-vscode-extension-publishing-and-changelog-generation-with-gitlab-ci-3pep</guid>
      <description>&lt;p&gt;When I build my first &lt;a href="https://marketplace.visualstudio.com/items?itemName=Jhecht.jhecht-moji" rel="noopener noreferrer"&gt;real VSCode Extension&lt;/a&gt; I released it by hand every time. This also meant that I was making up the CHANGELOG every time as well. I had roughly looked into what I would need to do in order to make the changelog / marketplace publishing automated. I never got around to doing this, since it looked to involve more time than I had, and since it was "only one extension, I'll likely not update it &lt;em&gt;that&lt;/em&gt; often."&lt;/p&gt;

&lt;p&gt;After creating &lt;a href="https://marketplace.visualstudio.com/items?itemName=Jhecht.git-angular" rel="noopener noreferrer"&gt;Git Angular&lt;/a&gt; I decided I would use it as a test bed for two things: fiddling around with &lt;a href="https://github.com/conventional-changelog/standard-version" rel="noopener noreferrer"&gt;Standard Version&lt;/a&gt; and finally cementing a way to publish extensions from Gitlab CI. &lt;/p&gt;

&lt;h1&gt;
  
  
  NOTES:
&lt;/h1&gt;

&lt;p&gt;Standard Version uses the Angular-style commits to create the changelog. This means that if you are coming from a different commit style, such as Emoji Commit, or just "whatever information seems relevant in the commit", then that part is going to be difficult. There are other presets, but I've never used them so I don't know much about them or how they are. I'm looking into creating one for the Git Emoji commit style, but don't hold your breath on when that will be available.&lt;/p&gt;

&lt;p&gt;Also, if you are like me and you look for an "elegant"-&lt;em&gt;ish&lt;/em&gt; solution, this won't be it. This is what I came to terms that I would have to do in order to get it (more or less) automated, and I figure it is worth documenting the process for some other soul to see later on. &lt;/p&gt;

&lt;h1&gt;
  
  
  Tl;DR:
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you have a Personal Access Token (PAT) from both Gitlab (created under User Settings &amp;gt; Access Tokens) and Azure Devops (instructions linked below for this step). Your Gitlab PAT should have write repository access. I would recommend maybe making these expire every month or so &lt;em&gt;just in case&lt;/em&gt; it somehow gets exposed. Sure, you have to remember to remake the token in a month, but the alternative is someone hijacking everything.&lt;/li&gt;
&lt;li&gt;Add those two tokens into the Settings &amp;gt; CI/CD &amp;gt; Variables. I named the Azure Token PAT and the Gitlab PAT to GL_PAT. You can name them whatever, but remember what you name them later on.

&lt;ul&gt;
&lt;li&gt;Make sure that the "publisher" value in your package.json is not taken, otherwise your deploys will have issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Copy the .gitlab-ci.yml file from the section below, editing the repository URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  First Thing: make an extension.
&lt;/h1&gt;

&lt;p&gt;I obviously have Git Angular that I can use, but if you have yet to make an extension then you should use &lt;a href="https://code.visualstudio.com/api/get-started/your-first-extension" rel="noopener noreferrer"&gt;the guide&lt;/a&gt;. Basically you are going to want to install &lt;code&gt;yo&lt;/code&gt; and &lt;code&gt;generator-code&lt;/code&gt;. You then run &lt;code&gt;yo code&lt;/code&gt; and follow the prompt. If you don't exactly know what sort of voodoo you want this extension to be, that's fine. Just make sure you are following the commit pattern mentioned by the Standard Version page I linked above. It makes most of your commits look something like &lt;code&gt;feat(settings): added in settings page&lt;/code&gt; or &lt;code&gt;fix(submodule): fixed logic error in submodule that would cause errors&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Second Thing: Prep a Gitlab Repo
&lt;/h1&gt;

&lt;p&gt;Go over to your Gitlab and make a new blank repo for it. Go into your extension directory and make sure you run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# only run this command if you didn't already initiate the folder as a git repo
git init 
# Change "YOUR-USERNAME" and "YOUR-REPO" to their respective values
git remote add https://gitlab.com/YOUR-USERNAME/YOUR-REPO.git origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For my Git Angular extension, this would be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add https://gitlab.com/jhechtf/git-angular.git origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  VSCode Marketplace Access Token
&lt;/h2&gt;

&lt;p&gt;The instructions for creating a PAT that you can use to publish to the VSCode Marketplace is a bit more involved than I would care to cover in-depth here. Please check &lt;a href="https://code.visualstudio.com/api/working-with-extensions/publishing-extension" rel="noopener noreferrer"&gt;this guide&lt;/a&gt;. Make sure you copy/paste that &lt;strong&gt;TEMPORARILY&lt;/strong&gt; somewhere on your computer. I recommend you only use this token for a single VSCode extension so that if, on the off change, this token gets exposed you can view activity from your account and revoke only the necessary token. &lt;/p&gt;

&lt;h2&gt;
  
  
  Gitlab Personal Access Token
&lt;/h2&gt;

&lt;p&gt;You can make a new Personal Access token by logging into Gitlab, and then clicking on your profile picture on the right side. From the dropdown menu click "Settings." &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F56gkunb4m4wos84cx126.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F56gkunb4m4wos84cx126.PNG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to name your Personal Access Token something you can distinguish quickly, and I would recommend setting an expiration date within about a month.  &lt;strong&gt;You need to make sure your PAT has write access to your repository, or this will not work.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F08ng5i1wrp53quzwtfsu.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F08ng5i1wrp53quzwtfsu.PNG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  .gitlab-ci.yml
&lt;/h1&gt;

&lt;p&gt;If you are unsure the structure of the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file, please &lt;a href="https://docs.gitlab.com/ee/ci/yaml/" rel="noopener noreferrer"&gt;check here&lt;/a&gt; for a rough version. I've commented my gitlab-ci file below, but let's talk about what needs to happen exactly in order for us to be able to push the files. The basics of it are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;make sure git is configured since &lt;code&gt;standard-version&lt;/code&gt; auto commits its changes to &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;CHANGELOG.md&lt;/code&gt; Without the two &lt;code&gt;git configure&lt;/code&gt; lines the job will fail with an error since git won't let an unknown person make a commit.&lt;/li&gt;
&lt;li&gt;I use yarn, but the equivalent npm command would &lt;code&gt;npm run release&lt;/code&gt;. This runs &lt;code&gt;standard-version&lt;/code&gt; from my &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Gitlab CI checks out a commit, not a branch. Therefore the changes committed in the release script will not be saved. We must therefore merge those changes back into the master branch.&lt;/li&gt;
&lt;li&gt;Merge the new commit into the master branch, and using our PAT push the code up. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The very basic Gitlab CI file that I made looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Smaller image, faster to download than the regular node:12 image.&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:12-alpine&lt;/span&gt;
&lt;span class="c1"&gt;# Stages list. I will eventually have more stages, but this was a proof-of-concept more than anything&lt;/span&gt;
&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;span class="c1"&gt;# Before any job, add the vsce globally, and install our node_modules.&lt;/span&gt;
&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yarn global add vsce&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yarn&lt;/span&gt;

&lt;span class="na"&gt;Deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# update our distro and add git.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk update &amp;amp;&amp;amp; apk add git&lt;/span&gt;
    &lt;span class="c1"&gt;# configure our newly-installed git to use our user name and email&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git config user.email $GITLAB_USER_EMAIL&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git config user.name $GITLAB_USER_NAME&lt;/span&gt;
    &lt;span class="c1"&gt;# I added a release task which simply runs the standard-version library.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yarn release&lt;/span&gt;
    &lt;span class="c1"&gt;# Gitlab checks out the commit, not the branch, putting any committed changes into a detatched-head scenario.&lt;/span&gt;
    &lt;span class="c1"&gt;# this gets the commit SHA and stores it in the $CUR_HEAD variable.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CUR_HEAD=$(git rev-parse HEAD)&lt;/span&gt;
    &lt;span class="c1"&gt;# checkout master and merge in our detatched head&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git checkout master &amp;amp;&amp;amp; git merge $CUR_HEAD&lt;/span&gt;
    &lt;span class="c1"&gt;# GITLAB_USER_LOGIN is your gitlab user name, and GL_PAT will be the Gitlab Personal Access Token you created earlier. We are pushing our current HEAD to the master branch&lt;/span&gt;
    &lt;span class="c1"&gt;# on the quoted repo URL&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git push --follow-tags "https://${GITLAB_USER_LOGIN}:${GL_PAT}@gitlab.com/jhechtf/git-angular.git" HEAD:master&lt;/span&gt;
    &lt;span class="c1"&gt;# finally, publish our extension by passing in our $PAT token.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vsce publish -p $PAT&lt;/span&gt;

  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Other considerations
&lt;/h1&gt;

&lt;p&gt;I have modified my repository so that only I may push to the master branch (developers can merge branches, but only I may push to it directly).&lt;/p&gt;

&lt;p&gt;the &lt;code&gt;when: manual&lt;/code&gt; makes it so that I must go in and start the Deploy job manually, so that things like the release tags aren't run. I am likely to keep this, as one push could theoretically spawn a million different patch pushes (which I don't want).&lt;/p&gt;

&lt;h1&gt;
  
  
  Closing Notes
&lt;/h1&gt;

&lt;p&gt;I am open to hearing about how other people have setup their own Extension publishing pipeline, so if you have a setup please let me know in the comments. I also wish that the Azure Devops dashboard would allow me to restrict the PATs to a specific project, but unfortunately that doesn't seem possible.&lt;/p&gt;

&lt;p&gt;Let me know if you have any clarifications you'd like me to make!&lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Introducing Git Angular: a VSCode extension for Angular-style commits</title>
      <dc:creator>Jim Burbridge</dc:creator>
      <pubDate>Sun, 18 Aug 2019 07:09:25 +0000</pubDate>
      <link>https://dev.to/jhechtf/introducing-git-angular-a-vscode-extension-for-angular-style-commits-4ii8</link>
      <guid>https://dev.to/jhechtf/introducing-git-angular-a-vscode-extension-for-angular-style-commits-4ii8</guid>
      <description>&lt;h2&gt;
  
  
  Why does this extension exist?
&lt;/h2&gt;

&lt;p&gt;A lot of the projects I work on have some variety of pattern you need to follow in order contribute. This largely is because the commit messages will become part of the release notes and/or changelog later on. &lt;/p&gt;

&lt;p&gt;My previous company had a very rough process for Git messages, and most of my personal projects tend to have commits designed for "Future Jim" to read. Because of that, I personally adopted the Git-Emoji commit style, as I enjoy a little bit of spice in my commits.&lt;/p&gt;

&lt;p&gt;My current company, however, is very particular about their commit structure. They use a version of &lt;a href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit"&gt;Angular's Commit Message Guidelines&lt;/a&gt;. The thing is I am having just &lt;em&gt;the hardest&lt;/em&gt; time with it, so I wrote this little extension to help myself, and I figured I would share it with other people.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it do?
&lt;/h2&gt;

&lt;p&gt;One thing, fairly simply: &lt;em&gt;helps you build the starting point for an Angular-style commit&lt;/em&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  ... OK?
&lt;/h2&gt;

&lt;p&gt;I know, that doesn't sound so awesome, and if I'm honest this extension isn't meant to be something like &lt;a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens"&gt;GitLens&lt;/a&gt;, it's just meant to be a simple helper that plugs in to VSCode's default Git extension.&lt;/p&gt;

&lt;p&gt;The biggest thing about Git Angular is that it is configurable, either globally or via workspaces. This was done because not every person who is using the Angular commit style will be using &lt;em&gt;Angular's&lt;/em&gt; commit style (much like my current company). You and your team could be using different types or scopes, and Git Angular allows for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use it?
&lt;/h2&gt;

&lt;p&gt;Unfortunately, VSCode has about a million extensions that have "Angular" in the title, so it's best to follow &lt;a href="https://marketplace.visualstudio.com/items?itemName=Jhecht.git-angular"&gt;this link&lt;/a&gt;. Otherwise, the easiset way I found to find it without a lot of fuss or muss is searching for "Git Angular" (quotes included) into the VSCode Extension search box. &lt;/p&gt;

&lt;p&gt;It contributes a single command, &lt;code&gt;gitAngular.commit&lt;/code&gt;, that you can bind to a keybinding or use from the command palette. I personally bind this to &lt;code&gt;ctrl+shift+c&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Let me know if you think there's something missing from the extension that many Angular-style commit users would enjoy to have.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>git</category>
    </item>
  </channel>
</rss>
