<?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: Zack Sheppard</title>
    <description>The latest articles on DEV Community by Zack Sheppard (@zackdotcomputer).</description>
    <link>https://dev.to/zackdotcomputer</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%2F104593%2Fcd17983a-a1b6-4976-89b9-c0745bb31bc1.jpg</url>
      <title>DEV Community: Zack Sheppard</title>
      <link>https://dev.to/zackdotcomputer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zackdotcomputer"/>
    <language>en</language>
    <item>
      <title>I Promise you won't have to await long to understand async in Javascript</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Tue, 17 Aug 2021 10:31:31 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/i-promise-you-won-t-have-to-await-long-to-understand-async-in-javascript-27ab</link>
      <guid>https://dev.to/zackdotcomputer/i-promise-you-won-t-have-to-await-long-to-understand-async-in-javascript-27ab</guid>
      <description>&lt;p&gt;As you're poking around with modern Javascript, it won't take you long to encounter one of the main asynchronous keywords: &lt;code&gt;Promise&lt;/code&gt;, &lt;code&gt;await&lt;/code&gt;, or &lt;code&gt;async&lt;/code&gt;. So, how do these they work, and why would you want to use them? (And then at the end, some pro-tips for getting the most out of them.)&lt;/p&gt;

&lt;p&gt;As with all things in asynchronous programming, we'll answer those questions eventually but the order in which we'll do so is not defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;writeBlogPost&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;writeHowAsyncWorks&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;writeWhyAsync&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;writeAsyncIsNotMultithreading&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="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;writeProTips&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;writeConclusion&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;
  
  
  Why Async?
&lt;/h2&gt;

&lt;p&gt;Since the beginning, Javascript has lived on the internet. This necessarily means that it has had to deal with tasks that could take an indeterminate amount of time (usually calls from your device out to a server somewhere). The way that Javascript dealt with this traditionally has been with "callbacks":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getImageAndDoSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// This is a simplified example, of course, since arrow functions&lt;/span&gt;
  &lt;span class="c1"&gt;// didn't exist back in the day...&lt;/span&gt;
  &lt;span class="nx"&gt;loadDataFromSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// Function argument 1: a URL&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://placekitten.com/200/300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Function argument 2: a callback&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;// Do something with `image`&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;Callbacks are references to functions that get called when the work is done. Our &lt;code&gt;loadDataFromSite&lt;/code&gt; function above will call our callback with &lt;code&gt;image&lt;/code&gt; defined if and when it has successfully loaded the data from the target URL. If it fails, it will call our callback with image set to &lt;code&gt;null&lt;/code&gt; and, hopefully, &lt;code&gt;error&lt;/code&gt; defined.&lt;/p&gt;

&lt;p&gt;This works fine when you're dealing with simple "get it and do one thing" loops. However, this can quickly enter &lt;strong&gt;callback hell&lt;/strong&gt; if you need to do multiple chained calls to a server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;apiCallbackHell&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;transformData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;transformed&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;collateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;collated&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;discombobulateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;discombobulated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;// And so on...&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a mess! Callback hell like this was the motivation behind the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;Promise API&lt;/a&gt;, which in turn spawned the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await"&gt;async/await API&lt;/a&gt;. In a moment we'll break down what this is doing, but for now let's just enjoy how &lt;em&gt;clean&lt;/em&gt; our function looks with async/await:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;notApiCallbackHell&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;loadData&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;transformed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;transformData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;collated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformed&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;discombobulated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;discombobulateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// And so on...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Side Quest: Async is not Multithreaded Javascript
&lt;/h3&gt;

&lt;p&gt;Before we break that down, though, let's clarify one common misconception: async code is not the same as multi-threaded code. At its core, Javascript remains a single-threaded environment.&lt;/p&gt;

&lt;p&gt;Under the hood of the language is something called the "event loop", which is the engine responsible for reading in a single instruction and performing it. That loop remains a single threaded process - it can only ever read in one instruction at a time and then move on.&lt;/p&gt;

&lt;p&gt;Callbacks and Promises make it look like this loop is doing multiple things at once, but it isn't. Let's imagine the instructions in our code as a pile of cards and the event loop is a dealer, pulling them off the top one-at-a-time and stacking them into a neat deck. If we have no callbacks or Promises then the pile our dealer can pull from is clear: it's just what we have in the program, reading through the lines of code top to bottom.&lt;/p&gt;

&lt;p&gt;Adding async code to the mix gives our dealer another pile to pull from - the code in our callback or Promise can be read independently from the instructions in the global scope of our program. However, there is still only one dealer (one thread) and they can still only read through one instruction at a time. It's just that now they share their efforts between the different piles. This means that if you put some &lt;strong&gt;very difficult&lt;/strong&gt; work into a Promise, you'll be creating a very big new pile for your dealer to pull from. This will slow down the execution of your other code, so interactive UI on your screen might get &lt;em&gt;verrrrrry&lt;/em&gt; slow as a result.&lt;/p&gt;

&lt;p&gt;The solution to this is to move your intense work to another thread - in our metaphor this would be the same as hiring a &lt;strong&gt;second dealer&lt;/strong&gt; to sort through the intense pile of instructions separately from our main dealer. How to do that is beyond the scope of this post, but if you're curious check out &lt;a href="https://blog.logrocket.com/node-js-multithreading-what-are-worker-threads-and-why-do-they-matter-48ab102f8b10/"&gt;Node's Worker Threads&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"&gt;the browser's Web Workers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the pieces here?
&lt;/h2&gt;

&lt;p&gt;So, we've heard of the main three tools in the async/await landscape, but what do they actually do and how do they work?&lt;/p&gt;

&lt;h3&gt;
  
  
  Promise
&lt;/h3&gt;

&lt;p&gt;The backbone of the async/await toolkit is the &lt;code&gt;Promise&lt;/code&gt; type. &lt;code&gt;Promise&lt;/code&gt;s are objects. They wrap code that does &lt;em&gt;something&lt;/em&gt;. Their original purpose was to make it easier to attach callbacks and error handlers to that code. There are several ways to create a promise, but the most basic one is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;// Do something&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;itSucceeded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;successResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failureReason&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;Here you can see the core feature of a &lt;code&gt;Promise&lt;/code&gt; - it is just a wrapper around callbacks! Inside of the execution block for our new &lt;code&gt;Promise&lt;/code&gt; we simply have two callbacks - one we should call if the promise successfully did its work (the &lt;code&gt;resolve&lt;/code&gt; callback) and one we should call if it failed (the &lt;code&gt;reject&lt;/code&gt; callback).&lt;/p&gt;

&lt;p&gt;We then get two functions on the &lt;code&gt;Promise&lt;/code&gt; that are the most important:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;somePromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPromise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;somePromise&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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;// Do something with a success&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;rejection&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;// Do something with a rejection&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;then&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; are extremely useful if you've been handed a &lt;code&gt;Promise&lt;/code&gt; from some other code. These are how you can attach your own callbacks to the &lt;code&gt;Promise&lt;/code&gt; to listen for when it resolves (in which case your &lt;code&gt;then&lt;/code&gt; callback will be called with the resolved value) or to handle a failure (in which case your &lt;code&gt;catch&lt;/code&gt; callback will be called with the rejection reason, if any).&lt;/p&gt;

&lt;p&gt;(Side note there is also a &lt;code&gt;finally&lt;/code&gt; which, as you might guess, runs after all the &lt;code&gt;then&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; handlers are finished.)&lt;/p&gt;

&lt;p&gt;Then and catch are also useful because they themselves return a &lt;code&gt;Promise&lt;/code&gt; now containing the return value of your handler.&lt;/p&gt;

&lt;p&gt;So, you can use &lt;code&gt;.then&lt;/code&gt; to chain together multiple steps, partly escaping callback hell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;promisePurgatory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;transformData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformed&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;collateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collated&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;discombobulateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collated&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="cm"&gt;/* and so on */&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;h3&gt;
  
  
  Async/Await
&lt;/h3&gt;

&lt;p&gt;You might have noticed, though, that &lt;code&gt;Promise&lt;/code&gt; doesn't completely get us out of needing a huge stack of callbacks. Sure they are now all on the same level, so we no longer need to tab into infinity. But, the community behind Javascript were sure they could do better. Enter &lt;code&gt;async&lt;/code&gt; and its partner &lt;code&gt;await&lt;/code&gt;. These two simplify &lt;code&gt;Promise&lt;/code&gt; programming tremendously.&lt;/p&gt;

&lt;p&gt;First of all is &lt;code&gt;async&lt;/code&gt; - this is a keyword you use to annotate a function to say that it returns a &lt;code&gt;Promise&lt;/code&gt;. You don't have to do anything further, if you mark a function as &lt;code&gt;async&lt;/code&gt;, it will now be treated the same as if you'd made it the execution block inside a promise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doSomeWork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Do some complicated work and then&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;alwaysThrows&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Oh no this function always throws&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;It was called alwaysThrows, what did you expect?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;automaticPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doSomeWork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Without having to call `new Promise` we have one.&lt;/span&gt;
&lt;span class="c1"&gt;// This will log 42:&lt;/span&gt;
&lt;span class="nx"&gt;automaticPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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;automaticReject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;alwaysThrows&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Even though the function throws, because it's async the throw&lt;/span&gt;
&lt;span class="c1"&gt;// is wrapped up in a Promise reject and our code doesn't crash:&lt;/span&gt;
&lt;span class="nx"&gt;automaticReject&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;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reason&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 by itself pretty useful - no longer do you have to remember how to instantiate a &lt;code&gt;Promise&lt;/code&gt; or worry about handling both the &lt;code&gt;reject&lt;/code&gt; case and also any &lt;code&gt;throw&lt;/code&gt; errors. But where it really shines is when you add in &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;await&lt;/code&gt; can only exist inside of an &lt;code&gt;async&lt;/code&gt; function, but it gives you a way to pause your function until some other &lt;code&gt;Promise&lt;/code&gt; finishes. You will then be handed the resolved value of that &lt;code&gt;Promise&lt;/code&gt; or, if it rejected, the rejection will be thrown. This lets you handle &lt;code&gt;Promise&lt;/code&gt; results directly without having to build callbacks for them. This is the final tool we need to truly escape callback hell:&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;// From above, now with error handling&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;notApiCallbackHell&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;loadData&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;transformed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;transformData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;collated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformed&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;discombobulated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;discombobulateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// And so on...&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="c1"&gt;// Remember - if the Promise rejects, await will just throw.&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;One of our ladders out of hell failed&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A couple Pro(mise) Tips
&lt;/h2&gt;

