<?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: Mat Silva</title>
    <description>The latest articles on DEV Community by Mat Silva (@matsilva).</description>
    <link>https://dev.to/matsilva</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%2F140610%2Fee9f3710-a861-40d3-816f-ca69ab943172.jpg</url>
      <title>DEV Community: Mat Silva</title>
      <link>https://dev.to/matsilva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matsilva"/>
    <language>en</language>
    <item>
      <title>From JavaScript to Scala</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Fri, 18 Apr 2025 19:24:50 +0000</pubDate>
      <link>https://dev.to/matsilva/from-javascript-to-scala-9ei</link>
      <guid>https://dev.to/matsilva/from-javascript-to-scala-9ei</guid>
      <description>&lt;p&gt;I was writing C# when Node.js came along. You could run JavaScript on the server now. I was in awe. It wasn’t perfect. But it was freeing and dynamic. I went all in.  &lt;/p&gt;

&lt;p&gt;Then came React. Its &lt;a href="https://web.archive.org/web/20150207070137/http://facebook.github.io/react/docs/thinking-in-react.html" rel="noopener noreferrer"&gt;mental model aligned perfectly&lt;/a&gt; with mine. It was simply the V in MVC. Declarative and flexible. It just made sense. Those were good times. I felt like I was standing at the beginning and could clearly see the future. I went all in, again.&lt;/p&gt;

&lt;p&gt;As JavaScript evolved it initially went where I was hoping it would, but then it blew past to... something else? We seemed to &lt;a href="https://dev.to/matsilva/how-javascript-lost-its-way-with-error-handling-can-we-fix-it-hf9"&gt;lose our way with error handling&lt;/a&gt;. &lt;a href="https://dev.to/matsilva/anyone-else-tired-of-having-ssr-shoved-down-their-throats-mgi"&gt;We shoved React SSR Frameworks down everyones throat&lt;/a&gt;. &amp;amp; we let TypeScript(a superset of javascript) win over Javascript and now it’s everywhere, too a fault. &lt;/p&gt;

&lt;p&gt;How do I know? Well when all of my non JS colleagues keep referring to node or javascript as Typescript... that means it's over.&lt;/p&gt;

&lt;p&gt;There are bits about Typescript I really like. I like being able to eliminate statically typed defects. No more guessing at what the &lt;code&gt;data&lt;/code&gt; arg is. That has been pretty damn sweet. But everything else? Just tends to get in the way...&lt;/p&gt;

&lt;p&gt;Pure ESM, while arguably a better approach to modules adds to the hard edges. &lt;/p&gt;

&lt;p&gt;I've tried ejecting from TypeScript and going back to plain JavaScript and pure ESM. But you quickly hit walls trying to tap into the JS ecosystem. Modern JS tooling seems overly dependent on it. You end up having to roll your own everything if you want to eject. You'll eventually find yourself coming back to TypeScript because sadly it is now the least path of resistance. &lt;/p&gt;

&lt;p&gt;I'm hopeful for the future of &lt;del&gt;JavaScript&lt;/del&gt;Typescript, but at present it doesn't quite spark joy for me.&lt;/p&gt;

&lt;p&gt;I started looking elsewhere. I picked up Golang. Bought the books. Built the apps. I liked it. And it worked rather well. Cross platform binaries out of the box was the chefs kiss. Maybe Go was it?&lt;/p&gt;

&lt;p&gt;Maybe not... I really liked it, but it felt too simple, if that even makes sense. I recognize 'simple' is arguably a good thing. But I wanted more depth. Something that could grow with me. Go felt better, but it didn’t make me want to build just for the sake of building again.&lt;/p&gt;

&lt;p&gt;Then, over a year ago, I joined &lt;a href="https://www.akaidentity.io" rel="noopener noreferrer"&gt;AKA Identity&lt;/a&gt; and had to jump into Scala. The architect chose it for AKA's data pipeline. I’d never given Scala much thought before. So at first, I had low expectations. Scala seemed to have a reputation, "Something something about functional purists". I pictured obscure, obfuscated one-liners. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sieve of Eratosthenes&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;(n: Int) =&amp;gt; (2 to n) |&amp;gt; (r =&amp;gt; r.foldLeft(r.toSet)((ps, x) =&amp;gt; if (ps(x)) ps -- (x * x to n by x) else ps))&lt;/code&gt;&lt;br&gt;
&lt;em&gt;source: &lt;a href="https://gist.github.com/mkaz/d11f8f08719d6d27bab5#10-sieve-of-eratosthenes" rel="noopener noreferrer"&gt;10 scala one liners to impress your friends&lt;/a&gt;&lt;/em&gt;  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As part of my team's book club, we picked up Oderskys' &lt;a href="https://www.artima.com/shop/programming_in_scala_5ed" rel="noopener noreferrer"&gt;Programming in Scala&lt;/a&gt;. I couldn’t put it down. I ended up getting &lt;a href="https://www.handsonscala.com/" rel="noopener noreferrer"&gt;more books&lt;/a&gt;. Along the way, I felt excited again. Scala could be powerful without being heavy handed. Expressive without being verbose. I could apply it creatively. Artfully. But only, if I wanted too... Scala for the most part, could be pragmatic and simple. &lt;/p&gt;

&lt;p&gt;&amp;amp; I really appreciated that the Scala devs at AKA leaned into writing pragmatic Scala. Had they not, it's entirely possible I would not have ever given Scala a fair shake.&lt;/p&gt;

&lt;p&gt;My time so far with Scala, reminds me of those early days with Node. The urge to build, creatively, outside of the box. It’s hard to explain. But it felt good. As I learned from Oderskys' writing and others, my mind adapted to Scala’s mental models. It was like the Tetris pieces were falling into place, at the right angle, and clicking. To say it was satisfying would be an understatement.&lt;/p&gt;

