<?xml-stylesheet href="/pretty-feed-v2.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Trys Mudford's Blog</title>
    <link>https://www.trysmudford.com/year/2018/</link>
    <description>Posts, thoughts, links and photos from Trys</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 31 Dec 2018 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.trysmudford.com/blog/index.xml" rel="self" type="application/rss+xml"/>
    
    <item>
      <title>JournalBook</title>
      <link>https://www.trysmudford.com/blog/announcing-journalbook/</link>
      <pubDate>Mon, 31 Dec 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/announcing-journalbook/</guid>
      <description><![CDATA[
<p>I&rsquo;ve been working on a little web product over the Christmas break, and I&rsquo;m proud to announce version 1 of <a href="https://journalbook.co.uk">JournalBook</a> 🎉</p>
<p><a href="https://journalbook.co.uk"><img src="/images/blog/journalbook.jpg" alt="JournalBook"></a></p>
<h3 id="whats-journalbook">What&rsquo;s JournalBook?</h3>
<p>JournalBook is a private, offline-first personal journal.</p>
<p>Your notes are <strong>only</strong> stored on your device — they&rsquo;re never sent to a server. You don&rsquo;t even need to sign-in to use it! It works offline, so you can reflect upon your day on the slow train journey home.</p>
<p>It&rsquo;s quick, lightweight, and developed <a href="https://github.com/trys/JournalBook">in the open</a>. You can even add it to your homescreen as an app.</p>
<h3 id="why-build-it">Why build it?</h3>
<p>On one of the last days of work in 2018, one of my colleagues asked us about our highlights from the year. Sure, I could remember the big ticket items, but I quickly struggled to remember anything past that.</p>
<p>I&rsquo;ve never been much of a writer, so keeping a diary or journal has never crossed my mind. But it dawned on me over the holiday that I would benefit from keeping some daily notes, not least to keep track of the small victories. I&rsquo;m a creature of habit, and most days blend into one routine, so pulling out differences can be a challenge.</p>
<p>After considering existing solutions, I decided that building a small Progressive Web App would be perfect for this use case. Something that would work entirely offline, reading and writing directly to my device. Not only would it be faster, it would be personal and private, like a physical journal.</p>
<p>It needed to be a product that worked on the underground whilst on my commute home. But it also needed to be fully-featured, as &lsquo;paper-like&rsquo; as possible, and a joy to use. I&rsquo;m hoping <a href="https://journalbook.co.uk">JournalBook</a> rises to those challenges.</p>
<hr>
<h3 id="how-does-it-work">How does it work?</h3>
<p>Right, sales pitch over, let&rsquo;s get technical. The stack is as follows:</p>
<ul>
<li>Preact</li>
<li>IndexedDB</li>
<li>Netlify</li>
</ul>
<p>I chose <a href="http://preactjs.com">Preact</a> as it&rsquo;s tiny and fast. This project would be more than achievable in Vanilla JS, but I&rsquo;m working day-to-day in React so this seemed like a good way to build something nice and quickly. It was mostly built on Boxing Day and I didn&rsquo;t want to get bogged down in application decisions!</p>
<p>IndexedDB wrapped with <a href="https://www.npmjs.com/package/idb">idb</a> was the perfect local database layer. It&rsquo;s all stored directly in the browser and I can separate the data far better than with LocalStorage. There are two data types: questions and entries. Each entry is autosaved to the cache each keypress so there&rsquo;s no need for &lsquo;save&rsquo; buttons, nor waiting for network requests to resolve.</p>
<p>As there&rsquo;s no servers or databases storing user information, this was (yet again) an opportunity to use the wonderful <a href="http://netlify.com">Netlify</a>. I&rsquo;ve waxed lyrical about Netlify in the past so I won&rsquo;t dwell on it too long, but once again <strong>it just worked</strong>. There&rsquo;s nothing like it.</p>
<p>Even though the application works entirely offline, it&rsquo;s still able to provide features like data import/export, data eradication and autosave. The former two features are thanks to <code>Blob</code> and <code>FileReader</code>. It&rsquo;s genuinely incredible to me that you can read and write data files <strong>entirely in the browser</strong>. That&rsquo;s bonkers! But amazingly, it&rsquo;s not that complex, 15-20 lines of code for each and we&rsquo;ve got personal data managment on the web!</p>
<h3 id="whats-next">What&rsquo;s next?</h3>
<p>To ensure I actually launched this product, and it didn&rsquo;t fall into the pile of abandoned side-projects, I first created a <a href="https://github.com/trys/JournalBook/projects/1">Roadmap</a> with features ranked in order of importance. There was an MVP column, a V1 column, and a backlog. By breaking it down this way, I could separate the &lsquo;musts&rsquo; from the &lsquo;coulds&rsquo; and the &lsquo;shoulds&rsquo;, and have sensible milestones for each release.</p>
<p>Now the V1 pile is clear, the product can be launched!</p>
<p>Next up is data visualisation, being able to navigate neatly to previous months/years, and the ability to search your content. I <em>really</em> don&rsquo;t want to have heavy tracking on this, as it goes against the spirit of the product, but it would be nice to know if people are using it. Basically, I want a <strong>90&rsquo;s hit counter as a service!</strong> So that&rsquo;s probably next on the list.</p>
<p>The product will continue to be developed in the open, so please file issues and suggestions on <a href="https://github.com/trys/JournalBook">GitHub</a>.</p>
<a href="http://journalbook.co.uk" class="button">Start Writing</a>

]]>
      </description>
    </item>
    
    <item>
      <title>Christmas in London</title>
      <link>https://www.trysmudford.com/blog/christmas-in-london/</link>
      <pubDate>Mon, 24 Dec 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/christmas-in-london/</guid>
      <description><![CDATA[
]]>
      </description>
    </item>
    
    <item>
      <title>All I Want for Christmas Is You</title>
      <link>https://www.trysmudford.com/blog/all-i-want-for-christmas/</link>
      <pubDate>Thu, 20 Dec 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/all-i-want-for-christmas/</guid>
      <description><![CDATA[
<div class="video-embed">
	
		<div style="position: relative; padding-bottom: 56.25%; padding-top: 30px; height: 0; overflow: hidden;">
			<iframe src="//www.youtube-nocookie.com/embed/jw0ZfyWmkD0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;" allowfullscreen="1" frameborder="0" title="YouTube Video"></iframe>
		</div>
	
</div>

<p>Ingrid Michaelson &amp; Leslie Odom Jr.</p>
]]>
      </description>
    </item>
    
    <item>
      <title>ApolloClient with SSR</title>
      <link>https://www.trysmudford.com/blog/apolloclient-with-ssr/</link>
      <pubDate>Mon, 19 Nov 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/apolloclient-with-ssr/</guid>
      <description><![CDATA[
<p>I recently came across an curious issue with <code>ApolloClient</code> on a server-side render. The GraphQL results wouldn&rsquo;t update until I restarted the server.</p>
<p>In a client-side app, a <code>new ApolloClient</code> gets created for each page load. But in a <code>node.js</code> service, it runs once on application launch and sits in memory till the whole application has been killed - that could be days or weeks.</p>
<p>Not only that, as the server-side <code>ApolloClient</code> sits in memory, it&rsquo;s shared between every user connection, and is therefore ripe for leaking data between connections. Not what we want.</p>
<p>To overcome this problem, we instantiate a <code>new ApolloClient</code> for each connection. We can wrap this up in a nice reusable method:</p>
<div class="highlight"><pre class="chroma"><code class="language-ts" data-lang="ts"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ApolloClient</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;apollo-client&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">createHttpLink</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;apollo-link-http&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">InMemoryCache</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;apollo-cache-inmemory&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">withClientState</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;apollo-link-state&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">ApolloLink</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;apollo-link&#39;</span><span class="p">;</span>

<span class="kr">const</span> <span class="nx">CreateClient</span> <span class="o">=</span> <span class="p">(</span><span class="nx">defaults</span> <span class="o">=</span> <span class="p">{},</span> <span class="nx">links</span>: <span class="kt">any</span><span class="p">[]</span> <span class="o">=</span> <span class="p">[])</span><span class="o">:</span> <span class="nx">ApolloClient</span><span class="o">&lt;</span><span class="p">{}</span><span class="o">&gt;</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="kr">const</span> <span class="nx">cache</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">InMemoryCache</span><span class="p">();</span>

  <span class="kr">const</span> <span class="nx">stateLink</span> <span class="o">=</span> <span class="nx">withClientState</span><span class="p">({</span>
    <span class="nx">cache</span><span class="p">,</span>
    <span class="nx">resolvers</span><span class="o">:</span> <span class="p">{},</span>
    <span class="nx">defaults</span>
  <span class="p">});</span>

  <span class="k">return</span> <span class="k">new</span> <span class="nx">ApolloClient</span><span class="p">({</span>
    <span class="nx">connectToDevTools</span>: <span class="kt">false</span><span class="p">,</span>
    <span class="nx">ssrMode</span>: <span class="kt">true</span><span class="p">,</span>
    <span class="nx">link</span>: <span class="kt">ApolloLink.from</span><span class="p">([</span>
      <span class="nx">stateLink</span><span class="p">,</span>
      <span class="p">...</span><span class="nx">links</span><span class="p">,</span>
      <span class="nx">createHttpLink</span><span class="p">({</span>
        <span class="nx">uri</span>: <span class="kt">process.env.GRAPHQL_URL</span>
      <span class="p">})</span>
    <span class="p">]),</span>
    <span class="nx">cache</span>
  <span class="p">});</span>
<span class="p">};</span>

<span class="kr">export</span> <span class="p">{</span> <span class="nx">CreateClient</span> <span class="p">};</span>
</code></pre></div><p>We can then import the file on launch, and crucially, run the <code>CreateClient</code> function for each request. Not only that, we can pass in <code>defaultState</code> and prime the <code>apollo-link-state</code> cache with any user defaults. Furthermore, we can add additional link helpers like <code>onError</code>.</p>
<div class="highlight"><pre class="chroma"><code class="language-jsx" data-lang="jsx"><span class="nx">server</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/*&#39;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="o">:</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Request</span><span class="p">,</span> <span class="nx">res</span><span class="o">:</span> <span class="nx">express</span><span class="p">.</span><span class="nx">Response</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
  <span class="kr">const</span> <span class="nx">defaultState</span> <span class="o">=</span> <span class="p">{};</span>
  <span class="kr">const</span> <span class="nx">errorLink</span> <span class="o">=</span> <span class="nx">onError</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{});</span>

  <span class="kr">const</span> <span class="nx">client</span><span class="o">:</span> <span class="nx">ApolloClient</span><span class="o">&lt;</span><span class="p">{}</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nx">CreateClient</span><span class="p">(</span><span class="nx">defaultState</span><span class="p">,</span> <span class="p">[</span><span class="nx">errorLink</span><span class="p">]);</span>

  <span class="kr">const</span> <span class="nx">Application</span> <span class="o">=</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span>
      <span class="p">&lt;</span><span class="nt">ApolloProvider</span> <span class="na">client</span><span class="o">=</span><span class="p">{</span><span class="nx">client</span><span class="p">}&gt;</span>
        <span class="p">&lt;</span><span class="nt">App</span> <span class="p">/&gt;</span>
      <span class="p">&lt;/</span><span class="nt">ApolloProvider</span><span class="p">&gt;</span>
    <span class="p">)</span>
  <span class="p">}</span>
</code></pre></div><h2 id="reusing-createclient">Reusing CreateClient</h2>
<p>We could&rsquo;ve run all that <code>CreateClient</code> code within the <code>server.get</code> method, but by moving it outside, we can reuse it in our tests. This time, there&rsquo;s no <code>defaultState</code> or additional links, so we can call <code>createClient</code> directly.</p>
<div class="highlight"><pre class="chroma"><code class="language-jsx" data-lang="jsx"><span class="kr">import</span> <span class="o">*</span> <span class="nx">as</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="nx">ApolloClient</span> <span class="nx">from</span> <span class="s1">&#39;apollo-client&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">ApolloProvider</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react-apollo&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">mount</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;enzyme&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">CreateClient</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@/gql/CreateClient&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">User</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@/pages/User&#39;</span><span class="p">;</span>

<span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;&lt;User /&gt; page&#39;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
  <span class="kr">const</span> <span class="nx">client</span><span class="o">:</span> <span class="nx">ApolloClient</span><span class="o">&lt;</span><span class="p">{}</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nx">CreateClient</span><span class="p">();</span>
  <span class="nx">it</span><span class="p">(</span><span class="s1">&#39;renders a user profile&#39;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
    <span class="nx">mount</span><span class="p">(</span>
      <span class="p">&lt;</span><span class="nt">ApolloProvider</span> <span class="na">client</span><span class="o">=</span><span class="p">{</span><span class="nx">client</span><span class="p">}&gt;</span>
        <span class="p">&lt;</span><span class="nt">User</span> <span class="na">match</span><span class="o">=</span><span class="p">{{</span> <span class="nx">params</span><span class="o">:</span> <span class="p">{</span> <span class="nx">username</span><span class="o">:</span> <span class="s1">&#39;trys&#39;</span> <span class="p">}</span> <span class="p">}}</span> <span class="p">/&gt;</span>
      <span class="p">&lt;/</span><span class="nt">ApolloProvider</span><span class="p">&gt;</span>
    <span class="p">);</span>
  <span class="p">});</span>
<span class="p">});</span>
</code></pre></div>]]>
      </description>
    </item>
    
    <item>
      <title>Heading gradients</title>
      <link>https://www.trysmudford.com/blog/heading-gradients-with-background-clip/</link>
      <pubDate>Sun, 18 Nov 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/heading-gradients-with-background-clip/</guid>
      <description><![CDATA[
<p>Inspired by Mandy Michael&rsquo;s <a href="https://www.youtube.com/watch?v=5qgUC_z8syw">amazing talk at ViewSource 2018</a>, I made a small tweak to my website. The <code>h1</code> title at the top of this post now has a fancy gradient as a fill colour.</p>
<p>The first part is a linear gradient background. This feature is only going to work on <code>-webkit</code> browsers so we can use the <code>-webkit-gradient</code>.</p>
<div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">h1</span> <span class="p">{</span>
  <span class="k">background-image</span><span class="p">:</span> <span class="kp">-webkit-</span><span class="nf">gradient</span><span class="p">(</span><span class="kc">linear</span><span class="p">,</span><span class="mi">0</span><span class="kt">%</span> <span class="mi">0</span><span class="kt">%</span><span class="p">,</span><span class="mi">100</span><span class="kt">%</span> <span class="mi">100</span><span class="kt">%</span><span class="p">,</span><span class="nf">from</span><span class="p">(</span><span class="mh">#96A0DE</span><span class="p">),</span><span class="nf">to</span><span class="p">(</span><span class="mh">#4CACC1</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div><p>Next, we need to clip the background so it only appears behind the text:</p>
<div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">h1</span> <span class="p">{</span>
  <span class="kp">-webkit-</span><span class="k">background-clip</span><span class="p">:</span> <span class="kc">text</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>Then we hide the text fill so the background shows through:</p>
<div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="nt">h1</span> <span class="p">{</span>
  <span class="kp">-webkit-</span><span class="n">text-fill-color</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>There are two final touches to make. Firstly, the headings are centred on my blog, and by default <code>h1</code> is a block-level element. This&rsquo;ll mean the heading, and therefore the gradient background will span the width of the parent, not the words inside. This would lead to a super-subtle gradient for short headings. By making the heading <code>display: inline-block</code>, the width and background are dictated by the word length.</p>
<p>Finally, this is a reasonably experimental feature only supported in <code>-webkit</code> browsers. We don&rsquo;t want half a working feature, so we can use <code>@support</code> queries to our advantage:</p>
<div class="highlight"><pre class="chroma"><code class="language-css" data-lang="css"><span class="p">@</span><span class="k">supports</span> <span class="o">(</span><span class="nt">-webkit-text-fill-color</span><span class="o">:</span> <span class="nt">transparent</span><span class="o">)</span> <span class="p">{</span>
  <span class="nt">h1</span> <span class="p">{</span>
    <span class="k">background-image</span><span class="p">:</span> <span class="kp">-webkit-</span><span class="nf">gradient</span><span class="p">(</span><span class="kc">linear</span><span class="p">,</span><span class="mi">0</span><span class="kt">%</span> <span class="mi">0</span><span class="kt">%</span><span class="p">,</span><span class="mi">100</span><span class="kt">%</span> <span class="mi">100</span><span class="kt">%</span><span class="p">,</span><span class="nf">from</span><span class="p">(</span><span class="mh">#96A0DE</span><span class="p">),</span><span class="nf">to</span><span class="p">(</span><span class="mh">#4CACC1</span><span class="p">));</span>
    <span class="kp">-webkit-</span><span class="k">background-clip</span><span class="p">:</span> <span class="kc">text</span><span class="p">;</span>
    <span class="kp">-webkit-</span><span class="n">text-fill-color</span><span class="p">:</span> <span class="kc">transparent</span><span class="p">;</span>
    <span class="k">display</span><span class="p">:</span> <span class="kc">inline-block</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div>]]>
      </description>
    </item>
    
    <item>
      <title>Named exports withApollo in Typescript React</title>
      <link>https://www.trysmudford.com/blog/named-exports-withapollo-typescript-react/</link>
      <pubDate>Tue, 06 Nov 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/named-exports-withapollo-typescript-react/</guid>
      <description><![CDATA[
<p>I came across a small hurdle when working with GraphQL fragments. To get access to the Apollo client, it needed to be wrapped in the <code>withApollo</code> higher-order component, a task which is usually straightforward. However, things are a little more tricky when the component uses named exports.</p>
<p>Here&rsquo;s a &lsquo;standard&rsquo; component as a starting point:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">import</span> <span class="o">*</span> <span class="nx">as</span> <span class="nx">React</span> <span class="nx">from</span> <span class="s1">&#39;react&#39;</span>

<span class="kr">class</span> <span class="nx">Sidebar</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
  <span class="kr">public</span> <span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// ...
</span><span class="c1"></span>  <span class="p">}</span>
<span class="p">}</span>

<span class="kr">export</span> <span class="p">{</span> <span class="nx">Sidebar</span> <span class="p">}</span>
</code></pre></div><p>On the surface, that final line looks like a ordinary object with property/value shorthand, but sadly that&rsquo;s not the case. Assignment within that &lsquo;object&rsquo; is not allowed, it <strong>only accepts a comma separated list</strong>. This prevents <code>withApollo</code> being assigned in a &lsquo;normal&rsquo; object-y way:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">export</span> <span class="p">{</span> <span class="nx">Sidebar</span><span class="o">:</span> <span class="nx">withApollo</span><span class="p">(</span><span class="nx">Sidebar</span><span class="p">)</span> <span class="p">}</span>
</code></pre></div><h2 id="the-solution">The solution</h2>
<p>Although not very elegant, the best solution I found was to rename the original class declaration and export the correctly named wrapped variable:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">import</span> <span class="p">{</span> <span class="nx">withApollo</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;react-apollo&#39;</span><span class="p">;</span>

<span class="kr">class</span> <span class="nx">SidebarComponent</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
  <span class="kr">public</span> <span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// ...
</span><span class="c1"></span>  <span class="p">}</span>
<span class="p">}</span>

<span class="kr">export</span> <span class="kr">const</span> <span class="nx">Sidebar</span> <span class="o">=</span> <span class="nx">withApollo</span><span class="p">(</span><span class="nx">SidebarComponent</span><span class="p">);</span>
</code></pre></div><h2 id="now-with-added-typescript">Now with added Typescript</h2>
<p>The above code works well in JS-land, but Typescript tends to get a bit grumpy. The component needs to be aware of props being passed in from the <code>withApollo</code> <abbr title="Higher-order component">HOC</abbr>. The solution is to add a new type to the component:</p>
<div class="highlight"><pre class="chroma"><code class="language-ts" data-lang="ts"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">React</span> <span class="kr">from</span> <span class="s1">&#39;react&#39;</span><span class="p">;</span>
<span class="kr">import</span> <span class="p">{</span> <span class="nx">withApollo</span><span class="p">,</span> <span class="nx">WithApolloClient</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;react-apollo&#39;</span><span class="p">;</span>

<span class="kr">class</span> <span class="nx">SidebarComponent</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span><span class="p">&lt;</span><span class="nt">WithApolloClient</span><span class="err">&lt;</span><span class="p">{}&gt;</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="kr">public</span> <span class="nx">render() {</span>
    <span class="c1">// ...
</span><span class="c1"></span>  <span class="p">}</span>
<span class="p">}</span>

<span class="kr">export</span> <span class="kr">const</span> <span class="nx">Sidebar</span> <span class="o">=</span> <span class="nx">withApollo</span><span class="p">(</span><span class="nx">SidebarComponent</span><span class="p">);</span>
</code></pre></div><p>If you already have some custom props defined on the component, they can be nested within the <code>WithApolloClient</code> annotation:</p>
<div class="highlight"><pre class="chroma"><code class="language-ts" data-lang="ts"><span class="kr">interface</span> <span class="nx">Props</span> <span class="p">{</span>
  <span class="nx">id</span>: <span class="kt">number</span><span class="p">;</span>
<span class="p">}</span>

<span class="kr">class</span> <span class="nx">SidebarComponent</span> <span class="kr">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span><span class="p">&lt;</span><span class="nt">WithApolloClient</span><span class="err">&lt;</span><span class="na">Props</span><span class="p">&gt;</span><span class="o">&gt;</span>
</code></pre></div>]]>
      </description>
    </item>
    
    <item>
      <title>Moving on</title>
      <link>https://www.trysmudford.com/blog/moving-on/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/moving-on/</guid>
      <description><![CDATA[
<p>Today I leave Tomango.</p>
<p>After six years, I&rsquo;m moving on from the agency where I kicked off my career. I&rsquo;ve learned all I know about web development in this time. But it&rsquo;s the right time to move onwards and upwards.</p>
<p>A huge thank you to Mark for supporting, encouraging and believing in me.</p>
<p>Thanks to Mike for creating such amazing and interesting design work. It&rsquo;s been such a pleasure to work on them with you.</p>
<p>Thanks to Simon for your incredible mentoring, support and sage advice - it&rsquo;s seriously appreciated!</p>
<p>Thanks to Tom &amp; Liam for your friendship, laughs and <em>sass</em>.</p>
<p>Thanks to Steve, Elliot &amp; Kieran for all your help and amazing skills!</p>
<p>Thanks to Alex, Tim and the rest of the Slack gang for keeping me sane these past few years!</p>
<p>Thanks to my parents and siblings for their ever-attentive ears when I&rsquo;ve rambled on about code and careers at you!</p>
<hr>
<p>On Monday I start at <a href="https://daisie.com">Daisie</a>. I&rsquo;m so, so excited to get my teeth into this new challenge and help build an amazing project. It&rsquo;s a huge gear-change for me. From a 15-minute drive and a rural agency, to a commute to the big smoke to build a product at a startup!</p>
<p>The time is right to be shaken out of my comfort zone - I can&rsquo;t wait!</p>
]]>
      </description>
    </item>
    
    <item>
      <title>Thoughts on Offline-first</title>
      <link>https://www.trysmudford.com/blog/offline-first-thoughts/</link>
      <pubDate>Wed, 26 Sep 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/offline-first-thoughts/</guid>
      <description><![CDATA[
<p>I&rsquo;ve spent the evening experimenting with offline-first techniques, and considering implications of this approach. Service Workers have such huge potential power, and I feel like we (developers on the web) have barely scratched the surface with what&rsquo;s possible.</p>
<p>Being such a new technology, standards and best practices are yet to be formed, and I&rsquo;m fascinated as to how these will evolve over the next couple of years.</p>
<p>Service Workers are most commonly used as a progressive enhancement, providing an offline fallback. But they can do so much more than that. What if they were central to your site architecture? What would that look like in practice? What if you build a <strong>Service worker-first web application?</strong></p>
<p>Disclaimer: it&rsquo;s impossible to be truly Service Worker/offline-first, a user must visit your site once on the network before the Service Worker can take hold. But the aim of this post is to consider the implications of moving towards an assumption of no network.</p>
<hr>
<p>Network-first with cache fallback is a pretty safe option when it comes to <abbr title="Progressive Web Apps">PWAs</abbr>, and a great starting point. But that only helps users with <strong>great or no connection</strong>, it doesn&rsquo;t help those with <a href="https://meyerweb.com/eric/thoughts/2018/08/07/securing-sites-made-them-less-accessible/">slow connections</a>, flaky connections, or high network costs.</p>
<blockquote>
<p>The true power of a PWA is with offline-first</p>
</blockquote>
<p>Offline-first has massive implications on UX and usability. Sadly it&rsquo;s not as simple as flicking the switch and letting the cache do the work.</p>
<p>The &lsquo;Webpack&rsquo; approach of &lsquo;pre-cache all the things&rsquo; is regularly bundled into <code>create-[FRAMEWORK]-app</code> starter files. That might work for small applications, but I don&rsquo;t believe it scales. Caching all routes is presumptive, and if you&rsquo;re making regular changes to your site, those installation requests are going to mount up. As with most things on the real-world web, <strong>nuance is required</strong>.</p>
<p>There is so much to consider.</p>
<h2 id="stale-content">Stale content</h2>
<p>How timely is your content. Does it matter if you&rsquo;re reading &lsquo;yesterdays&rsquo; website? My kneejerk reaction was yes, it does matter! But after dwelling on it, I think I&rsquo;ve concluded <a href="https://adactio.com/journal/4437">it depends</a>.</p>
<p>Some pages are so time-sensitive that no content is better than old content. But that&rsquo;s pretty rare and I reckon most users would prefer to read something a little old, rather than nothing.</p>
<p>Are there some pages that must be served network-first? If so, how should they be flagged to the browser/Service Worker in a scalable system or CMS?</p>
<p>Could we use last-updated <code>&lt;meta&gt;</code> tags, or a <abbr title="Time to live">TTL</abbr> concept to keep content fresh? A means of checking whether the cached-content has past it&rsquo;s sell-by date before deciding which caching strategy to use?</p>
<p>Running a background fetch after serving cached content helps keep everything up to date, but the user will always be one page refresh behind the &lsquo;live&rsquo; content. This approach helps slow/flaky networks, but it still incurs a request per file, and the associated mobile data costs. Perhaps this background fetch should be limited to HTML requests only?</p>
<h2 id="refreshing">Refreshing</h2>
<p>There are times when it&rsquo;s crucial to get the user to see the latest version of the site. This could be for breaking news, a security fix, or a major new release.</p>
<p>Other times, you may wish to prompt the user with what&rsquo;s changed, or just inform them that a new version of the page is available.</p>
<p>The <code>activate</code> event in the Service Worker lifecycle is the right point to check for new caches, so it&rsquo;s also a good time to potentially alert the user to the change.</p>
<p>I wonder whether using different caches is a good distinguishing factor for these refresh events. When a cache is deleted, you can react accordingly. A deletion of the most crucial cache may send a message prompting the browser to perform an immediate reload, whereas a change to your CSS/JS cache may only prompt an update message.</p>
<p>Clear lines of communication between the Service Worker and browser are really important for an offline-first site. I think it feels right that the Service Worker should provide declarative information to the browser, rather than force changes itself.</p>
<p>There&rsquo;s a difference between sending a message of &lsquo;refresh the browser now&rsquo; and &lsquo;the crucial cache has changed, how would you like to handle that information&rsquo;. The first is a hammer/nut solution, but the second puts the control in the hands of the developer. They can decide when the time is right to refresh.</p>
<p>If a user was typing in your chat system, refreshing or even prompting for a refresh would be very disruptive. Much like the <code>beforeinstallprompt</code> event, delaying an update notification may be the smart move.</p>
<p>Workers use <code>postMessage</code> to communicate. It&rsquo;s all string-based, so establishing an early standard pattern of communication with stringified objects is a good plan.</p>
<h2 id="slow-networks">Slow networks</h2>
<p>One of the biggest issues with the network-first approach is slow connections. In fact, network-first, cache-fallback sites perform best when you turn off your Wi-Fi. This is one of the main attractions to an offline-first approach!</p>
<p>I wonder whether a well-defined <code>setTimeout</code> race condition could be used to keep some assets as network-first, but with a sensible time limit. If the timer pings, the cached version could be served and the live version requested in the background, perhaps posting a message to the user alerting them to the new content.</p>
<h2 id="content-updates">Content updates</h2>
<p>Like refreshing, it&rsquo;s important to consider the best way to introduce new content into an existing page. If we view a page as offline-first, there may be regular arrivals of fresh content that need to be injected into the stale page.</p>
<p>For example, when you load the Twitter native app, you don&rsquo;t immediately see the latest feed (let&rsquo;s not dwell on non-chronological feeds just yet); you see the feed from where you left off last time. This happens regardless of your <a href="https://youtu.be/LinpRhB4aWU?t=21s">network conditions</a>. If you&rsquo;re online, the latest posts are fetched and injected at the top of the page, and you&rsquo;re alerted that new content is available.</p>
<p>We need to be mindful of scroll position, page performance and screenreaders when injecting new content into a page.</p>
<h2 id="authentication">Authentication</h2>
<p>Handling login states in Service Workers requires yet more thought.</p>
<p>In some regards, the man-in-the-middle nature of Service Workers provides a neat way to handle all unauthorised requests. Listening for 403 errors in <code>Response.status</code> could be a good way to prompt the browser to redirect the user to the login screen. But given Service Workers are not supported by all browsers, it&rsquo;s safer to ensure a server &amp; client-side alternative is also put in place.</p>
<p>Purging most caches at the time of logout is probably a good step, but it&rsquo;ll be important to leave a login page in a different cache. Again, nuance will be required to get authentication to feel just right in a website.</p>
<h2 id="releases">Releases</h2>
<p>The &lsquo;pre-cache all the things&rsquo; technique does throw up an interesting point about &lsquo;releases&rsquo;. The web is an ever-changing landscape, and fortunately, we don&rsquo;t have to deal with app store walled gardens. But maybe there&rsquo;s a thing or two that could be learned from staged releases.</p>
<p>With an offline-only approach, the only file requested at runtime is the Service Worker itself. Until that file is altered, the browser will keep merrily serving the cached files. This gives us the option to stage releases and prompt refreshes when they&rsquo;re ready. I certainly don&rsquo;t think that the daily multi-megabyte native app update pattern is worth copying, but perhaps there are elements worth exploring?</p>
<p>We need to be aware of local cache sizes, and handle them responsibly. Perhaps giving the user control to choose how much is being stored?</p>
<p>Consider a user on an expensive mobile data contract, do they need to load each user avatar on your web site? Thanks to the Service Worker pre-request design, we can cut off requests before they hit the network altogether, returning a pre-cached fallback image.</p>
<h2 id="non-service-worker-support">Non Service Worker support</h2>
<p>Service Workers have <a href="https://caniuse.com/#feat=serviceworkers">great browser support</a> but we can&rsquo;t take that as a given. A service worker-first approach should <strong>still be progressively enhanced</strong>, but should also leverage the power of offline-first more than we currently do.</p>
<blockquote>
<p>Serving content should always be the first priority, regardless of your Service Worker approach.</p>
</blockquote>
<p>Classic <a href="/blog/cache-busting/">cache-busting</a> techniques still have their place, and need to be accounted for in our Service Workers. Again, clear lines of communication will ensure you&rsquo;re handling your caching responsibilities correctly. For example, <code>/style.css?ver=20180927</code>, <code>/style.20180927.css</code>, and <code>/style.css</code> may need to be viewed as the same URL within the Service Worker.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Like all new technologies, patterns will emerge over time and standards will be forged. This is by no means to suggest a &lsquo;bootstrap&rsquo; approach is right for all sites. But if we&rsquo;re bundling generic Service Workers into starter files, we need to be sure they&rsquo;re working as effectively as possible.</p>
<p>I&rsquo;m so excited to see how we can use Service Workers to improve the web.</p>
]]>
      </description>
    </item>
    
    <item>
      <title>Making some updates</title>
      <link>https://www.trysmudford.com/blog/making-some-updates/</link>
      <pubDate>Sun, 23 Sep 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/making-some-updates/</guid>
      <description><![CDATA[
<p>After <a href="/blog/down-the-rabbit-warren/">falling down the rabbit warren</a>, I thought it was time to perform some housekeeping on my site. This was spread over two evenings with the commits from day one <a href="https://github.com/trys/trysv4/commit/b5a72e3b3404e9892d8b66100e92b2972cf2dbde">here</a>. The day two commits are linked from their respective headings below.</p>
<h2 id="npm-updates">NPM updates</h2>
<p>This site is written in Hugo and is compiled with <a href="https://www.npmjs.com/package/hugo-bin">hugo-bin</a>. There are a few other <code>devDependencies</code> to take care of too.</p>
<p>NPM has a handy feature that warns you if your packages are getting out of date, or if any major security fixes are available. A quick run of <code>npm audit fix</code> did the job here.</p>
<h2 id="fonts---stage-1">Fonts - stage 1</h2>
<p>As ever, Zach Leatherman <a href="https://www.zachleat.com/web/font-checklist/">provided the secrets</a> to font optimisation!</p>
<h3 id="preload">Preload</h3>
<p>I added a preload statement for the two web fonts on the site; it tells the browser to start downloading them earlier. Without a preload hint, the browser has to recieve and parse the CSS requesting the font, before it can make the request. I only preload the <code>woff2</code> font as most browsers can serve this format now.</p>
<p><code>&lt;link rel=&quot;preload&quot; href=&quot;/fonts/[font_file].woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;</code></p>
<h3 id="font-display">Font-display</h3>
<p>Adding <code>font-display: swap</code> to the <code>@font-face</code> block asks browsers to perform a FOUT, rather than a FOIT. It&rsquo;s not hugely supported, but thanks to the declarative nature of CSS, that doesn&rsquo;t matter!</p>
<h2 id="tidying-up-the-home-page">Tidying up the home page</h2>
<p>I <del>have</del> had two projects on the home page. They were mostly superfluous fluff. They&rsquo;re gone now - saving two image requests!</p>
<hr>
<p>That was enough for one evening, so I came back to the site today and make a few more changes&hellip;</p>
<h2 id="fonts---stage-2">Fonts - stage 2</h2>
<h3 id="subsettinghttpsgithubcomtrystrysv4commitb6a68ccea1cc49822ede4c95edcf01b6691a490f"><a href="https://github.com/trys/trysv4/commit/b6a68ccea1cc49822ede4c95edcf01b6691a490f">Subsetting</a></h3>
<p>After finally getting <code>pip</code> installed (it all got a bit <a href="https://www.youtube.com/watch?v=AbSehcT19u0">&lsquo;Hal changing a lightbulb&rsquo;</a>), <a href="https://www.zachleat.com/web/glyphhanger/">Glyphhanger</a> took huge chunks out of my font files by subsetting them.</p>
<p>It&rsquo;s truly amazing. The two <code>17kb .woff2</code> files became <code>4kb</code>!</p>
<p>I added the new fonts to the static directory and updated the <code>@font-face</code> references.</p>
<h3 id="service-worker-font-referenceshttpsgithubcomtrystrysv4commit86199800f0726074368951c60f742b4c7e5341dc"><a href="https://github.com/trys/trysv4/commit/86199800f0726074368951c60f742b4c7e5341dc">Service Worker font references</a></h3>
<p>After running the site through WebPageTest, I was still seeing the old files being served. It transpired that the Service Worker was precaching them! Fortunately that was a quick change to the font references in the SW.</p>
<h2 id="meta-descriptionhttpsgithubcomtrystrysv4commitabaa30f2bb313f3edac924002234a5c75bc7839c"><a href="https://github.com/trys/trysv4/commit/abaa30f2bb313f3edac924002234a5c75bc7839c">Meta description</a></h2>
<p>I ran Lighthouse on the site, it showed 100 on all counts, apart from an SEO issue. Thanks to the brilliant descriptions, it showed that the home page was missing a meta description. Again, a nice quick fix.</p>
<h2 id="redirects-errorhttpsgithubcomtrystrysv4commitcc5ee0d5fb8cf821b59089f968cec905987aa3a6"><a href="https://github.com/trys/trysv4/commit/cc5ee0d5fb8cf821b59089f968cec905987aa3a6">Redirects error</a></h2>
<p>When I checked the build status of a deployment, Netlify warned me that one of the redirects wasn&rsquo;t formatted correctly. This is a new feature in Netlify&rsquo;s deployment process, and it&rsquo;s super-helpful. It alerts you to mixed-content warnings, header/redirect issues and more! It&rsquo;s all outlined <a href="https://www.netlify.com/blog/2018/09/05/more-confident-deployments-thanks-to-netlify-deploy-summaries/">here</a>.</p>
<h2 id="google-analytics">Google Analytics</h2>
<p>The cache time on Google Analytics has always frustrated me. WebPageTest and Google PageSpeed insights always complains that the GA JS file isn&rsquo;t being cached heavily enough. Thanks to the wonderful <a href="https://github.com/jehna/ga-lite">ga-lite</a> package, you can serve high-cache and minimal analytics! It&rsquo;s all compatibe with GA, but a quarter of the size.</p>
<hr>
<h2 id="results">Results</h2>
<p>The home page was: <strong>147kb</strong><br>
The home page now is: <strong>28kb</strong></p>
<p>An article page was: <strong>41kb</strong>
An article page now is: <strong>16kb</strong></p>
<p>WebPageTest is showing all A&rsquo;s and Lighthouse is all 100&rsquo;s.</p>
]]>
      </description>
    </item>
    
    <item>
      <title>Down the rabbit warren</title>
      <link>https://www.trysmudford.com/blog/down-the-rabbit-warren/</link>
      <pubDate>Sat, 22 Sep 2018 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/down-the-rabbit-warren/</guid>
      <description><![CDATA[
<p>Thanks to a tip-off from <a href="http://tomruzyllo.com">Tom</a>, some links from my sister and a great slack community, much of the evening has been spent heading down a warren of blog posts and essays.</p>
<ul>
<li><a href="http://tonsky.me/blog/disenchantment/">Software disenchantment</a></li>
<li><a href="http://tonsky.me/blog/compatibility/">JavaScript v. backward compatibility</a></li>
<li><a href="https://grumpy.website">Grumpy website</a></li>
<li><a href="https://josephg.com/blog/electron-is-flash-for-the-desktop/">Electron is flash for the desktop</a></li>
<li><a href="http://idlewords.com/talks/website_obesity.htm">The website obesity crisis</a></li>
<li><a href="http://idlewords.com/talks/what_happens_next_will_amaze_you.htm#six_fixes">Six Fixes</a></li>
<li><a href="https://www.zachleat.com/web/glyphhanger/">It’s dangerous to go stallone. Take Glyphhanger</a></li>
<li><a href="https://www.copyediting.com/disabling-ableist-language/#.W6alsBNKjBL">Disabling Ableist Language</a></li>
<li><a href="https://www.autistichoya.com/p/ableist-words-and-terms-to-avoid.html">Ableism/Language</a></li>
<li><a href="https://adactio.com/journal/14355">A framework for web performance</a></li>
<li><a href="https://medium.com/@aerotwist/the-9am-rush-hour-2d7ae687efd5">The 9am Rush Hour</a></li>
<li><a href="https://www.youtube.com/watch?v=XB4cjbYywqg">Apple - Accessibility</a></li>
</ul>
<p>The weird, wild web is wonderful.</p>
]]>
      </description>
    </item>
    
  </channel>
</rss>