&lt;p&gt;Now that you understand the basics of &lt;code&gt;Promise&lt;/code&gt;, &lt;code&gt;async&lt;/code&gt;, and &lt;code&gt;await&lt;/code&gt; a little better, here's a few Pro Tips to keep in mind while using them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;async&lt;/code&gt; and &lt;code&gt;.then&lt;/code&gt; will flatten returned &lt;code&gt;Promise&lt;/code&gt;s automatically.&lt;/strong&gt; Both &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;.then&lt;/code&gt; are smart enough to know that if you return a &lt;code&gt;Promise&lt;/code&gt; for some value, your end user does &lt;em&gt;not&lt;/em&gt; want a &lt;code&gt;Promise&lt;/code&gt; for a &lt;code&gt;Promise&lt;/code&gt; for some value. You can return either your value directly or a &lt;code&gt;Promise&lt;/code&gt; for it and it will get flattened down correctly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Promise.all&lt;/code&gt; for joining, not multiple &lt;code&gt;await&lt;/code&gt;s.&lt;/strong&gt; If you have several &lt;code&gt;Promise&lt;/code&gt;s that don't depend on each other and you want to wait for all of them, your first instinct might be to do:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;waitForAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Don't do this&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;doPromiseOne&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;two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;doPromiseTwo&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;three&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;doPromiseThree&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 is going to cause you problems, though, because you're going to wait for promise one to finish before you start promise two, and so on. Instead, you should use the built-in function &lt;code&gt;Promise.all&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;waitForAll&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;three&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;doPromiseOne&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;doPromiseTwo&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;doPromiseThree&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 way your code will create all three promises up front and run through them simultaneously. You're still going to &lt;code&gt;await&lt;/code&gt; all three finishing, but it will take much less time because you can spend downtime on promiseOne working on promiseTwo or Three.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Promise.allSettled&lt;/code&gt; if failure is acceptable.&lt;/strong&gt; The downside of &lt;code&gt;Promise.all&lt;/code&gt; or serial &lt;code&gt;await&lt;/code&gt;s is that if one of your &lt;code&gt;Promise&lt;/code&gt;s reject, then the whole chain is rejected. This is where &lt;code&gt;Promise.allSettled&lt;/code&gt; comes in. It works the same as &lt;code&gt;Promise.all&lt;/code&gt; except that it will wait until all the arguments have resolved &lt;strong&gt;or&lt;/strong&gt; rejected and then pass you back an array of the &lt;code&gt;Promise&lt;/code&gt;s themselves. This is useful if you're trying to do some work but it's ok if it fails.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Arrow functions can be &lt;code&gt;async&lt;/code&gt; too.&lt;/strong&gt; Last but most certainly not least, it's important to keep in mind that arrow functions can be marked as &lt;code&gt;async&lt;/code&gt; too! This is really really useful if you're trying to create a callback handler where you'll want to use &lt;code&gt;await&lt;/code&gt;, such as for an &lt;code&gt;onSubmit&lt;/code&gt; for a form:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Imagining we're in react...&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&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;serverResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;submitValuesToServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/submitted/success&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Form contents */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  .finally(...)
&lt;/h2&gt;

&lt;p&gt;Let me know in the comments down below what questions you now have about &lt;code&gt;Promise&lt;/code&gt;, &lt;code&gt;async&lt;/code&gt;, and &lt;code&gt;await&lt;/code&gt;. Even though I use these three in every Node and React app I write, there are still tons of nuances to learn about them.&lt;/p&gt;

&lt;p&gt;If you enjoyed this, please leave me a like, and maybe check out my last "back to basics" article on &lt;a href="https://blog.zack.computer/taming-this-in-javascript"&gt;the ins and outs of &lt;code&gt;this&lt;/code&gt; in JS&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>node</category>
    </item>
    <item>
      <title>Your Product Shouldn't Be an App</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Mon, 19 Jul 2021 15:48:57 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/your-product-shouldn-t-be-an-app-447k</link>
      <guid>https://dev.to/zackdotcomputer/your-product-shouldn-t-be-an-app-447k</guid>
      <description>&lt;p&gt;Recently, I've run into a few big ideas that make me feel like it's 2010 all over again. In the worst way. They remind me that back in the heady days of 2010, we were &lt;em&gt;fools&lt;/em&gt; for apps.&lt;/p&gt;

&lt;p&gt;Need to know what song is playing on the radio right now? App! Are new-hires lost in your office and you want to give them a map? Enterprise app! Need to order a sandwich from the independent deli on the corner? Whitelabel app!&lt;/p&gt;

&lt;p&gt;Ultimately these all fail the core test of making a product: they have identified a real need but fail to fulfill it better than the competition.&lt;/p&gt;

&lt;p&gt;What do I mean by that? Well, let's look at our examples: if I want to know what's on the radio right now, does it make more sense for me to open an app and see it or should I just &lt;strong&gt;turn on the radio?&lt;/strong&gt; If I need to help new-hires orient themselves in my office, should I hire someone to make a map app, get an enterprise distribution certificate for the app store, and debug issues people have installing that app, or should I &lt;strong&gt;draw a map and give them a photocopy?&lt;/strong&gt; If I want to order a sandwich from the deli, do I install their one-off app, make an account, and place an order or do I just &lt;strong&gt;walk down the street?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In all of these cases, the competition isn't another app, it's a better way of solving the problem. Even though the wild crappy-app days of the 20-teens are behind us, this lesson still holds true when we think about designing products today.&lt;/p&gt;

&lt;p&gt;What's wonderful about this is that you can usually find a way to achieve your goals far quicker and cheaper than by building a full app. Here are some alternatives you need to consider before you dive into the world of designing and developing a full-fledged app:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Info-products
&lt;/h2&gt;

&lt;p&gt;If the goal of your app is to communicate something to your users, the first question to ask yourself is whether that could be better accomplished by written words or videos. Simplifying your product to an info-product like this has two big advantages. First, larger media platforms like  &lt;a href="https://substack.com"&gt;Substack&lt;/a&gt;,  &lt;a href="https://www.skillshare.com/teach"&gt;Skillshare&lt;/a&gt;,  &lt;a href="https://teachable.com"&gt;Teachable&lt;/a&gt;,  &lt;a href="https://gumroad.com"&gt;Gumroad&lt;/a&gt;, or even Youtube are almost guaranteed to reach a larger market than a purpose-built app or site. Second, you can often communicate your ideas and make a sellable product in drastically less time than if you were trying to capture those same ideas in the framework of an app.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Communities
&lt;/h2&gt;

&lt;p&gt;If your app is trying to bring people together but not necessarily to form a market, you might be better off hosting a private Discord or building a community site on top of a platform like  &lt;a href="https://circle.so"&gt;Circle&lt;/a&gt;,  &lt;a href="https://tribe.so"&gt;Tribe&lt;/a&gt;, or Dev.to's own &lt;a href="https://www.forem.com"&gt;Forem&lt;/a&gt;. Communities especially are an interesting opportunity when added on top of info-products, as they give you the chance to keep your customers engaged with you between releases of new content.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Webapps
&lt;/h2&gt;

&lt;p&gt;While still &lt;em&gt;kind of&lt;/em&gt; an app, web apps are much easier to build, maintain, and distribute to users than a native app (especially given the wealth of  &lt;a href="https://www.nocode.tech/category/web-app-builders"&gt;Nocode tools&lt;/a&gt; for building them). Let me stress this point, the simplicity and speed of launching a website makes the stress of launching a true native app feel like hiking Everest. Web based apps can also make much more sense depending on the context you expect your users to be in when they need whatever solution you provide. If you think a user is going to be at work on their computer, for example, it makes more sense for your product to be a website rather than an app that will require they switch contexts to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Non-tech Products
&lt;/h2&gt;

&lt;p&gt;Finally, does your product need to be a tech product at all? Let's take a hypothetical product of "&lt;a href="https://kern.al/idea/covid-safe-office-bonding?new_idea=true"&gt;COVID-friendly activities for office bonding&lt;/a&gt;" for example. For version one, you could jump straight to building this as a productized digital app experience that can lead customers on group tours or scavenger hunts. But, you will be able to execute more quickly, get more feedback, and generate revenue immediately if you instead take the old-school route and lead your first few experiences personally. Once you have run a couple sessions, you'll have money in the bank and a much better sense for the pacing and content that leads to a good experience, and from there you'll be in a much stronger position to think about app-ifying your product.&lt;/p&gt;

&lt;p&gt;And therein lies the last, most important lesson here. Choosing not to app-ify your product from day one doesn't mean you'll &lt;strong&gt;never&lt;/strong&gt; turn it into an app or other digital product. Rather, this is about developing your product intelligently. If you jump straight to an app without validating your guesses about what will solve your users' problems most effectively, it's likely you'll build the wrong thing and wind up wasting all that effort. The App Store is already littered with the abandoned corpses of apps that failed to learn this lesson, don't be another one of them.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>mobile</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Speedy and Stylish - How to style NextJS with Bootstrap 5, SASS, and PurgeCSS</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Thu, 10 Jun 2021 15:33:05 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/speedy-and-stylish-how-to-style-nextjs-with-bootstrap-5-sass-and-purgecss-2pb1</link>
      <guid>https://dev.to/zackdotcomputer/speedy-and-stylish-how-to-style-nextjs-with-bootstrap-5-sass-and-purgecss-2pb1</guid>
      <description>&lt;p&gt;Quick how-to for you today. I'm setting up a new web app project with these parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I want it to be based on &lt;a href="https://nextjs.org"&gt;Next.JS&lt;/a&gt; because it's my favorite React framework.&lt;/li&gt;
&lt;li&gt;I want to style it with &lt;a href="https://getbootstrap.com"&gt;Bootstrap 5&lt;/a&gt; because I need more help setting up a consistent theme than Tailwind would give me.&lt;/li&gt;
&lt;li&gt;I want to write the styles in &lt;a href="https://sass-lang.com"&gt;SASS&lt;/a&gt; because that's what Bootstrap uses under the hood, which makes customizing the Bootstrap theme easier.&lt;/li&gt;
&lt;li&gt;I want to run the styling through &lt;a href="https://purgecss.com"&gt;PurgeCSS&lt;/a&gt; to avoid shipping unnecessary Bootstrap bloat.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  So how do you do that?
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. NextJS
&lt;/h2&gt;

&lt;p&gt;Setting up a new NextJS project is foolishly easy. First, pick an &lt;a href="https://github.com/vercel/next.js/tree/canary/examples"&gt;example&lt;/a&gt; to base your project on. I personally chose &lt;code&gt;with-typescript-eslint-jest&lt;/code&gt; because I like writing in Typescript much more than vanilla JS and I like having ESLint in VSCode to automatically style my files when I hit save.&lt;/p&gt;

&lt;p&gt;Second, run one of these (depending on whether you want to use npm or yarn), substituting in your chosen example template and replacing &lt;code&gt;your-project&lt;/code&gt; with the name for your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app &lt;span class="nt"&gt;-e&lt;/span&gt; with-typescript-eslint-jest your-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create next-app &lt;span class="nt"&gt;-e&lt;/span&gt; with-typescript-eslint-jest your-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that from here onward I'll be writing everything in &lt;code&gt;yarn&lt;/code&gt; commands, so be sure to substitute &lt;code&gt;npm&lt;/code&gt; if that's what you're using.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's it, you're done. You have a basic Next.JS app ready to go. Start it up with &lt;code&gt;yarn dev&lt;/code&gt; and see your site running at &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Bootstrap 5 in SASS
&lt;/h2&gt;

