<?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: Jono Cairns</title>
    <description>The latest articles on DEV Community by Jono Cairns (@jonocairns).</description>
    <link>https://dev.to/jonocairns</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%2F654191%2F05d8f3c3-ab12-4ee1-976e-5376c954355b.png</url>
      <title>DEV Community: Jono Cairns</title>
      <link>https://dev.to/jonocairns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jonocairns"/>
    <language>en</language>
    <item>
      <title>Caching, Azure and Static Sites (Create React App)</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Wed, 23 Nov 2022 23:28:30 +0000</pubDate>
      <link>https://dev.to/jonocairns/caching-azure-and-static-sites-create-react-app-j3p</link>
      <guid>https://dev.to/jonocairns/caching-azure-and-static-sites-create-react-app-j3p</guid>
      <description>&lt;p&gt;The &lt;a href="https://create-react-app.dev/"&gt;Create React App&lt;/a&gt; is a template starter that greatly assists with bootstrapping applications. Running the build command for this framework will output static files you can drop into Azure and host. This is awesome and easy but there's a hidden gotcha when it comes to frequent deployments of these files. By default, there are no cache-control headers set for these blob containers, even if hosted via frontdoor. This means two things. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Frontdoor (if you're using it) will cache these files for 1-3 days if no cache-control header is present.&lt;/li&gt;
&lt;li&gt;If no cache control header is set, browsers will attempt &lt;a href="https://mdn1.moz.one/en-US/docs/Web/HTTP/Caching#freshness_lifetime"&gt;heuristic freshness&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What's heuristic freshness????&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A response's freshness lifetime is the length of time between its generation by the origin server and its expiration time. The freshness lifetime for a response is calculated based on several headers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the cache is shared and a Cache-Control header with a s-maxage=N directive is present, the freshness lifetime is N.&lt;/li&gt;
&lt;li&gt;If a Cache-Control header with a max-age=N directive is present, the freshness lifetime is N.&lt;/li&gt;
&lt;li&gt;If an Expires header is present, the freshness lifetime is its value minus the Date header value.&lt;/li&gt;
&lt;li&gt;Otherwise, no explicit expiration time is present in the response. A heuristic freshness checking approach might be applicable
If an origin server does not explicitly specify freshness (for example, using a Cache-Control or Expires header), then a heuristic approach may be used.
If this is the case, look for a Last-Modified header. If the header is present, then the cache's freshness lifetime is equal to the value of the Date header minus the value of the Last-modified header divided by 10. The expiration time is computed as follows:
expirationTime = responseTime + freshnessLifetime - currentAge&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;TL;DR you should control cache-control.&lt;/p&gt;

&lt;p&gt;OK - how do we do that? You can do this at many levels but I prefer doing it at deployment time. Most proxies and the like generally respect cache headers of the origin if they're set, so you get slightly more direct and reliable control (and caching is hard enough as it is without involving multiple layers).&lt;/p&gt;

&lt;p&gt;If you use pipelines or run a script to upload the files, I'd suggest using &lt;a href="https://learn.microsoft.com/en-us/cli/azure/?view=azure-cli-latest"&gt;az&lt;/a&gt;. It's a command line tool for communicating with Azure.&lt;/p&gt;

&lt;p&gt;Now when we get to the point of uploading the files to Azure, we effectively want to split it into two steps. One to upload the files we want to cache (&lt;a href="https://create-react-app.dev/docs/production-build/#static-file-caching"&gt;everything under static according to the CRA docs&lt;/a&gt;). Then one to upload everything else which we don't want to cache.&lt;/p&gt;

&lt;p&gt;We want to upload these files in two steps. One step to upload everything with no-cache and another step to upload the static directory and set the cache max-age header.&lt;/p&gt;