&lt;p&gt;So now, I’m thinking about writing this series; From JS to Scala. &lt;/p&gt;

&lt;p&gt;If you're a fellow js dev and feel like I did, largely stuck and and a bit unsatisfied, looking for creative freedom. Maybe Scala will do it for you, too. &lt;/p&gt;

&lt;p&gt;Fwiw, I am not making a 'die hard' switch to Scala. I'll continue to write in TypeScript, Go, and other languages. Scala hasn't replaced them, it made me better at using them. It opened up my mental model and changed how I think about the problem at hand. It made me a more thoughtful coder.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Heres what I am thinking so far:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Async, Multithreading, Coroutines: As They Should Be&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare how Scala and Node.js handle concurrency and CPU-bound tasks.
&lt;/li&gt;
&lt;li&gt;Why async in Node.js trips up developers, who inadvertently block the main thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How this compares to Async in Scala:&lt;/strong&gt; Native multithreading and coroutine support mean true parallelism without blocking the main thread.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Types: Practical and Reliable Typing Without Verbosity/Gymnastics&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why Scala’s type system feels more natural, less verbose, and more flexible compared to TypeScript.
&lt;/li&gt;
&lt;li&gt;Using case classes and sealed traits for structured, type-safe data.
&lt;/li&gt;
&lt;li&gt;How type inference reduces boilerplate without sacrificing clarity.
&lt;/li&gt;
&lt;li&gt;Compare a simple(at least it should be) implementation of returning [Error, GenericType] in TypeScript vs Scala.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For-Comprehensions: Concise Async Control Flow&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use for-comprehensions for asynchronous operations and data transformation.
&lt;/li&gt;
&lt;li&gt;Replace complex callback chains or async/await patterns without reducing all errors into a single try-catch channel like JavaScript does.
&lt;/li&gt;
&lt;li&gt;Real-world examples comparing JS async/await and promise chains to Scala’s for-comprehensions.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pattern Matching for Control Flow&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How Scala’s pattern matching offers a more intuitive way to manage control flow.
&lt;/li&gt;
&lt;li&gt;Demonstrate pattern matching with both simple and complex data types.
&lt;/li&gt;
&lt;li&gt;Show how pattern matching can cleanly handle data processing and branching logic compared to typical control flow you'd see in Javascript.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Options and the None Type: No More Null &amp;amp; Undefined Shenanigans&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compare Scala’s Options approach to TypeScript’s nullable types.
&lt;/li&gt;
&lt;li&gt;Highlight the confusion between valid JavaScript and TypeScript's rigidity, where making valid JS work freely often results in weird and inconsistent handling of null, undefined, and other falsey values.
&lt;/li&gt;
&lt;li&gt;&amp;amp; How ultimately, Scala’s Option makes handling potential value absence straightforward, eliminating null and undefined entirely.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Writing APIs That Feel Native&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Imagine being able to define a custom operator in TypeScript, like Akka’s &lt;code&gt;!&lt;/code&gt; operator in Scala, to send messages with a simple syntax: &lt;code&gt;myService ! "Hello, World!"&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;In TypeScript, achieving this would require writing a custom compiler plugin, and even then, it would be cumbersome to adopt and maintain. In Scala, the ability to express syntax like this is built in. It enables creative expression, to solve the problem at hand.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pragmatic Scalability: Avoiding Clever Code&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This will show that Scala can be written using simple and pragmatic semantics. Which is important for new comers like myself.&lt;/li&gt;
&lt;li&gt;Discusses the reality that Scala can also enable very obscure, albeit clever, code. &amp;amp; as Odersky says, we should apply this artfully.&lt;/li&gt;
&lt;li&gt;Highlight libraries that promote pragmatic Scala usage, like those by Li Haoyi (e.g., &lt;a href="https://github.com/com-lihaoyi" rel="noopener noreferrer"&gt;lihaoyi’s libraries&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Practical examples of balancing expressiveness with readability.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Building and Deploying a Scala App: From Nuts to Soup&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A full example of building, testing, and deploying a Scala application. It can be a lot easier than you'd think.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&amp;amp; I am sure plenty more after I groom my past notes from the books I've read.&lt;/p&gt;

&lt;p&gt;** Topic Ideas From Feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/scala/comments/1k13xq4/comment/mqqj1rp/" rel="noopener noreferrer"&gt;React to Scala step by step&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/scala/comments/1k13xq4/comment/mqsh39g/" rel="noopener noreferrer"&gt;Redux to Scala step by step&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>scala</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What Senior Frontend Developers Actually Care About</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Wed, 26 Mar 2025 14:07:16 +0000</pubDate>
      <link>https://dev.to/matsilva/what-senior-frontend-developers-actually-care-about-5cnb</link>
      <guid>https://dev.to/matsilva/what-senior-frontend-developers-actually-care-about-5cnb</guid>
      <description>&lt;p&gt;Years ago, I completed &lt;a href="https://github.com/matsilva/logdna-takehome" rel="noopener noreferrer"&gt;a take-home challenge&lt;/a&gt; that landed me a senior frontend job at LogDNA. Technology has moved on—Playwright is replacing Cypress, SSR frameworks like Next and Remix surpassed single-page apps—but the core principles haven’t changed. Good principles outlast tech trends.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Architecture That Scales
&lt;/h2&gt;

&lt;p&gt;Senior developers build code designed to grow. Scalability isn't just about technical performance or user experience; it also involves internal processes to easily onboard new developers and sustain long-term maintenance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear Structure&lt;/strong&gt;: Logical separation between UI and backend, clearly shown in a monorepo structure:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  packages/
    ├── ui/                  # Frontend application
    │   ├── src/
    │   │   ├── api-client/  # API client layer
    │   │   ├── form/        # Form components and state
    │   │   ├── layout/      # Layout components
    │   │   ├── translate/   # i18n utilities
    │   │   └── types/       # TypeScript type definitions
    │   └── package.json
    └── server/              # Backend application
        └── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Predictable Typing&lt;/strong&gt;: Strongly typed systems (e.g., TypeScript) with shared types:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AlertDetails&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HOURLY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DAILY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplified State Management&lt;/strong&gt;: Reactive state handling with minimal boilerplate (MobX):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FormInputState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;observable&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Forms&lt;/strong&gt;: Real-time, robust validation (Joi schemas):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alertSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;required&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;
  
  
  2. Testing as a Priority
&lt;/h2&gt;

&lt;p&gt;Quality code requires thorough testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear Logic Testing&lt;/strong&gt;: Straightforward unit tests for components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-world Scenarios&lt;/strong&gt;: Cypress for end-to-end user behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inclusive Design Testing&lt;/strong&gt;: Axe-core for accessibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Coverage&lt;/strong&gt;: Validating both success and error scenarios.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Developer Experience
&lt;/h2&gt;

&lt;p&gt;Good developers write readable, maintainable code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Formatting&lt;/strong&gt;: Prettier to streamline readability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logical Organization&lt;/strong&gt;: Components, tests, and styles grouped logically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDE Integration&lt;/strong&gt;: TypeScript catches errors during development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear Documentation&lt;/strong&gt;: Simple, comprehensive README files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Thoughtful User Experience
&lt;/h2&gt;

&lt;p&gt;Senior developers see what others miss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Immediate Feedback&lt;/strong&gt;: Real-time validation with clear interactions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipients&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Keyboard navigation, ARIA roles, and managed focus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent States&lt;/strong&gt;: Clear loading indicators and actionable error messages:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;loading&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="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form.save&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inclusive Design&lt;/strong&gt;: UX designed for all users.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Internationalization from the Start
&lt;/h2&gt;

&lt;p&gt;Thinking global from day one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalable Translations&lt;/strong&gt;: Externalize all strings:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;i18next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;fallbackLng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadPath&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear Localization&lt;/strong&gt;: Maintainable file structures by locale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Performance Matters
&lt;/h2&gt;

&lt;p&gt;Performance is prioritized&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Builds&lt;/strong&gt;: Fast-loading, minimal bundle sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainable Build Outputs&lt;/strong&gt;: Cleanly structured artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React Render Optimizations&lt;/strong&gt;: Using MobX for precise JSX updates, outperforming React’s native state handling in efficiency and clarity:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TextInput&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;form&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;}&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Built-in Security
&lt;/h2&gt;