&lt;p&gt;Next, let's add Bootstrap 5. If you want just a few Bootstrap elements, you can get away with using the &lt;a href="https://github.com/react-bootstrap/react-bootstrap"&gt;react-bootstrap&lt;/a&gt; package. Their 2.0 build (based on Bootstrap 5) is in beta release right now. But, I want to build larger, more personalized themes, so I'm going to install Bootstrap directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add bootstrap@^5.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add Bootstrap's raw source to your node_modules. Now Bootstrap has two parts to it - the styling and the javascript - that combine to create the pretty and pretty functional components.&lt;/p&gt;

&lt;p&gt;First, let's add the styling. We're going to write our styles in SASS because it allows us to extend and override values in Bootstrap's themes. You can read more about  &lt;a href="https://getbootstrap.com/docs/5.0/customize/sass/"&gt;customizing Bootstrap in SASS here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Luckily, NextJS ships with built-in support for SASS. So it's as easy as adding the &lt;code&gt;sass&lt;/code&gt; package and creating &lt;code&gt;styles/index.scss&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add sass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: override to give us a salmon body background&lt;/span&gt;
&lt;span class="nv"&gt;$body-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#ffbbbb&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s"&gt;"../node_modules/bootstrap/scss/bootstrap";&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then importing it in &lt;code&gt;pages/_app.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../styles/index.scss&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AppProps&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refresh your development site and you should find the basic Bootstrap "reboot" styles are applied and the background is now a nice salmon color.&lt;/p&gt;

&lt;p&gt;Next, the Javascript. We only have to do this if we use one of the dynamic components like &lt;code&gt;Alert&lt;/code&gt;. If so, we first have to install the &lt;code&gt;popper&lt;/code&gt; dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @popperjs/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we use &lt;a href="https://getbootstrap.com/docs/5.0/getting-started/webpack/#importing-javascript"&gt;Bootstrap's recommendations&lt;/a&gt; on importing their JS into a Webpack environment. In &lt;code&gt;_app.tsx&lt;/code&gt; pick one of these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If you want to pull in the whole Bootstrap JS library:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bootstrap&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 you only need a single component:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Alert&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bootstrap/js/dist/alert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These each tell Webpack to include the relevant source file(s) in the final bundle it makes when we build our app for production or export.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Keep it trim with PurgeCSS
&lt;/h2&gt;

&lt;p&gt;One of the advantages of TailwindCSS over Bootstrap has been that it automatically trims out the bloat of the framework that you don't use, so you don't wind up shipping styling for &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; elements if you don't use any on your site. It accomplishes this through  &lt;a href="https://purgecss.com"&gt;PurgeCSS&lt;/a&gt;, which is trivial for it because it is based on &lt;a href="https://github.com/postcss/postcss"&gt;PostCSS&lt;/a&gt; and dynamic style generation in the first place.&lt;/p&gt;

&lt;p&gt;NextJS ships with PostCSS already, so we can give Bootstrap this same superpower by adding PurgeCSS to Next. Unfortunately, as the  &lt;a href="https://purgecss.com/guides/next.html"&gt;PurgeCSS page on this&lt;/a&gt; notes, customizing PostCSS turns off NextJS's built in optimizations, so we have to recreate them. Luckily, this isn't hard. First, install the packages we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; autoprefixer postcss @fullhuman/postcss-purgecss postcss-flexbugs-fixes postcss-preset-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the pieces are in place, we put them all into our build pipeline by creating a custom &lt;code&gt;postcss.config.js&lt;/code&gt; file in our project's root folder:&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;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;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postcss-flexbugs-fixes&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postcss-preset-env&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;autoprefixer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flexbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-2009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;custom-properties&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@fullhuman/postcss-purgecss&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/**/*.{js,jsx,ts,tsx}&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="s2"&gt;./pages/**/*.{js,jsx,ts,tsx}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;defaultExtractor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\w&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;/&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;!:&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/g&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="na"&gt;safelist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html&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="s2"&gt;body&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="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 first half of this file is pulled directly from &lt;a href="https://nextjs.org/docs/advanced-features/customizing-postcss-config#customizing-plugins"&gt;NextJS's documentation&lt;/a&gt; on customizing PostCSS. The second half adds in PurgeCSS and configures it to remove all classes whose names do not appear in the &lt;code&gt;src&lt;/code&gt; or &lt;code&gt;pages&lt;/code&gt; directories. It also tells it to manually to leave any &lt;code&gt;html&lt;/code&gt; or &lt;code&gt;body&lt;/code&gt; styles alone, since those two elements are rendered outside of the scope of our Next project's source files.&lt;/p&gt;

&lt;p&gt;Ok, so refresh your local dev build again and... nothing changes! This is intentional - PurgeCSS &lt;em&gt;shouldn't&lt;/em&gt; be purging any classes that are used. This also includes the styles we need in Reboot - Bootstrap's cross-browser standardizing stylesheet. If we use an element type that Reboot standardizes, then PurgeCSS will recognize that and won't touch the corresponding style.&lt;/p&gt;

&lt;h1&gt;
  
  
  That's it
&lt;/h1&gt;

&lt;p&gt;There you go - an easy 1, 2, 3 and now you have a new NextJS project set up with efficiently and intelligently trimmed-down Bootstrap 5 styling. Hope this is helpful for you while you're setting up a project.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>css</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How To: Deploy Next.js Apps with Docker Containers (Efficiently!)</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Mon, 07 Jun 2021 10:54:16 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/how-to-deploy-next-js-apps-with-docker-containers-efficiently-48e6</link>
      <guid>https://dev.to/zackdotcomputer/how-to-deploy-next-js-apps-with-docker-containers-efficiently-48e6</guid>
      <description>&lt;p&gt;So let's say you've written an awesome app in Next.js and you want to deploy it to a nifty containerized platform like &lt;a href="https://m.do.co/c/44917aecbb0c" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt; or &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt;. But let's say that you, like me at the start of last week, have never containerized a Node app before and need a crash course in how to do that? &lt;/p&gt;

&lt;p&gt;Here's what I learned going through this process to deploy &lt;a href="https://tweetsweep.app" rel="noopener noreferrer"&gt;Tweet Sweep&lt;/a&gt; to fly.io - both the naive first steps for making a container work at all and then also some &lt;strong&gt;necessary&lt;/strong&gt; optimizations for it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starter Instructions - How to Dockerfile&lt;/li&gt;
&lt;li&gt;Optimize It - Make it Production Ready&lt;/li&gt;
&lt;li&gt;Just give me a Dockerfile I can blindly copy paste&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Follow Along
&lt;/h2&gt;

&lt;p&gt;If you want to follow along, you will need &lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt; and  &lt;a href="https://yarnpkg.com" rel="noopener noreferrer"&gt;Yarn&lt;/a&gt;  installed. To keep things replicable, I'm using the &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/blog-starter-typescript" rel="noopener noreferrer"&gt;Next.js Blog-Starter-Typescript example&lt;/a&gt; in these instructions. You can set that up locally with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create next-app &lt;span class="nt"&gt;--example&lt;/span&gt; blog-starter-typescript blog-starter-typescript-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a side note, the tips and tricks in here are generic for all containerized Node apps, but the Dockerfiles themselves will only work as an untweaked copy-paste if you're using Next.js. So, if you're using a different platform you might have to tweak which files get retained in your final container.&lt;/p&gt;

&lt;p&gt;&lt;a id="basics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics - Just make it work
&lt;/h2&gt;

&lt;p&gt;So let's start with the 101 - what is Docker and why you want to use it. At its core, Docker Containers are tiny virtual computers serialized to disk in a standardized format. To make them, you need three ingredients:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A starter image to build upon - usually this is a full operating system image with some pre-installed software from &lt;a href="https://hub.docker.com" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New files to add - in this case the code for your app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The steps to combine those first two components. This is what is stored in a &lt;code&gt;Dockerfile&lt;/code&gt; and a &lt;code&gt;.dockerignore&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using these three components you can wrap up your software into a standardized container that can be run on any machine that has the Docker software installed. (Note that this has a big "in theory" caveat attached - if you are doing complex, advanced operations then you might run into the limits of Docker's capabilities. However, for a straight-forward Next.js app like the one I'm using here, it works very well.)&lt;/p&gt;

&lt;h3&gt;
  
  
  The Naive Dockerfile
&lt;/h3&gt;

&lt;p&gt;So what do these instructions look like for our Next.js application?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Naively Simple Node Dockerfile&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14.17-alpine&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/app/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; node:node /home/app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=node:node . .&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn build

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "yarn", "start" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put these in a file named &lt;code&gt;Dockerfile&lt;/code&gt; in the root folder of your app.&lt;/p&gt;

&lt;h4&gt;
  
  
  Understanding the Dockerfile
&lt;/h4&gt;

&lt;p&gt;So what does this do? Well, Docker will step through these instructions one by one and do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14.17-alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Docker that your app is building on &lt;a href="https://hub.docker.com/_/node" rel="noopener noreferrer"&gt;a container&lt;/a&gt; that has Alpine Linux and Node 14.17 (with &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt;) preinstalled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/app/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; node:node /home/app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=node:node . .&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are our first real instructions - we make a directory called /home/app, give ownership of it to a user named &lt;code&gt;node&lt;/code&gt;, make it the "working directory" for our container (where Docker expects our main program files to live), and copy the files in the directory where we ran &lt;code&gt;docker build&lt;/code&gt; into the container. Remember the container is basically a virtual little computer, so we have to copy our files in there to access them!&lt;/p&gt;