&lt;p&gt;First pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az storage blob upload-batch `
    --account-name $storageAccountName `
    --destination '$web' `
    --source $sourceFolderPath `
    --content-cache 'no-cache'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az storage blob upload-batch `
    --account-name $storageAccountName `
    --destination '$web' `
    --source $sourceFolderPath `
    --pattern static/* `
    --overwrite true `
    --content-cache 'max-age=31536000'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r30jm2ym--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62s0t816uxkxchzzt1ue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r30jm2ym--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62s0t816uxkxchzzt1ue.png" alt="example screenshot of Azure with the cache control headers set" width="880" height="937"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if you navigate to your blob container you should see the correct cache-control headers set for the files you want cached and not cached. You should also see the headers returned in browser devtools.&lt;/p&gt;

&lt;p&gt;Happy cache-or-not'ing&lt;/p&gt;

</description>
      <category>caching</category>
      <category>azure</category>
      <category>javascript</category>
      <category>cra</category>
    </item>
    <item>
      <title>Enhancing Windows Terminal</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Tue, 22 Nov 2022 20:56:56 +0000</pubDate>
      <link>https://dev.to/jonocairns/windows-terminal-2jgb</link>
      <guid>https://dev.to/jonocairns/windows-terminal-2jgb</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V9n_DI6K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j32pdhdsyizc9mwj0h49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V9n_DI6K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j32pdhdsyizc9mwj0h49.png" alt="terminal example" width="880" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you need: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latest version of windows terminal&lt;/li&gt;
&lt;li&gt;Latest version of powershell &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Install-Module -Name PackageManagement -Repository PSGallery -Force&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Install-Module -Name PowerShellGet -Repository PSGallery -Force&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Install-Module PSReadLine -AllowPrerelease -Force&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Install-Module posh-git -Scope CurrentUser&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Install-Module -Name Terminal-Icons -Repository PSGallery&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now install oh-my-posh from &lt;a href="https://ohmyposh.dev/docs/installation/windows"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now install a nerd font so you can get all the nice symbols and stuff &lt;a href="https://ohmyposh.dev/docs/installation/fonts"&gt;detailed here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your powershell profile by typing &lt;code&gt;code $PROFILE&lt;/code&gt; in the terminal. Add the following config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Import-Module -Name Terminal-Icons

Import-Module posh-git

oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH/star.omp.json" | Invoke-Expression

Import-Module PSReadLine

Set-PSReadLineOption -PredictionSource History

Set-PSReadLineOption -PredictionViewStyle ListView

Set-PSReadLineOption -EditMode Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extra: if you want to be able to open terminal at set locations, hit &lt;code&gt;CTRL + SHIFT ,&lt;/code&gt; then add a line called startupActions like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "startupActions": "new-tab --tabColor #3B78FF -p \"Windows.Terminal.PowershellCore\" -d C:\\GIT\\Proj1 ; new-tab --tabColor #C19C00 -p \"Windows.Terminal.PowershellCore\" -d C:\\GIT\\Proj1",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another one - if you want the folder names to show up in the tabs do this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;code "$env:POSH_THEMES_PATH/star.omp.json"&lt;/code&gt; (replace the file name with the theme you are using)&lt;/p&gt;

&lt;p&gt;add   &lt;code&gt;"console_title_template": "{{.Folder}}{{if .Root}} :: root{{end}}",&lt;/code&gt; to the root anywhere&lt;/p&gt;

</description>
      <category>terminal</category>
      <category>programming</category>
    </item>
    <item>
      <title>Describing technical details to non technical people</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Sat, 19 Feb 2022 00:20:36 +0000</pubDate>
      <link>https://dev.to/jonocairns/describing-technical-details-to-non-technical-people-2d8h</link>
      <guid>https://dev.to/jonocairns/describing-technical-details-to-non-technical-people-2d8h</guid>
      <description>&lt;p&gt;If you’re a software engineer it’s almost certain you’ve had to do this at some point. Explaining why a seemingly small UI change will take weeks, or attempting to explain why switching frameworks is a good idea, is a struggle we have all run in to, or will eventually run in to at some point. &lt;/p&gt;

&lt;p&gt;I’m by no means an expert at this, but it’s an issue I have grappled with my whole career, so I’ve compiled a list out some things that I’ve found useful in this process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Establish trust with management or other areas of the business. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why is this important? People need to know you back up what you say. This means estimates are relatively close, deadlines are met and even things like showing up to meetings on time is the norm. This may seem like a no-brainer, but I do feel people get a bad rep in our community for failing to do any or all of the above. The way I navigate this area is to set expectations early and overestimate things I’m not entirely confident about. This involves things like making sure you’re on the same page in terms of scope and context, as well as  establishing what value this particular feature brings to the company. It also means keeping yourself honest and being OK with not knowing everything. If you are truly not sure about how long something takes, then add a larger variance for the timeframe.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use applicable metaphors to get your point across. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Metaphors provide context even when there is extreme complexity in a particular topic. It also means you understand a problem well if you can condense and simplify it to anyone. An example I had a while back was when I worked at a company similar to hello fresh. The week to week software was constantly worked on, and worked well. When Christmas time came around the orignal developers were rushed for time and just copied all the table structure for the week to week processes and prefixed them with Christmas. This technique wasn’t changed for a long time because it just worked. The downsides started showing over time where bugs started to happen and the prep time for Christmas required a full time engineer for at least a month to get everything ready. My metaphor for this situation was we had two paths to deliver food to people, one I liked to call a super highway - this was our week to week BAU process. The other was an old walkway that hadn’t been resurfaced in a while. In my description I was saying the flow of traffic and size of the trucks going on it were getting bigger (attempting to describe scale here) and the old pathway just wasn’t handling the load. My proposal involved moving the Christmas system over to the week to week system as it was essentially the same. The only difference being the products for a specific week. So we had this super highway we could now send our Christmas trucks on this same highway. It’d get the benefit of being worked on and updated during the year, meaning any resurfacing and widening needed for upcoming Christmas traffic was already done. It also wouldn’t require someone to work full time clearing the path on a separate, inferior road each year. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Articulate and be confident in your reasoning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one is a tough one for me and I find words escape me regularly. Things that help me with this is adding pro/cons lists or even building technical documents that go through all the reasoning for a specific approach. In the technical document it’s good to keep a simple tl;dr for each of your main points then have a couple of paragraphs with the actual background, context and reasoning so if people push you for more info you can easily push deeper. This makes people a lot more confident in you as well as it shows you know what you’re talking about. You won’t look like a big tech leader at a senate hearing just saying “I’ll need to get back to you on that one”. &lt;/p&gt;

&lt;p&gt;In conclusion this is a very hard part of our job and will only get harder the longer your career progresses. There is a lot of value in trying to see what methods work for getting people on board with your ideas. So far I’ve been over trust, using metaphors and citing research as key parts of helping in this area. What things work for you? I still consider myself a newbie in this area so keen to hear what other people have to say.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Transient test environments</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Tue, 13 Jul 2021 01:53:09 +0000</pubDate>
      <link>https://dev.to/jonocairns/transient-test-environments-3ia9</link>
      <guid>https://dev.to/jonocairns/transient-test-environments-3ia9</guid>
      <description>&lt;p&gt;"Works on my machine" - A developer&lt;/p&gt;

&lt;p&gt;These four words have been said by almost all developers. If you dig into the underlying issue there's potential to make your build pipeline more robust and be able to better support a scaling engineering team.&lt;/p&gt;

&lt;p&gt;If you have more than one developer on your team you've also likely run into a problem where you're both working in similar areas - when your change goes out to QA they report a bunch of issues with parts that don't relate to what you've been working on. The key problem is testing &lt;em&gt;isolated&lt;/em&gt; change-sets. This only gets harder the more people you have on the team.&lt;/p&gt;

&lt;p&gt;OK - how can we make this better? What if a PR spun up a complete replica of your production environment, with sanitized data, once you marked it as 'ready for test'? This entire environment would only have your changes on it so you wouldn't be able to play the blame game with other developers!&lt;/p&gt;

&lt;p&gt;Tools/things to make this happen&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to have control of a domain name and subroutes. I managed to write a simple CLI app to add CNAMES via the Cloudflare API, I'm sure whatever you're using will have something similar. I picked pr-2344.company.co.nz (2344 was the PR number from Github), you could also use branch names (mybranch.company.co.nz) but you could run in to conflicts so YMMV.&lt;/li&gt;
&lt;li&gt;You need to have containerized (or similar) your front end (bonus points for also doing your backend!). This is not an easy step but has a LOT of other benefits, especially for a scaling company. If you just have a bunch of files or a SPA, you can deploy to s3 (or whatever platform you like)&lt;/li&gt;
&lt;li&gt;You may need to tweak CORS so your PR front end can communicate with your test/dev backend (if you haven't containerized that part yet)&lt;/li&gt;
&lt;li&gt;Authentication (if you have it), needs to be OK with running on a subdomain. This is usually fine, you may need to tweak redirects to ensure it plays nicely.&lt;/li&gt;
&lt;li&gt;You need some sort of trigger to spin up the application. You can use webhooks from GitHub and watch for specific tags being added to a pull request, or you can just build each time a PR is pushed to origin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9DuBzyOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qajr0dxydf2nnq59mhfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9DuBzyOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qajr0dxydf2nnq59mhfi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4ZKDZQbB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uz64a16yqt11sy1rljm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4ZKDZQbB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uz64a16yqt11sy1rljm2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what are the key benefits to take away from this?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test in isolation! Having stable data and a small change-set is KEY for testing. If you are currently testing in a standalone test environment and frequently get your data changed/blown away, I feel your pain!&lt;/li&gt;
&lt;li&gt;Forced in to thinking about containerization! This is generally an afterthought for new companies as you usually have bigger fish to fry, but it's a lot easier to start with than to migrate to - so keep this in mind when starting a new project.
&lt;/li&gt;
&lt;li&gt;Enable developers to treat an environment like their local environment! There's a lot more ownership involved when an entire environment is your own. If there are issues on there it can only be either existing or related to your change-set.&lt;/li&gt;
&lt;li&gt;Demo-able and shareable environments before they hit the main code-base! With these environments, you can just share the URL to BAs / PMs or even your end-users. Since the code never hits the production branch you don't have to worry about blocking the build pipeline to get a change out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Side note: I think there's no need for a development environment with this strategy. A test environment is still required to test the aggregate of changes together and should be gated by QA.&lt;/p&gt;

&lt;p&gt;Netlify currently does this all for you and has an excellent platform to get you started! &lt;a href="https://docs.netlify.com/domains-https/custom-domains/multiple-domains/"&gt;https://docs.netlify.com/domains-https/custom-domains/multiple-domains/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ci</category>
      <category>testing</category>
      <category>pipelines</category>
    </item>
    <item>
      <title>Create react app version check</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Thu, 01 Jul 2021 03:30:34 +0000</pubDate>
      <link>https://dev.to/jonocairns/create-react-app-version-check-2o7j</link>
      <guid>https://dev.to/jonocairns/create-react-app-version-check-2o7j</guid>
      <description>&lt;p&gt;The &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;create react app&lt;/a&gt; is a great tool to bootstrap any new project you're working on. They bundle a bunch of useful tool chains in to one single package so you can hit the ground running. Here are some of the things it provides out of the box.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React, JSX, ES6, TypeScript and Flow syntax support.&lt;/li&gt;
&lt;li&gt;Language extras beyond ES6 like the object spread operator.&lt;/li&gt;
&lt;li&gt;Autoprefixed CSS, so you don’t need -webkit- or other prefixes.&lt;/li&gt;
&lt;li&gt;A fast interactive unit test runner with built-in support for coverage reporting.&lt;/li&gt;
&lt;li&gt;A live development server that warns about common mistakes.&lt;/li&gt;
&lt;li&gt;A build script to bundle JS, CSS, and images for production, with hashes and sourcemaps.&lt;/li&gt;
&lt;li&gt;An offline-first service worker and a web app manifest, meeting all the Progressive Web App criteria. (Note: Using the service worker is opt-in as of &lt;a href="mailto:react-scripts@2.0.0"&gt;react-scripts@2.0.0&lt;/a&gt; and higher)&lt;/li&gt;
&lt;li&gt;Hassle-free updates for the above tools with a single dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this you can add something like &lt;a href="https://reactrouter.com/" rel="noopener noreferrer"&gt;react-router&lt;/a&gt; and you have the bones for a new SPA (single page application).&lt;/p&gt;

&lt;p&gt;That's all great but since it's a single page application, how do people using the site know that there's a newer version available? This is especially important if you have updated API contracts in a deployment. &lt;/p&gt;

&lt;p&gt;Unless you have a defined pipeline to do this already I've got a cheap and easy way to inform your users that they may need to refresh the page to get the latest changes.&lt;/p&gt;

&lt;p&gt;The create-react-app creates a manifest.json file when the &lt;code&gt;yarn build&lt;/code&gt; command is run. This file essentially tells the application where/what files exist. The file names are hashed for each build. This means we can tell if something has changed, as long as we poll this manifest file somehow...&lt;/p&gt;

&lt;p&gt;So we need to create a component of sorts that can sit at a high level, it needs to be responsible for polling this manifest and telling the UI if there has been a change.&lt;/p&gt;

&lt;p&gt;Here's an example I wrote, using material UI to display a snackbar whenever the version had changed. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import {Button} from '@material-ui/core';
import {CloseOutlined} from '@material-ui/icons';
import {useSnackbar} from 'notistack';
import React, {useState} from 'react';

const MANIFEST = '/asset-manifest.json';
const POLL_INTERVAL = 60000;

export const VersionCheck: React.FC = ({children}) =&amp;gt; {
  const {enqueueSnackbar, closeSnackbar} = useSnackbar();
  const [dismissedVersion, setDismissedVersion] = useState('');

  React.useEffect(() =&amp;gt; {
    const getLatestVersion = async () =&amp;gt; {
      const response = await fetch(MANIFEST);
      return await response.text();
    };

    const init = async () =&amp;gt; {
      try {
        const latestVersion = await getLatestVersion();
        localStorage.setItem('tend-version', latestVersion);
      } catch (ex) {
        // log to sentry / or something
      } finally {
        setTimeout(poll, POLL_INTERVAL);
      }
    };

    const poll = async () =&amp;gt; {
      try {
        const currentVersion = localStorage.getItem('tend-version');
        const latestVersion = await getLatestVersion();

        if (currentVersion &amp;amp;&amp;amp; currentVersion !== latestVersion &amp;amp;&amp;amp; latestVersion !== dismissedVersion) {
          enqueueSnackbar('A new version is available', {
            variant: 'info',
            persist: true,
            preventDuplicate: true,
            action: (key) =&amp;gt; (
              &amp;lt;&amp;gt;
                &amp;lt;Button color="inherit" onClick={() =&amp;gt; window.location.reload()}&amp;gt;
                  Refresh
                &amp;lt;/Button&amp;gt;
                &amp;lt;Button
                  color="inherit"
                  variant="text"
                  onClick={() =&amp;gt; {
                    setDismissedVersion(latestVersion);
                    closeSnackbar(key);
                  }}&amp;gt;
                  &amp;lt;CloseOutlined /&amp;gt;
                &amp;lt;/Button&amp;gt;
              &amp;lt;/&amp;gt;
            ),
          });
        }
      } catch (ex) {
        // log somewhere
      } finally {
        setTimeout(poll, POLL_INTERVAL);
      }
    };

    if (process.env.NODE_ENV === 'production') {
      init();
    }
  }, [closeSnackbar, dismissedVersion, enqueueSnackbar]);

  return &amp;lt;&amp;gt;{children}&amp;lt;/&amp;gt;;
};


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

&lt;/div&gt;

&lt;p&gt;This would display the following snackbar when the deployed files had changed. &lt;/p&gt;

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

&lt;p&gt;Why would you want this? With a SPA there's sometimes no need at all to refresh the website to get the latest files. This means clients consuming your APIs can potentially have very out of date code running. If you have made key contract changes between your API and clients you'll need to tell them somehow. This can potentially short circuit bug reports about recently touched parts of the UI not working correctly.&lt;/p&gt;

</description>
      <category>react</category>
      <category>version</category>
    </item>
    <item>
      <title>Choosing a design framework</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Wed, 23 Jun 2021 00:05:12 +0000</pubDate>
      <link>https://dev.to/jonocairns/choosing-a-design-framework-1n45</link>
      <guid>https://dev.to/jonocairns/choosing-a-design-framework-1n45</guid>
      <description>&lt;p&gt;Designing a UI is hard. Reinventing the wheel each time you need a button adds a tone of technical debt for future maintainers to pay, it also creates inconsistency across your application.&lt;/p&gt;

&lt;p&gt;In my experience, the best time to pick a design framework is when you start a new project. The second best time is now. It's similar to a builder who custom builds all their tools for each new house they build, or even for each project they have IN their house! In this post, I’ll go over some reasons as to why it’s so crucial to have a solid design system in place.&lt;/p&gt;

&lt;p&gt;Here are some examples of front-end design frameworks that I’d recommend taking a look at. They’re very similar in the problems they solve so I won’t argue which is best, it’s mainly the fact that you &lt;strong&gt;have&lt;/strong&gt; a design framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material-ui.com/"&gt;Material UI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Big companies have spent large sums of money on R&amp;amp;D to make their UIs easy to use and to look nice. Having a repository of pre-built components at your fingertips means you can hit the ground running with your new or existing project. You no longer have to write all the logic for how a button operates/looks, simply import it and continue building.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Their utility functions / surgical classes are really useful. In bootstrap and tailwind, these are some of the main selling points. Here are some simple examples of what you can do with these frameworks.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tailwind:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;p className="text-gray-500"&amp;gt;{person.email}&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Bootstrap:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;span className="text-white-50"&amp;gt;{person.email}&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Material:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const classes = useStyles();

...

&amp;lt;span className={classes.span}&amp;gt;{person.email}&amp;lt;/span&amp;gt;...const 

useStyles = makeStyles((theme) =&amp;gt; ({
    span: {
        color: 'rgba(255,255,255,.5)'
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is this useful? There are a few reasons.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spacing modifiers provide consistent ways of spacing components in your UI. No more specific pixel margin or padding that makes the UI slightly off at different viewports&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Styling with these utilities becomes faster and faster the more you learn the framework. There will be a bit of a learning curve, but it will pay dividends in a short period.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The frameworks are usually based on a set REM size, meaning your UI should scale reasonably well when people use different zoom sizes or screens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The flex-box utilities are very well documented and make mobile/desktop development EXTREMELY easy. Here’s an example with bootstrap, these three columns will correctly display at any viewport size (within reason).&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="container"&amp;gt;
  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="col"&amp;gt;
      Column
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="col"&amp;gt;
      Column
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="col"&amp;gt;
      Column
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Theming is a big thing in these frameworks, just because you pick one doesn’t mean your site now has to look like the base theme. You can add a lot of customization, like primary colours, box-sizing, borders, etc. Most of the frameworks have a tone of documentation on how to do this so I won’t go into it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mobile AND desktop first. Most of the design frameworks have a bunch of help when it comes to layout. These make it super easy to operate in the mindset of “what does this look like on mobile”. Using things like flex-box and rows/columns are easy to set for different viewports. E.g. making something span 3 columns on desktop but 3 rows on mobile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox or Chrome or Safari? These libraries tend to handle slight differences in browsers and browser standards. Their maintainers will also be constantly checking comparability with a set of standard browsers you may not have the man/women power to do yourself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS is a lot harder than people think. I think that’s because the actual hard part is maintenance, not so much adding something in for right now. It gets exponentially harder to manage for each line added to the system. Moving this to the component level means there is a direct link between the functional side and the design side. This means when refactoring components, you won’t be worried about deleting CSS that’s actively used for something else, you’ll just kill the component and the styles will die with it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OK — adding a design system is all great and all but what about my legacy system stuck in 1990? Never fear, there are some ways to get around this problem.&lt;/p&gt;

&lt;p&gt;So the first step would be adding a new repository for your design framework, add the base framework to this and also add storybook. Here you can play around with the themes and try and get some basic components working and looking similar to your existing designs. If you can, package these in a private/public npm package.&lt;/p&gt;

&lt;p&gt;If you’re currently not using react / vue / angular you may only be able to leverage the surgical classes provided by the design frameworks. This is still a big win in my opinion but if you then also want to migrate to a new front-end framework I’d look at using a proxy of sorts. Azure frontdoor (or nginx if you’re a nerd like me) is a perfect tool for this migration as it allows you to run your existing system AND new system side by side. Your proxy will just divert traffic to different pages depending on the migration status.&lt;/p&gt;

&lt;p&gt;So you have an existing system with the page /contacts. You are looking for this to be the first page you migrate to the new design / functional framework. You’ve used the create-react-app or something similar and added your design library to it and it’s deploying nicely. So far your proxy is diverting ALL traffic to your legacy system. Now you create the /contact page in your new front-end application, get it talking with your existing backend and it’s working nicely. on release day you just need to update the proxy to say — OK, route the /contacts page to the new system, route everything else to the old system. Did it blow up? Just flip it back to the old route. DNS switchovers are still the nicest form of releasing (but that’s probably another topic).&lt;/p&gt;

&lt;p&gt;I hope this all made sense, I’ve likely glazed over some harder parts due to me not wanting to write a book but let me know if you’d like clarification on any of the areas. The TL;DR is to get a design system in place, the earlier the better. The time payoff is larger the longer your company is afloat. Developers won’t hate their life maintaining it and feature work will be significantly faster.&lt;/p&gt;

</description>
      <category>design</category>
      <category>framework</category>
      <category>styling</category>
    </item>
    <item>
      <title>Mono-repository with typescript and yarn workspaces</title>
      <dc:creator>Jono Cairns</dc:creator>
      <pubDate>Wed, 23 Jun 2021 00:02:35 +0000</pubDate>
      <link>https://dev.to/jonocairns/mono-repository-with-typescript-and-yarn-workspaces-45m4</link>
      <guid>https://dev.to/jonocairns/mono-repository-with-typescript-and-yarn-workspaces-45m4</guid>
      <description>&lt;p&gt;Monoliths have their place in many systems. Usually, they stem from the ease of use, allowing cross-cutting changes to be completed in a single pull request. They also have a lot of downsides, but that’s a whole other can of worms.&lt;/p&gt;

&lt;p&gt;Here are the main points we had trouble with in our monolith:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do you share code between sub-projects?&lt;/li&gt;
&lt;li&gt;How do you manage typescript compilation for dependant projects? E.g. if a depends on b and I make a change to a, I want b to be compiled as well with the latest version of a.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was an example of my repository structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;projectA/
projectB/
projectC/
packages/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside my packages/ directory, I had some core shared libraries, like types / shared utils, etc.&lt;/p&gt;

&lt;p&gt;Ok — so how do you get it all to work together?&lt;/p&gt;

&lt;p&gt;Since we were already using yarn, it seemed like yarn workspaces would be an ideal fit. If I can get the same thing done with the same tools that's a big win.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a root tsconfig.json
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    "noImplicitAny": true,
  },
  "exclude": [
    "**/node_modules",
    "**/.*/",
    "**/jest.config.js",
    "**/.build"
  ],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In your root package.json add your ‘packages’
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  ...
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*",
      "projectA",
      "projectB",
      "projectC",
    ]
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;in each of your projects + packages, you need to give them the correct name in their respective package.json files e.g. in projectA/package.json
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "@company/projectA",
  ...
  "scripts": {
    "watch": "tsc -b -w --preserveWatchOutput",
    ...
  },
  "dependancies": {
    "@company/types",
    "@company/logging",
    "@company/clients"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now run yarn install at the root, and then at each package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now is a very important part. You need to add a tsconfig.json file for each of the projects. This is to assist typescript with the dependency tree. Below is an example of projectA as it depends on 3 packages — clients, types, and logging. This tells typescript to recompile if it senses any changes in the parent package.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "extends": "../tsconfig",
  "compilerOptions": {
    "outDir": ".build"
  },
  "rootDir": ".",
  "references": [
    {
      "path": "../packages/clients"
    },
    {
      "path": "../packages/types"
    },
    {
      "path": "../packages/logging"
    },
  ],
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, along with the correct tsc options provided (primarily -b) any changes to projectA will recompile the dependencies if required and also compile the project itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now while running in the context of projectA you will be able to make changes to the packages it depends on e.g. /packages/types and it will recompile and display errors if there are any, along with being able to change things in projectA as normal.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>monorepository</category>
      <category>yarn</category>
      <category>workspaces</category>
    </item>
  </channel>
</rss>