&lt;p&gt;Security isn't optional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strict Validation&lt;/strong&gt;: Sanitized inputs with schemas:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML Escaping&lt;/strong&gt;: Preventing XSS by escaping HTML:
&lt;/li&gt;
&lt;/ul&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;sanitized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hoek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escapeHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;CORS Protection&lt;/strong&gt;: Configured secure cross-origin resource sharing:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;additionalHeaders&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="s1"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CORS_ORIGIN&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Discipline&lt;/strong&gt;: Discerns what data presents risks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Handling&lt;/strong&gt;: Configured secure access policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Choosing Quality Tools (at the Time)
&lt;/h2&gt;

&lt;p&gt;Quality is in careful selection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intentional Choices&lt;/strong&gt;: Tools aligned with clear goals (e.g., TypeScript, MobX, Tailwind).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balance and Pragmatism&lt;/strong&gt;: Effective solutions, minimal complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What This Means
&lt;/h2&gt;

&lt;p&gt;Senior frontend developers aren’t swayed by trends. They adhere to timeless principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global readiness&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core Idea
&lt;/h2&gt;

&lt;p&gt;Hiring senior developers is about finding those who build on lasting principles. They know it's not just about what to build but how to build it. Solid foundations always matter more than the latest technologies.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>JavaScript Lost Its Way With Error Handling</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Mon, 24 Mar 2025 16:54:16 +0000</pubDate>
      <link>https://dev.to/matsilva/how-javascript-lost-its-way-with-error-handling-can-we-fix-it-hf9</link>
      <guid>https://dev.to/matsilva/how-javascript-lost-its-way-with-error-handling-can-we-fix-it-hf9</guid>
      <description>&lt;h2&gt;
  
  
  Reasoning About JavaScript Errors Used to Be Simple
&lt;/h2&gt;

&lt;p&gt;We had a dedicated channel in callbacks. We knew when something went wrong for that function.&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file.txt&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;err&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="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="nf"&gt;log&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You checked for the error. You dealt with it.&lt;br&gt;&lt;br&gt;
No surprises. No magic.&lt;/p&gt;

&lt;p&gt;It wasn’t pretty, because callback hell. But it was clear.&lt;/p&gt;
&lt;h2&gt;
  
  
  Then Came Async/Await
&lt;/h2&gt;

&lt;p&gt;It looked clean. Linear. Easy to follow. Arguably, it still is.&lt;/p&gt;

&lt;p&gt;But we started throwing errors again, to a fault. &lt;/p&gt;

&lt;p&gt;Now errors are all in the same channel.&lt;/p&gt;