&lt;p&gt;We then become that &lt;code&gt;node&lt;/code&gt; user. By default Docker runs as &lt;code&gt;root&lt;/code&gt; on the contained machine. But that is pretty dangerous since it gives root privileges to whatever code we run, meaning a little security flaw in Node or one of our NPM dependencies could potentially give access to our whole server. So, to avoid that, we switch to a non-root user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We install our NPM dependencies and build our Next.js server in production mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "yarn", "start" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally these two commands give Docker instructions it will use when it tries to run this software. The first tells Docker that this container expects connections on port 3000, so it should expose that leaving the container (we'll wire it up in a moment with the &lt;code&gt;-p&lt;/code&gt; flag). The second tells Docker that the command to run to start this container is &lt;code&gt;yarn start&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Build and Run!
&lt;/h4&gt;

&lt;p&gt;Now it's time to execute those steps and make your container. Run the following command in a terminal in your project directory (you can replace &lt;code&gt;some-name&lt;/code&gt; with a personal tag like &lt;code&gt;zacks-blog-1.0&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; some-name &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your built image, containing the virtual machine ready to run your web app, will now show up locally if you check &lt;code&gt;docker image ls&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker image ls
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
some-name     latest    4c73a8c8d35c   2 minutes ago    622MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's start it up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 some-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(You can add the &lt;code&gt;-d&lt;/code&gt; flag after &lt;code&gt;run&lt;/code&gt; to run the server in the background instead.)&lt;/p&gt;

&lt;p&gt;You'll see logs same as if you'd run &lt;code&gt;yarn start&lt;/code&gt; normally. And, due to the &lt;code&gt;-p 3000:3000&lt;/code&gt; flag, your container will now be connected to your local port 3000, so if you visit &lt;code&gt;http://localhost:3000&lt;/code&gt; you'll see your blog template:&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1622987457269%2FSykIBi-7S.jpeg" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1622987457269%2FSykIBi-7S.jpeg" alt="It worked"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a id="optimized"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimize it - Getting this production ready
&lt;/h2&gt;

&lt;p&gt;Great! You have now containerized your app. But before you go deploying it to your favorite hosting platform, there are a few things we need to do.&lt;/p&gt;

&lt;p&gt;You might have noticed above that the size of our built image is over 600MB - that's over 4x the size of our project on disk outside of the container! This problem only compounds as your apps get more complex - the built versions of the &lt;a href="https://use.tweetsweep.app" rel="noopener noreferrer"&gt;Tweet Sweep Frontend&lt;/a&gt; container were more almost 5GB at this point! That's a lot of data to upload to your servers!&lt;/p&gt;

&lt;p&gt;Almost all of this size issue is related to one particular quirk of Docker - almost every line in the &lt;code&gt;Dockerfile&lt;/code&gt; creates a new "layer" in your final Docker image. Each layer captures the changes made to the virtual machine after that line runs. This is a powerful optimization tool because it allows Docker to reuse work it's already done - for example if you have some setup that never changes like our &lt;code&gt;mkdir&lt;/code&gt; line, Docker can compute that layer once and reuse it for all subsequent builds. However, it can also lead to image size issues (since lots of unneeded files might wind up being stored in those layers) and security issues (since you might capture secret values in those layers that could be siphoned off by someone who gets access to your final image).&lt;/p&gt;

&lt;p&gt;You can see the layers and their respective sizes using this command (credit to  &lt;a href="https://medium.com/trendyol-tech/how-we-reduce-node-docker-image-size-in-3-steps-ff2762b51d5a" rel="noopener noreferrer"&gt;this post&lt;/a&gt; where I got it from):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;--human&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; &lt;span class="s2"&gt;"{{.CreatedBy}}: {{.Size}}"&lt;/span&gt; some-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CMD &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"yarn"&lt;/span&gt; &lt;span class="s2"&gt;"start"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;: 0B
EXPOSE map[3000/tcp:&lt;span class="o"&gt;{}]&lt;/span&gt;: 0B
RUN /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; yarn build &lt;span class="c"&gt;# buildkit: 10.6MB&lt;/span&gt;
RUN /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfil&lt;/span&gt;…: 340MB
USER node: 0B
COPY &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="c"&gt;# buildkit: 155MB&lt;/span&gt;
WORKDIR /home/app: 0B
RUN /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/app/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chown&lt;/span&gt; …: 0B
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["node"]: 0B&lt;/span&gt;
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENTRYPOINT ["docker-entry…: 0B&lt;/span&gt;
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) COPY file:238737301d473041…: 116B&lt;/span&gt;
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; &lt;span class="nt"&gt;--virtual&lt;/span&gt; .bui…: 7.62MB
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENV YARN_VERSION=1.22.5: 0B&lt;/span&gt;
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; addgroup &lt;span class="nt"&gt;-g&lt;/span&gt; 1000 node     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; addu…: 104MB
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  ENV NODE_VERSION=14.17.0: 0B&lt;/span&gt;
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop)  CMD ["/bin/sh"]: 0B&lt;/span&gt;
/bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="c"&gt;#(nop) ADD file:282b9d56236cae296…: 5.62MB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this we can see that about 117MB of the image size happen before our first command - this the base size of the Alpine-Node image we're building on so there isn't much we can do about that. But let's focus on the two main optimizations we can do &lt;em&gt;after&lt;/em&gt; that point:&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy: Ignore Stuff
&lt;/h3&gt;

&lt;p&gt;In our naive Dockerfile we run the command &lt;code&gt;COPY --chown=node:node . .&lt;/code&gt;. This copies &lt;strong&gt;all&lt;/strong&gt; the files in our current directory into the Docker container. This is almost always &lt;strong&gt;not&lt;/strong&gt; what you want! For example, you might have an .env file with secrets in it that will wind up in plain-text in the final Docker image. (You should use the env secrets feature on your hosting platform instead.)&lt;/p&gt;

&lt;p&gt;In this app's case this unnecessarily copies the &lt;code&gt;node_modules&lt;/code&gt; folder (since we then yarn install it again) and &lt;code&gt;.next&lt;/code&gt; folder (since we rebuild the app inside the container). We can fix this with a &lt;code&gt;.dockerignore&lt;/code&gt; file. This file, in the root of our project, tells Docker to skip certain files and folders when running &lt;code&gt;COPY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .dockerignore file
.DS_Store
.next
node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Advanced: Get your Container a Container
&lt;/h3&gt;

&lt;p&gt;Now the galaxy brain move here is to use containers for our container. We're going to create two that are used &lt;em&gt;only&lt;/em&gt; to build the application separately from the one that's uploaded to the server. This saves us from having to upload the layers containing all the files used or created en route to that destination. Here's the Dockerfile for that (with comments explaining along the way what each block does):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(Edit: After I posted this, Vercel got in touch to point out they have &lt;a href="https://nextjs.org/docs/deployment#docker-image" rel="noopener noreferrer"&gt;their own post&lt;/a&gt; with a sample Dockerfile. I've now incorporated some tips from theirs into this one.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a id="final-dockerfile"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Double-container Dockerfile for separated build process.&lt;/span&gt;
&lt;span class="c"&gt;# If you're just copy-pasting this, don't forget a .dockerignore!&lt;/span&gt;

&lt;span class="c"&gt;# We're starting with the same base image, but we're declaring&lt;/span&gt;
&lt;span class="c"&gt;# that this block outputs an image called DEPS that we&lt;/span&gt;
&lt;span class="c"&gt;# won't be deploying - it just installs our Yarn deps&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:14-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;deps&lt;/span&gt;

&lt;span class="c"&gt;# If you need libc for any of your deps, uncomment this line:&lt;/span&gt;
&lt;span class="c"&gt;# RUN apk add --no-cache libc6-compat&lt;/span&gt;

&lt;span class="c"&gt;# Copy over ONLY the package.json and yarn.lock&lt;/span&gt;
&lt;span class="c"&gt;# so that this `yarn install` layer is only recomputed&lt;/span&gt;
&lt;span class="c"&gt;# if these dependency files change. Nice speed hack!&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json yarn.lock ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;

&lt;span class="c"&gt;# END DEPS IMAGE&lt;/span&gt;

&lt;span class="c"&gt;# Now we make a container to handle our Build&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:14-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;BUILD_IMAGE&lt;/span&gt;

&lt;span class="c"&gt;# Set up our work directory again&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Bring over the deps we installed and now also&lt;/span&gt;
&lt;span class="c"&gt;# the rest of the source code to build the Next&lt;/span&gt;
&lt;span class="c"&gt;# server for production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=deps /app/node_modules ./node_modules&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn build

&lt;span class="c"&gt;# Remove all the development dependencies since we don't&lt;/span&gt;
&lt;span class="c"&gt;# need them to run the actual server.&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt; &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt; &lt;span class="nt"&gt;--prefer-offline&lt;/span&gt;

&lt;span class="c"&gt;# END OF BUILD_IMAGE&lt;/span&gt;

&lt;span class="c"&gt;# This starts our application's run image - the final output of build.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14-alpine&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV production&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-g&lt;/span&gt; 1001 &lt;span class="nt"&gt;-S&lt;/span&gt; nodejs
&lt;span class="k"&gt;RUN &lt;/span&gt;adduser &lt;span class="nt"&gt;-S&lt;/span&gt; nextjs &lt;span class="nt"&gt;-u&lt;/span&gt; 1001

&lt;span class="c"&gt;# Pull the built files out of BUILD_IMAGE - we need:&lt;/span&gt;
&lt;span class="c"&gt;# 1. the package.json and yarn.lock&lt;/span&gt;
&lt;span class="c"&gt;# 2. the Next build output and static files&lt;/span&gt;
&lt;span class="c"&gt;# 3. the node_modules.&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=BUILD_IMAGE --chown=nextjs:nodejs /app/package.json /app/yarn.lock ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=BUILD_IMAGE --chown=nextjs:nodejs /app/node_modules ./node_modules&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=BUILD_IMAGE --chown=nextjs:nodejs /app/public ./public&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=BUILD_IMAGE --chown=nextjs:nodejs /app/.next ./.next&lt;/span&gt;

&lt;span class="c"&gt;# 4. OPTIONALLY the next.config.js, if your app has one&lt;/span&gt;
&lt;span class="c"&gt;# COPY --from=BUILD_IMAGE --chown=nextjs:nodejs  ./&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nextjs&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "yarn", "start" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Results
&lt;/h3&gt;

&lt;p&gt;Now if you build that (again with &lt;code&gt;docker build -t some-name-optimized .&lt;/code&gt;) and run it (&lt;code&gt;docker run -p 3000:3000 some-name-optimized&lt;/code&gt;) you'll be able to connect to it on localhost:3000 same as before. &lt;/p&gt;

&lt;p&gt;What has changed, then? Well, if we list our images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image &lt;span class="nb"&gt;ls                      
&lt;/span&gt;REPOSITORY           TAG      IMAGE ID       CREATED       SIZE
some-name-optimized  latest   518ed80eae02   1 hour ago    243MB
some-name            latest   4c73a8c8d35c   2 hours ago   622MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see we've reduce our final build image's size by almost a factor of 3! That's a &lt;strong&gt;lot&lt;/strong&gt; less data we'll need to upload to our server with every deploy! I saw similar results when I employed this strategy on Tweet Sweep's containers, saving me &lt;em&gt;gigabytes&lt;/em&gt; of upload bandwidth with every deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Deploy
&lt;/h2&gt;

&lt;p&gt;Ok, so now that we have our app containerizing successfully, how do we actually deploy? For this, I've been using &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;fly.io&lt;/a&gt; because their support for Docker is strong and their service has a generous free tier. But if you'd rather use &lt;a href="https://devcenter.heroku.com/categories/deploying-with-docker" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt; or  &lt;a href="https://m.do.co/c/44917aecbb0c" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt; they have strong support for Docker as well.&lt;/p&gt;