&lt;p&gt;Like 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="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/user/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&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;fastify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notFound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&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 seems fine—until you need to do more than one thing.&lt;br&gt;&lt;br&gt;
Suddenly, your &lt;code&gt;catch&lt;/code&gt; block becomes a patchwork of if-statements:&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;fastify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/user/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&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;fastify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notFound&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="nf"&gt;getUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;req&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="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User not found: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;req&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="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unauthorized access`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&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;req&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unexpected error&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;p&gt;You're using &lt;code&gt;catch&lt;/code&gt; not just for exceptions, but for expected things:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user not found
&lt;/li&gt;
&lt;li&gt;Invalid auth
&lt;/li&gt;
&lt;li&gt;Bad input
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're forced to &lt;strong&gt;reverse-engineer intent&lt;/strong&gt; from the thrown error.&lt;br&gt;&lt;br&gt;
You lose clarity. You lose control.&lt;/p&gt;
&lt;h2&gt;
  
  
  Other Languages Seem To Do Better
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Go
&lt;/h3&gt;

&lt;p&gt;Go keeps it simple. Errors are values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;You deal with the error. Or you don’t. But you don’t ignore it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scala
&lt;/h3&gt;

&lt;p&gt;Scala uses types to make the rules clear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Either&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Throwable&lt;/span&gt;, &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;readString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file.txt"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;}.&lt;/span&gt;&lt;span class="py"&gt;toEither&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Left&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Error: $err"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Right&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"Success: $data"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You must handle both outcomes.&lt;br&gt;&lt;br&gt;
No free passes. No silent failures.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;Option&lt;/code&gt; for missing values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;maybeValue&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;maybeValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;getOrElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;null&lt;/code&gt;. No &lt;code&gt;undefined&lt;/code&gt;. No guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What JavaScript Could Be
&lt;/h2&gt;

&lt;p&gt;We don’t have to do 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="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;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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;We could do 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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;err&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to read file:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File contents:&lt;/span&gt;&lt;span class="dl"&gt;'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s clear. It’s honest. It works.&lt;/p&gt;

&lt;p&gt;Or we use a result wrapper:&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;result&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;Result&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isErr&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="nf"&gt;error&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="nx"&gt;error&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="nx"&gt;value&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;You know what's expected. You know what blew up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Write Better Code?
&lt;/h2&gt;

&lt;p&gt;Here are some tools to help with that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/davidbanham/await-to-js" rel="noopener noreferrer"&gt;&lt;code&gt;await-to-js&lt;/code&gt;&lt;/a&gt; — &lt;code&gt;[err, data]&lt;/code&gt; pattern
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/supermacro/neverthrow" rel="noopener noreferrer"&gt;&lt;code&gt;neverthrow&lt;/code&gt;&lt;/a&gt; — type-safe error handling
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/traverse1984/oxide.ts" rel="noopener noreferrer"&gt;&lt;code&gt;oxide.ts&lt;/code&gt;&lt;/a&gt; — Rust-style &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt; types for TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One Last Thing
&lt;/h2&gt;

&lt;p&gt;This is a bit of the old “you made your bed, now lie in it.”&lt;br&gt;
We started throwing everything into a single channel.&lt;br&gt;
We didn’t think it through.&lt;/p&gt;

&lt;p&gt;But it’s fixable.&lt;/p&gt;

&lt;p&gt;Choose better patterns.&lt;br&gt;
Throw less.&lt;br&gt;
Write what you mean.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>fastify</category>
      <category>errors</category>
      <category>async</category>
    </item>
    <item>
      <title>Anyone Else Tired of Having SSR Shoved Down Their Throats?</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Wed, 19 Mar 2025 14:42:48 +0000</pubDate>
      <link>https://dev.to/matsilva/anyone-else-tired-of-having-ssr-shoved-down-their-throats-mgi</link>
      <guid>https://dev.to/matsilva/anyone-else-tired-of-having-ssr-shoved-down-their-throats-mgi</guid>
      <description>&lt;p&gt;You see back in the day, deploying a single page app(SPA) or static site was dead simple. We had tools like now, firebase deploy, etc that offered one command deployments for &lt;em&gt;any&lt;/em&gt; client side app framework. I loved those tools.&lt;/p&gt;

&lt;p&gt;But when I reached for them to build a client side app, their OOTB SPA support was largely, gone?&lt;/p&gt;

&lt;p&gt;What the heck happened? &lt;/p&gt;

&lt;p&gt;&lt;em&gt;SSR frameworks did&lt;/em&gt;. &lt;em&gt;The entire React ecosystem has over rotated&lt;/em&gt;. What was once the V in MVC, is now an overly-prescriptive framework that encourages newcomers to 'lock in' to a recommended full-stack framework.&lt;/p&gt;

&lt;p&gt;Go look at the react docs today. See for yourself. (as of 4-18-2025).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t4xxsg3nh3lveoim2vs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t4xxsg3nh3lveoim2vs.png" alt="Image description" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And note...&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The push to full-stack frameworks&lt;/li&gt;
&lt;li&gt;No mention of  vite  as an option to scaffold a react app.&lt;/li&gt;
&lt;li&gt;A big green note &lt;em&gt;explainering&lt;/em&gt; our misconceptions about these frame-works...&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;It seems to me that the writing is on the wall&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even react router now leads with the 'framework' mode first. Pushing client side apps further and further into 2nd and 3rd class citizens.&lt;/p&gt;

&lt;p&gt;&amp;amp; for that reason, I have my client side react apps pinned on react router 6.30.0. I'm also  tempted to fork this version, rip out the server side framework bits and make the client a first class citizen again.&lt;/p&gt;

&lt;p&gt;Could someone explain to me why we are acting like frontend teams need full stack platforms just to build and ship client side apps? &lt;/p&gt;

&lt;p&gt;&amp;amp; how the heck did we let these platforms convince us they can charge us for bandwidth for our app's static assets? – A commodity that is practically free due to CDN technology.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is stockholm syndrome for $800? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe I'm just getting old? But while I was wrestling these frameworks, I had a moment where I was like why is this so much harder than it needs to be? Are people really happy with with this for client side only apps? &lt;/p&gt;

&lt;p&gt;I just needed to be able to ship a relatively simple client side app, quickly. So I reached for &lt;a href="https://vite.dev/guide/#scaffolding-your-first-vite-project" rel="noopener noreferrer"&gt;vite to scaffold my react app&lt;/a&gt;. Thank you vite for making this dead simple!&lt;/p&gt;

&lt;p&gt;But now for deployments... oof. Wow. How did we take so many steps backwards? &lt;/p&gt;

&lt;p&gt;Did I really need to reinvent the wheel? I guess so... so I did and it was kinda glorious. I dusted off an ole' &lt;a href="https://dev.to/matsilva/boost-the-ux-of-your-react-app-with-hash-based-content-caching-2h8g"&gt;nginx hash and cache strategy&lt;/a&gt; I wrote about years ago.&lt;/p&gt;

&lt;p&gt;&amp;amp; turned it into a CLI called &lt;strong&gt;godeploy&lt;/strong&gt;. It does what I needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generates Nginx configs
&lt;/li&gt;
&lt;li&gt;Handles hashed assets for proper caching **&lt;/li&gt;
&lt;li&gt;Packs everything into a Docker container &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I made it &lt;a href="https://github.com/matsilva/godeploy" rel="noopener noreferrer"&gt;open source&lt;/a&gt;.  If you want to host your own frontend using an nginx server that will beat the pants off of any SSR runtime, it's yours to do so.&lt;/p&gt;

&lt;p&gt;But I still missed the one-command deploy. &lt;/p&gt;

&lt;p&gt;So you bet your sweet buns I built that too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;godeploy deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app goes live at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://your-autogenerated-subdomain.spa.godeploy.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All too easy. As it should be.&lt;/p&gt;

&lt;p&gt;Now this is a hosted service, not open source. But it feels like the old days. One command. Done.&lt;/p&gt;




&lt;p&gt;In case you are wondering, I most definitely like Tony Montana right now, getting high on my own supply with GoDeploy. &lt;/p&gt;

&lt;p&gt;&amp;amp; As an ROI junky in a past life, I had to throw in my deployment stats in the dashboard.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b4qmebeft6rckzms60o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1b4qmebeft6rckzms60o.png" alt="Image description" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ixaChKsXo7U" rel="noopener noreferrer"&gt;Just look at those graphs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyway no pressure. I'm just shipping what I needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://godeploy.app/" rel="noopener noreferrer"&gt;https://godeploy.app&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/matsilva/godeploy" rel="noopener noreferrer"&gt;https://github.com/matsilva/godeploy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>vue</category>
      <category>ssr</category>
    </item>
    <item>
      <title>The Tech Shed - Remote Work Space</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Wed, 28 Aug 2019 20:18:12 +0000</pubDate>
      <link>https://dev.to/matsilva/the-tech-shed-remote-work-space-8gl</link>
      <guid>https://dev.to/matsilva/the-tech-shed-remote-work-space-8gl</guid>
      <description>&lt;p&gt;Hi I am &lt;a href="https://twitter.com/matsilva"&gt;Mat Silva&lt;/a&gt; &amp;amp; I work remotely. I wanted to share some pictures of my work space (what I call the "tech shed").&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BW7JdyDj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tjop7194nk91kg6lyjnd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BW7JdyDj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tjop7194nk91kg6lyjnd.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NHv_q0Zi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2lkqibznkog6shk4eq75.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NHv_q0Zi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2lkqibznkog6shk4eq75.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wfG_5a9d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/acgiagxh3cj3c78c3cxk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wfG_5a9d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/acgiagxh3cj3c78c3cxk.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XwHti5nU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/i731fs72hto1vink85rn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XwHti5nU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/i731fs72hto1vink85rn.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gkRjAlJd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xm64ra7l6dktjpwld6ez.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkRjAlJd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xm64ra7l6dktjpwld6ez.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
I am still working on better cable management 😬&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ViKKvi88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fawispsx7zr5prqywmdn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ViKKvi88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fawispsx7zr5prqywmdn.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
When it rains, I really enjoy being able to feel close to it.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2-uUioxw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/snquselz8jg77y4btm6s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2-uUioxw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/snquselz8jg77y4btm6s.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jwNaQ1Sd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/eq16pcm1lg0q9jtyrzbk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jwNaQ1Sd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/eq16pcm1lg0q9jtyrzbk.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Here is a little bit wider of a view...&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n0LjtQf5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/m0d3fgqfmkozxobjsewd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n0LjtQf5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/m0d3fgqfmkozxobjsewd.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&amp;amp; every now and then my dogs want to hang with me in here.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eacmZbqe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6af0gg228tynuy10kb8i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eacmZbqe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6af0gg228tynuy10kb8i.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;UPDATE:&lt;br&gt;
Added some sweet lighting &amp;amp; more art from &lt;a href="https://www.patreon.com/GenelJumalon"&gt;@geneljumalon&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZZoMl9V5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p6orzev3rdok29as1qwf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZZoMl9V5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p6orzev3rdok29as1qwf.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Got a cool setup for your workspace? Share in the comments.&lt;/p&gt;

</description>
      <category>remote</category>
      <category>workspace</category>
    </item>
    <item>
      <title>Fetch API gotcha in cypress.io and how to fix it.</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Tue, 27 Aug 2019 17:23:40 +0000</pubDate>
      <link>https://dev.to/matsilva/fetch-api-gotcha-in-cypress-io-and-how-to-fix-it-7ah</link>
      <guid>https://dev.to/matsilva/fetch-api-gotcha-in-cypress-io-and-how-to-fix-it-7ah</guid>
      <description>&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt;&lt;br&gt;
When you use the fetch API on the client side, you cannot stub routes in &lt;a href="https://www.cypress.io/"&gt;cypress.io&lt;/a&gt; because of the &lt;a href="https://github.com/cypress-io/cypress/issues/95"&gt;lack in support&lt;/a&gt; in cypress atm. &lt;/p&gt;

&lt;p&gt;This is something I ran into when implementing the graphql &lt;a href="https://www.apollographql.com/docs/react/"&gt;apollo-client&lt;/a&gt; &lt;a href="https://www.apollographql.com/docs/link/links/rest/"&gt;apollo-link-rest&lt;/a&gt;, since it uses the fetch api out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is what I did to fix it:&lt;/strong&gt;&lt;br&gt;
First I made sure to polyfill the fetch api using &lt;a href="https://github.com/whatwg/fetch"&gt;whatwg-fetch&lt;/a&gt;, but only in development or testing environments, since I don't need it in production builds.&lt;/p&gt;

&lt;p&gt;So in my the main entry point to my app &lt;code&gt;index.tsx&lt;/code&gt;, I added this near the top.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//**this will get stripped out of production builds by webpack */&lt;/span&gt;
&lt;span class="c1"&gt;//@ts-ignore&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;PRODUCTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;whatwg-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//for polyfill cypress test &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For my &lt;code&gt;webpack.development.js&lt;/code&gt; config file, I added this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DefinePlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;PRODUCTION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and in my &lt;code&gt;webpack.production.js&lt;/code&gt; config file, I added this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DefinePlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;PRODUCTION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="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;Next I added a new &lt;code&gt;visitWithDelWinFetch&lt;/code&gt; command to cypress which will delete the fetch api on the &lt;code&gt;window&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Cypress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visitWithDelWinFetch&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;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&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="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;onBeforeLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;win&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;win&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&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 will kick in the fetch polyfill. Now you'll be able to stub routes like you'd expect in cypress.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/api/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getApiPath&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visitWithDelWinFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And to give credit where it's due, this was largely inspired by &lt;a href="https://github.com/cypress-io/cypress/issues/95#issuecomment-281273126"&gt;this solution&lt;/a&gt; in the comments.&lt;/p&gt;

&lt;p&gt;Also note that if you don't care about ever using the fetch api in your tests, you could avoid having a separate visit command using &lt;a href="https://github.com/cypress-io/cypress/issues/95#issuecomment-343214638"&gt;this solution&lt;/a&gt; paired with the fetch polyfill.&lt;/p&gt;

</description>
      <category>fetch</category>
      <category>cypress</category>
      <category>fix</category>
      <category>apolloclient</category>
    </item>
    <item>
      <title>Boost the UX of your React app with hash based content caching.</title>
      <dc:creator>Mat Silva</dc:creator>
      <pubDate>Sun, 04 Aug 2019 15:38:44 +0000</pubDate>
      <link>https://dev.to/matsilva/boost-the-ux-of-your-react-app-with-hash-based-content-caching-2h8g</link>
      <guid>https://dev.to/matsilva/boost-the-ux-of-your-react-app-with-hash-based-content-caching-2h8g</guid>
      <description>&lt;h2&gt;
  
  
  What problem are we trying to solve?
&lt;/h2&gt;

&lt;p&gt;Say you have a JavaScript app that gets served up at &lt;code&gt;http://mysite.com/js/myapp.js&lt;/code&gt;. A typical performance optimization is to tell the browser to cache &lt;code&gt;myapp.js&lt;/code&gt; so that the user doesn't have to re-download the asset every time they use the app. If you practice continuous delivery, the problem you run into is delivering new app updates. If &lt;code&gt;myapp.js&lt;/code&gt; is cached, the user won't get the new updates until either a) they clear their cache or b) the &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#max-age" rel="noopener noreferrer"&gt;max-age&lt;/a&gt; expires.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;From the google dev docs:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ideally, you should aim to cache as many responses as possible on the client for the longest possible period, and provide validation tokens for each response to enable efficient revalidation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What we're going to do in this guide is we're going to come up with a way to cache our application assets for the longest possible time: FOREVER! Well sort of.. we are going to be using a hash based content caching strategy, which the &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#defining_optimal_cache-control_policy" rel="noopener noreferrer"&gt;google dev docs&lt;/a&gt; mentions it gives you the best of both worlds: client-side caching and quick updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started with create-react-app
&lt;/h3&gt;

&lt;p&gt;So to get started, we are going to use good ole &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;create react app&lt;/a&gt; to quickly standup a new single page application.&lt;/p&gt;

&lt;p&gt;Let's create a new app, &lt;code&gt;create-react-app content-cache&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So in a new directory, &lt;code&gt;~/code&lt;/code&gt;, lets run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app content-cache
cd content-cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now you'll have a new app setup in &lt;code&gt;~/code/content-cache&lt;/code&gt; and you should now be in the &lt;code&gt;content-cache&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now we can run &lt;code&gt;npm run build&lt;/code&gt; which will output all the assets for your app in &lt;code&gt;./build&lt;/code&gt;. With these assets now available, let's take a look at serving these with nginx.&lt;/p&gt;

&lt;h3&gt;
  
  
  nginx + docker = yayyyyyy
&lt;/h3&gt;

&lt;p&gt;Let's go ahead and create a new file, &lt;code&gt;touch ~/code/content-cache/Dockerfile&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM nginx:1.13-alpine

RUN apk add --no-cache bash curl

COPY nginx/ /

CMD ["/docker-entrypoint.sh", "nginx", "-g", "daemon off;"]

EXPOSE 8080

COPY build/static/ /usr/share/nginx/html/

COPY package.json /

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

&lt;/div&gt;



&lt;p&gt;You'll notice we are missing a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;nginx/&lt;/code&gt;folder being copied.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;docker-entrypoint.sh&lt;/code&gt; script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's go ahead and add those now.&lt;/p&gt;

&lt;p&gt;Create a new directory, &lt;code&gt;mkdir -p ~/code/content-cache/nginx/etc/nginx&lt;/code&gt; and then create a new file &lt;code&gt;touch ~/code/content-cache/nginx/etc/nginx/nginx.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then open up the file and copy the following contents into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    gzip  on;
    gzip_types text/plain application/xml application/javascript text/css;

    include /etc/nginx/conf.d/*.conf;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of this is boilerplate nginx config, so I am not going to spend time explaining it, you can learn more from the &lt;a href="https://docs.nginx.com/nginx/admin-guide/web-server" rel="noopener noreferrer"&gt;nginx docs&lt;/a&gt;. Just note that we are including &lt;code&gt;/etc/nginx/conf.d/*.conf&lt;/code&gt;, which includes the &lt;code&gt;default.conf&lt;/code&gt; file, we'll be creating next.&lt;/p&gt;

&lt;p&gt;Let's go ahead and create the file, &lt;code&gt;touch ~/code/content-cache/nginx/etc/nginx/conf.d/default.conf&lt;/code&gt; and add the following contents to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen       8080;

    # include the hash based content
    include /etc/nginx/conf.d/app/*.conf;

    location ~ ^/$ {
        # we are serving the app at `/a/`
        return 303 a/;
    }

    # serve other static assets
    location / {
        root   /usr/share/nginx/html;
        index  /index.html;
        try_files $uri /index.html;
        include /etc/nginx/conf.d/app/preload.headers;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to be serving the app at &lt;code&gt;/a/&lt;/code&gt;, which is a strategy used to make life a bit easier when dealing with reverse proxying to backend APIs that live on the same domain.&lt;/p&gt;

&lt;p&gt;So again, make note that we are including &lt;code&gt;/etc/nginx/conf.d/app/*.conf;&lt;/code&gt;, which is our hash based content.&lt;/p&gt;

&lt;p&gt;Now let's move on to creating a new file &lt;code&gt;touch ~/code/content-cache/nginx/docker-entrypoint.sh&lt;/code&gt; where the magic happens.&lt;/p&gt;

&lt;p&gt;Paste in the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash

mkdir -p /etc/nginx/conf.d/app
pushd /usr/share/nginx/html/js/ &amp;gt; /dev/null

APP_JS=/app/js/app.js
for js in main.*.*.js
do
    cat  &amp;gt; /etc/nginx/conf.d/app/js.conf &amp;lt;&amp;lt;EOF
location ~* ^/app/js/main.js([.]map)?\$ {
    expires off;
    add_header Cache-Control "no-cache";
    return 303 ${js}\$1;
}
location ~* ^/app/js/(main[.][a-z0-9][a-z0-9]*[.]js(?:[.]map)?)\$ {
    alias   /usr/share/nginx/html/js/\$1;
    expires max;
    add_header Cache-Control "public; immutable";
}
EOF
    APP_JS="/js/${js}"
    break;
done
RUNTIME_JS=/app/js/runtime.js
for js in runtime~main.*.js
do
    cat  &amp;gt; /etc/nginx/conf.d/app/js.conf &amp;lt;&amp;lt;EOF
location ~* ^/app/js/runtime~main.js([.]map)?\$ {
    expires off;
    add_header Cache-Control "no-cache";
    return 303 ${js}\$1;
}
location ~* ^/app/js/(runtime~main[.][a-z0-9][a-z0-9]*[.]js(?:[.]map)?)\$ {
    alias   /usr/share/nginx/html/js/\$1;
    expires max;
    add_header Cache-Control "public; immutable";
}
EOF
    RUNTIME_JS="/js/${js}"
    break;
done
VENDOR_JS=/app/js/vendor.js
for js in 2.*.*.js
do
    cat &amp;gt;&amp;gt; /etc/nginx/conf.d/app/js.conf &amp;lt;&amp;lt;EOF
location ~* ^/app/js/2[.]js([.]map)?\$ {
    expires off;
    add_header Cache-Control "no-cache";
    return 303 ${js}\$1;
}
location ~* ^/app/js/(2[.][a-z0-9][a-z0-9]*[.]js(?:[.]map)?)\$ {
    alias   /usr/share/nginx/html/js/\$1;
    expires max;
    add_header Cache-Control "public; immutable";
}
EOF
    VENDOR_JS="/js/${js}"
    break;
done

cd ../css
APP_CSS=/app/css/main.css
for css in main.*.*.css
do
    cat &amp;gt; /etc/nginx/conf.d/app/css.conf &amp;lt;&amp;lt;EOF
location ~* ^/app/css/main.css([.]map)?\$ {
    expires off;
    add_header Cache-Control "no-cache";
    return 303 ${css}\$1;
}
location ~* ^/app/css/(main[.][a-z0-9][a-z0-9]*[.]css(?:[.]map)?)\$ {
    alias   /usr/share/nginx/html/css/\$1;
    expires max;
    add_header Cache-Control "public; immutable";
}
EOF
    APP_CSS="/css/${css}"
done

cd ..

cat &amp;gt; /etc/nginx/conf.d/app/preload.headers &amp;lt;&amp;lt;EOF
add_header Cache-Control "public; must-revalidate";
add_header Link "&amp;lt;${APP_CSS}&amp;gt;; rel=preload; as=style; type=text/css; nopush";
add_header Link "&amp;lt;${VENDOR_JS}&amp;gt;; rel=preload; as=script; type=text/javascript; nopush";
add_header Link "&amp;lt;${APP_JS}&amp;gt;; rel=preload; as=script; type=text/javascript; nopush";
add_header X-Frame-Options "SAMEORIGIN" always;
EOF

cat &amp;gt; index.html &amp;lt;&amp;lt;EOF
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"/&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"/&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="ie=edge"/&amp;gt;
    &amp;lt;title&amp;gt;Create React app&amp;lt;/title&amp;gt;
    &amp;lt;link href="${APP_CSS}" rel="stylesheet"&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div id="root"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script type="text/javascript" src="${VENDOR_JS}"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="${APP_JS}"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="${RUNTIME_JS}"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
EOF

popd &amp;gt; /dev/null

exec "$@"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go ahead and break this down bit by bit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p /etc/nginx/conf.d/app
pushd /usr/share/nginx/html/js/ &amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a new directory and uses &lt;code&gt;pushd&lt;/code&gt; to cd into the &lt;code&gt;/usr/share/nginx/html/js&lt;/code&gt; directory, while redirecting the output to &lt;code&gt;/dev/null&lt;/code&gt; so the console doesn't get noisy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_JS=/a/js/app.js
for js in main.*.*.js
do
    cat  &amp;gt; /etc/nginx/conf.d/app/js.conf &amp;lt;&amp;lt;EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a for loop, which iterates over the javascript files matching &lt;code&gt;main.*.*.js&lt;/code&gt;, which is the pattern for our hashed content files. It then concatenates the location blocks into a file &lt;code&gt;/etc/nginx/conf.d/app/js.conf&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;location ~* ^/a/js/main.js([.]map)?\$ {
    expires off;
    add_header Cache-Control "no-cache";
    return 303 ${js}\$1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also are redirecting any requests to &lt;code&gt;/a/js/main.js&lt;/code&gt; to the matching hash based filed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location ~* ^/a/js/(main[.][a-z0-9][a-z0-9]*[.]js(?:[.]map)?)\$ {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also notice we are matching &lt;code&gt;.map&lt;/code&gt; files so that we can load source map files as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    alias   /usr/share/nginx/html/js/\$1;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we are caching those hash based files to the MAX!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    expires max;
    add_header Cache-Control "public; immutable";
}
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then store the hashed asset file in &lt;code&gt;APP_JS&lt;/code&gt; so we can use that later in the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    APP_JS="/js/${js}"
    break;
done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next three for loops do the same as above, but for the different asset files. The runtime files &lt;code&gt;runtime~main.*.js&lt;/code&gt;, the vendor files &lt;code&gt;2.*.*.js&lt;/code&gt;, and the css files &lt;code&gt;main.*.*.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next we set our &lt;code&gt;preload.headers&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;cat &amp;gt; /etc/nginx/conf.d/app/preload.headers &amp;lt;&amp;lt;EOF
add_header Cache-Control "public; must-revalidate";
add_header Link "&amp;lt;${APP_CSS}&amp;gt;; rel=preload; as=style; type=text/css; nopush";
add_header Link "&amp;lt;${VENDOR_JS}&amp;gt;; rel=preload; as=script; type=text/javascript; nopush";
add_header Link "&amp;lt;${APP_JS}&amp;gt;; rel=preload; as=script; type=text/javascript; nopush";
add_header X-Frame-Options "SAMEORIGIN" always;
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the browser to preload these assets and store these files in the http cache. We specify &lt;code&gt;nopush&lt;/code&gt; so that the server knows we only want to preload it for now.&lt;/p&gt;

&lt;p&gt;We then dynamically create our &lt;code&gt;index.html&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; index.html &amp;lt;&amp;lt;EOF
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"/&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"/&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="ie=edge"/&amp;gt;
    &amp;lt;title&amp;gt;Create React app&amp;lt;/title&amp;gt;
    &amp;lt;link href="${APP_CSS}" rel="stylesheet"&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div id="root"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script type="text/javascript" src="${VENDOR_JS}"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the &lt;code&gt;APP_JS&lt;/code&gt; variable to set the src for our js file. We also do the same for the other asset files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;script type="text/javascript" src="${APP_JS}"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script type="text/javascript" src="${RUNTIME_JS}"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we change back to the original directory with &lt;code&gt;popd &amp;gt; /dev/null&lt;/code&gt; and then execute any args passed to this script &lt;code&gt;exec "$@"&lt;/code&gt;. That's important otherwise the args after the &lt;code&gt;"/docker-entrypoint.sh"&lt;/code&gt; will not work in our Dockerfile command: &lt;code&gt;CMD ["/docker-entrypoint.sh", "nginx", "-g", "daemon off;"]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's see it all in action
&lt;/h3&gt;

&lt;p&gt;We're going to build and run the Docker container.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;~/code/content-cache&lt;/code&gt;, run: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chmod +x ./nginx/docker-entrypoint.sh&lt;/code&gt; - make the script executable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker build -t nginx/test .&lt;/code&gt; - this builds the image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker run --name="nginx-test-app" -p 8080:8080 nginx/test&lt;/code&gt; - this runs the docker container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that your app is running, head to &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;. Open up the network tab in your dev tools and refresh the page. You should see the JavaScript and CSS assets should now be getting cached. It should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc0lsuttah38kt9osoh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc0lsuttah38kt9osoh0.png" alt="hashed content in network tab" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking good! Now let's do another build just to make sure it is working as intended. Kill the current docker container by pressing ctr + c and then running &lt;code&gt;docker rm nginx-test-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now run &lt;code&gt;npm run build &amp;amp;&amp;amp; docker build -t nginx/test .&lt;/code&gt; then  &lt;code&gt;docker run --name="nginx-test-app" -p 8080:8080 nginx/test&lt;/code&gt;, open up &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; and checkout the network tab to confirm that the asset files are from the latest build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc0lsuttah38kt9osoh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc0lsuttah38kt9osoh0.png" alt="latest build assets in network tab" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤘Now we're talking! At this point now, we have the best of both worlds setup: &lt;em&gt;&lt;em&gt;Max content caching and quick updates&lt;/em&gt;&lt;/em&gt; when a new version of our app is deployed.&lt;/p&gt;

&lt;p&gt;Feel free to use this technique and modify to fit your own needs. The link to the repo is below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/matsilva/nginx-hash-cache" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Credits:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/connolly_s" rel="noopener noreferrer"&gt;@connolly_s&lt;/a&gt; - showed me the light with this strategy 🤣&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>caching</category>
      <category>performance</category>
      <category>ngnix</category>
      <category>react</category>
    </item>
  </channel>
</rss>