&lt;p&gt;With Fly, I'd recommend just following their &lt;a href="https://fly.io/docs/app-guides/run-a-global-image-service/#deploying-docker-images-to-fly" rel="noopener noreferrer"&gt;step by step instructions&lt;/a&gt; for deploying Docker. TLDR; you have to create an app on your account and a corresponding &lt;code&gt;fly.toml&lt;/code&gt; file locally, then the command &lt;code&gt;flyctl deploy&lt;/code&gt; will automatically run your Dockerfile build, upload all the resulting layers to their service (this is why it's important to optimize their size!), and then start them on a VM server. After that, deploys really are as easy as running &lt;code&gt;flyctl deploy&lt;/code&gt; again thanks to the compartmentalization of containers!&lt;/p&gt;

&lt;h2&gt;
  
  
  More Optimizations?
&lt;/h2&gt;

&lt;p&gt;I'm still learning Docker so these optimizations are just the first I've come across. If you've played around with it and know some more ins-and-outs one should include while containerizing a NodeJS app, please do let me know down in the comments.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>node</category>
      <category>docker</category>
    </item>
    <item>
      <title>App 101: What is a Work Queue and how to make one in Node</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Mon, 17 May 2021 15:16:00 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/app-101-what-is-a-work-queue-and-how-to-make-one-in-node-26n0</link>
      <guid>https://dev.to/zackdotcomputer/app-101-what-is-a-work-queue-and-how-to-make-one-in-node-26n0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A lot of the details about building an app are mysterious, even if you've been a programmer for years. So, I'm going to bundle up some of the discussions I've had with friends who are starting their own apps into these App101 posts. Follow along and we'll bring you up to speed on the decisions that you'll have to make when building a web-based app today.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;If you boil it down far enough, most internet programming follows this cycle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Receive HTTP Request -&amp;gt; Do Work -&amp;gt; Deliver HTTP Response&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This works fine 99% of the time because usually the work we're doing is simple: update a record in the database, pull some data and return it as json, and so on. However, once in a rare while this cycle breaks down. Maybe you find yourself in a situation where the "do work" step is too time- or resource-consuming to finish before the requester times out. Or maybe the &lt;em&gt;actual&lt;/em&gt; work is only being scheduled by this request and can't start until its scheduled time. These are classic cases where you might want to build a work queue on your backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Work Queue?
&lt;/h2&gt;

&lt;p&gt;A work queue is like a todo list for your server. You put &lt;strong&gt;messages&lt;/strong&gt; into the queue, which are often no more than simple dictionary objects. You assign one or more &lt;strong&gt;workers&lt;/strong&gt; to the top of the queue. Your workers then peel a message off the queue one-by-one, does some work, and then marks them as processed.&lt;/p&gt;

&lt;p&gt;You can process these messages in whatever order you want. Most queues start with first-in, first-out processing (FIFO) processing, where the oldest message in the queue is the next to be processed. However, many queue tools support additional features like scheduling messages - so they can't be processed before a certain time - and adding priority values - so that higher priority messages can jump the queue like a first class passenger at the airport.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Why Use Queues?
&lt;/h2&gt;

&lt;p&gt;So now we know how a queue works, let's get back to the &lt;strong&gt;why&lt;/strong&gt; of using one. The main benefit of queues is that &lt;strong&gt;they allow you to constrain resources and not constrain time&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;What do I mean by that? Well, when you are handling an HTTP request, you are time constrained - you only have so many seconds to return a value before the connection to your client times out or breaks. You're not, though, resource constrained - if you're using a serverless architecture or a load balancer your host might just spin up ever more instances of your API server to handle additional traffic. This is bad in both directions when you have heavy work to do, though.&lt;/p&gt;

&lt;p&gt;Let's imagine you have a request that is really hard to process and takes 60 seconds, for example calculating some complex AI response. As the time needed to handle that request goes up then not only does your failure rate go up (since connections time out while your working), &lt;em&gt;but also&lt;/em&gt; your infrastructure costs go up because you need more web servers to handle your traffic (since your existing instances are spending all their time doing this heavy work).&lt;/p&gt;

&lt;p&gt;Queues solve this problem in two ways. First, they escape your time constraint by moving the work to another process. Your web server can now return a "working on it" message almost immediately. Plus, because you pulled the processing out of your web server and into the queue worker, this heavy work no longer runs the risk of slowing or crashing your server. The second way they solve the constraint issue is that they allow you to constrain your infrastructure costs. Now you can control the number of workers who are working on the queue without causing failures. If your traffic goes up, it just means the queue takes longer to do the work rather than necessitating more infrastructure to handle that traffic.&lt;/p&gt;

&lt;p&gt;That is, though, also why you may &lt;em&gt;not&lt;/em&gt; want to use a queue. When you have more work coming in, the time to handle each job goes up because the queue gets longer. Additionally, you've added complexity to your API - now your client is dealing with an asynchronous process, so it will need to call back later to check "is my job done yet?" However, if you have heavy work that necessitates this, queues are often the better solution than just hoping the connection doesn't time out.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Queue
&lt;/h2&gt;

&lt;p&gt;It can take years to truly master the administration and tuning of queues. (Indeed, I am far from a master here.) However, it takes only minutes to &lt;em&gt;start&lt;/em&gt; learning those skills. I found two easy ways to start experimenting with queues today:&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Serverless Queues
&lt;/h3&gt;

&lt;p&gt;The quickest way to start experimenting with queues is with a serverless queue manager like &lt;a href="https://aws.amazon.com/sqs/"&gt;AWS SQS&lt;/a&gt; or &lt;a href="https://cloud.google.com/tasks"&gt;GCP Cloud Tasks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These services are cheap (both will handle &lt;strong&gt;billions&lt;/strong&gt; of messages per month for free), and both can be configured to run your worker a serverless FaaS process (Amazon's documentation for that is &lt;a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-lambda-function-trigger.html"&gt;here&lt;/a&gt;, and Google's is &lt;a href="https://cloud.google.com/tasks/docs/creating-appengine-handlers"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;They have two downsides, though. First, like many GCP and AWS products, they both have a bit of a painful learning curve as you learn to configure the tool. The main one, though, is that both of these have time limits to how long your worker can run. They are long - Google's is 10 minutes and Amazon's is 15 - but you should consider this if your work might approach that threshold. That was, eventually, why I went with Option 2 during my own experimentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: Roll it Yourself
&lt;/h3&gt;

&lt;p&gt;The other choice is to roll your queue yourself. This is the route I took for my current side project,  &lt;a href="https://tweetsweep.app"&gt;Tweet Sweep&lt;/a&gt;, because I really wanted to learn how the system worked under the hood and I was worried my queue workers might take longer than 15 minutes.&lt;/p&gt;

&lt;p&gt;If you're working in Node, I'd recommend using one of the two most maintained open source projects: &lt;a href="https://github.com/bee-queue/bee-queue"&gt;bee-queue&lt;/a&gt; and &lt;a href="https://github.com/taskforcesh/bullmq"&gt;BullMQ&lt;/a&gt;. Both have the features I've mentioned here, so you can get started with priorities and scheduling. Personally, I chose bee-queue because its api for creating parallelized workers was more straight-forward.&lt;/p&gt;

&lt;p&gt;With these packages (and, most likely, with any similar package in your preferred language), setting up the queue has two steps. First, you need a location for the queue messages to be stored while they're awaiting processing. Usually, this is a Redis datastore, since it's very fast and it is generally accepted as OK that you might lose queue messages if your infrastructure fails and needs to restart. Second, you will need a computer acting as your worker. Usually, this is process on a server that attaches to your queue(s) in the datastore and, when a new message is published to one, pulls it down and processes it.&lt;/p&gt;

&lt;p&gt;A hot tip: while learning to build my own queue, I found &lt;a href="https://fly.io"&gt;fly.io&lt;/a&gt; really useful. Its free tier comes with both a preconfigured Redis store and enough CPU budget to run two processes full-time, so you can run your API server and queue worker side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go out and get in line
&lt;/h2&gt;

&lt;p&gt;I've used queues at every company I've worked at. Indeed, Foursquare had tens of queues handling tasks like score calculation on a check-in or resizing profile images that were uploaded. Even this month, I'm helping a current client explore them for a long application processing step during onboarding. They're a tremendously useful tool and they can, when appropriately used, take a huge amount of strain off of your API servers and network hardware. But the first step to being able to use them in your own apps is learning the basics - let me know how you get on with queues down in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>node</category>
      <category>serverless</category>
    </item>
    <item>
      <title>App 101: Jamstack vs Traditional Webapps</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Tue, 04 May 2021 13:56:17 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/app-101-jamstack-vs-traditional-webapps-3pbe</link>
      <guid>https://dev.to/zackdotcomputer/app-101-jamstack-vs-traditional-webapps-3pbe</guid>
      <description>&lt;p&gt;My friend is a data scientist and I've helping him start making his first web app during lockdown. It's reminded me that there is a lot of App101 that you might not know even if you're already a programmer. So, I'm going to bundle up some of those discussions into these App101 posts to bring you up to speed on the decisions that you'll have to make when building a web app today.&lt;/p&gt;




&lt;h1&gt;
  
  
  Tales of Yore: Old Webapps and the Invention of the API
&lt;/h1&gt;

&lt;p&gt;Let's start with a little bit of (oversimplified) history.&lt;/p&gt;

&lt;p&gt;For the first 20 years the web existed, there was basically one way to build a web app that did more than just serve static content. You would get a database (often MySQL) and you would write a bit of software (often PHP or Perl) that would receive HTTP requests, interact with the database, and then return HTML with the next page to show the user. Basically the whole internet worked like Amazon.com: you'd click links or submit &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;s, those actions would cause HTTP GET or POST requests, and the server would return fully formed pages back to your browser.&lt;/p&gt;

&lt;p&gt;That all started to change around 2000 with the invention of &lt;a href="https://en.wikipedia.org/wiki/Ajax_%28programming%29"&gt;AJAX&lt;/a&gt;. AJAX used Javascript to move some of the work off the server and onto the user's computer. Now the browser could perform single actions without requiring a whole HTML page be sent over the wire. Instead, your code would call a special URL to get back just a snippet of HTML to substitute onto the page. This snippet later became structured data, first XML and then JSON, that would be used to calculate the HTML changes locally. This was the evolution of the modern web API - a structured set of URLs for loading or changing data on a server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Monolith Webapps: The old school architecture
&lt;/h1&gt;

&lt;p&gt;By 2015 the rise of mobile apps, a new class of non-html travelers on the internet, solidified the API as part of standard web app architecture. This meant the way we now build traditional webapps had been set:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rXe-SuGO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1620131982055/qZyD9VaiM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rXe-SuGO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1620131982055/qZyD9VaiM.png" alt="Chart showing a web and API server both using the same Database and the web app using both servers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the way that many modern app frameworks still work: Django, Ruby on Rails, etc. Many of these frameworks exist to try to simplify this setup by making the API and Web codebases easier to manage, or by automatically generating the Javascript for the website so you don't have to code your site twice.&lt;/p&gt;

&lt;p&gt;Traditional apps built like this have their advantages. They are well-understood and traditional, they have decades of solid tooling built for them, and they generate websites that are roughly what browsers and search engines expect.&lt;/p&gt;

&lt;p&gt;However, this architecture has a couple of clear issues as well. A minor one is that both the API and the web renderer have to interpret the data coming from your database and an inconsistency between those interpretations can cause some pretty weird bugs for your users.&lt;/p&gt;

&lt;p&gt;A much more serious risk, though, is that both your web renderer and your API have direct connections to your database. This can create serious headaches because the database is often the most fragile and resource-limited part of your architecture, while your website is often your most exposed. That combination opens up a lot of surface area for bugs or hacks to appear. One of the most common is that heavy traffic might overload your database, as was often the case with Twitter in its early days. Meanwhile, a security issue with one of your pages might allow direct access to the data, as has happened many times with Wordpress over the years. While these risks are today often mitigated by well designed frameworks, the connection to the database remains a vulnerability.&lt;/p&gt;

&lt;h1&gt;
  
  
  Jamstack: The upstart
&lt;/h1&gt;

&lt;p&gt;Around 2015 engineers began to ask, "what if we solve those issues by cutting the link between the web server and the database?" Since many of the larger apps already had full-featured APIs, it was a pretty natural leap to have the website consume data solely via the API. This takes the spider's web of dependencies above and changes it into a linear conga of data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ebKkmuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1620133187539/yWThLkMpJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ebKkmuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1620133187539/yWThLkMpJ.png" alt="Chart showing Jamstack architecture. Now only the API relies on the Database and the website calls the API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you do this, you find you get a whole host of benefits. Now, the only code you need to worry about having direct access to your database is your API. That gives you one location where proper escaping and rate limiting can protect your uptime. Plus, your API code is now the one source of truth for all your data, so you no longer need to worry about those pesky interpretation bugs.&lt;/p&gt;

&lt;p&gt;What I love about the Jamstack is that from this starting point the community began to find even more advantages. Around this time Node.js was skyrocketing in popularity and having Javascript on the server meant that your server-side renderer could literally run the same code as the browsers would. Going even further, though, people realized the server-side renderer could run no code at all! Instead, you could render all your pages during your deploy and serve purely static files through a service like Netlify or a CDN like Cloudfront. This gave rise to a whole generation of tools like Gatsby, Hugo, and Jekyll.&lt;/p&gt;

&lt;p&gt;However, JAMStack does come with its own issues and complexities. The main issue is that you have to now handle your API's code and deployment in addition to your webapp's. For lightweight projects, this is often unnecessary overhead. Even if you ignore the extra code, handling the deploys of the static files, the API, and potentially also the server-side renderer is clearly more work than a traditional single-deploy app would have been. But, for apps that might have to handle a lot of requests for static content (like a blog or marketing site) or web+mobile apps that will be dealing with similar requests from multiple different sources, the advantages you gain in simplifying your architecture outweighs the complexity you add to your deploy.&lt;/p&gt;

&lt;h1&gt;
  
  
  So which is right for you?
&lt;/h1&gt;

&lt;p&gt;The JAMStack is still a very new development in the web world, even if it has its own conference and &lt;a href="https://jamstack.org"&gt;fancy .org website&lt;/a&gt; now. This means there's still a lot of innovation and improvement to be reaped there. You can see this in the development of  &lt;a href="https://blog.zack.computer/the-race-is-on-to-be-the-rails-of-react"&gt;frameworks that make generating Jamstack applications&lt;/a&gt; easier and in the roll-out of  &lt;a href="https://www.netlify.com/products/functions/"&gt;server products&lt;/a&gt; that make it seamless to deploy snippets of dynamic server-side rendering code alongside large chunks of static code.&lt;/p&gt;

&lt;p&gt;However, the traditional form of webapp is far from dead. Single-deploy frameworks like Rails, Laravel, and Django are often still the right choice if you'd like to keep your code and deploy process simple at the expense of some hidden complexity in your architecture.&lt;/p&gt;

&lt;p&gt;As for my friend who's working through App 101 right now, we decided the right choice was to work with &lt;a href="https://www.djangoproject.com"&gt;Django&lt;/a&gt; for his project. It gave him a simple, single codebase in a language he was familiar with where he could build his API, admin pages, and database schema at once. I may love Jamstack, but it wasn't right for him because of the added complexity managing and deploying it. That may be the case for you too, or you might take to it as enthusiastically as I have. I'd love to hear what you decided to use for your projects and why.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>Let life get in the way</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Tue, 20 Apr 2021 10:26:08 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/let-life-get-in-the-way-32ep</link>
      <guid>https://dev.to/zackdotcomputer/let-life-get-in-the-way-32ep</guid>
      <description>&lt;p&gt;I made zero progress on my side-projects this past week. Indeed, I just barely got the work done for my freelance contracts. I was the opposite of a 24/7 hustler. And that's ok, because I was spending that time letting life get in the way of work.&lt;/p&gt;

&lt;p&gt;Specifically one very small bit of life: my new four-legged side project, &lt;a href="https://www.instagram.com/bigcityislay/"&gt;Islay&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iChV3_ZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1618913569977/ud1h7bdBs.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iChV3_ZG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1618913569977/ud1h7bdBs.jpeg" alt="Islay"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this post is not (just) an excuse to share adorable photos of this tiny puppy now living in my house. This post is about taking a breath after months of quarantine hustle and realizing I lost sight of that quasi-mythical goal: "work-life balance."&lt;/p&gt;

&lt;p&gt;For myself, and I assume I'm not alone in this, it can be easy to get sucked into games about making numbers go "up and to the right" - whether that's getting obsessed with the performance of an API server, maximizing finances, or driving up the engagement stats on a &lt;a href="https://blog.zack.computer"&gt;blog&lt;/a&gt; or &lt;a href="https://twitter.com/zackdotcomputer"&gt;Twitter&lt;/a&gt;. These are games with "high scores" where it's easy to monitor whether we're winning and every time the numbers go up, a little dopamine burst whispers "good job." But the tightly-coupled simplicity of that system makes it addictively, dangerously easy to slip into the habit of working almost every waking moment.&lt;/p&gt;

&lt;p&gt;I don't have the be-all and end-all answer to perfect work-life balance and in no way would I - someone who has happily plugged away on projects for 60+ hours a week for basically all of 2021 until this week - pretend that I do. All I can share is what has worked for me looking backwards. A decade ago, finding work-life balance was about unplugging completely and sitting in a park or a bar with people. In 2019 work-life balance was becoming a deep-dive nerd about photography.&lt;/p&gt;

&lt;p&gt;This week, work-life balance was teaching this little furry destroyer-of-toys how to sit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xr6s94hH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1618854177364/hOTf8DXOA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xr6s94hH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1618854177364/hOTf8DXOA.jpeg" alt="Sit! Good girl!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The common factor to these was a &lt;strong&gt;living&lt;/strong&gt; goal. One that isn't measured in numbers like commits or reps or engagement but rather in moments like stories told or photos made or lessons taught. I don't know if that's the recipe to success. What I do know is I've signed up for a new big project in raising Islay. The payoff for this project will be a little spitfire who will come demand I stop working if I've been grinding too long, because she's a dog and she knows nothing about numbers or making them go up, right, or in any direction at all.&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>motivation</category>
      <category>watercolor</category>
    </item>
    <item>
      <title>Back to Basics: Understanding and Conquering "this" in Javascript</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Mon, 29 Mar 2021 11:36:43 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/back-to-basics-understanding-and-conquering-this-in-javascript-4pbd</link>
      <guid>https://dev.to/zackdotcomputer/back-to-basics-understanding-and-conquering-this-in-javascript-4pbd</guid>
      <description>&lt;p&gt;I've been thinking about &lt;code&gt;this&lt;/code&gt; a lot recently because I've been messing around with a lot of chained callback functions in my web code. This is a good opportunity to go back to basics and recap how &lt;code&gt;this&lt;/code&gt; works in Javascript and what tools exist to tame its quirks.&lt;/p&gt;

&lt;p&gt;For new developers coming from a more typically object-oriented language like Java or Swift, Javascript's weird use of the &lt;code&gt;this&lt;/code&gt; keyword is a trap waiting to crash your code at any moment. This is especially dangerous if you're using React's class components, where you're often defining methods on your class to act as a callback handler. If you blindly assume that &lt;code&gt;this&lt;/code&gt; is going to behave the way you've come to expect, you're gonna have a bad time. So, let's understand &lt;code&gt;this&lt;/code&gt; enemy so we can learn how to fight it:&lt;/p&gt;

&lt;h2&gt;
  
  
  What is &lt;code&gt;this&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ZpNEeC9UmJw9AOGoSb/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ZpNEeC9UmJw9AOGoSb/giphy.gif" alt="What's This"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start with the basics of how we expect &lt;code&gt;this&lt;/code&gt; to work under the best circumstances:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theirName&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theirName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello I'm &lt;/span&gt;&lt;span class="dl"&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;name&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;william&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;william&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Prints out "Hello I'm Bill"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty straightforward: there is a class of object called &lt;code&gt;Person&lt;/code&gt;. Each &lt;code&gt;Person&lt;/code&gt; remembers a variable called &lt;code&gt;name&lt;/code&gt; and has a method called &lt;code&gt;introduce&lt;/code&gt;. When you call &lt;code&gt;introduce&lt;/code&gt; on a person it looks at that person's &lt;code&gt;name&lt;/code&gt; and prints an introduction. &lt;strong&gt;So, &lt;code&gt;this&lt;/code&gt; is a reference to the object whose instance of &lt;code&gt;introduce&lt;/code&gt; we're looking at, right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, not quite. Take a look at this:&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;// Continued from above&lt;/span&gt;

&lt;span class="c1"&gt;// This doesn't RUN william's introduce function,&lt;/span&gt;
&lt;span class="c1"&gt;// it makes a REFERENCE to it&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;introduceWilliam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;william&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Because it's a reference to a method that worked,&lt;/span&gt;
&lt;span class="c1"&gt;// we might assume the reference will also work but...&lt;/span&gt;
&lt;span class="nx"&gt;introduceWilliam&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Uncaught TypeError! Cannot read property 'name' of undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we've delved below the calm surface into the dark depths of a functional programming language written in the 90's.&lt;/p&gt;

&lt;p&gt;You have to remember that as far as Javascript is concerned &lt;strong&gt;functions are just another kind of object&lt;/strong&gt;. They can be stored, passed around, and executed anywhere.&lt;/p&gt;

&lt;p&gt;When you call &lt;code&gt;someThing.someFunc()&lt;/code&gt;, Javascript parses that you want to &lt;strong&gt;execute the instructions in &lt;code&gt;someFunc&lt;/code&gt; in the context of &lt;code&gt;someThing&lt;/code&gt;&lt;/strong&gt;. That is to say, set &lt;code&gt;this&lt;/code&gt; to &lt;code&gt;someThing&lt;/code&gt; and then execute the instructions.&lt;/p&gt;

&lt;p&gt;But if you make a reference to &lt;code&gt;someFunc&lt;/code&gt;, you could execute it anywhere. Above, we called it in the global context, which leaves &lt;code&gt;this&lt;/code&gt; as &lt;code&gt;undefined&lt;/code&gt; when you're in strict mode. You can even use the function's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call"&gt;&lt;code&gt;call&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply"&gt;&lt;code&gt;apply&lt;/code&gt;&lt;/a&gt; methods (functions on a function!) to provide any context and args you desire.&lt;/p&gt;

&lt;p&gt;Let's write some mildly horrifying code to demonstrate this:&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;// Still using william from above&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;william&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bill&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 a reference to william's introduce method&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;introduce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;william&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Make an unrelated object - Bagel the Beagle&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bagel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Beagle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;// Run function with manual `this` - Dogs can talk now&lt;/span&gt;
&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;puppy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Prints "Hello I'm Bagel"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Taming &lt;code&gt;this&lt;/code&gt; Beast
&lt;/h2&gt;

&lt;p&gt;This &lt;code&gt;this&lt;/code&gt; is incredibly, and often unnecessarily, powerful. Like many incredibly powerful things, it is also incredibly dangerous. Because of how often we pass around references to functions - to use as callbacks for &lt;code&gt;button&lt;/code&gt;s or &lt;code&gt;form&lt;/code&gt;s, for example - the unbound nature of &lt;code&gt;this&lt;/code&gt; is just lying in wait to trip you up.&lt;/p&gt;

&lt;p&gt;So how do we tame &lt;code&gt;this&lt;/code&gt;? I could shake my cane at you and croak &lt;em&gt;"Well, back in **my&lt;/em&gt;* day..."* but the truth is that the ES5 and ES2015 revisions to Javascript gave us everything we need to clamp down wandering &lt;code&gt;this&lt;/code&gt; values:&lt;/p&gt;

&lt;h3&gt;
  
  
  Function.prototype.bind()
&lt;/h3&gt;

&lt;p&gt;Added in ES5, the first tool we got was the  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind"&gt;&lt;code&gt;bind()&lt;/code&gt;&lt;/a&gt; function, a standardization of &lt;code&gt;this&lt;/code&gt; hacks that the various utility libraries of the 2000's had innovated.&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;// Bind this reference to introduce so this is ALWAYS william.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;alwaysIntroduceWilliam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;william&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;william&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;alwaysIntroduceWilliam&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Prints "Hello I'm Bill"&lt;/span&gt;
&lt;span class="nx"&gt;alwaysIntroduceWilliam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;puppy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Prints "Hello I'm Bill"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bind&lt;/code&gt; does what it says on the tin. It binds the function to a chosen &lt;code&gt;this&lt;/code&gt; - ensuring that the instructions inside are &lt;strong&gt;always&lt;/strong&gt; run in the context we choose. Here you can see that even if we try to use &lt;code&gt;call&lt;/code&gt; to set a different &lt;code&gt;this&lt;/code&gt;, the &lt;code&gt;bind&lt;/code&gt; overpowers and we're always introducing &lt;code&gt;william&lt;/code&gt;. This was a great first step towards fixing &lt;code&gt;this&lt;/code&gt;, but these days is less commonly used because of...&lt;/p&gt;

&lt;h3&gt;
  
  
  Arrow'd =&amp;gt;
&lt;/h3&gt;

&lt;p&gt;Added in ES2015, arrow functions gave us (almost accidentally) the most common way of fixing &lt;code&gt;this&lt;/code&gt; to the value that we expect. This is because an arrow function &lt;strong&gt;creates a closure over the context in which it was defined.&lt;/strong&gt; What that means is that all the variables referenced inside the arrow will always reference the same points in memory as when the arrow was first parsed.&lt;/p&gt;

&lt;p&gt;This is incredibly useful for capturing local variables so that they can be used later, but it has the added benefit of capturing the value of &lt;code&gt;this&lt;/code&gt; that was set when the arrow was defined. And, since &lt;code&gt;this&lt;/code&gt; is (basically) always going to be the object being created during construction, we can use arrow functions to make methods where &lt;code&gt;this&lt;/code&gt; will behave exactly like we expect:&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;// Rewriting Person with arrows&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ArrowPerson&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theirName&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theirName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;introduce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The arrow captures `this` so it is actually a&lt;/span&gt;
    &lt;span class="c1"&gt;// reference to THIS Person.&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello I'm &lt;/span&gt;&lt;span class="dl"&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;name&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrowBill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ArrowPerson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Arrow Bill&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;arrowBill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "Hello I'm Arrow Bill"&lt;/span&gt;

&lt;span class="c1"&gt;// Now `this` is fixed even as we pass the function around:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;introduceRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arrowBill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;introduce&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;introduceRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// "Hello I'm Arrow Bill"&lt;/span&gt;
&lt;span class="nx"&gt;introduceRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;puppy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Hello I'm Arrow Bill"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;this&lt;/code&gt; all makes more sense now
&lt;/h2&gt;

&lt;p&gt;I hope you understand &lt;code&gt;this&lt;/code&gt; a little bit better now. To be honest, I think I understand it better just from &lt;em&gt;writing&lt;/em&gt; this all out. And, because the Javascript &lt;code&gt;this&lt;/code&gt; can affect all your code that transpiles into Javascript, hopefully this will also help you understand the twists and turns of function context in other languages like Typescript.&lt;/p&gt;

&lt;p&gt;If you have any questions about &lt;code&gt;this&lt;/code&gt;, drop them in the comments below. Even after years writing for the web, I'm still learning so I'm sure there are terrible dangers and cool facts about &lt;code&gt;this&lt;/code&gt; I forgot or don't yet know.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>Programming as the Means of Last Resort</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Mon, 22 Mar 2021 14:37:12 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/programming-as-a-means-of-last-resort-39ec</link>
      <guid>https://dev.to/zackdotcomputer/programming-as-a-means-of-last-resort-39ec</guid>
      <description>&lt;p&gt;There's a coming-of-age moment for programmers where you're checking out a product's website, you switch to their &lt;code&gt;/pricing&lt;/code&gt; page, and immediately scoff &lt;strong&gt;"no way - I'll just build it myself."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's be honest - it's a little bit of a rush. You look at something that costs $20, $200, even $2000 and feel a surge of confidence. You know your field and your abilities well enough to understand (or at least guess) how this thing was built, and you feel powerful enough to do that work yourself.&lt;/p&gt;

&lt;p&gt;Congratulations. Now stop.&lt;/p&gt;

&lt;p&gt;It's a trap. You've heard the saying, "when all you have is a hammer, everything looks like a nail." Programming is like that but also you have the superpower to actually transform anything into a nail. But even if you are that strange superhero, sometimes it's still cheaper and easier to just buy some glue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mqgt9HrJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://imgs.xkcd.com/comics/hard_reboot_2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mqgt9HrJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://imgs.xkcd.com/comics/hard_reboot_2x.png" alt="Sometimes you should solve it the easy way"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's time to internalize that &lt;strong&gt;programming is the means of last resort&lt;/strong&gt;. This is the crux of what "no-coders" have figured out - you can actually build a reasonably good prototype for a huge majority of digital products without writing a line of code. Even as someone who loves to code and wouldn't personally go zero-code, it's time I start asking before I &lt;code&gt;git init&lt;/code&gt; a new project: can I borrow this from somewhere or does it make sense to buy it?&lt;/p&gt;

&lt;h2&gt;
  
  
  "Borrow", if you can
&lt;/h2&gt;

&lt;p&gt;Of course, if you can get exactly what you need for free, go for that. Your first thought here is probably to look for a snippet you can copy-paste off Stack Overflow, or an open-source Github project you can pull in via npm. Those are great instincts, but remember that sometimes free closed-source software can fit the bill as well. If you are starting a new mailing list,  &lt;a href="https://app.convertkit.com/referrals/l/8d6157c0-0827-4089-a1a6-8cfb0af5d9ef"&gt;ConvertKit&lt;/a&gt; has a generous free tier. If you need to host a website, &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;'s free tier can cover you up to literally tens of thousands of visitors. Etc.&lt;/p&gt;

&lt;p&gt;But this isn't especially new advice - so much of the web is built on the back of open-source packages from Apache to basically everything on &lt;code&gt;npm&lt;/code&gt;. It's once you pass the limits of what is available for free that your engineer brain starts to trap you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buy, if you are able
&lt;/h2&gt;

&lt;p&gt;There are so many small, repetitive tasks hidden within building a digital product that are trivial - both in terms of difficulty and price - that you can now solve with SaaS and PaaS tools thanks to the explosion in No Code. But first you need to to have a conversation with that voice in your head goading you into building it yourself. Remind it that building it yourself isn't the same as it being free. You have limited hours in your day, the same way you have limited dollars in your bank account.&lt;/p&gt;

&lt;p&gt;As an example, last week I was writing &lt;a href="https://blog.zack.computer/shipped-is-better-than-perfect"&gt;a blog post&lt;/a&gt; about a lesson I learned while working on &lt;a href="https://www.tweetsweep.app"&gt;Tweet Sweep&lt;/a&gt; and I needed a simple website to link to for that work-in-progress. I know how to build websites, so I started on the ~2 hour journey of spinning up a simple Next.js site on Netlify. But then I remembered this post draft and I put down my hammer.&lt;/p&gt;

&lt;p&gt;Instead, I signed up for &lt;a href="https://try.carrd.co/wvjydw31"&gt;Carrd&lt;/a&gt; - a No Code darling - for $14 / year. It took me 10 minutes, I made a website about 80% as good as the one I would have made from scratch, and I saved over an hour of my life. For me, this tiny transaction of 90 minutes of freedom for less than the price of a take-out dinner felt like the biggest win of my week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build, if you must
&lt;/h2&gt;

&lt;p&gt;The cost-benefit analysis of buying a tool could go the other way, though. There are SaaS tools out there that precisely solve problems I've faced, but which unconscionable amounts of money (or who I would feel morally icky working with). While paying $1000 to save 50 hours is the same ROI as I was happy to take with Carrd, it's not one I would take for some simple reason: I don't have $1000 to stake on a side-project.&lt;/p&gt;

&lt;p&gt;Worse, you might find that there is nothing out there that does quite what you want. For a number of reasons, I've moved away from Google Analytics for my projects to &lt;a href="https://plausible.io/"&gt;Plausible&lt;/a&gt;, but there's no reasonably-priced Google Analytics alternative for native applications (that I know about). So I'm out of luck if I want an affordable solution for native analytics.&lt;/p&gt;

&lt;p&gt;Situations like these are why it's good to still have the hammer of being able to "make it yourself" in your back pocket. Building still makes sense if you don't have the budget to buy a premade solution or if a premade solution doesn't even exist to be bought. In those cases, you have the power as a coder to either find the time to build your own workaround.&lt;/p&gt;

&lt;p&gt;But I know myself well enough to know that I can afford one, maybe two, of these construction detours in the course of a project. That is why I need to make programming my means of last resort. Every time I take the long way around, I risk coming to dread the project or getting so engrossed in one of those detours I'll wind up  &lt;a href="https://blog.zack.computer/suspenseful-coding-in-react"&gt;making &lt;strong&gt;it&lt;/strong&gt; instead&lt;/a&gt;  of the thing I was working on initially. So I have to be wise, ration out my attention, and keep my eye on the prize, as it were. I think that's the secret to how the No-Code community seems to turn out prototypes with such terrifying speed - if you're stringing together premade links into a chain you can move so much faster than if you get feel compelled to craft each link by hand.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Intro photo by  &lt;a href="https://flickr.com/photos/oemebamo/3695925672/in/photolist-6CAzWq-2SmfSo-EhdsQv-Ef16dQ-874kCc-RFZYL9-qRLq7X-dDiwq3-4qje48-rNthwD-rvZEoq-qRLqua-rw6X1v-rueEmx-qRLpJn-6xe2Xo-rvZDh7-RF3EsV-qRLr5Z-rNtibV-2bU4Rep-5Ur6sm-qRLqrV-a3sQWJ-6Hz1Wp-5d3Zzf-rNtkb6-rueGqn-rNtk3R-rLgqJw-rLgqtw-qRLqwe-rNyjtD-rNykaD-rLgqbh-qRLqDP-rNyjFT-qRyoAW-rLgqjJ-rueFca-rNrE9m-rNrD71-CVvwaN-rueFZx-qRLqX4-rvYu3q-rvYucy-rNrEUj-rLgqdm-rueFuK"&gt;Jurriaan Persyn&lt;/a&gt;  - Licensed CC-BY-NC&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nocode</category>
      <category>weeklylearn</category>
      <category>app</category>
      <category>development</category>
    </item>
    <item>
      <title>Understanding Suspense-ful coding in React</title>
      <dc:creator>Zack Sheppard</dc:creator>
      <pubDate>Mon, 08 Mar 2021 18:02:01 +0000</pubDate>
      <link>https://dev.to/zackdotcomputer/understanding-suspense-ful-coding-in-react-3n53</link>
      <guid>https://dev.to/zackdotcomputer/understanding-suspense-ful-coding-in-react-3n53</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR; &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; is cool and a useful way to handle async loads in your React apps, but it has some tricky gotchas about data flow and caching if you try to use it with bare &lt;code&gt;Promise&lt;/code&gt;s. I wrote an npm package to avoid these pitfalls that I've open-sourced - &lt;a href="https://github.com/zackdotcomputer/suspension"&gt;suspension&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;I've been working this week on a little webapp to practice integrating React apps with Firebase backends. As part of this project, I pulled in  &lt;a href="https://github.com/FirebaseExtended/reactfire"&gt;reactfire&lt;/a&gt;, which is the first module I've used that had first class support for the new React &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; component. I'd heard about this component before but it was finally time to do a deep dive into what it was, how it worked, and how I could integrate it more deeply into my React apps going forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Suspense?
&lt;/h2&gt;

&lt;p&gt;Suspense was the first component from React's &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html"&gt;experimental Concurrent mode&lt;/a&gt; to be merged into the non-experimental release (way back in 16.6). Suspense's job is to detect the need for an async load and render a fallback loading UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CalendarApp&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;viewedDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setViewedDay&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="c1"&gt;// Assuming that CalendarDayView is ready to work with Suspense,&lt;/span&gt;
  &lt;span class="c1"&gt;// this renders your loading spinner while today's data is loading.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LoadingSpinner&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CalendarDayView&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;viewedDay&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that was all it did, it would be basically syntactic sugar over the tried-and-true pattern of &lt;code&gt;if (callStatus === "loading") { return &amp;lt;LoadingSpinner /&amp;gt;; }&lt;/code&gt;. But Suspense has a superpower that very few people are talking about, but to understand it we have to first understand how this component works.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Suspense work?
&lt;/h2&gt;

&lt;p&gt;Suspense works by mildly abusing the &lt;code&gt;throw&lt;/code&gt; statement. A component or hook that wants to indicate that it is still loading and needs more time should &lt;code&gt;throw&lt;/code&gt; a &lt;code&gt;Promise&lt;/code&gt; that will resolve when the component is ready for its render to be reattempted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CalendarDayView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Let's imagine our ORM has a cache of days' agendas we can check&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;calendarDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cachedValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// To hook into Suspense, we recognize if we need to load and&lt;/span&gt;
  &lt;span class="c1"&gt;// throw a Promise that resolves when we're ready to try again.&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;cacheResult&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;loadingPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;calendarDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;loadingPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;calendarDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&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;loadingPromise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Otherwise do the render&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Calendar for &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cacheResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dayString&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and so on&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;When we &lt;code&gt;throw&lt;/code&gt; a Promise like this, React climbs the virtual DOM to find the nearest &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; component and hands it the Promise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This removes the whole tree under that Suspense from the rendered DOM and replaces it with the &lt;code&gt;fallback&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is how Suspense can give us superpowers. Because the &lt;code&gt;throw&lt;/code&gt; interrupts our component's render process, we are guaranteed that if we get past it we are not loading. In the Calendar example above, we can be &lt;strong&gt;certain&lt;/strong&gt; that if we get to the JSX at the bottom of the page then &lt;code&gt;cacheResult&lt;/code&gt; is non-null and defined so we no longer have to guard against it being a missing value during a load. When the &lt;code&gt;Promise&lt;/code&gt; that we threw resolves or rejects the &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; will automatically try to re-render its children, giving us another chance to draw our calendar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gotcha 1 - Handling Errors
&lt;/h3&gt;

&lt;p&gt;So one small gotcha here is that we've nicely separated out the "loading" case, but our component would still have to deal with the "API failed" case itself. Well, the React team have a suggestion for that too - again just &lt;code&gt;throw&lt;/code&gt; your &lt;code&gt;Error&lt;/code&gt;s and catch them with &lt;a href="https://reactjs.org/docs/error-boundaries.html"&gt;an error-boundary&lt;/a&gt; higher up in the tree. If you're committing to use Suspense, this is almost always the right answer as well since it neatly separates your components into loading, failed, and success cases. This is especially easy thanks to the &lt;a href="https://github.com/bvaughn/react-error-boundary"&gt;react-error-boundary&lt;/a&gt; package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gotcha 2 - Avoiding Infinite Loading
&lt;/h3&gt;

&lt;p&gt;There is a big gotcha with this system: &lt;strong&gt;how do you make sure you have your result when Suspense tries again?&lt;/strong&gt; Since Suspense throws away the tree under it, the state of the component that threw the Promise (and by extension your hooks' state) will be destroyed during the load.&lt;/p&gt;

&lt;p&gt;This is fine if you're loading from an API like our imaginary ORM above, where you can easily get the value if it's already cached. But if you're loading something from an API that always returns a Promise, like &lt;code&gt;fetch&lt;/code&gt;, how do you get the result when you are told to retry? If you just naively call again, you can get stuck in an infinite load where every retry kicks off another call.&lt;/p&gt;

&lt;p&gt;To escape this spiral, you need a cache that exists outside of your &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;. This can be as complex as a fully cached data layer like Firestore or Apollo or it can be as simple as a stateful hook outside of your &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use this with my Promises today?
&lt;/h2&gt;

&lt;p&gt;So, to recap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; components catch Promises that their children throw if they're not ready to render.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They remove their children from rendering and display the Fallback instead. This destroys the children's state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Because of this, you're almost always going to want a cache for the data so it's accessible when you get asked to re-render.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Putting all this together, the easiest way to convert existing Promise-based accesses to ones ready for Suspense would be to have a top-level cache that your components could send Promises to and later access the results synchronously. If you are already using a heavy datastore layer like Apollo or Redux, then you can use that. If you weren't using one of those, you could use a stateful hook tool like &lt;a class="comment-mentioned-user" href="https://dev.to/andreiduca"&gt;@andreiduca&lt;/a&gt;
's &lt;a href="https://github.com/andreiduca/use-async-resource"&gt;use-async-resource&lt;/a&gt; package. But I wanted a hook I could use inside the target component so I didn't have to prop-drill my reader function through the &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt;, so I built that:&lt;/p&gt;

&lt;h3&gt;
  
  
  Suspension - hook any async API to Suspense
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/zackdotcomputer/suspension"&gt;Suspension&lt;/a&gt; uses the cache and call setup described above. You wrap your components in the &lt;code&gt;&amp;lt;SuspensionRig&amp;gt;&lt;/code&gt; cache provider, which can also act as both a Suspense and/or an error boundary. Then, whenever you need data from a Promise, you pass it to suspension via a hook and it handles the logic of deciding whether to load, throw, or return a value for you.&lt;/p&gt;

&lt;p&gt;Here's how we'd rewrite our Calendar app from above to use Suspension. First we swap out our base Suspense for a SuspensionRig:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SuspensionRig&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;suspension&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CalendarApp&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;viewedDay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setViewedDay&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&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;(&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SuspensionRig&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LoadingSpinner&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CalendarDayView&lt;/span&gt; &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;viewedDay&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;SuspensionRig&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we rip out our cache-or-load logic from above and replace it with one call to the &lt;code&gt;useSuspension&lt;/code&gt; hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSuspension&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;suspension&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CalendarDayView&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;renderDay&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;renderDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// useSuspension takes a function that triggers your async work,&lt;/span&gt;
  &lt;span class="c1"&gt;//  a cache key to track the result, and the dependencies that&lt;/span&gt;
  &lt;span class="c1"&gt;//  trigger a new load (passed as args to your load function).&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSuspension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;calendarDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load-day-view&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;renderDay&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// The hook guarantees that `today` will always be defined.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Calendar for &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dayString&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and so on&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;All our logic about caching and trigger loads and throwing values gets collapsed into the hook and Suspension handles it all for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  await React.future()
&lt;/h2&gt;

&lt;p&gt;Learning about &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; this past week has reignited my excitement about React. The whole experimental concurrent feature set feels like a new, simplified mental model for understanding concurrent loads in our UI.&lt;/p&gt;

&lt;p&gt;Please check out Suspension - &lt;code&gt;npm install suspension&lt;/code&gt; is ready to go. I hope it helps you dive into &lt;code&gt;&amp;lt;Suspense&amp;gt;&lt;/code&gt; sooner and with more confidence - let me know if you find it useful or run into issues. The project's Issues and PRs are open for requests and contributions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zackdotcomputer/suspension"&gt;View Suspension on Github&lt;/a&gt; to read more about how to use it.&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
