<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Localhost Feed]]></title><description><![CDATA[Modern web development guides hints and tips.]]></description><link>http://github.com/dylang/node-rss</link><generator>GatsbyJS</generator><lastBuildDate>Thu, 12 Nov 2020 19:15:42 GMT</lastBuildDate><item><title><![CDATA[Open Graph Images with Gatsby and Now]]></title><description><![CDATA[So, I followed the awesome video content and blog post from Leigh
Halliday and I now have a way to generate Social Sharing cards for
Twitter…]]></description><link>https://scottspence.com/unpublished/serverless-og-images/</link><guid isPermaLink="false">https://scottspence.com/unpublished/serverless-og-images/</guid><pubDate>Thu, 30 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So, I followed the awesome video content and blog post from Leigh
Halliday and I now have a way to generate Social Sharing cards for
Twitter, Facebook and LinkedIn without having to add a cover image to
every post I do.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Moving Large Markdown Assets to a CDN]]></title><description><![CDATA[I've spent a while today trying to bring down the size of this
project, I have several posts that are particularly large so I wanted
to work…]]></description><link>https://scottspence.com/2020/04/30/large-md-assets-to-cdn/</link><guid isPermaLink="false">https://scottspence.com/2020/04/30/large-md-assets-to-cdn/</guid><pubDate>Thu, 30 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve spent a while today trying to bring down the size of this
project, I have several posts that are particularly large so I wanted
to work out a way to reduce that.&lt;/p&gt;&lt;p&gt;I’m an Ubuntu user and wanted to see if there was a way I could
identify the larger files in the project.&lt;/p&gt;&lt;p&gt;I found &lt;a href=&quot;https://serverfault.com/questions/200949/how-can-i-find-the-biggest-directories-in-unix-ubuntu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this SO question&lt;/a&gt; which details using the &lt;code&gt;du&lt;/code&gt; command (&lt;a href=&quot;https://ss64.com/bash/du.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Disk
Usage&lt;/a&gt;) which I used to list out the folder sizes. I put the following
command into my terminal:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;du --max-depth=7 /home/scott/repos/thelocalhost/posts/ | sort -n
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It gave a similar output to this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;592   /thelocalhost/posts/2017/01/04/twitter-mctwitbot
2412    /thelocalhost/posts/2017/01/28/twitter-bot-bootstrap
38708   /thelocalhost/posts/2018/12/24/wsl-bootstrap-2019
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The output was a bit noisier that what I’ve put here actually, lot’s
of output, but it helped identify large assets in folders. That
&lt;code&gt;wsl-bootstrap-2019&lt;/code&gt; folder is nearly 40mb in size! 😱&lt;/p&gt;&lt;h2 id=&quot;markdown-file-structure&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#markdown-file-structure&quot; aria-label=&quot;markdown file structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Markdown file structure&lt;/h2&gt;&lt;p&gt;I have become quite particular about my Markdown as of late and like
to &lt;a href=&quot;https://thelocalhost.io/2020/04/18/add-tracking-links-to-your-markdown/#the-other-problem-for-me-anyway-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;structure things in a certain&lt;/a&gt; way. I started to do this with the
images and gifs that are in here as well.&lt;/p&gt;&lt;p&gt;So, as an example this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;![twitter logo](./twitter-bird.png)

I got to doing this from finding it on [GitHub](https://github.com) I
think I was looking for the Twitter icon in bootstrap whilst
working...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Will become this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;![twitter logo]

I got to doing this from finding it on [GitHub] I think I was looking
for the Twitter icon in bootstrap whilst working...

&amp;lt;!-- Links --&amp;gt;

[github]: https://github.com

&amp;lt;!-- Images --&amp;gt;

[twitter logo]: ./twitter-bird.png
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It looks like the second option here takes more space but the links at
the bottom of the document aren’t visible and it makes the writing
experience a lot easier to parse and manage when there are a lot of
links and assets in the document.&lt;/p&gt;&lt;h2 id=&quot;cool-story-bro&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#cool-story-bro&quot; aria-label=&quot;cool story bro permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cool story bro&lt;/h2&gt;&lt;p&gt;So I’m putting this here to document what I did, the assets in the
large folder I mentioned earlier have now been removed and added to
the Now CDN in their own folder.&lt;/p&gt;&lt;p&gt;So now at the end of each document, rather than have a load of local
files in the same folder they can all be references to the CDN.&lt;/p&gt;&lt;p&gt;How do I add them to a CDN? I make a folder with the same(ish) folder
structure then reference the CDN in place of the local images:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;images-on-now-sh/
├─ 2020/
├── this-post-im-talking-about/
│   ├─ image1.png
│   ├─ image2.png
│   └─ image3.png
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The whole reason I did this was so that if I wanted to I could run all
these through a service like &lt;a href=&quot;https://images.weserv.nl/docs/#how-it-works&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Images.weserv.nl&lt;/a&gt; where I could add the
URL to their service like so:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;[image1]: //images.weserv.nl/?url=https://images-on-now-sh/2020/this-post-im-talking-about/image1.png&amp;amp;w=300&amp;amp;h=300
&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title><![CDATA[A Digital Garden]]></title><description><![CDATA[I have spent the last two days now questioning how and what I write
after reading a  post from Richard Haines . In his post he mentioned
how…]]></description><link>https://scottspence.com/2020/04/27/a-digital-garden/</link><guid isPermaLink="false">https://scottspence.com/2020/04/27/a-digital-garden/</guid><pubDate>Mon, 27 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have spent the last two days now questioning how and what I write
after reading a &lt;a href=&quot;https://richardhaines.dev/on-my-mind/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;post from Richard Haines&lt;/a&gt;. In his post he mentioned
how he stumbled across the Digital Garden idea.&lt;/p&gt;&lt;p&gt;Richard’s post led me to &lt;a href=&quot;https://www.christopherbiscardi.com/what-is-a-digital-garden&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chris Biscardi’s thoughts&lt;/a&gt; on that and in
turn Joel Hooks.&lt;/p&gt;&lt;p&gt;Both Joel and Chris mention a post from &lt;a href=&quot;https://twitter.com/amyhoy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Amy Hoy&lt;/a&gt; (who I’ve just
realised I follow on Twitter) in the post Amy talks about the &lt;a href=&quot;https://stackingthebricks.com/how-blogs-broke-the-web/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How the
Blog Broke the Web&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As I’m writing this I’m actually in an Egghead.io Zoom webinar on the
subject.&lt;/p&gt;&lt;h2 id=&quot;publish-all-the-things&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#publish-all-the-things&quot; aria-label=&quot;publish all the things permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Publish all the things&lt;/h2&gt;&lt;p&gt;I decided that where I write about what I learn doesn’t have to be a
job, something else to add to my current cognitive load.&lt;/p&gt;&lt;p&gt;I was a bit hasty about publishing everything on my site, there’s no
rush for it to be ‘released’ though, I’ll do it as and when I get
round to it.&lt;/p&gt;&lt;p&gt;I spent some time cleaning up the site however, I removed all
unnecessary cover images and use an Open Graph tool to generate social
sharing cards.&lt;/p&gt;&lt;p&gt;The posts folder on this site before and after I purged all the
assets.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;70mb folder size with cover images&lt;/li&gt;&lt;li&gt;47mb after removing images&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I’ll go into more detail on this in the upcoming post [Moving from Now
to Netlify then back to Now], I think the title explains a lot of what
the content will be on that one&lt;/p&gt;&lt;p&gt;So this is going to work with the notion that I’ll write about things
as they come to me, add them here and add to them periodically as an
when needed.&lt;/p&gt;&lt;p&gt;This could possibly change after I finish listening to the Egghead.io
webinar.&lt;/p&gt;&lt;p&gt;I’m feeling quite liberated about the not saving things behind a
published flag now.&lt;/p&gt;&lt;p&gt;Even though I have the most ridiculous filing system&lt;/p&gt;&lt;p&gt;Also publish! Like I’m O’Reilly 😂&lt;/p&gt;&lt;p&gt;The content here is primarily for me and if it helps anyone else then
that’s a massive plus, you’re welcome. 🐱&lt;/p&gt;&lt;h2 id=&quot;unpublish-all-the-things&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#unpublish-all-the-things&quot; aria-label=&quot;unpublish all the things permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unpublish all the things&lt;/h2&gt;&lt;p&gt;It did! I’ve unpublished a lot of half arsed posts, some just a title
and a link. Sorry if you’re reading this and wondering why there’s a
post titled &lt;strong&gt;Shaving the Yak!&lt;/strong&gt; with the total content of one
sentence and two links!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Continuous Deployments on Non Essential Projects]]></title><description><![CDATA[Quite a while ago now I was introduced to tools like Renovate and
Greenkeeper, at the time I thought they were awesome, keeping your…]]></description><link>https://scottspence.com/2020/04/27/continus-deployment/</link><guid isPermaLink="false">https://scottspence.com/2020/04/27/continus-deployment/</guid><pubDate>Mon, 27 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quite a while ago now I was introduced to tools like Renovate and
Greenkeeper, at the time I thought they were awesome, keeping your
projects patches and secure so I went and used them in every project I
made.&lt;/p&gt;&lt;h2 id=&quot;busy-work&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#busy-work&quot; aria-label=&quot;busy work permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Busy work&lt;/h2&gt;&lt;p&gt;That was an incredible PITA (Pain in the Arse)&lt;/p&gt;&lt;p&gt;So what have I learned&lt;/p&gt;&lt;p&gt;Using Renovate may sound like a good idea, everything is kept current&lt;/p&gt;&lt;p&gt;But if you have a lot of projects with a dependency that has high
release rates or that you use in every project (Gatsby, Prettier) then
when update time comes there’s a lot of ‘busy work’ involved.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Configure Custom Domain Email with Zoho and Now]]></title><description><![CDATA[In this guide I'm going to cover the configuring of your custom domain
with Vercel's Now platform using the Now CLI. I'll be primarily…]]></description><link>https://scottspence.com/2020/04/25/custom-email-domain-with-now/</link><guid isPermaLink="false">https://scottspence.com/2020/04/25/custom-email-domain-with-now/</guid><pubDate>Sat, 25 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this guide I’m going to cover the configuring of your custom domain
with Vercel’s Now platform using the Now CLI.&lt;/p&gt;&lt;p&gt;I’ll be primarily covering the steps you take after setting up an
account with an email provider, the email provider I’m using is &lt;a href=&quot;https://www.zoho.com/mail/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zoho
Mail&lt;/a&gt; if you don’t use either of these services then this guide may
not be much use to you.&lt;/p&gt;&lt;h2 id=&quot;what-youll-need&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-youll-need&quot; aria-label=&quot;what youll need permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What you’ll need&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;a super awesome custom domain&lt;/li&gt;&lt;li&gt;a &lt;a href=&quot;https://www.zoho.com/mail/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zoho Mail&lt;/a&gt; account&lt;/li&gt;&lt;li&gt;a &lt;a href=&quot;https://vercel.com/signup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vercel.co&lt;/a&gt; account&lt;/li&gt;&lt;li&gt;The &lt;a href=&quot;https://vercel.com/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Now CLI&lt;/a&gt; installed&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It’s implied that you have a machine set up for web development
already and are familiar with using the terminal.&lt;/p&gt;&lt;p&gt;If you need to get set up for Windows &lt;a href=&quot;https://thelocalhost.blog/2018/12/24/wsl-bootstrap-2019/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;I have written a guide&lt;/a&gt;
previously on that topic.&lt;/p&gt;&lt;p&gt;If you’re a Linux user, check out this video on getting set up:&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-eSAsdQuQ-1o&quot; src=&quot;https://www.youtube.com/embed/eSAsdQuQ-1o?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;set-up-an-account&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#set-up-an-account&quot; aria-label=&quot;set up an account permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set up an account&lt;/h2&gt;&lt;p&gt;Zoho mail offer a 5 GB &lt;a href=&quot;https://workplace.zoho.eu/orgsignup.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;forever free plan&lt;/a&gt;, so as long as you can
manage your email archiving then you are good to go.&lt;/p&gt;&lt;p&gt;You also get up to five users and a 25mb file attachment limit with
hosting for a single domain.&lt;/p&gt;&lt;p&gt;Pretty good right!&lt;/p&gt;&lt;h2 id=&quot;create-an-admin-super-user&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-an-admin-super-user&quot; aria-label=&quot;create an admin super user permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create an admin super user&lt;/h2&gt;&lt;p&gt;When you sign up with &lt;a href=&quot;https://www.zoho.com/mail/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zoho Mail&lt;/a&gt; you will be prompted to create a
super admin user for your zoho account and you’re given the
opportunity to set up two factor authentication (2fa).&lt;/p&gt;&lt;p&gt;Zoho will even tell you about their authenticator app, which is only
for authenticating with Zoho. Use this is you like, I use a 2fa app
that you can use for multiple services.&lt;/p&gt;&lt;h2 id=&quot;verify-you-own-the-domain&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#verify-you-own-the-domain&quot; aria-label=&quot;verify you own the domain permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Verify you own the domain&lt;/h2&gt;&lt;p&gt;You will be given a code to verify that you are the owner of the
domain, which you will need to add as a &lt;code&gt;TXT&lt;/code&gt; entry on your domain
with the Now CLI.&lt;/p&gt;&lt;p&gt;The verification token will look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;zoho-verification=se4567894.zmverify.zoho.eu
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add that to your domain DNS with the Now CLI, you can check your
domain DNS entries with the &lt;code&gt;ls&lt;/code&gt; command.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# list your dns entries
now dns ls yourdomain.com
# add the zoho verification as a TXT record
now dns add yourdomain.com @ TXT zoho-verification=se4567894.zmverify.zoho.eu
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;add-the-mx-records&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-the-mx-records&quot; aria-label=&quot;add the mx records permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add the MX records&lt;/h2&gt;&lt;p&gt;Now to configure the &lt;code&gt;MX&lt;/code&gt; records. MX records are essential to receive
emails in your domain. The MX records for your domain will look
something like this:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Host Name&lt;/th&gt;&lt;th&gt;Address&lt;/th&gt;&lt;th&gt;Priority&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;@ / Blank&lt;/td&gt;&lt;td&gt;mx.zoho.eu&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;@ / Blank&lt;/td&gt;&lt;td&gt;mx2.zoho.eu&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;@ / Blank&lt;/td&gt;&lt;td&gt;mx3.zoho.eu&lt;/td&gt;&lt;td&gt;50&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Add them much in the same way as with the verification token with the
Now CLI this time specifying an &lt;code&gt;MX&lt;/code&gt; instead of &lt;code&gt;TXT&lt;/code&gt; and there’s a
second argument for the priority:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now dns add yourdomain.com @ MX mx.zoho.eu 10
now dns add yourdomain.com @ MX mx.zoho.eu 20
now dns add yourdomain.com @ MX mx.zoho.eu 50
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;set-the-sender-policy-framework-spf&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#set-the-sender-policy-framework-spf&quot; aria-label=&quot;set the sender policy framework spf permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set the Sender Policy Framework (SPF)&lt;/h2&gt;&lt;p&gt;To ensure that valid emails from your domain get delivered to your
users, and spoofed emails from other spammers are identified by the
other email services, it’s recommend you add an SPF record for your
domain.&lt;/p&gt;&lt;p&gt;This will go into a &lt;code&gt;TXT&lt;/code&gt; record like with the verification token:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now dns add yourdomain.com @ TXT &amp;#x27;v=spf1 include:zoho.eu ~all&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Note: You may need to wait a while after making these changes before
the DNS updates can be verified via Zoho.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Make a simple, personal, URL shortener with Now.sh]]></title><description><![CDATA[Remember services like  Bitly  and  TinyURL ? Yeah, they still exist,
shortening your URLs for you, they've been around for a long time too…]]></description><link>https://scottspence.com/2020/04/19/url-shortener-with-nowsh/</link><guid isPermaLink="false">https://scottspence.com/2020/04/19/url-shortener-with-nowsh/</guid><pubDate>Sun, 19 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Remember services like &lt;a href=&quot;https://bitly.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bitly&lt;/a&gt; and &lt;a href=&quot;https://tinyurl.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TinyURL&lt;/a&gt;? Yeah, they still exist,
shortening your URLs for you, they’ve been around for a long time too.&lt;/p&gt;&lt;p&gt;Bitly founded in 2008 and TinyURL founded in 2002 😱&lt;/p&gt;&lt;p&gt;In this post I’m detailing how I made my own Bitly with Now.sh.&lt;/p&gt;&lt;p&gt;You can make your own one too as I’m about to detail the process here,
or you can &lt;strong&gt;&lt;a href=&quot;#-heres-a-video-detailing-the-process&quot;&gt;TL;DR&lt;/a&gt;&lt;/strong&gt; for the video.&lt;/p&gt;&lt;p&gt;What you need:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Node (to run the now CLI)&lt;/li&gt;&lt;li&gt;The &lt;a href=&quot;https://vercel.com/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;now CLI&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://vercel.com/signup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vercel.com account&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/join&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub account&lt;/a&gt; (not essential)&lt;/li&gt;&lt;li&gt;Yor own domain (not essential)&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;examples-why-would-i-use-a-short-url&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#examples-why-would-i-use-a-short-url&quot; aria-label=&quot;examples why would i use a short url permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Examples, why would I use a short URL?&lt;/h2&gt;&lt;p&gt;I use short URLs for sharing my content, if you take a look at this
blog post URL is quite long and not something you can reel off quickly
to someone.&lt;/p&gt;&lt;p&gt;There’s a talk I did about Gatsby, titled “Build-time and Client
Run-time Data Fetching in Gatsby” the URL for it is:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://gatsby-build-and-run-time-data-fetching-talk.now.sh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gatsby-build-and-run-time-data-fetching-talk.now.sh&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;With a short URL I can condense it down a bit:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://ss10.dev/gatsby-data-fetching&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ss10.dev/gatsby-data-fetching&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Not massively shorter, and granted the original URL has no place being
that long!&lt;/p&gt;&lt;p&gt;Other examples could be the “Build a coding blog from scratch with
Gatsby and MDX” guide I did at the end of last year:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Full URL &lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Short URL &lt;a href=&quot;https://ss10.dev/bab-guide&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ss10.dev/bab-guide&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Or if you have a crazy URL no one is going to be able to recite from
memory, like my YouTube channel URL:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Full URL &lt;a href=&quot;https://www.youtube.com/channel/UCnngLXpLSFsKkDhFoO9Ct3w&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/channel/UCnngLXpLSFsKkDhFoO9Ct3w&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Short URL &lt;a href=&quot;https://ss10.dev/youtube&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ss10.dev/youtube&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Shorter still &lt;a href=&quot;https://ss10.dev/yt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ss10.dev/yt&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I do have a vanity URL for my YouTube channel which is
&lt;a href=&quot;https://www.youtube.com/c/ScottSpencePlease&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/c/ScottSpencePlease&lt;/a&gt;, but it’s case sensitive.
🤦‍♂&lt;/p&gt;&lt;h2 id=&quot;do-i-have-to-use-vercel-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#do-i-have-to-use-vercel-&quot; aria-label=&quot;do i have to use vercel  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Do I have to use Vercel? 🤔&lt;/h2&gt;&lt;p&gt;No, you can use Netlify as well. There’s a great &lt;a href=&quot;https://www.youtube.com/watch?v=HL6paXyx6hM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kent C Dodds example
with Netlify&lt;/a&gt; that I used before moving to Vercel.&lt;/p&gt;&lt;p&gt;You don’t have to use Netlify either, you do you. 😸&lt;/p&gt;&lt;p&gt;There’s many ways to do it and the best way for you may be different
to me. You will need a domain name and a hosting service, that’s what
I’m doing with Vercel here.&lt;/p&gt;&lt;h2 id=&quot;redirects&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#redirects&quot; aria-label=&quot;redirects permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Redirects&lt;/h2&gt;&lt;p&gt;The way I’m doing this is with redirects, so it will be like in the
examples earlier, give a path to your URL then use a redirect rule.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;source&amp;quot;: &amp;quot;/yt&amp;quot;,
  &amp;quot;destination&amp;quot;: &amp;quot;https://www.youtube.com/channel/UCnngLXpLSFsKkDhFoO9Ct3w&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;get-set-up-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#get-set-up-&quot; aria-label=&quot;get set up  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get set up 🛠&lt;/h2&gt;&lt;p&gt;If you don’t have a machine set up for web development I have written
about getting set up &lt;a href=&quot;https://thelocalhost.blog/2018/12/24/wsl-bootstrap-2019/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;for Windows&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;There’s also a video I’ve made to go from scratch to Create React App
on Ubuntu 19.04.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-eSAsdQuQ-1o&quot; src=&quot;https://www.youtube.com/embed/eSAsdQuQ-1o?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;If you’re following along and you haven’t done so already, you’ll need
to install the Vercel CLI:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# if you&amp;#x27;re using npm, then
# npm i -g now
yarn global add now
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then you’ll need to authenticate with the CLI:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now login
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You will be prompted with a phrase, something like &lt;code&gt;Handsome Turtle&lt;/code&gt;
that should match the phrase in the email Vercel sends you. You can
authenticate by clicking the link in the email.&lt;/p&gt;&lt;h2 id=&quot;create-the-project&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-the-project&quot; aria-label=&quot;create the project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create the project&lt;/h2&gt;&lt;p&gt;I’m going to create a directory for the project to live in, then
change into that directory and make the project with &lt;code&gt;yarn init -y&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir short-urls # create directory
cd short-urls # change to newly created dir
yarn init -y # initialise the project
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s going to create my &lt;code&gt;package.json&lt;/code&gt; file with the project details
in it.&lt;/p&gt;&lt;p&gt;Next to create the &lt;code&gt;now.json&lt;/code&gt; file this is going to be where all the
redirects live:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch now.json
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the &lt;code&gt;now.json&lt;/code&gt; file I’m going to add the Vercel Now platform
version then the redirects array with the first redirect being where I
want my domain to default to.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;version&amp;quot;: 2,
  &amp;quot;redirects&amp;quot;: [
    {
      &amp;quot;source&amp;quot;: &amp;quot;/&amp;quot;,
      &amp;quot;destination&amp;quot;: &amp;quot;https://scottspence.me&amp;quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;deploy-the-project&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#deploy-the-project&quot; aria-label=&quot;deploy the project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deploy the project&lt;/h2&gt;&lt;p&gt;That is all the configuration I need for now, now I’m going to deploy
the project using the CLI this will push the project to the Vercel
hosting service.&lt;/p&gt;&lt;p&gt;To deploy the current directory I’ll do the following command:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As this is the first time I’ve deployed this project there will be a
lot of prompts from the CLI, I’ll answer the default answer to all of
these questions:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;- Set up and deploy project?: y
- Which scope (this is my user account): Scott Spence
- Link to an existing project?: n
- Whats your project name (hit return): short-urls
- In which directory is your code located (hit return)?: /
- Want to override the settings?: n
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The CLI will output two URLs, the first to my project on Vercel Now
and the second for the actual project. I’ll click on the first one and
and inspect the project.&lt;/p&gt;&lt;p&gt;As I set the root of the redirect to go to my portfolio site that’s
what I have in my project overview in Vercel.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/920be865823e277d7de4076c16bf0cef/47aef/vercel-project-overview.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:53.75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;214\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20214\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20107v107h401V0H0v107m21-51v59l1%2057h186V56l-93-1-94%201m86%2041c-10%206-9%2020%203%2026%204%202%205%201%202-3l-2-6v-8l1-1h7l-4-1c-4-1-5-2-2-4s7%200%208%204a25%2025%200%20010%2011l-2%205c-4%204-1%204%205%201%2011-7%205-26-8-26l-8%202m-63%2059c-1%204%200%204%2016%204%2013%200%2015%200%2016-2%202-3-1-4-16-4-12%200-15%200-16%202m37-1v3c0%202%201%202%2016%202h16v-5l-16-1-16%201m36%201c-1%204%200%204%2016%204s18%200%2016-4c0-2-3-2-16-2-12%200-15%200-16%202m37%200c-2%203%201%204%2016%204h16v-5l-16-1c-14%200-16%200-16%202\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/920be865823e277d7de4076c16bf0cef/60a22/vercel-project-overview.webp 160w,/static/920be865823e277d7de4076c16bf0cef/4c812/vercel-project-overview.webp 320w,/static/920be865823e277d7de4076c16bf0cef/0ba47/vercel-project-overview.webp 640w,/static/920be865823e277d7de4076c16bf0cef/e46b2/vercel-project-overview.webp 960w,/static/920be865823e277d7de4076c16bf0cef/0ca5b/vercel-project-overview.webp 1063w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/920be865823e277d7de4076c16bf0cef/69538/vercel-project-overview.png 160w,/static/920be865823e277d7de4076c16bf0cef/72799/vercel-project-overview.png 320w,/static/920be865823e277d7de4076c16bf0cef/6af66/vercel-project-overview.png 640w,/static/920be865823e277d7de4076c16bf0cef/d9199/vercel-project-overview.png 960w,/static/920be865823e277d7de4076c16bf0cef/47aef/vercel-project-overview.png 1063w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/920be865823e277d7de4076c16bf0cef/6af66/vercel-project-overview.png&quot; alt=&quot;vercel project overview&quot; title=&quot;vercel project overview&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I can now take that URL (now-short-urls-fzph462o0.now.sh) add it to a
browser and it will redirect to &lt;a href=&quot;https://scottspence.me&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://scottspence.me&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Now when I deploy this with the &lt;code&gt;--prod&lt;/code&gt; flag in the Vercel CLI it
will use the project URL (now-short-urls.now.sh).&lt;/p&gt;&lt;p&gt;Ok so that was quite straightforward, right?&lt;/p&gt;&lt;p&gt;Now each time I want to add a short URL I’ll add it to the &lt;code&gt;now.json&lt;/code&gt;
file and run the Vercel CLI again to deploy the project.&lt;/p&gt;&lt;p&gt;But I can take out the deployment part and leave that to the Vercel
GitHub integration.&lt;/p&gt;&lt;p&gt;So, better get that project on GitHub!&lt;/p&gt;&lt;h2 id=&quot;add-the-project-to-github&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-the-project-to-github&quot; aria-label=&quot;add the project to github permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add the Project to GitHub&lt;/h2&gt;&lt;p&gt;Go to GitHub, click on the plus icon next to my profile picture,
select ’&lt;a href=&quot;https://github.com/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;New repository&lt;/a&gt;‘.&lt;/p&gt;&lt;p&gt;Enter the new project name and click the ‘Create repository’ button.&lt;/p&gt;&lt;p&gt;GitHub supplies the git commands to get the project onto GitHub.&lt;/p&gt;&lt;p&gt;Before that I’m going to initialise my project and add what I have to
git:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git init
git add .
git commit -m &amp;#x27;init 🔥&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then add the remote repository and push to it:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git remote add origin git@github.com:spences10/short-urls.git
git push -u origin master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s it the project is now on GitHub and I can start using the
Vercel GitHub integration.&lt;/p&gt;&lt;h2 id=&quot;use-vercel-for-github&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-vercel-for-github&quot; aria-label=&quot;use vercel for github permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Vercel for GitHub&lt;/h2&gt;&lt;p&gt;Vercel has a GitHub integration so that you can deploy automatically
from a push to your master branch on your project or via a pull
request.&lt;/p&gt;&lt;p&gt;The Vercel documentation for this is really good so I’m going to link
that &lt;a href=&quot;https://vercel.com/docs/v2/git-integrations/vercel-for-github&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The docs will walk you through setting up the GitHub integration with
your GitHub account and linking a project.&lt;/p&gt;&lt;p&gt;There are also integrations available for &lt;a href=&quot;https://vercel.com/docs/v2/git-integrations/vercel-for-gitlab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitLab&lt;/a&gt; and &lt;a href=&quot;https://vercel.com/docs/v2/git-integrations/vercel-for-bitbucket&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bitbucket&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Now each time I add a short url to my project all I have to do is git
commit and push to GitHub and the Vercel GitHub integration will take
care of the rest.&lt;/p&gt;&lt;h2 id=&quot;add-my-domain-to-vercel&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-my-domain-to-vercel&quot; aria-label=&quot;add my domain to vercel permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add my domain to Vercel&lt;/h2&gt;&lt;p&gt;Now I’m going to add my own domain to Vercel from the ‘Settings’ panel
of my project I can select ‘Domains’ and add in my own domain.&lt;/p&gt;&lt;p&gt;My domain isn’t supplied by Vercel so I will need to configure the DNS
settings in my domain provider by adding the custom DNS configuration
supplied here by Vercel.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/1a61d18a56f360b8fc4d92ed3767365b/cd78c/vercel-domains-settings.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:61.875%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;247\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20247\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20124v123h401V0H0v124M107%205c0%201-2%202-8%202l-8-1-2-1c-3%200-3%200-3%203%200%202%202%204%204%202h2c2%201%206%201%206-1l1%201%201%202v-2c0-2%200-2%201-1%201%202%209%202%2010%200h1c0%203%204%202%205-1%200-2-1-2-4-2-3%201-4%200-4-1l-1-1-1%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/1a61d18a56f360b8fc4d92ed3767365b/60a22/vercel-domains-settings.webp 160w,/static/1a61d18a56f360b8fc4d92ed3767365b/4c812/vercel-domains-settings.webp 320w,/static/1a61d18a56f360b8fc4d92ed3767365b/0ba47/vercel-domains-settings.webp 640w,/static/1a61d18a56f360b8fc4d92ed3767365b/e46b2/vercel-domains-settings.webp 960w,/static/1a61d18a56f360b8fc4d92ed3767365b/5b1dd/vercel-domains-settings.webp 1236w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/1a61d18a56f360b8fc4d92ed3767365b/69538/vercel-domains-settings.png 160w,/static/1a61d18a56f360b8fc4d92ed3767365b/72799/vercel-domains-settings.png 320w,/static/1a61d18a56f360b8fc4d92ed3767365b/6af66/vercel-domains-settings.png 640w,/static/1a61d18a56f360b8fc4d92ed3767365b/d9199/vercel-domains-settings.png 960w,/static/1a61d18a56f360b8fc4d92ed3767365b/cd78c/vercel-domains-settings.png 1236w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/1a61d18a56f360b8fc4d92ed3767365b/6af66/vercel-domains-settings.png&quot; alt=&quot;vercel domains settings&quot; title=&quot;vercel domains settings&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;The cool thing with Vercel is that I can have many domains pointing to
the same project.&lt;/p&gt;&lt;h2 id=&quot;heres-a-video-detailing-the-process-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heres-a-video-detailing-the-process-&quot; aria-label=&quot;heres a video detailing the process  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here’s a video detailing the process 📺&lt;/h2&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-y807T6Q1qqw&quot; src=&quot;https://www.youtube.com/embed/y807T6Q1qqw?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;resources&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#resources&quot; aria-label=&quot;resources permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=HL6paXyx6hM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kent C Dodds example with Netlify&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://vercel.com/docs/configuration#project/redirects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vercel’s documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/spences10/now-short-urls&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub project&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://dev.to/commonshost/build-your-own-url-shortener-in-15-minutes-279n&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Use Commons Host&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Add Analytics Tracking Links to your Markdown]]></title><description><![CDATA[I'm talking Fathom Analytics again, this time about tracking link
clicks in my Markdown. I have written about how to  track custom events…]]></description><link>https://scottspence.com/2020/04/18/add-tracking-links-to-your-markdown/</link><guid isPermaLink="false">https://scottspence.com/2020/04/18/add-tracking-links-to-your-markdown/</guid><pubDate>Sat, 18 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m talking Fathom Analytics again, this time about tracking link
clicks in my Markdown.&lt;/p&gt;&lt;p&gt;I have written about how to &lt;a href=&quot;https://thelocalhost.blog/2020/01/02/track-custom-events-with-fathom-analytics/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;track custom events&lt;/a&gt; with Fathom
previously and this is really an extension to that post.&lt;/p&gt;&lt;p&gt;If you would like to try Fathom and get a £10 discount on your first
invoice check &lt;a href=&quot;https://usefathom.com/ref/HG492L&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my affiliate link&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This situation is specific to using MDX and the MDXProvider as it
gives the ability to override rendering of links.&lt;/p&gt;&lt;h2 id=&quot;the-problem-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-problem-&quot; aria-label=&quot;the problem  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The problem 🤔&lt;/h2&gt;&lt;p&gt;I’d like to add a &lt;a href=&quot;https://usefathom.com/support/goals&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fathom goal&lt;/a&gt; to a link in my Markdown, to do this
I’ll need to get the goal ID I’ve created in Fathom to the link so
that when it’s clicked it’s logged with Fathom.&lt;/p&gt;&lt;p&gt;So I can add an &lt;code&gt;onClick&lt;/code&gt; event to the &lt;code&gt;a&lt;/code&gt; tag using the MDXProvider
and pass that ID to the analytics provider.&lt;/p&gt;&lt;h2 id=&quot;the-solution-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-solution-&quot; aria-label=&quot;the solution  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The solution 💡&lt;/h2&gt;&lt;p&gt;Ok, so I need a way to add a prop to a specific link that contains the
goal ID for Fathom.&lt;/p&gt;&lt;p&gt;Using a made up attribute added to the markup for the goal ID I can
pick out the ID and pass it to the analytics provider from the &lt;code&gt;A&lt;/code&gt;
component I’m using to override the links in the Markdown.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{2,7}&quot;&gt;export const A = props =&amp;gt; {
  const fa = useAnalytics()
  return (
    &amp;lt;a
      {...props}
      id={props.id}
      onClick={() =&amp;gt; fa(props.goal)}
      target=&amp;quot;_blank&amp;quot;
      rel=&amp;quot;noopener noreferrer&amp;quot;
    &amp;gt;
      {props.children}
    &amp;lt;/a&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the Markdown will look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# My awesome Markdown

Fathom Analytics recently added a feature for
&amp;lt;a href=&amp;quot;https://usefathom.com/blog/bypass-adblockers&amp;quot; goal=&amp;quot;IBQBRDPP&amp;quot;&amp;gt;custom
domains&amp;lt;/a&amp;gt; with their service.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, job done right?&lt;/p&gt;&lt;p&gt;Wellllll…&lt;/p&gt;&lt;p&gt;No.&lt;/p&gt;&lt;h2 id=&quot;the-other-problem-for-me-anyway-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-other-problem-for-me-anyway-&quot; aria-label=&quot;the other problem for me anyway  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The other problem (for me anyway) 😧&lt;/h2&gt;&lt;p&gt;I spend a lot of my time in Markdown files and I rarely use inline
links. With an inline Markdown link the link from that last example it
would look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# My awesome Markdown

Fathom Analytics recently added a feature for
[custom domains](https://usefathom.com/blog/bypass-adblockers) with
their service.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Doesn’t read great does it?&lt;/p&gt;&lt;p&gt;When there is a lot of prose (text) it can be difficult to read when
there are a lot of links in there.&lt;/p&gt;&lt;p&gt;I prefer to use the link text and reference it at the bottom of my
document, like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# My awesome Markdown

Fathom Analytics recently added a feature for [custom domains] with
their service.

&amp;lt;!-- Links --&amp;gt;

[custom domains]: https://usefathom.com/blog/bypass-adblockers
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;the-other-solution-🤯&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-other-solution-%F0%9F%A4%AF&quot; aria-label=&quot;the other solution 🤯 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The other solution 🤯&lt;/h2&gt;&lt;p&gt;So, I’d prefer to have the goal ID in the link but not cluttering up
my beautifully crafted Markdown with &lt;code&gt;a&lt;/code&gt; tags everywhere. 😁&lt;/p&gt;&lt;p&gt;How do I do that then?&lt;/p&gt;&lt;p&gt;The way I worked out how to do it was to use a URL parameter and
intercept it in the &lt;code&gt;A&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;In the Markdown I add the goal ID to the URL, on line 9:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot; metastring=&quot;{8-9}&quot;&gt;# My awesome Markdown

Fathom Analytics recently added a feature for [custom domains] with
their service.

&amp;lt;!-- Links --&amp;gt;

[custom domains]:
  https://usefathom.com/blog/bypass-adblockers?goalId=&amp;quot;IBQBRDPP&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This way the structure of the Markdown is unchanged making a much
nicer writing experience.&lt;/p&gt;&lt;p&gt;How to use the goal ID from the URL parameter?&lt;/p&gt;&lt;p&gt;First up I used an &lt;code&gt;onClick&lt;/code&gt; handler to pull out the &lt;code&gt;goalId&lt;/code&gt; for the
analytics provider.&lt;/p&gt;&lt;p&gt;Using the &lt;code&gt;URL(props.href).searchParams&lt;/code&gt; means that I can pull out the
&lt;code&gt;goalId&lt;/code&gt; using the &lt;code&gt;.get&lt;/code&gt; function.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{3-8}&quot;&gt;export const A = props =&amp;gt; {
  const fa = useAnalytics()
  const onClick = () =&amp;gt; {
    if (props.href.includes(`goalId`)) {
      const params = new URL(props.href).searchParams
      fa(params.get(`goalId`))
    }
  }

  return (
    &amp;lt;a {...props} onClick={onClick}&amp;gt;
      {props.children}
    &amp;lt;/a&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The only thing with this was that the &lt;code&gt;goalId&lt;/code&gt; would still be in the
URL.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:531px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/a8b55efd542a1abaf4905a646549dea6/d4713/url-with-goalid-showing.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:8.124999999999998%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;32\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2032\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2016v15h401V0H0v16\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/a8b55efd542a1abaf4905a646549dea6/60a22/url-with-goalid-showing.webp 160w,/static/a8b55efd542a1abaf4905a646549dea6/4c812/url-with-goalid-showing.webp 320w,/static/a8b55efd542a1abaf4905a646549dea6/a33a1/url-with-goalid-showing.webp 531w&quot; sizes=&quot;(max-width: 531px) 100vw, 531px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/a8b55efd542a1abaf4905a646549dea6/69538/url-with-goalid-showing.png 160w,/static/a8b55efd542a1abaf4905a646549dea6/72799/url-with-goalid-showing.png 320w,/static/a8b55efd542a1abaf4905a646549dea6/d4713/url-with-goalid-showing.png 531w&quot; sizes=&quot;(max-width: 531px) 100vw, 531px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/a8b55efd542a1abaf4905a646549dea6/d4713/url-with-goalid-showing.png&quot; alt=&quot;url with goalid showing&quot; title=&quot;url with goalid showing&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I didn’t really like the way this looked, especially if someone was
going to share that link after clicking it.&lt;/p&gt;&lt;p&gt;So reading into the URL API a bit more and reading up on some
&lt;a href=&quot;https://stackoverflow.com/a/12151322/1138354&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;StackOverflow posts&lt;/a&gt; I found that I could delete the parameter after
using it.&lt;/p&gt;&lt;p&gt;In the next block of code here, on line 3, I’m checking if the
&lt;code&gt;props.href&lt;/code&gt; contains a &lt;code&gt;goalId&lt;/code&gt; parameter.&lt;/p&gt;&lt;p&gt;I can then manipulate the &lt;code&gt;props.href&lt;/code&gt; in &lt;code&gt;useEffect&lt;/code&gt; and setting the
&lt;code&gt;goalId&lt;/code&gt; in state first on line 10.&lt;/p&gt;&lt;p&gt;Then I can delete the &lt;code&gt;goalId&lt;/code&gt; from the &lt;code&gt;url&lt;/code&gt; on line 11.&lt;/p&gt;&lt;p&gt;The props have been changed now so I’ll need to provide the new &lt;code&gt;href&lt;/code&gt;
to the &lt;code&gt;a&lt;/code&gt; tag in the props, on line 25.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{3-5,7-14,17-19,25}&quot;&gt;export const A = props =&amp;gt; {
  const fa = useAnalytics()
  const containsGoalId = props.href.includes(`goalId`)
  const [goalId, setGoalId] = useState(``)
  const [newHref, setNewHref] = useState(``)

  useEffect(() =&amp;gt; {
    if (containsGoalId) {
      const url = new URL(props.href)
      setGoalId(url.searchParams.get(`goalId`))
      url.searchParams.delete(`goalId`)
      setNewHref(url.href)
    }
  }, [containsGoalId, props.href])

  const onClick = () =&amp;gt; {
    if (goalId) {
      fa(goalId)
    }
  }

  return (
    &amp;lt;a
      {...props}
      href={containsGoalId ? newHref : props.href}
      onClick={onClick}
    &amp;gt;
      {props.children}
    &amp;lt;/a&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now clicking the link will only call the analytics provider when
there’s a goal ID in the &lt;code&gt;href&lt;/code&gt; passed to the component in the props.&lt;/p&gt;&lt;h2 id=&quot;heres-a-video-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heres-a-video-&quot; aria-label=&quot;heres a video  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here’s a video 📺&lt;/h2&gt;&lt;p&gt;In this video detail what I’ve been writing about.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-Ihbx0BVIhZk&quot; src=&quot;https://www.youtube.com/embed/Ihbx0BVIhZk?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;resources-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#resources-&quot; aria-label=&quot;resources  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources 📑&lt;/h2&gt;&lt;p&gt;These resources helped me along the way.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URL&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN URL API&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/delete&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN searchParams Delete&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SO Get Query String Values&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/22753052/remove-url-parameters-without-refreshing-page&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SO Remove Query String Values&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2016/01/urlsearchparams&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Google URLSearchParams&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Create a Custom Domain for Fathom Analytics]]></title><description><![CDATA[Fathom Analytics recently added a really neat feature for  custom
domains  with their service. What does that mean then? Well it's for…]]></description><link>https://scottspence.com/2020/04/16/fathom-create-custom-domain/</link><guid isPermaLink="false">https://scottspence.com/2020/04/16/fathom-create-custom-domain/</guid><pubDate>Thu, 16 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Fathom Analytics recently added a really neat feature for &lt;a href=&quot;https://usefathom.com/blog/bypass-adblockers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;custom
domains&lt;/a&gt; with their service.&lt;/p&gt;&lt;p&gt;What does that mean then? Well it’s for bypassing ad-blocking
extensions, not that Fathom wants to collect all your data, &lt;a href=&quot;https://usefathom.com/blog/bypass-adblockers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;far from
it&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The purpose of this post is to cover setting up my custom domain as I
have a specific domain provider and I’m using Vercel’s now.sh and
Netlify for hosting my projects I want to add the Fathom custom
domains to.&lt;/p&gt;&lt;p&gt;Fathom has provided instructions for &lt;a href=&quot;https://ca.godaddy.com/help/add-a-cname-record-19236&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Godaddy&lt;/a&gt;, &lt;a href=&quot;https://support.cloudflare.com/hc/en-us/articles/360020615111-Configuring-a-CNAME-setup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CloudFlare&lt;/a&gt;, &lt;a href=&quot;https://help.hover.com/hc/en-us/articles/217282457-Managing-DNS-records-#h_5eab4aa7-b044-4cc6-a3c0-5869f583edc8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hover&lt;/a&gt;
and &lt;a href=&quot;https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NameCheap&lt;/a&gt; however, Like I mentioned, I have a custom DNS with my
domain provider and I’m not be able to add a new CNAME record which is
what I need to generate my Fathom custom (sub)domain.&lt;/p&gt;&lt;h2 id=&quot;create-a-custom-domain&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-a-custom-domain&quot; aria-label=&quot;create a custom domain permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a custom domain&lt;/h2&gt;&lt;p&gt;Fathom’s &lt;a href=&quot;https://usefathom.com/support/custom-domains&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt; covers it pretty well, you go into your
settings panel on Fathom and add in the domain of your site which I
followed, pretty straight forward.&lt;/p&gt;&lt;p&gt;Fathom then give me two values, the first is the sub-domain that I’m
going to create and the other is the Fathom DNS server.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:540px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/918a662955a145472c8b3a65061649e2/07484/fathom-dns-record-for-site.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:103.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;413\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20413\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20207v206h401V0H0v207M15%2012l-1%20193c0%20188%200%20191%202%20192h366c2-1%202-4%202-192l-1-193c-2-2-366-2-368%200m15%20323l-1%2016c0%2013%200%2016%202%2016%203%202%20184%201%20185%200l1-16-1-16c-2-1-185-2-186%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/918a662955a145472c8b3a65061649e2/60a22/fathom-dns-record-for-site.webp 160w,/static/918a662955a145472c8b3a65061649e2/4c812/fathom-dns-record-for-site.webp 320w,/static/918a662955a145472c8b3a65061649e2/9e625/fathom-dns-record-for-site.webp 540w&quot; sizes=&quot;(max-width: 540px) 100vw, 540px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/918a662955a145472c8b3a65061649e2/69538/fathom-dns-record-for-site.png 160w,/static/918a662955a145472c8b3a65061649e2/72799/fathom-dns-record-for-site.png 320w,/static/918a662955a145472c8b3a65061649e2/07484/fathom-dns-record-for-site.png 540w&quot; sizes=&quot;(max-width: 540px) 100vw, 540px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/918a662955a145472c8b3a65061649e2/07484/fathom-dns-record-for-site.png&quot; alt=&quot;fathom dns record for a site&quot; title=&quot;fathom dns record for a site&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;add-the-custom-domain-to-my-site&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-the-custom-domain-to-my-site&quot; aria-label=&quot;add the custom domain to my site permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add the custom domain to my site&lt;/h2&gt;&lt;p&gt;I set about working out how to add a CNAME to this blog but couldn’t
find any good examples so I reached out to Fathom with a tweet:&lt;/p&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/spences10/status/1250786419536277505?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;p&gt;After I sent that I found &lt;a href=&quot;https://gist.github.com/jaydenseric/f4147d7d9788d1f46b30e4ac7b57e6b2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this gist&lt;/a&gt; which detailed the command for
adding the sub-domain which made sense to me.&lt;/p&gt;&lt;h2 id=&quot;add-dns-record-in-vercels-nowsh&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-dns-record-in-vercels-nowsh&quot; aria-label=&quot;add dns record in vercels nowsh permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add DNS record in Vercel’s now.sh&lt;/h2&gt;&lt;p&gt;With the two values from Fathom dashboard, the CNAME is the sub-domain
and the VALUE is the DNS server.&lt;/p&gt;&lt;p&gt;So in the now CLI I did the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now dns add randomsite.com cdrjcy CNAME starman.fathomdns.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then I checked that the changes were added using the now dns command
to list out my DNS settings:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now dns ls
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It depends on how quickly these are propagated to see if the record is
created, for me it was a refresh on the Fathom dashboard and it said
the domain was active with a couple of emails from Fathom to confirm
they were created.&lt;/p&gt;&lt;h2 id=&quot;dns-editor-for-vercel-domains&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#dns-editor-for-vercel-domains&quot; aria-label=&quot;dns editor for vercel domains permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;DNS Editor for Vercel domains&lt;/h2&gt;&lt;p&gt;It was after I worked out how to add the CNAME with the CLI that I
found the &lt;a href=&quot;https://vercel.com/integrations/dns&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DNS Editor for Vercel domains&lt;/a&gt; which Jack mentioned in the
reply to my tweet! 🤦‍♂&lt;/p&gt;&lt;p&gt;It’s a free integration on the Vercel Marketplace which is super
straightforward to use once you add it to your Vercel account you can
pick it from the Integrations section on your Vercel Dashboard.&lt;/p&gt;&lt;h2 id=&quot;select-custom-domain-in-site-settings&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#select-custom-domain-in-site-settings&quot; aria-label=&quot;select custom domain in site settings permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Select custom domain in site settings&lt;/h2&gt;&lt;p&gt;Now that the domain is set up I need to select that in the Sites
dashboard, click on the Site ID for my site the pick the domain from
the select list and verify it’s working on my site that is already
configured with Fathom.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/3af1a934a7a66f45d754f3cfa36bb80e/1d69c/pick-custom-domain-in-site-settings.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:76.25%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;305\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20305\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20153v152h401V0H0v153M12%2013v140l1%20139h372V13l-186-1-187%201m11%20236c-2%203-1%2020%200%2021l41%201h39v-23l-40-1c-36%200-40%200-40%202\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/3af1a934a7a66f45d754f3cfa36bb80e/60a22/pick-custom-domain-in-site-settings.webp 160w,/static/3af1a934a7a66f45d754f3cfa36bb80e/4c812/pick-custom-domain-in-site-settings.webp 320w,/static/3af1a934a7a66f45d754f3cfa36bb80e/0ba47/pick-custom-domain-in-site-settings.webp 640w,/static/3af1a934a7a66f45d754f3cfa36bb80e/08b4d/pick-custom-domain-in-site-settings.webp 750w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/3af1a934a7a66f45d754f3cfa36bb80e/69538/pick-custom-domain-in-site-settings.png 160w,/static/3af1a934a7a66f45d754f3cfa36bb80e/72799/pick-custom-domain-in-site-settings.png 320w,/static/3af1a934a7a66f45d754f3cfa36bb80e/6af66/pick-custom-domain-in-site-settings.png 640w,/static/3af1a934a7a66f45d754f3cfa36bb80e/1d69c/pick-custom-domain-in-site-settings.png 750w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/3af1a934a7a66f45d754f3cfa36bb80e/6af66/pick-custom-domain-in-site-settings.png&quot; alt=&quot;pick custom domain in site settings&quot; title=&quot;pick custom domain in site settings&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;add-dns-record-in-netlify&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-dns-record-in-netlify&quot; aria-label=&quot;add dns record in netlify permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add DNS record in Netlify&lt;/h2&gt;&lt;p&gt;I’m going to do the same with Netlify now, it’s a bit more
straightforward with Netlify, I go to my sites page, select Domains,
pick my domain scroll to the bottom of the list and select ‘Add new
record’, add the details from the Fathom Domains page.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:634px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/388b4824b94966a449b57c7fd59f5fa8/374ac/create-new-dns-record-netlify.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:90.625%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;363\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20363\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20182v181h401V0H0v182M12%2013l-2%201v337l2%201c3%202%20371%203%20374%201%202-1%202-4%202-171V13l-3-1c-4-2-370-1-373%201m14%20304l-1%2010c0%2012%200%2012%2017%2012%2016%200%2016%200%2016-12l-1-10-15-1-16%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/388b4824b94966a449b57c7fd59f5fa8/60a22/create-new-dns-record-netlify.webp 160w,/static/388b4824b94966a449b57c7fd59f5fa8/4c812/create-new-dns-record-netlify.webp 320w,/static/388b4824b94966a449b57c7fd59f5fa8/14369/create-new-dns-record-netlify.webp 634w&quot; sizes=&quot;(max-width: 634px) 100vw, 634px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/388b4824b94966a449b57c7fd59f5fa8/69538/create-new-dns-record-netlify.png 160w,/static/388b4824b94966a449b57c7fd59f5fa8/72799/create-new-dns-record-netlify.png 320w,/static/388b4824b94966a449b57c7fd59f5fa8/374ac/create-new-dns-record-netlify.png 634w&quot; sizes=&quot;(max-width: 634px) 100vw, 634px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/388b4824b94966a449b57c7fd59f5fa8/374ac/create-new-dns-record-netlify.png&quot; alt=&quot;create new dns record netlify&quot; title=&quot;create new dns record netlify&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;It didn’t take long to validate the record in the Fathoms setting page
then I picked the custom domain like I did in the previous step.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Add a Table of Contents with Smooth scroll using Gatsby and MDX]]></title><description><![CDATA[The main purpose for me documenting this is to demonstrate
implementing a table of contents with smooth scroll to the anchors in
a Gatsby…]]></description><link>https://scottspence.com/2020/02/13/smooth-scroll-toc-gatsby/</link><guid isPermaLink="false">https://scottspence.com/2020/02/13/smooth-scroll-toc-gatsby/</guid><pubDate>Thu, 13 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The main purpose for me documenting this is to demonstrate
implementing a table of contents with smooth scroll to the anchors in
a Gatsby project using MDX.&lt;/p&gt;&lt;p&gt;In the process I’m also setting up the Gatsby starter with MDX.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;TL;DR, go here:&lt;/strong&gt; &lt;a href=&quot;#make-a-toc-component&quot;&gt;Make a TOC component&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I like using styled-components for my styling and would like to use
them in this example, so I’m going to clone the Gatsby starter I made
in a &lt;a href=&quot;https://thelocalhost.blog/2020/02/06/globally-style-gatsby-styled-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;clone-the-gatsby-default-starter-with-styled-components&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#clone-the-gatsby-default-starter-with-styled-components&quot; aria-label=&quot;clone the gatsby default starter with styled components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Clone the Gatsby Default Starter with styled-components&lt;/h2&gt;&lt;p&gt;Spin up a new project using the template I made:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx gatsby new \
  gatsby-toc-example \
  https://github.com/spences10/gatsby-starter-styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once that has finished installing I’m going to &lt;code&gt;cd&lt;/code&gt; into the project
(&lt;code&gt;cd gatsby-toc-example&lt;/code&gt;) and install dependencies for using MDX in
Gatsby.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# you can use npm if you like
yarn add gatsby-plugin-mdx \
  @mdx-js/mdx \
  @mdx-js/react
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;add-some-content&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-some-content&quot; aria-label=&quot;add some content permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add some content&lt;/h2&gt;&lt;p&gt;Create a &lt;code&gt;posts&lt;/code&gt; directory with a &lt;code&gt;toc-example&lt;/code&gt; directory in it which
contains the &lt;code&gt;index.mdx&lt;/code&gt; file I’ll be adding the content to.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p posts/toc-example
touch posts/toc-example/index.mdx
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’ll paste in some content, I’ll take from the &lt;a href=&quot;https://raw.githubusercontent.com/spences10/thelocalhost.blog/authoring/posts/2020/02/13/smooth-scroll-toc-gatsby/index.mdx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;markdown from this
post!&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;configure-the-project-to-use-mdx&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure-the-project-to-use-mdx&quot; aria-label=&quot;configure the project to use mdx permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure the project to use MDX&lt;/h2&gt;&lt;p&gt;To enable MDX in the project I’ll add the &lt;code&gt;gatsby-plugin-mdx&lt;/code&gt;
configuration to the &lt;code&gt;gatsby-config.js&lt;/code&gt; file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  resolve: `gatsby-plugin-mdx`,
  options: {
    extensions: [`.mdx`, `.md`],
    gatsbyRemarkPlugins: [],
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’ll also need to add the posts directory to the
&lt;code&gt;gatsby-source-filesystem&lt;/code&gt; config as well.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  resolve: `gatsby-source-filesystem`,
  options: {
    name: `posts`,
    path: `${__dirname}/posts`,
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Stop the dev server (&lt;code&gt;Ctrl+c&lt;/code&gt; in the terminal) and start with the new
configuration.&lt;/p&gt;&lt;p&gt;Once the dev server has started back up, I’ll validate the Gatsby MDX
config by seeing if &lt;code&gt;allMdx&lt;/code&gt; is available in the Graph&lt;em&gt;i&lt;/em&gt;QL
explorer (&lt;code&gt;localhost:8000/___graphql&lt;/code&gt;).&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  allMdx {
    nodes {
      excerpt
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;configure-gatsby-node-to-create-the-fields-and-pages&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure-gatsby-node-to-create-the-fields-and-pages&quot; aria-label=&quot;configure gatsby node to create the fields and pages permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure Gatsby node to create the fields and pages&lt;/h2&gt;&lt;p&gt;Here I’ll make all the paths for the files in the &lt;code&gt;posts&lt;/code&gt; directory,
currently it’s only &lt;code&gt;gatsby-toc-example&lt;/code&gt;. I’ll do that with
&lt;code&gt;createFilePath&lt;/code&gt; when creating the node fields with &lt;code&gt;createNodeField&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, actions, getNode }) =&amp;gt; {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Stop and start the gatsby dev server again as I changed
&lt;code&gt;gatsby-node.js&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;In the Gatsby GraphQL explorer (Graph&lt;em&gt;i&lt;/em&gt;QL) validate that the
fields are being created.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  allMdx {
    nodes {
      fields {
        slug
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;create-a-post-template&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-a-post-template&quot; aria-label=&quot;create a post template permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a post template&lt;/h2&gt;&lt;p&gt;To make the pages for the content in the &lt;code&gt;posts&lt;/code&gt; directory, I’ll need
a template to use with the Gatsby &lt;code&gt;createPages&lt;/code&gt; API.&lt;/p&gt;&lt;p&gt;To do that, I’ll create a &lt;code&gt;templates&lt;/code&gt; directory in &lt;code&gt;src&lt;/code&gt; then make a
&lt;code&gt;post-template.js&lt;/code&gt; file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src/templates
touch src/templates/post-template.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For now, I’m going to return a &lt;code&gt;h1&lt;/code&gt; with &lt;strong&gt;Hello template&lt;/strong&gt; so I can
validate the page was created by Gatsby node.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;

export default () =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;Hello template&amp;lt;/h1&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Save the template, now to create the pages in &lt;code&gt;gatsby-node.js&lt;/code&gt; I’m
adding the following.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{2,4-35}&quot;&gt;const { createFilePath } = require(`gatsby-source-filesystem`)
const path = require(`path`)

exports.createPages = ({ actions, graphql }) =&amp;gt; {
  const { createPage } = actions
  const postTemplate = path.resolve(&amp;#x27;src/templates/post-template.js&amp;#x27;)

  return graphql(`
    {
      allMdx(sort: { fields: [frontmatter___date], order: DESC }) {
        nodes {
          fields {
            slug
          }
        }
      }
    }
  `).then(result =&amp;gt; {
    if (result.errors) {
      throw result.errors
    }

    const posts = result.data.allMdx.nodes

    posts.forEach((post, index) =&amp;gt; {
      createPage({
        path: post.fields.slug,
        component: postTemplate,
        context: {
          slug: post.fields.slug,
        },
      })
    })
  })
}

exports.onCreateNode = ({ node, actions, getNode }) =&amp;gt; {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I know there’s a lot in there to unpack, so, if you need more detail
check out the sections in the ”&lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Build a coding blog from scratch with
Gatsby and MDX&lt;/a&gt;”, listed here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog/#index-page-posts-query&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Index page posts query&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog/#slugs-and-paths&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Slugs and Paths&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog/#link-paths&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Link Paths&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog/#adding-a-blog-post-template&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adding a Blog Post Template&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://thelocalhost.blog/2019/10/31/build-an-mdx-blog/#build-out-blog-post-template&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Build out Blog Post Template&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;confirm-the-pages-were-created-with-gatsbys-built-in-404-page&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#confirm-the-pages-were-created-with-gatsbys-built-in-404-page&quot; aria-label=&quot;confirm the pages were created with gatsbys built in 404 page permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Confirm the pages were created with Gatsby’s built in 404 page&lt;/h2&gt;&lt;p&gt;Stop and start the dev server as there’s been changes to Gatsby node.&lt;/p&gt;&lt;p&gt;Check the page has been created, to do that add &lt;code&gt;/404.js&lt;/code&gt; to the dev
server url which will show all the available pages in the project.&lt;/p&gt;&lt;p&gt;From here I can select the path created to &lt;code&gt;/toc-example/&lt;/code&gt; and confirm
the page was created.&lt;/p&gt;&lt;h2 id=&quot;build-out-the-post-template-to-use-the-mdxrenderer&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#build-out-the-post-template-to-use-the-mdxrenderer&quot; aria-label=&quot;build out the post template to use the mdxrenderer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Build out the post template to use the MDXRenderer&lt;/h2&gt;&lt;p&gt;Now I can add the data to the &lt;code&gt;post-template.js&lt;/code&gt; page from a GraphQL
query. I’ll do that with the Gatsby &lt;code&gt;graphql&lt;/code&gt; tag and query some
frontmatter, body and the table of contents.&lt;/p&gt;&lt;p&gt;This query is taking the &lt;code&gt;String!&lt;/code&gt; parameter of &lt;code&gt;slug&lt;/code&gt; passed to it
from &lt;code&gt;createPage&lt;/code&gt; in &lt;code&gt;gatsby-node.js&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;query PostBySlug($slug: String!) {
  mdx(fields: { slug: { eq: $slug } }) {
    frontmatter {
      title
      date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
    }
    body
    excerpt
    tableOfContents
    timeToRead
    fields {
      slug
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Destructure the &lt;code&gt;body&lt;/code&gt; and &lt;code&gt;frontmatter&lt;/code&gt; data from &lt;code&gt;data.mdx&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt;
is the results of the &lt;code&gt;PostBySlug&lt;/code&gt; query. Wrap the &lt;code&gt;body&lt;/code&gt; data in the
&lt;code&gt;&amp;lt;MDXRenderer&amp;gt;&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;frontmatter.title&lt;/code&gt; and &lt;code&gt;frontmatter.date&lt;/code&gt; can be used in &lt;code&gt;h1&lt;/code&gt; and
&lt;code&gt;p&lt;/code&gt; tags for now.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{1-2,5-6,9-10,16-32}&quot;&gt;import { graphql } from &amp;#x27;gatsby&amp;#x27;
import { MDXRenderer } from &amp;#x27;gatsby-plugin-mdx&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

export default ({ data }) =&amp;gt; {
  const { body, frontmatter } = data.mdx
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
      &amp;lt;MDXRenderer&amp;gt;{body}&amp;lt;/MDXRenderer&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

export const query = graphql`
  query PostBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      frontmatter {
        title
        date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
      }
      body
      excerpt
      tableOfContents
      timeToRead
      fields {
        slug
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’m going to be using &lt;code&gt;tableOfContents&lt;/code&gt; later when I make a table of
contents component.&lt;/p&gt;&lt;h2 id=&quot;add-page-elements-for-the-mdxprovider&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-page-elements-for-the-mdxprovider&quot; aria-label=&quot;add page elements for the mdxprovider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add page elements for the MDXProvider&lt;/h2&gt;&lt;p&gt;The content (headings, paragraphs, etc.) were reset with
&lt;code&gt;styled-reset&lt;/code&gt; in the template being used so will need to be added in.&lt;/p&gt;&lt;p&gt;I’m going to be amending the already existing &lt;code&gt;H1&lt;/code&gt; and &lt;code&gt;&amp;lt;P&amp;gt;&lt;/code&gt;
styled-components to be React components so that I can spread in the
props I need for the heading ID.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{1,4,11-13}&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

export const StyledH1 = styled.h1`
  font-size: ${({ theme }) =&amp;gt; theme.fontSize[&amp;#x27;4xl&amp;#x27;]};
  font-family: ${({ theme }) =&amp;gt; theme.font.serif};
  margin-top: ${({ theme }) =&amp;gt; theme.spacing[8]};
  line-height: ${({ theme }) =&amp;gt; theme.lineHeight.none};
`

export const H1 = props =&amp;gt; {
  return &amp;lt;StyledH1 {...props}&amp;gt;{props.children}&amp;lt;/StyledH1&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Create a &lt;code&gt;&amp;lt;H2&amp;gt;&lt;/code&gt; component based off of the &lt;code&gt;&amp;lt;H1&amp;gt;&lt;/code&gt;, adjust the spacing
and font size.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

export const StyledH2 = styled.h2`
  font-size: ${({ theme }) =&amp;gt; theme.fontSize[&amp;#x27;3xl&amp;#x27;]};
  font-family: ${({ theme }) =&amp;gt; theme.font.serif};
  margin-top: ${({ theme }) =&amp;gt; theme.spacing[6]};
  line-height: ${({ theme }) =&amp;gt; theme.lineHeight.none};
`

export const H2 = props =&amp;gt; {
  return &amp;lt;StyledH2 {...props}&amp;gt;{props.children}&amp;lt;/StyledH2&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’ll need to add the newly created &lt;code&gt;H2&lt;/code&gt; to the index file for
&lt;code&gt;page-elements&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{2}&quot;&gt;export * from &amp;#x27;./h1&amp;#x27;
export * from &amp;#x27;./h2&amp;#x27;
export * from &amp;#x27;./p&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Same with the &lt;code&gt;&amp;lt;P&amp;gt;&lt;/code&gt; as I did with the &lt;code&gt;H1&lt;/code&gt;, I’ll switch it to use
React.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

export const StyledP = styled.p`
  margin-top: ${({ theme }) =&amp;gt; theme.spacing[3]};
  strong {
    font-weight: bold;
  }
  em {
    font-style: italic;
  }
`

export const P = props =&amp;gt; {
  const { children, ...rest } = props
  return &amp;lt;StyledP {...rest}&amp;gt;{children}&amp;lt;/StyledP&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Importing the modified components into the &lt;code&gt;root-wrapper.js&lt;/code&gt; I can now
pass them into the &lt;code&gt;&amp;lt;MDXProvider&amp;gt;&lt;/code&gt; which is used to map to the HTML
elements created in markdown.&lt;/p&gt;&lt;p&gt;There’s a complete listing of all the HTML elements that can be
customised on the &lt;a href=&quot;https://mdxjs.com/getting-started#table-of-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDX table of components&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In this example I’m mapping the &lt;code&gt;H1&lt;/code&gt;, &lt;code&gt;H2&lt;/code&gt; and &lt;code&gt;P&lt;/code&gt; components to the
corresponding HTML elements and passing them into the &lt;code&gt;&amp;lt;MDXProvider&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{1,5,8-12,17,19}&quot;&gt;import { MDXProvider } from &amp;#x27;@mdx-js/react&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import { ThemeProvider } from &amp;#x27;styled-components&amp;#x27;
import Layout from &amp;#x27;./src/components/layout&amp;#x27;
import { H1, H2, P } from &amp;#x27;./src/components/page-elements&amp;#x27;
import { GlobalStyle, theme } from &amp;#x27;./src/theme/global-style&amp;#x27;

const components = {
  h1: props =&amp;gt; &amp;lt;H1 {...props} /&amp;gt;,
  h2: props =&amp;gt; &amp;lt;H2 {...props} /&amp;gt;,
  p: props =&amp;gt; &amp;lt;P {...props} /&amp;gt;,
}

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;ThemeProvider theme={theme}&amp;gt;
    &amp;lt;GlobalStyle /&amp;gt;
    &amp;lt;MDXProvider components={components}&amp;gt;
      &amp;lt;Layout&amp;gt;{element}&amp;lt;/Layout&amp;gt;
    &amp;lt;/MDXProvider&amp;gt;
  &amp;lt;/ThemeProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;add-gatsby-remark-autolink-headers-for-adding-ids-to-headers&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-gatsby-remark-autolink-headers-for-adding-ids-to-headers&quot; aria-label=&quot;add gatsby remark autolink headers for adding ids to headers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add gatsby-remark-autolink-headers for adding id’s to headers&lt;/h2&gt;&lt;p&gt;Now I have a page, with some content and headers I should now be able
to navigate to the individual headings, right?&lt;/p&gt;&lt;p&gt;Well, not quite, although the headers are there, there’s no IDs in
them to scroll to yet.&lt;/p&gt;&lt;p&gt;I can use &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-remark-autolink-headers/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-remark-autolink-headers&lt;/a&gt; to create the heading IDs.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-remark-autolink-headers
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add &lt;code&gt;gatsby-remark-autolink-headers&lt;/code&gt; in the Gatsby MDX config.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{5}&quot;&gt;{
  resolve: `gatsby-plugin-mdx`,
  options: {
    extensions: [`.mdx`, `.md`],
    gatsbyRemarkPlugins: [`gatsby-remark-autolink-headers`],
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As I’ve changed the &lt;code&gt;gatsby-config.js&lt;/code&gt; file I’ll need to stop and
start the dev server.&lt;/p&gt;&lt;p&gt;Fix the weird positioning on the SVGs for the links added by
&lt;code&gt;gatsby-remark-autolink-headers&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Do that by making some reusable CSS with a tagged template literal,
I’ll put it in it’s own file &lt;code&gt;heading-link.js&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch src/components/page-elements/heading-link.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then add the CSS in as a template literal:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;export const AutoLink = `
  a {
    float: left;
    padding-right: 4px;
    margin-left: -20px;
  }
  svg {
    visibility: hidden;
  }
  &amp;amp;:hover {
    a {
      svg {
        visibility: visible;
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then I’m going to use that (&lt;code&gt;AutoLink&lt;/code&gt;) in the &lt;code&gt;H2&lt;/code&gt; and anywhere else
that could have a link applied to it (any heading element).&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{10}&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { AutoLink } from &amp;#x27;./linked-headers&amp;#x27;

export const StyledH2 = styled.h2`
  font-size: ${({ theme }) =&amp;gt; theme.fontSize[&amp;#x27;3xl&amp;#x27;]};
  font-family: ${({ theme }) =&amp;gt; theme.font.serif};
  margin-top: ${({ theme }) =&amp;gt; theme.spacing[6]};
  line-height: ${({ theme }) =&amp;gt; theme.lineHeight.none};
  ${AutoLink}
`

export const H2 = props =&amp;gt; {
  return &amp;lt;StyledH2 {...props}&amp;gt;{props.children}&amp;lt;/StyledH2&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Clicking around on the links now should scroll to each one smoothly
and have the SVG for the link only visible on hover.&lt;/p&gt;&lt;h2 id=&quot;make-a-toc-component&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#make-a-toc-component&quot; aria-label=&quot;make a toc component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make a TOC component&lt;/h2&gt;&lt;p&gt;From here onwards is what the whole post boils down to! I did want to
go through the process of how you would do something similar yourself
though, so I’m hoping this has helped in some way.&lt;/p&gt;&lt;p&gt;For the TOC with smooth scroll you need several things:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;scroll-behavior: smooth;&lt;/code&gt; added to your &lt;code&gt;html&lt;/code&gt;, this is part of the
starter I made in a &lt;a href=&quot;https://thelocalhost.blog/2020/02/06/globally-style-gatsby-styled-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;previous post&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;IDs in the headings to scroll to, this is done with
&lt;code&gt;gatsby-remark-autolink-headers&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;A table of contents which is provided by Gatsby MDX with
&lt;code&gt;tableOfContents&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The first two parts have been covered so now to create a TOC
component, with styled-components.&lt;/p&gt;&lt;p&gt;In the &lt;code&gt;post-template.js&lt;/code&gt; I’ll create a &lt;code&gt;Toc&lt;/code&gt; component for some
positioning and create a scrollable div to use inside of that.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const Toc = styled.ul`
  position: fixed;
  left: calc(50% + 400px);
  top: 110px;
  max-height: 70vh;
  width: 310px;
  display: flex;
  li {
    line-height: ${({ theme }) =&amp;gt; theme.lineHeight.tight};
    margin-top: ${({ theme }) =&amp;gt; theme.spacing[3]};
  }
`

const InnerScroll = styled.div`
  overflow: hidden;
  overflow-y: scroll;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; content is overlapping with the TOC here so I’m going to
add a &lt;code&gt;maxWidth&lt;/code&gt; inline on the &lt;code&gt;layout.js&lt;/code&gt; component.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;lt;main style={{ maxWidth: &amp;#x27;640px&amp;#x27; }}&amp;gt;{children}&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;conditionally-render-the-toc&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#conditionally-render-the-toc&quot; aria-label=&quot;conditionally render the toc permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conditionally render the TOC&lt;/h2&gt;&lt;p&gt;Time to map over the &lt;code&gt;tableOfContents&lt;/code&gt; object:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;{
  typeof tableOfContents.items === &amp;#x27;undefined&amp;#x27; ? null : (
    &amp;lt;Toc&amp;gt;
      &amp;lt;InnerScroll&amp;gt;
        &amp;lt;H2&amp;gt;Table of contents&amp;lt;/H2&amp;gt;
        {tableOfContents.items.map(i =&amp;gt; (
          &amp;lt;li key={i.url}&amp;gt;
            &amp;lt;a href={i.url} key={i.url}&amp;gt;
              {i.title}
            &amp;lt;/a&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/InnerScroll&amp;gt;
    &amp;lt;/Toc&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s the full &lt;code&gt;post-template.js&lt;/code&gt; file, I’ve reused the
&lt;code&gt;page-elements&lt;/code&gt; components for the &lt;code&gt;h1&lt;/code&gt;, &lt;code&gt;h2&lt;/code&gt; on the TOC and &lt;code&gt;p&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{4-5,7-18,20-23,26,29-44}&quot;&gt;import { graphql } from &amp;#x27;gatsby&amp;#x27;
import { MDXRenderer } from &amp;#x27;gatsby-plugin-mdx&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { H1, H2, P } from &amp;#x27;../components/page-elements&amp;#x27;

const Toc = styled.ul`
  position: fixed;
  left: calc(50% + 400px);
  top: 110px;
  max-height: 70vh;
  width: 310px;
  display: flex;
  li {
    line-height: ${({ theme }) =&amp;gt; theme.lineHeight.tight};
    margin-top: ${({ theme }) =&amp;gt; theme.spacing[3]};
  }
`

const InnerScroll = styled.div`
  overflow: hidden;
  overflow-y: scroll;
`

export default ({ data }) =&amp;gt; {
  const { body, frontmatter, tableOfContents } = data.mdx
  return (
    &amp;lt;&amp;gt;
      &amp;lt;H1&amp;gt;{frontmatter.title}&amp;lt;/H1&amp;gt;
      &amp;lt;P&amp;gt;{frontmatter.date}&amp;lt;/P&amp;gt;
      {typeof tableOfContents.items === &amp;#x27;undefined&amp;#x27; ? null : (
        &amp;lt;Toc&amp;gt;
          &amp;lt;InnerScroll&amp;gt;
            &amp;lt;H2&amp;gt;Table of contents&amp;lt;/H2&amp;gt;
            {tableOfContents.items.map(i =&amp;gt; (
              &amp;lt;li key={i.url}&amp;gt;
                &amp;lt;a href={i.url} key={i.url}&amp;gt;
                  {i.title}
                &amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
            ))}
          &amp;lt;/InnerScroll&amp;gt;
        &amp;lt;/Toc&amp;gt;
      )}
      &amp;lt;MDXRenderer&amp;gt;{body}&amp;lt;/MDXRenderer&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

export const query = graphql`
  query PostBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      frontmatter {
        title
        date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
      }
      body
      excerpt
      tableOfContents
      timeToRead
      fields {
        slug
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s it, I can play around navigating between headings now from the
TOC.&lt;/p&gt;&lt;h2 id=&quot;-heres-a-video-detailing-the-process&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#-heres-a-video-detailing-the-process&quot; aria-label=&quot; heres a video detailing the process permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;📺 Here’s a video detailing the process.&lt;/h2&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-Kp51KajhluE&quot; src=&quot;https://www.youtube.com/embed/Kp51KajhluE?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;resources-that-helped-me&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#resources-that-helped-me&quot; aria-label=&quot;resources that helped me permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources that helped me&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://johno.com/mdx-table-of-contents-components-in-gatsby&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;4pine’s blog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://theme-ui.com/guides/linked-headings/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Theme UI guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/ChristopherBiscardi/gatsby-mdx/issues/396&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby MDX repo issue 396&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/ChristopherBiscardi/gatsby-mdx/issues/140&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby MDX repo issue 140&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/ChristopherBiscardi/gatsby-mdx/issues/204&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby MDX repo issue 204&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/mdx-js/mdx/issues/810&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDX JS repo issue 810&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/remarkjs/remark-slug&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;remark-slug repo&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h2&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;&lt;hr/&gt;</content:encoded></item><item><title><![CDATA[Globally Style the Gatsby Default Starter with styled-components v5]]></title><description><![CDATA[I'm going to go over globally styling the Gatsby Default Starter with
styled-components v5, I've done this in the  past with
styled…]]></description><link>https://scottspence.com/2020/02/06/globally-style-gatsby-styled-components/</link><guid isPermaLink="false">https://scottspence.com/2020/02/06/globally-style-gatsby-styled-components/</guid><pubDate>Thu, 06 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m going to go over globally styling the Gatsby Default Starter with
styled-components v5, I’ve done this in the &lt;a href=&quot;https://thelocalhost.blog/2018/11/29/gatsby-starter-to-styled-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;past with
styled-components v4&lt;/a&gt; but I’ve changed my approach and want to
document it.&lt;/p&gt;&lt;p&gt;I’ll be swapping out the styles included with a CSS reset and adding
in global style with the styled-components &lt;code&gt;createGlobalStyle&lt;/code&gt; helper
function and also adding in the styled-components theme provider.&lt;/p&gt;&lt;p&gt;To start I’ll make a new Gatsby project using npx:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx gatsby new gatsby-starter-styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;install-styled-components-dependencies&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-styled-components-dependencies&quot; aria-label=&quot;install styled components dependencies permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install styled-components dependencies&lt;/h2&gt;&lt;p&gt;I’m using yarn to install my dependencies, the backslash is to have
the packages on multiple lines instead of one long line:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-plugin-styled-components \
  styled-components \
  babel-plugin-styled-components \
  styled-reset
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;configure-gatsby-plugin-styled-components-and-createglobalstyle&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure-gatsby-plugin-styled-components-and-createglobalstyle&quot; aria-label=&quot;configure gatsby plugin styled components and createglobalstyle permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure &lt;code&gt;gatsby-plugin-styled-components&lt;/code&gt; and &lt;code&gt;createGlobalStyle&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;Pop &lt;code&gt;gatsby-plugin-styled-components&lt;/code&gt; into the &lt;code&gt;gatsby-config.js&lt;/code&gt; file
&lt;code&gt;plugins&lt;/code&gt; array:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{2}&quot;&gt;  plugins: [
    `gatsby-plugin-styled-components`,
    `gatsby-plugin-react-helmet`,
    {
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now I’m going to create a &lt;code&gt;global-style.js&lt;/code&gt; file in a new directory
&lt;code&gt;src/theme&lt;/code&gt; then import the styled-components helper function
&lt;code&gt;createGlobalStyle&lt;/code&gt; into that, this is where the styles for the site
are going to live now.&lt;/p&gt;&lt;p&gt;Create the dir and file with the terminal command:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src/theme &amp;amp;&amp;amp; touch src/theme/global-style.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The base styles go in here, along with the &lt;code&gt;styled-reset&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;To start with I’ll create the &lt;code&gt;GlobalStyle&lt;/code&gt; object and add in the the
reset.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { createGlobalStyle } from &amp;#x27;styled-components&amp;#x27;
import reset from &amp;#x27;styled-reset&amp;#x27;

export const GlobalStyle = createGlobalStyle`
  ${reset}
`
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;remove-current-styling&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#remove-current-styling&quot; aria-label=&quot;remove current styling permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Remove current styling&lt;/h2&gt;&lt;p&gt;Remove the current styling that is used in the &lt;code&gt;&amp;lt;Layout&amp;gt;&lt;/code&gt; component,
it’s the &lt;code&gt;import &amp;#x27;./layout.css&amp;#x27;&lt;/code&gt; line, I’ll also delete the
&lt;code&gt;layout.css&lt;/code&gt; file as I’m going to be adding in my styles.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{5}&quot;&gt;import { graphql, useStaticQuery } from &amp;#x27;gatsby&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import Header from &amp;#x27;./header&amp;#x27;
import &amp;#x27;./layout.css&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the site has the base browser default styles, time to add in my
own styles. Before that I’m going to confirm the reset is doing it
thing.&lt;/p&gt;&lt;h2 id=&quot;confirm-css-reset&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#confirm-css-reset&quot; aria-label=&quot;confirm css reset permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Confirm CSS reset&lt;/h2&gt;&lt;p&gt;Now I have the base browser styles I’m going to confirm the CSS reset
in the &lt;code&gt;&amp;lt;Layout&amp;gt;&lt;/code&gt; component. This is where I’ve removed the previous
global styles (&lt;code&gt;layout.css&lt;/code&gt;) from.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{4,19}&quot;&gt;import { graphql, useStaticQuery } from &amp;quot;gatsby&amp;quot;
import PropTypes from &amp;quot;prop-types&amp;quot;
import React from &amp;quot;react&amp;quot;
import { GlobalStyle } from &amp;quot;../theme/global-style&amp;quot;
import Header from &amp;quot;./header&amp;quot;

const Layout = ({ children }) =&amp;gt; {
  // static query for the data here
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Header siteTitle={data.site.siteMetadata.title} /&amp;gt;
      &amp;lt;div
        style={{
          margin: `0 auto`,
          maxWidth: 960,
          padding: `0 1.0875rem 1.45rem`,
        }}
      &amp;gt;
        &amp;lt;GlobalStyle /&amp;gt;
        &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
        &amp;lt;footer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the code example here 👆I’ve I removed the &lt;code&gt;useStaticQuery&lt;/code&gt; hook
for readability.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/39c26fbeac89322ffc9491b0efa0ad13/573d3/reset-page.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:64.375%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;256\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20256\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2015v15h401V0H0v15m114%2056c-2%202-1%204%201%207%203%202%205%203%203%201v-2c2%200%203%203%202%203-2%201%208%206%2015%209%207%202%209%201%208-5%200-5-2-11-4-10l1%203%202%206v3l-3-3c-4-3-16-9-21-10-2%200-3%200-2-2h-2m-6%2018c-6%206-5%2016%204%2020s20-6%2016-16c-4-9-13-11-20-4m-34%207c-2%201-2%201%200%201l2%201-2%202c-1%201%200%201%204%201s5%200%204-1c-2%200-3-3-1-3%203%200%208%205%208%207a564%20564%200%20000%208c-1-6-2-8-7-9-11-4-20%207-13%2014%202%203%203%203%209%203s7%200%206%201c-4%202-13%201-16-2-3-4-4-11%200-14%201-2%202-3%200-4-1-2-6-1-4%200%201%201%200%202-1%203-3%202-3%207%200%2010%202%203%202%203%201%204l-1%201-1%201v2l-1%201h-2l1%201v1h-1l-2-1c-1%200-2-6-1-7v1h1c1-2%201-3-1-3-3%201-4%208-1%2012l1%203c-1%202-4-1-8-6l-3-3v1c2%201%200%203-2%203s-1%201%201%204c2%201%203%203%202%203l1%201h1v1h1v1c0-1%202%200%202%202%202%203%204%203%207%200l2-2%201%204%201%205-1-6c0-4%200-5%203-8l3-2v7l-1%208-1%202-1%202v1c2%202%205%201%205-2%200-2%200-2-1%200-1%201-1%201-1-1s3-3%206-2c3%200%202%204-1%205l-2%202%203%202c1%201%203%202%204%201%202-1%2010%208%2011%2013s0%2010-3%2015c-2%203-3%2011-1%2013%205%203%207%202%208-5l2-8%201-4%201-1c2%200%202-7%200-10l-4-10-2-5-2%202-4%202c-2%201-2%201-3-1%200-1%200-2%202-3l1-2c-2-2-1-7%201-7s2%201%202%203c0%204%202%205%204%203%202%200%202-1%201-1s-3-6-3-13v-5l3%205%203%206c-2%204-2%207-1%207l1-4c0-2%200-2%201-1l3%201v-1c-2-1-2-1-1-3s1-2%202-1v3c-1%202%201%201%206-4%206-6%206-7%203-7l-2-2c0-2-1-1-2%201-3%202-3%202-1%204l2%202-2-1c-3-2-3-2-3%200-2%203-3-2-3-7l-1-5v2c0%203%200%203-1%202-2-3-2-4%200-6v-1l-3-1c-1-2%201-3%207-5%203-1%203-1%201-1-3%200-3%200-3-4l-1-5v5l-1%205c-2%200-2-1-2-4%200-8-13-16-20-13m-3%2010c-2%202-3%203-1%203h1l-2%201v4l1%202c0%202%202%202%203%201l4-1h6c2%202%204%201%203-1v-1l2-2c0-2-1-2-4-2l-7-1c-2-1-4-2-5-1v-1h4c4%201%205%201%201-1s-4-2-6%200m35%206l-3%201-5%202c-2%201%201%204%205%204h4l-3-1c-6-1-1-2%2011-2s17%201%2011%202c-3%201-3%201%200%201%204%200%207-3%205-4l-3-1-4-2c-3-1-19-2-18%200m-36%2019v5c0%202%201%203%208%203h7v-3l-1-5c-2-2-13-1-14%200m-6%2021l-2%2011c-4%209-4%209-1%208%204-1%206%208%202%2010-3%202-4%200-4-5%200-3%200-3-1-2l-1%204c-1%201%200%209%201%2010l1-2v-2l1%203v2l1%202%201%204v5c-2%207%203%2012%208%208%203-2%204-10%201-13l-4-21%201-5%206-12%201-2h-1c-1%202-9-1-9-4-1-1-1%200-1%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/39c26fbeac89322ffc9491b0efa0ad13/60a22/reset-page.webp 160w,/static/39c26fbeac89322ffc9491b0efa0ad13/4c812/reset-page.webp 320w,/static/39c26fbeac89322ffc9491b0efa0ad13/0ba47/reset-page.webp 640w,/static/39c26fbeac89322ffc9491b0efa0ad13/e46b2/reset-page.webp 960w,/static/39c26fbeac89322ffc9491b0efa0ad13/af3f0/reset-page.webp 1280w,/static/39c26fbeac89322ffc9491b0efa0ad13/44758/reset-page.webp 1650w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/39c26fbeac89322ffc9491b0efa0ad13/69538/reset-page.png 160w,/static/39c26fbeac89322ffc9491b0efa0ad13/72799/reset-page.png 320w,/static/39c26fbeac89322ffc9491b0efa0ad13/6af66/reset-page.png 640w,/static/39c26fbeac89322ffc9491b0efa0ad13/d9199/reset-page.png 960w,/static/39c26fbeac89322ffc9491b0efa0ad13/21b4d/reset-page.png 1280w,/static/39c26fbeac89322ffc9491b0efa0ad13/573d3/reset-page.png 1650w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/39c26fbeac89322ffc9491b0efa0ad13/6af66/reset-page.png&quot; alt=&quot;reset page&quot; title=&quot;reset page&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Ok, cool, looks pretty reset to me!&lt;/p&gt;&lt;h2 id=&quot;create-the-new-browser-base-styles&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-the-new-browser-base-styles&quot; aria-label=&quot;create the new browser base styles permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create the new browser base styles&lt;/h2&gt;&lt;p&gt;Time to add in some more styles to the global style. First, the
&lt;code&gt;box-sizing&lt;/code&gt; reset, take a look at the CSS Tricks post on &lt;a href=&quot;https://css-tricks.com/box-sizing/#article-header-id-3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Box Sizing&lt;/a&gt;
for a great explanation of why we do this.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{7-12}&quot;&gt;import { createGlobalStyle } from &amp;#x27;styled-components&amp;#x27;
import reset from &amp;#x27;styled-reset&amp;#x27;

export const GlobalStyle = createGlobalStyle`
  ${reset}

  *, *:before, *:after {
    box-sizing: border-box;
  }
  html {
    box-sizing: border-box;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then I’m adding in the smooth scroll html property and some additional
styles for base font size and colour along with base line height
letter spacing and background colour.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{12-15,17-21}&quot;&gt;import { createGlobalStyle } from &amp;#x27;styled-components&amp;#x27;
import reset from &amp;#x27;styled-reset&amp;#x27;

export const GlobalStyle = createGlobalStyle`
  ${reset}

  *, *:before, *:after {
    box-sizing: border-box;
  }
  html {
    box-sizing: border-box;
    scroll-behavior: smooth;
    font-family: &amp;#x27;Segoe UI&amp;#x27;, Tahoma, Geneva, Verdana, sans-serif;
    font-size: 16px;
    color: &amp;#x27;#1a202c&amp;#x27;;
  }
  body {
    line-height: 1.5;
    letter-spacing: 0;
    background-color: &amp;#x27;#f7fafc&amp;#x27;;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;place-globalstyle-at-the-top-of-the-react-tree-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#place-globalstyle-at-the-top-of-the-react-tree-&quot; aria-label=&quot;place globalstyle at the top of the react tree  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Place &lt;code&gt;GlobalStyle&lt;/code&gt; at the top of the React tree 🌳&lt;/h2&gt;&lt;p&gt;I’m adding this as high up the component tree as possible so that the
global styles will affect everything that is ‘underneath’ it.&lt;/p&gt;&lt;p&gt;In the case of the Gatsby Default Starter you’ll notice that the
&lt;code&gt;&amp;lt;Layout&amp;gt;&lt;/code&gt; component wraps a the &lt;code&gt;index.js&lt;/code&gt; page, &lt;code&gt;page-2.js&lt;/code&gt; and the
&lt;code&gt;404.js&lt;/code&gt; page so adding the &lt;code&gt;&amp;lt;GlobalStyle /&amp;gt;&lt;/code&gt; component here is a
sound option.&lt;/p&gt;&lt;p&gt;There is an alternative to adding it to the layout and that is to use
the Gatsby Browser and Gatsby SSR API &lt;a href=&quot;https://www.gatsbyjs.org/docs/browser-apis/#wrapRootElement&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wrapRootElement&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If I add in the following code to &lt;code&gt;gatsby-browser.js&lt;/code&gt; the styles are
applied.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import Layout from &amp;#x27;./src/components/layout&amp;#x27;
import { GlobalStyle } from &amp;#x27;./src/theme/global-style&amp;#x27;

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;GlobalStyle /&amp;gt;
    &amp;lt;Layout&amp;gt;{element}&amp;lt;/Layout&amp;gt;
  &amp;lt;/&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I also have a double header, that’s because the layout component is
still wrapping the index page, page 2 and the 404 page. I’ll remove
the layout component from those locations so I have it in one place to
manage.&lt;/p&gt;&lt;h2 id=&quot;make-a-root-wrapper-to-keep-things-dry-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#make-a-root-wrapper-to-keep-things-dry-&quot; aria-label=&quot;make a root wrapper to keep things dry  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make a Root Wrapper to keep things DRY 🌵&lt;/h2&gt;&lt;p&gt;I also need to add the same code into &lt;code&gt;gatsby-ssr.js&lt;/code&gt; so so that the
styles are rendered on the server when the site is built.&lt;/p&gt;&lt;p&gt;Rather than have the code duplicated in the two files I’ll create a
&lt;code&gt;root-wrapper.js&lt;/code&gt; file &lt;em&gt;(you can call it what you like!)&lt;/em&gt; and add it
to the root of the project. I’ll import that into both the
&lt;code&gt;gatsby-browser.js&lt;/code&gt; and &lt;code&gt;gatsby-ssr.js&lt;/code&gt; files:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { wrapRootElement as wrap } from &amp;#x27;./root-wrapper&amp;#x27;

export const wrapRootElement = wrap
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;global-fonts-with-gatsby-plugin-google-fonts&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#global-fonts-with-gatsby-plugin-google-fonts&quot; aria-label=&quot;global fonts with gatsby plugin google fonts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Global fonts with &lt;code&gt;gatsby-plugin-google-fonts&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;Onto the main reason for this post, with the &lt;a href=&quot;https://styled-components.com/releases#v5.0.0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;v5 release&lt;/a&gt; of
styled-components the use of &lt;code&gt;@imports&lt;/code&gt; in &lt;code&gt;createGlobalStyle&lt;/code&gt; isn’t
working, (that approach is &lt;a href=&quot;https://thelocalhost.blog/2018/11/29/gatsby-starter-to-styled-components/#3-global-style&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;detailed here&lt;/a&gt;) it’s recommended that you
embed these into your HTML index file, etc.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;NOTE: At this time we recommend not using @import inside of
&lt;code&gt;createGlobalStyle&lt;/code&gt;. We’re working on better behavior for this
functionality but it just doesn’t really work at the moment and it’s
better if you just embed these imports in your HTML index file, etc.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;But! As I’m using Gatsby, of course, &lt;em&gt;&lt;strong&gt;“There’s a Plugin For
That™️”&lt;/strong&gt;&lt;/em&gt; so I’m going to use &lt;code&gt;gatsby-plugin-google-fonts&lt;/code&gt; for this,
I’m using this in place of &lt;code&gt;gatsby-plugin-web-font-loader&lt;/code&gt; because it
uses &lt;code&gt;display=swap&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-plugin-google-fonts
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Configure, I’ll add three fonts, sans, sans serif and monospace to the
Gatsby plugin array in &lt;code&gt;gatsby-config.js&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  resolve: `gatsby-plugin-google-fonts`,
  options: {
    fonts: [
      `cambay\:400,700`,
      `arvo\:400,700`,
      `ubuntu mono\:400,700`,
    ],
    display: &amp;#x27;swap&amp;#x27;,
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I can now use these fonts throughout my site.&lt;/p&gt;&lt;h2 id=&quot;styled-components-theme-provider&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#styled-components-theme-provider&quot; aria-label=&quot;styled components theme provider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;styled-components Theme provider&lt;/h2&gt;&lt;p&gt;The &lt;a href=&quot;https://styled-components.com/docs/api#themeprovider&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components ThemeProvider&lt;/a&gt; is a great solution for managing
your styles throughout a project.&lt;/p&gt;&lt;p&gt;Part of the inspiration for my approach came from Sid’s talk at React
Advanced which &lt;a href=&quot;https://thelocalhost.blog/2019/11/06/react-advanced-london-2019/#siddharth-kshetrapal---design-systems-design-system&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;I wrote about&lt;/a&gt; and part from watching the Tailwind CSS
courses from Adam Wathan on Egghead.io check out the playlist here:
&lt;a href=&quot;https://egghead.io/playlists/introduction-to-tailwind-and-the-utility-first-workflow-0b697b10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction to Tailwind and the Utility first workflow&lt;/a&gt;&lt;/p&gt;&lt;p&gt;With the ThemeProvider I can have things like colours, sizes, font
weights in one place so that there is a consistent set of presets to
choose from when styling.&lt;/p&gt;&lt;p&gt;In the &lt;code&gt;global-style.js&lt;/code&gt; file I’m creating a theme object to hold all
the values for the theme.&lt;/p&gt;&lt;p&gt;For the font I’ll add in the types I defined in the Gatsby config, for
serif, sans serif and monospace.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{4-10}&quot;&gt;import { createGlobalStyle } from &amp;#x27;styled-components&amp;#x27;
import reset from &amp;#x27;styled-reset&amp;#x27;

export const theme = {
  font: {
    sans: &amp;#x27;Cambay, sans-serif&amp;#x27;,
    serif: &amp;#x27;Arvo, sans&amp;#x27;,
    monospace: &amp;#x27;&amp;quot;Ubuntu Mono&amp;quot;, monospace&amp;#x27;,
  },
}

export const GlobalStyle = createGlobalStyle`
  ${reset}

  *, *:before, *:after {
    box-sizing: border-box;
  }
  html {
    box-sizing: border-box;
    scroll-behavior: smooth;
    font-family: &amp;#x27;Segoe UI&amp;#x27;, Tahoma, Geneva, Verdana, sans-serif;
    font-size: 16px;
    color: &amp;#x27;#1a202c&amp;#x27;;
  }
  body {
    line-height: 1.5;
    letter-spacing: 0;
    background-color: &amp;#x27;#f7fafc&amp;#x27;;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now I’ll need to add the &lt;code&gt;&amp;lt;ThemeProvider&amp;gt;&lt;/code&gt; high up in the React render
tree, same as with the global style, I’ll add it to the
&lt;code&gt;root-wrapper.js&lt;/code&gt; file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{2,4,7,10}&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import { ThemeProvider } from &amp;#x27;styled-components&amp;#x27;
import Layout from &amp;#x27;./src/components/layout&amp;#x27;
import { GlobalStyle, theme } from &amp;#x27;./src/theme/global-style&amp;#x27;

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;ThemeProvider theme={theme}&amp;gt;
    &amp;lt;GlobalStyle /&amp;gt;
    &amp;lt;Layout&amp;gt;{element}&amp;lt;/Layout&amp;gt;
  &amp;lt;/ThemeProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When I want to pick a font type to use in the project I can use the
&lt;code&gt;theme&lt;/code&gt; object and pick out the desired type.&lt;/p&gt;&lt;p&gt;Like setting the HTML font-family to sans serif:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{10}&quot;&gt;export const GlobalStyle = createGlobalStyle`
  ${reset}

  *, *:before, *:after {
    box-sizing: border-box;
  }
  html {
    box-sizing: border-box;
    scroll-behavior: smooth;
    font-family: ${({ theme }) =&amp;gt; theme.font.sans};
    font-size: 16px;
    color: &amp;#x27;#1a202c&amp;#x27;;
  }
  body {
    line-height: 1.5;
    letter-spacing: 0;
    background-color: &amp;#x27;#f7fafc&amp;#x27;;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The base font is now set to Cambay, why stop there though, I’ll bring
in some fonts sizes and font weights from the &lt;a href=&quot;https://github.com/tailwindcss/designing-with-tailwindcss/blob/master/01-getting-up-and-running/07-customizing-your-design-system/tailwind-full.config.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tailwind full config&lt;/a&gt;
and add them to the &lt;code&gt;theme&lt;/code&gt; object.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{10-32,45}&quot;&gt;import { createGlobalStyle } from &amp;#x27;styled-components&amp;#x27;
import reset from &amp;#x27;styled-reset&amp;#x27;

export const theme = {
  font: {
    sans: &amp;#x27;Cambay, sans-serif&amp;#x27;,
    serif: &amp;#x27;Arvo, sans&amp;#x27;,
    monospace: &amp;#x27;&amp;quot;Ubuntu Mono&amp;quot;, monospace&amp;#x27;,
  },
  fontSize: {
    xs: &amp;#x27;0.75rem&amp;#x27;,
    sm: &amp;#x27;0.875rem&amp;#x27;,
    base: &amp;#x27;1rem&amp;#x27;,
    lg: &amp;#x27;1.125rem&amp;#x27;,
    xl: &amp;#x27;1.25rem&amp;#x27;,
    &amp;#x27;2xl&amp;#x27;: &amp;#x27;1.5rem&amp;#x27;,
    &amp;#x27;3xl&amp;#x27;: &amp;#x27;1.875rem&amp;#x27;,
    &amp;#x27;4xl&amp;#x27;: &amp;#x27;2.25rem&amp;#x27;,
    &amp;#x27;5xl&amp;#x27;: &amp;#x27;3rem&amp;#x27;,
    &amp;#x27;6xl&amp;#x27;: &amp;#x27;4rem&amp;#x27;,
  },
  fontWeight: {
    hairline: &amp;#x27;100&amp;#x27;,
    thin: &amp;#x27;200&amp;#x27;,
    light: &amp;#x27;300&amp;#x27;,
    normal: &amp;#x27;400&amp;#x27;,
    medium: &amp;#x27;500&amp;#x27;,
    semibold: &amp;#x27;600&amp;#x27;,
    bold: &amp;#x27;700&amp;#x27;,
    extrabold: &amp;#x27;800&amp;#x27;,
    black: &amp;#x27;900&amp;#x27;,
  },
}

export const GlobalStyle = createGlobalStyle`
  ${reset}

  *, *:before, *:after {
    box-sizing: border-box;
  }
  html {
    box-sizing: border-box;
    scroll-behavior: smooth;
    font-family: ${({ theme }) =&amp;gt; theme.font.sans};
    font-size: ${({ theme }) =&amp;gt; theme.fontSize.lg};
    color: &amp;#x27;#1a202c&amp;#x27;;
  }
  body {
    line-height: 1.5;
    letter-spacing: 0;
    background-color: &amp;#x27;#f7fafc&amp;#x27;;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’ll add the base font at &lt;code&gt;.lg&lt;/code&gt; (&lt;code&gt;1.125rem&lt;/code&gt;), I’ll also add in line
height and line spacing defaults but I’ll save adding the whole config
here to save you a codewall, you get the idea though, right?&lt;/p&gt;&lt;p&gt;Here’s the rest of the GlobalStyle with defaults applied.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{12,15-17}&quot;&gt;export const GlobalStyle = createGlobalStyle`
  ${reset}

  *, *:before, *:after {
    box-sizing: border-box;
  }
  html {
    box-sizing: border-box;
    scroll-behavior: smooth;
    font-family: ${({ theme }) =&amp;gt; theme.font.sans};
    font-size: ${({ theme }) =&amp;gt; theme.fontSize.lg};
    color: ${({ theme }) =&amp;gt; theme.colours.grey[900]};
  }
  body {
    line-height: ${({ theme }) =&amp;gt; theme.lineHeight.relaxed};
    letter-spacing: ${({ theme }) =&amp;gt; theme.letterSpacing.wide};
    background-color: ${({ theme }) =&amp;gt; theme.colours.white};
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;shared-page-elements&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#shared-page-elements&quot; aria-label=&quot;shared page elements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shared Page Elements&lt;/h2&gt;&lt;p&gt;The current page is still missing basic styles for &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;p&lt;/code&gt; so I’m
going to create those in a new directory
&lt;code&gt;src/components/page-elements&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src/components/page-elements
touch src/components/page-elements/h1.js
touch src/components/page-elements/p.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And add some base styles to those for &lt;code&gt;h1&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import styled from &amp;#x27;styled-components&amp;#x27;

export const H1 = styled.h1`
  font-size: ${({ theme }) =&amp;gt; theme.fontSize[&amp;#x27;4xl&amp;#x27;]};
  font-family: ${({ theme }) =&amp;gt; theme.font.serif};
  margin-top: ${({ theme }) =&amp;gt; theme.spacing[8]};
  line-height: ${({ theme }) =&amp;gt; theme.lineHeight.none};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And the same sort of thing for the &lt;code&gt;p&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import styled from &amp;#x27;styled-components&amp;#x27;

export const P = styled.p`
  font-size: ${({ theme }) =&amp;gt; theme.fontSize.base};
  margin-top: ${({ theme }) =&amp;gt; theme.spacing[3]};
  strong {
    font-weight: bold;
  }
  em {
    font-style: italic;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then it’s a case of replacing the &lt;code&gt;h1&lt;/code&gt;’s and &lt;code&gt;p&lt;/code&gt;’s in the project to
use the styled components.&lt;/p&gt;&lt;p&gt;Here’s the &lt;code&gt;index.js&lt;/code&gt; file as an example:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{4-5,11-13}&quot;&gt;import { Link } from &amp;#x27;gatsby&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import Image from &amp;#x27;../components/image&amp;#x27;
import { H1 } from &amp;#x27;../components/page-elements/h1&amp;#x27;
import { P } from &amp;#x27;../components/page-elements/p&amp;#x27;
import SEO from &amp;#x27;../components/seo&amp;#x27;

const IndexPage = () =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;SEO title=&amp;quot;Home&amp;quot; /&amp;gt;
    &amp;lt;H1&amp;gt;Hi people&amp;lt;/H1&amp;gt;
    &amp;lt;P&amp;gt;Welcome to your new Gatsby site.&amp;lt;/P&amp;gt;
    &amp;lt;P&amp;gt;Now go build something great.&amp;lt;/P&amp;gt;
    &amp;lt;div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}&amp;gt;
      &amp;lt;Image /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;Link to=&amp;quot;/page-2/&amp;quot;&amp;gt;Go to page 2&amp;lt;/Link&amp;gt;
  &amp;lt;/&amp;gt;
)

export default IndexPage
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;export-all-your-styled-components-from-an-index-file&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#export-all-your-styled-components-from-an-index-file&quot; aria-label=&quot;export all your styled components from an index file permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Export all your styled-components from an index file&lt;/h2&gt;&lt;p&gt;As the amount of page elements grows you may want to consider using an
&lt;code&gt;index.js&lt;/code&gt; file instead of having an import for each individual
component you can import from one file.&lt;/p&gt;&lt;p&gt;Let’s take a quick look at that, so let’s say I import the &lt;code&gt;h1&lt;/code&gt; and
&lt;code&gt;p&lt;/code&gt; into a file, it’ll looks something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { H1 } from &amp;#x27;../components/page-elements/h1&amp;#x27;
import { P } from &amp;#x27;../components/page-elements/p&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you have several elements your using in the file the imports could
get a bit cluttered.&lt;/p&gt;&lt;p&gt;I’ve taken to creating an &lt;code&gt;index.js&lt;/code&gt; file that will export all the
components, like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;export * from &amp;#x27;./h1&amp;#x27;
export * from &amp;#x27;./p&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then when importing the components it will look like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { H1, P } from &amp;#x27;../components/page-elements&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s it for this one!&lt;/p&gt;&lt;h2 id=&quot;heres-a-video-detailing-the-process-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heres-a-video-detailing-the-process-&quot; aria-label=&quot;heres a video detailing the process  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here’s a video detailing the process 📺&lt;/h2&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-8jlh_FyuM8c&quot; src=&quot;https://www.youtube.com/embed/8jlh_FyuM8c?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h2&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;&lt;h2 id=&quot;resources&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#resources&quot; aria-label=&quot;resources permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Dd-Y9K7IKmk&amp;amp;feature=emb_title&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Design Systems Design System - Siddharth Kshetrapal&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/tailwindcss/designing-with-tailwindcss/blob/master/01-getting-up-and-running/07-customizing-your-design-system/tailwind-full.config.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tailwind full config&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://egghead.io/playlists/introduction-to-tailwind-and-the-utility-first-workflow-0b697b10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Introduction to Tailwind and the Utility first workflow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://egghead.io/playlists/design-and-implement-common-tailwind-components-8fbb9b19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Design and Implement Common Tailwind Components&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://egghead.io/playlists/build-a-responsive-navbar-with-tailwind-4d328a35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Build a Responsive Navbar with Tailwind&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://egghead.io/playlists/build-and-style-a-dropdown-in-tailwind-7f34fead&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Build and Style a Dropdown in Tailwind&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Upgrade Windows Subsystem Linux - Ubuntu 18.04 to Ubuntu 19.10]]></title><description><![CDATA[In this guide I'm going to detail upgrading a Windows Subsystem Linux
(WSL) Ubuntu install from the current version 18.04 to 19.10 this is…]]></description><link>https://scottspence.com/2020/01/28/update-wsl-ubuntu-from-18.10-to-19.10/</link><guid isPermaLink="false">https://scottspence.com/2020/01/28/update-wsl-ubuntu-from-18.10-to-19.10/</guid><pubDate>Tue, 28 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this guide I’m going to detail upgrading a Windows Subsystem Linux
(WSL) Ubuntu install from the current version 18.04 to 19.10 this is
an intermediary release before Ubuntu 20.04 is released on 2020
April 23.&lt;/p&gt;&lt;p&gt;I have documented &lt;a href=&quot;https://thelocalhost.blog/2019/04/01/update-wsl-from-18.04-18.10/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this process in the past&lt;/a&gt; for moving from Ubuntu
version 18.04 to 18.10. You can see &lt;a href=&quot;https://dev.to/spences10/comment/9n19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my comments&lt;/a&gt; as I went through
the process back then.&lt;/p&gt;&lt;h2 id=&quot;-heres-a-video-detailing-the-process&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#-heres-a-video-detailing-the-process&quot; aria-label=&quot; heres a video detailing the process permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;📺 Here’s a video detailing the process.&lt;/h2&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-IErQ4RnzPOg&quot; src=&quot;https://www.youtube.com/embed/IErQ4RnzPOg?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;check-the-current-ubuntu-version&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#check-the-current-ubuntu-version&quot; aria-label=&quot;check the current ubuntu version permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Check the current Ubuntu version&lt;/h2&gt;&lt;p&gt;Ok, to check the current installed version of Ubuntu from the terminal
I enter &lt;code&gt;lsb_release -a&lt;/code&gt; to get the currently installed Ubuntu version
displayed.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;LSB stands for Linux Standard Base and the ‘-a’ is for ‘all
information’&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lsb_release -a
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The output looks like this:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:505px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/56f1518727b9d6339ef9cbc2f7813813/c0cb9/01.current-version.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:31.874999999999996%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;128\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20128\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2064v64h401V0H0v64m0%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/56f1518727b9d6339ef9cbc2f7813813/60a22/01.current-version.webp 160w,/static/56f1518727b9d6339ef9cbc2f7813813/4c812/01.current-version.webp 320w,/static/56f1518727b9d6339ef9cbc2f7813813/c5db7/01.current-version.webp 505w&quot; sizes=&quot;(max-width: 505px) 100vw, 505px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/56f1518727b9d6339ef9cbc2f7813813/69538/01.current-version.png 160w,/static/56f1518727b9d6339ef9cbc2f7813813/72799/01.current-version.png 320w,/static/56f1518727b9d6339ef9cbc2f7813813/c0cb9/01.current-version.png 505w&quot; sizes=&quot;(max-width: 505px) 100vw, 505px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/56f1518727b9d6339ef9cbc2f7813813/c0cb9/01.current-version.png&quot; alt=&quot;01 current version&quot; title=&quot;01 current version&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;do-the-release-upgrade&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#do-the-release-upgrade&quot; aria-label=&quot;do the release upgrade permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Do the release upgrade!&lt;/h2&gt;&lt;p&gt;To start the upgrade I enter the terminal command
&lt;code&gt;do-release-upgrade&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo do-release-upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:578px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/805fa66fa97906724e4644eceacbae5b/508ef/02.do-release-upgrade.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:28.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;112\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20112\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2056v56h401V0H0v56m0%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/805fa66fa97906724e4644eceacbae5b/60a22/02.do-release-upgrade.webp 160w,/static/805fa66fa97906724e4644eceacbae5b/4c812/02.do-release-upgrade.webp 320w,/static/805fa66fa97906724e4644eceacbae5b/03fb9/02.do-release-upgrade.webp 578w&quot; sizes=&quot;(max-width: 578px) 100vw, 578px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/805fa66fa97906724e4644eceacbae5b/69538/02.do-release-upgrade.png 160w,/static/805fa66fa97906724e4644eceacbae5b/72799/02.do-release-upgrade.png 320w,/static/805fa66fa97906724e4644eceacbae5b/508ef/02.do-release-upgrade.png 578w&quot; sizes=&quot;(max-width: 578px) 100vw, 578px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/805fa66fa97906724e4644eceacbae5b/508ef/02.do-release-upgrade.png&quot; alt=&quot;02 do release upgrade&quot; title=&quot;02 do release upgrade&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;This will prompt me if my &lt;code&gt;release-upgrades&lt;/code&gt; file isn’t set to
&lt;code&gt;normal&lt;/code&gt;.&lt;/p&gt;&lt;h2 id=&quot;set-release-upgrades-to-normal&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#set-release-upgrades-to-normal&quot; aria-label=&quot;set release upgrades to normal permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set release upgrades to normal&lt;/h2&gt;&lt;p&gt;Open the &lt;code&gt;release-upgrades&lt;/code&gt; file path to edit, in this example I’m
using &lt;a href=&quot;https://help.ubuntu.com/community/Nano&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nano&lt;/a&gt; to edit the file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo nano /etc/update-manager/release-upgrades
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the file I change the &lt;code&gt;Prompt&lt;/code&gt; from &lt;code&gt;Prompt=lts&lt;/code&gt; to
&lt;code&gt;Prompt=normal&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/396a67aa70e77081cacb71f123e08cad/c946b/03.release-upgrades-normal.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:74.37499999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;299\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20299\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20150v149h401V0H0v150M3%208v5h394V3H3v5m0%20277v10h9v-21H3v11m63-11v18c0%203%200%203%205%203h4v-20l-5-1h-4m62%2011v10h9v-21h-9v11m63%200v10h9v-21h-9v11m63-10l-1%2010v10h9v-21h-4l-4%201m62%2010v10h9v-21h-9v11\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/396a67aa70e77081cacb71f123e08cad/60a22/03.release-upgrades-normal.webp 160w,/static/396a67aa70e77081cacb71f123e08cad/4c812/03.release-upgrades-normal.webp 320w,/static/396a67aa70e77081cacb71f123e08cad/0ba47/03.release-upgrades-normal.webp 640w,/static/396a67aa70e77081cacb71f123e08cad/82ef0/03.release-upgrades-normal.webp 805w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/396a67aa70e77081cacb71f123e08cad/69538/03.release-upgrades-normal.png 160w,/static/396a67aa70e77081cacb71f123e08cad/72799/03.release-upgrades-normal.png 320w,/static/396a67aa70e77081cacb71f123e08cad/6af66/03.release-upgrades-normal.png 640w,/static/396a67aa70e77081cacb71f123e08cad/c946b/03.release-upgrades-normal.png 805w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/396a67aa70e77081cacb71f123e08cad/6af66/03.release-upgrades-normal.png&quot; alt=&quot;03 release upgrades normal&quot; title=&quot;03 release upgrades normal&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;To save the file in Nano I use Ctrl+o to write out the file, confirm
(Enter/Return) then to close use I Ctrl+x.&lt;/p&gt;&lt;h2 id=&quot;do-the-release-upgrade-for-realsies&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#do-the-release-upgrade-for-realsies&quot; aria-label=&quot;do the release upgrade for realsies permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Do the release upgrade, for realsies&lt;/h2&gt;&lt;p&gt;Now the &lt;code&gt;release-upgrades&lt;/code&gt; file is set to &lt;code&gt;normal&lt;/code&gt; I can do the
&lt;a href=&quot;https://help.ubuntu.com/lts/serverguide/installing-upgrading.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;do-release-upgrade&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/a48e73b6af82c743301d46ca098e03d1/2e237/04.release-upgrade-for-realsies.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:23.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;92\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2092\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2046v46h401V0H0v46\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/a48e73b6af82c743301d46ca098e03d1/60a22/04.release-upgrade-for-realsies.webp 160w,/static/a48e73b6af82c743301d46ca098e03d1/4c812/04.release-upgrade-for-realsies.webp 320w,/static/a48e73b6af82c743301d46ca098e03d1/0ba47/04.release-upgrade-for-realsies.webp 640w,/static/a48e73b6af82c743301d46ca098e03d1/02aff/04.release-upgrade-for-realsies.webp 790w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/a48e73b6af82c743301d46ca098e03d1/69538/04.release-upgrade-for-realsies.png 160w,/static/a48e73b6af82c743301d46ca098e03d1/72799/04.release-upgrade-for-realsies.png 320w,/static/a48e73b6af82c743301d46ca098e03d1/6af66/04.release-upgrade-for-realsies.png 640w,/static/a48e73b6af82c743301d46ca098e03d1/2e237/04.release-upgrade-for-realsies.png 790w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/a48e73b6af82c743301d46ca098e03d1/6af66/04.release-upgrade-for-realsies.png&quot; alt=&quot;04 release upgrade for realsies&quot; title=&quot;04 release upgrade for realsies&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;You may be aware of an &lt;a href=&quot;https://dev.to/spences10/comment/9n3j&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lxd error&lt;/a&gt; that occurs on the Ubuntu 18.04 to
Ubuntu 18.10 upgrade. This is where there is a prompt saying &lt;a href=&quot;https://askubuntu.com/questions/1119301/your-system-is-unable-to-reach-the-snap-store&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;“Your
system is unable to reach the snap store”&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I’m going to skip this during the upgrade but you can &lt;em&gt;&lt;strong&gt;optionally&lt;/strong&gt;&lt;/em&gt;
run this when doing this for yourself, here’s the command:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo dpkg --force depends -P lxd; sudo dpkg --force depends -P lxd-client
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pick the same command again in the terminal, if I arrow up a a couple
of commands I can use it again.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo do-release-upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’m now prompted with the details of what is going to happen in the
upgrade:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:626px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/d4e06ebd5c9d732cffeaf9c8d0273841/af590/05.upgrade-confirmation.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:44.375%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;178\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20178\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2089v89h401V0H0v89m0%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/d4e06ebd5c9d732cffeaf9c8d0273841/60a22/05.upgrade-confirmation.webp 160w,/static/d4e06ebd5c9d732cffeaf9c8d0273841/4c812/05.upgrade-confirmation.webp 320w,/static/d4e06ebd5c9d732cffeaf9c8d0273841/63b03/05.upgrade-confirmation.webp 626w&quot; sizes=&quot;(max-width: 626px) 100vw, 626px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/d4e06ebd5c9d732cffeaf9c8d0273841/69538/05.upgrade-confirmation.png 160w,/static/d4e06ebd5c9d732cffeaf9c8d0273841/72799/05.upgrade-confirmation.png 320w,/static/d4e06ebd5c9d732cffeaf9c8d0273841/af590/05.upgrade-confirmation.png 626w&quot; sizes=&quot;(max-width: 626px) 100vw, 626px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/d4e06ebd5c9d732cffeaf9c8d0273841/af590/05.upgrade-confirmation.png&quot; alt=&quot;05 upgrade confirmation&quot; title=&quot;05 upgrade confirmation&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I respond with &lt;code&gt;y&lt;/code&gt; to continue and start the upgrade.&lt;/p&gt;&lt;h2 id=&quot;warnings-and-configs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#warnings-and-configs&quot; aria-label=&quot;warnings and configs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Warnings and configs&lt;/h2&gt;&lt;p&gt;When I’m prompted about &lt;code&gt;libc6&lt;/code&gt; for restarting services during package
upgrades I use the tab key to select &lt;code&gt;&amp;lt;Yes&amp;gt;&lt;/code&gt; then return to continue.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/1cc150556cfed1f2b15fa369dbaacb46/e1031/06.config-libc6.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;299\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20299\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20150v149h401V0H0v150m7-6l1%2079h380v-71l1-78v-8H7v78m108%2053v5h23v-10l-12-1h-11v6M9%20215v3h378v-3c0-2%200-2-1%200v2H10v-2c-1-2-1-2-1%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/1cc150556cfed1f2b15fa369dbaacb46/60a22/06.config-libc6.webp 160w,/static/1cc150556cfed1f2b15fa369dbaacb46/4c812/06.config-libc6.webp 320w,/static/1cc150556cfed1f2b15fa369dbaacb46/0ba47/06.config-libc6.webp 640w,/static/1cc150556cfed1f2b15fa369dbaacb46/76c9f/06.config-libc6.webp 803w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/1cc150556cfed1f2b15fa369dbaacb46/69538/06.config-libc6.png 160w,/static/1cc150556cfed1f2b15fa369dbaacb46/72799/06.config-libc6.png 320w,/static/1cc150556cfed1f2b15fa369dbaacb46/6af66/06.config-libc6.png 640w,/static/1cc150556cfed1f2b15fa369dbaacb46/e1031/06.config-libc6.png 803w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/1cc150556cfed1f2b15fa369dbaacb46/6af66/06.config-libc6.png&quot; alt=&quot;06 config libc6&quot; title=&quot;06 config libc6&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Next I have the &lt;code&gt;Lxd&lt;/code&gt; warning I mentioned earlier, in this case I’m
going to arrow down and select the option to &lt;code&gt;&amp;lt;Skip&amp;gt;&lt;/code&gt; then hit return
to continue.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/c71b11ddfc5f0f3d0c8827901b8cdef0/764be/07.lxd-warning.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:74.37499999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;298\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20298\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20149v149h401V0H0v149m8%200c0%20116%200%20125%202%20125h378l-1-125V25l-189-1H8v125M157%2027c0%202-1%202-73%202H10v3c0%202%200%202%201%200v-2h146v2c1%201%201%200%201-2v-5l-1%202m80%203c0%202%200%203%201%202v-2h147v2c1%202%201%202%201%200v-3H238v-2c-1-1-1%200-1%203m-55%20184l1%202h1l-1%201-1%203v2h27v-10h-13c-13%200-14%200-14%202M10%20267v3h376l-188-1H11v-2c-1-2-1-2-1%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/c71b11ddfc5f0f3d0c8827901b8cdef0/60a22/07.lxd-warning.webp 160w,/static/c71b11ddfc5f0f3d0c8827901b8cdef0/4c812/07.lxd-warning.webp 320w,/static/c71b11ddfc5f0f3d0c8827901b8cdef0/0ba47/07.lxd-warning.webp 640w,/static/c71b11ddfc5f0f3d0c8827901b8cdef0/e94a4/07.lxd-warning.webp 806w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/c71b11ddfc5f0f3d0c8827901b8cdef0/69538/07.lxd-warning.png 160w,/static/c71b11ddfc5f0f3d0c8827901b8cdef0/72799/07.lxd-warning.png 320w,/static/c71b11ddfc5f0f3d0c8827901b8cdef0/6af66/07.lxd-warning.png 640w,/static/c71b11ddfc5f0f3d0c8827901b8cdef0/764be/07.lxd-warning.png 806w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/c71b11ddfc5f0f3d0c8827901b8cdef0/6af66/07.lxd-warning.png&quot; alt=&quot;07 lxd warning&quot; title=&quot;07 lxd warning&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;In the following screens I’m being asked about package configuration,
I’m going to be picking the option to
&lt;code&gt;install the package maintainer&amp;#x27;s version&lt;/code&gt; for all of them.&lt;/p&gt;&lt;p&gt;Same with &lt;code&gt;openssh-server&lt;/code&gt; arrow up key to to
&lt;code&gt;install the package maintainer&amp;#x27;s version&lt;/code&gt; and hit return to continue.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/bfad8f011380589631f7857a44b4e99e/27b7a/08.openssh-servier-config.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;300\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20300\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20150v150h401V0H0v150m12%200v94h371v-94l1-94H261v5l-1%206V56H131v5l-1%206V56H12v94m67-16v5h233v-10H79v5M14%20236v3h368v-3c0-2%200-2-1%200v2H15v-2c-1-2-1-2-1%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/bfad8f011380589631f7857a44b4e99e/60a22/08.openssh-servier-config.webp 160w,/static/bfad8f011380589631f7857a44b4e99e/4c812/08.openssh-servier-config.webp 320w,/static/bfad8f011380589631f7857a44b4e99e/0ba47/08.openssh-servier-config.webp 640w,/static/bfad8f011380589631f7857a44b4e99e/95e88/08.openssh-servier-config.webp 804w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/bfad8f011380589631f7857a44b4e99e/69538/08.openssh-servier-config.png 160w,/static/bfad8f011380589631f7857a44b4e99e/72799/08.openssh-servier-config.png 320w,/static/bfad8f011380589631f7857a44b4e99e/6af66/08.openssh-servier-config.png 640w,/static/bfad8f011380589631f7857a44b4e99e/27b7a/08.openssh-servier-config.png 804w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/bfad8f011380589631f7857a44b4e99e/6af66/08.openssh-servier-config.png&quot; alt=&quot;08 openssh servier config&quot; title=&quot;08 openssh servier config&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Then there’s the &lt;code&gt;release-upgrades&lt;/code&gt; configuration and yeah I’m going
to select to &lt;code&gt;install the package maintainer&amp;#x27;s version&lt;/code&gt; and confirm to
continue.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:537px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/5c27fb195ae859a7575b1376cd6132f3/b1cde/09.release-upgrades-config.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:40%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;161\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20161\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2081v80h401V0H0v81m0%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/5c27fb195ae859a7575b1376cd6132f3/60a22/09.release-upgrades-config.webp 160w,/static/5c27fb195ae859a7575b1376cd6132f3/4c812/09.release-upgrades-config.webp 320w,/static/5c27fb195ae859a7575b1376cd6132f3/27c24/09.release-upgrades-config.webp 537w&quot; sizes=&quot;(max-width: 537px) 100vw, 537px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/5c27fb195ae859a7575b1376cd6132f3/69538/09.release-upgrades-config.png 160w,/static/5c27fb195ae859a7575b1376cd6132f3/72799/09.release-upgrades-config.png 320w,/static/5c27fb195ae859a7575b1376cd6132f3/b1cde/09.release-upgrades-config.png 537w&quot; sizes=&quot;(max-width: 537px) 100vw, 537px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/5c27fb195ae859a7575b1376cd6132f3/b1cde/09.release-upgrades-config.png&quot; alt=&quot;09 release upgrades config&quot; title=&quot;09 release upgrades config&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;finish-up-install&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#finish-up-install&quot; aria-label=&quot;finish up install permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Finish up install&lt;/h2&gt;&lt;p&gt;One of the last few prompts is to confirm the removal of the obsolete
packages, confirm &lt;code&gt;y&lt;/code&gt; to continue.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:338px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/be96c886864a0920396fcffe2c546315/2b41d/10.finish-up-install.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:56.875%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;227\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20227\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20114v113h401V0H0v114m0%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/be96c886864a0920396fcffe2c546315/60a22/10.finish-up-install.webp 160w,/static/be96c886864a0920396fcffe2c546315/4c812/10.finish-up-install.webp 320w,/static/be96c886864a0920396fcffe2c546315/9a593/10.finish-up-install.webp 338w&quot; sizes=&quot;(max-width: 338px) 100vw, 338px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/be96c886864a0920396fcffe2c546315/69538/10.finish-up-install.png 160w,/static/be96c886864a0920396fcffe2c546315/72799/10.finish-up-install.png 320w,/static/be96c886864a0920396fcffe2c546315/2b41d/10.finish-up-install.png 338w&quot; sizes=&quot;(max-width: 338px) 100vw, 338px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/be96c886864a0920396fcffe2c546315/2b41d/10.finish-up-install.png&quot; alt=&quot;10 finish up install&quot; title=&quot;10 finish up install&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Restart is required now, so I confirm with &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:439px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/f720e506166f0f6898567559fbca187d/e3b18/11.restart-prompt.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:30%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;121\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20121\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2061v60h401V0H0v61m0%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/f720e506166f0f6898567559fbca187d/60a22/11.restart-prompt.webp 160w,/static/f720e506166f0f6898567559fbca187d/4c812/11.restart-prompt.webp 320w,/static/f720e506166f0f6898567559fbca187d/023f2/11.restart-prompt.webp 439w&quot; sizes=&quot;(max-width: 439px) 100vw, 439px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/f720e506166f0f6898567559fbca187d/69538/11.restart-prompt.png 160w,/static/f720e506166f0f6898567559fbca187d/72799/11.restart-prompt.png 320w,/static/f720e506166f0f6898567559fbca187d/e3b18/11.restart-prompt.png 439w&quot; sizes=&quot;(max-width: 439px) 100vw, 439px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/f720e506166f0f6898567559fbca187d/e3b18/11.restart-prompt.png&quot; alt=&quot;11 restart prompt&quot; title=&quot;11 restart prompt&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now I have the confirmation that the do release upgrade completed
successfully. I press Ctrl+c&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/3f0a6842f37baa0f0e96b0468168a9e6/01267/12.finish-upgrade.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:18.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;72\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2072\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2036v36h401V0H0v36\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/3f0a6842f37baa0f0e96b0468168a9e6/60a22/12.finish-upgrade.webp 160w,/static/3f0a6842f37baa0f0e96b0468168a9e6/4c812/12.finish-upgrade.webp 320w,/static/3f0a6842f37baa0f0e96b0468168a9e6/0ba47/12.finish-upgrade.webp 640w,/static/3f0a6842f37baa0f0e96b0468168a9e6/69b3e/12.finish-upgrade.webp 713w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/3f0a6842f37baa0f0e96b0468168a9e6/69538/12.finish-upgrade.png 160w,/static/3f0a6842f37baa0f0e96b0468168a9e6/72799/12.finish-upgrade.png 320w,/static/3f0a6842f37baa0f0e96b0468168a9e6/6af66/12.finish-upgrade.png 640w,/static/3f0a6842f37baa0f0e96b0468168a9e6/01267/12.finish-upgrade.png 713w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/3f0a6842f37baa0f0e96b0468168a9e6/6af66/12.finish-upgrade.png&quot; alt=&quot;12 finish upgrade&quot; title=&quot;12 finish upgrade&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Then have to press &lt;code&gt;x&lt;/code&gt; to destroy!&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:404px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/49c154256be46d63b6dc1298907787f8/494f9/13.press-x.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:8.124999999999998%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;33\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2033\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2017v16h401V0h-48a408%20408%200%2000-48%201L153%200H0v17M7%205L6%2015v10h385V5L199%204%207%205\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/49c154256be46d63b6dc1298907787f8/60a22/13.press-x.webp 160w,/static/49c154256be46d63b6dc1298907787f8/4c812/13.press-x.webp 320w,/static/49c154256be46d63b6dc1298907787f8/3a65f/13.press-x.webp 404w&quot; sizes=&quot;(max-width: 404px) 100vw, 404px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/49c154256be46d63b6dc1298907787f8/69538/13.press-x.png 160w,/static/49c154256be46d63b6dc1298907787f8/72799/13.press-x.png 320w,/static/49c154256be46d63b6dc1298907787f8/494f9/13.press-x.png 404w&quot; sizes=&quot;(max-width: 404px) 100vw, 404px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/49c154256be46d63b6dc1298907787f8/494f9/13.press-x.png&quot; alt=&quot;13 press x&quot; title=&quot;13 press x&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;That takes me back to the regular prompt where I can check with
&lt;code&gt;lsb_release -a&lt;/code&gt; what version I’m now on.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:504px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/c0cac6ec5e1203fba1cdd7becdcd5391/08115/14.done.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:61.24999999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;245\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20245\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20123v122h401V0H0v123m0%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/c0cac6ec5e1203fba1cdd7becdcd5391/60a22/14.done.webp 160w,/static/c0cac6ec5e1203fba1cdd7becdcd5391/4c812/14.done.webp 320w,/static/c0cac6ec5e1203fba1cdd7becdcd5391/062aa/14.done.webp 504w&quot; sizes=&quot;(max-width: 504px) 100vw, 504px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/c0cac6ec5e1203fba1cdd7becdcd5391/69538/14.done.png 160w,/static/c0cac6ec5e1203fba1cdd7becdcd5391/72799/14.done.png 320w,/static/c0cac6ec5e1203fba1cdd7becdcd5391/08115/14.done.png 504w&quot; sizes=&quot;(max-width: 504px) 100vw, 504px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/c0cac6ec5e1203fba1cdd7becdcd5391/08115/14.done.png&quot; alt=&quot;14 done&quot; title=&quot;14 done&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Confirmation the Windows Subsystem Linux version of Ubuntu I’m using
is now on 19.10.&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up!&lt;/h2&gt;&lt;p&gt;That’s it! I upgraded a WSL Ubuntu version from 18.04 to 19.10.&lt;/p&gt;&lt;p&gt;First, I changed the default behaviour of the release upgrader from
&lt;code&gt;lts&lt;/code&gt; to &lt;code&gt;normal&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Then &lt;code&gt;do-release-upgrade&lt;/code&gt;, and I skipped the &lt;code&gt;Lxd&lt;/code&gt; configuration. It
isn’t needed on WSL but is part of the Ubuntu image on the Microsoft
Store 🤔&lt;/p&gt;&lt;p&gt;I accept &lt;code&gt;install the package maintainer&amp;#x27;s version&lt;/code&gt; on any
configuration prompts.&lt;/p&gt;&lt;p&gt;Done.&lt;/p&gt;&lt;h2 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h2&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Track Custom Events With Fathom Analytics]]></title><description><![CDATA[In this guide I'm going to go through how to track custom events in a
Gatsby site using Fathom analytics. Preamble At the end of last month…]]></description><link>https://scottspence.com/2020/01/02/track-custom-events-with-fathom-analytics/</link><guid isPermaLink="false">https://scottspence.com/2020/01/02/track-custom-events-with-fathom-analytics/</guid><pubDate>Thu, 02 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this guide I’m going to go through how to track custom events in a
Gatsby site using Fathom analytics.&lt;/p&gt;&lt;h2 id=&quot;preamble&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#preamble&quot; aria-label=&quot;preamble permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Preamble&lt;/h2&gt;&lt;p&gt;At the end of last month (November 2019) I started using &lt;a href=&quot;https://usefathom.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Fathom
Analytics&lt;/a&gt; in place of Google Analytics.&lt;/p&gt;&lt;p&gt;I wanted a simpler way to track visitors to my sites and Fathom offers
that with a great, really intuitive interface and simple design.&lt;/p&gt;&lt;p&gt;So far, I love it, and would like to recommend it to others! Fathom
have an awesome affiliate program where every customer can take part!&lt;/p&gt;&lt;p&gt;For every paying customer I refer with &lt;a href=&quot;https://usefathom.com/ref/HG492L&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my unique code&lt;/a&gt;, I’ll get a
25% lifetime commission on that customers payments, and if you use
that code too &lt;a href=&quot;https://usefathom.com/ref/HG492L&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;you’ll get a \$10 discount on your first invoice&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;For now here’s some of the Fathom marketing copy.&lt;/p&gt;&lt;h2 id=&quot;why-fathom&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#why-fathom&quot; aria-label=&quot;why fathom permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Fathom?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;You don’t need to display those cookie notices as they don’t use
cookies, nor do they track invasive data.&lt;/li&gt;&lt;li&gt;They are focused on privacy for website visitors, they don’t track
visitors, save their personal information, or need it to be
profitable.&lt;/li&gt;&lt;li&gt;They have hundreds of customers and track tens of millions of page
views per month, so they may be a small company, but they’re doing
big things!&lt;/li&gt;&lt;li&gt;They can handle viral content, so your site won’t slow down because
of them, an they wont ever stop tracking for you because of a spike
in popularity.&lt;/li&gt;&lt;li&gt;All of the plans allow for unlimited websites to be tracked and
receive top-notch customer support. Plans start at \$14 a month.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Do you use Google Analytics (GA) for any of your sites? I’ve used it
in the past and it gives the sort of information you’d expect but it
can be quite confusing to navigate and find that information.&lt;/p&gt;&lt;p&gt;What you get with Fathom out of the box is very similar to GA, but
it’s all there on one page. You get the standard metrics like, ‘Unique
visits’, ‘Page views’, ‘Avg time on site’ and ‘Bounce rate’.&lt;/p&gt;&lt;p&gt;There’s also the breakdown of the most popular pages and referring
sites.&lt;/p&gt;&lt;p&gt;The difference (apart from the simple to use interface), you’re not
giving away your visitors data to the big G!&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Want to track what users of your site are clicking and navigating
to?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;But say you want to track how many times a user of your site clicked a
particular button or link?&lt;/p&gt;&lt;h2 id=&quot;-heres-a-video-detailing-the-process&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#-heres-a-video-detailing-the-process&quot; aria-label=&quot; heres a video detailing the process permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;📺 Here’s a video detailing the process.&lt;/h2&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-yeMCma4Ae7Q&quot; src=&quot;https://www.youtube.com/embed/yeMCma4Ae7Q?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;set-up-fathom-account&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#set-up-fathom-account&quot; aria-label=&quot;set up fathom account permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set-up Fathom account&lt;/h2&gt;&lt;p&gt;If you want to follow along you’re going to need a Fathom Analytics
account, if you haven’t already got one then please consider signing
up with my affiliate link, &lt;a href=&quot;https://usefathom.com/ref/HG492L&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my unique code&lt;/a&gt; will get you a \$10
discount off of your first invoice! 🤝&lt;/p&gt;&lt;h2 id=&quot;addconfig-fathom-gatsby-plugin&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#addconfig-fathom-gatsby-plugin&quot; aria-label=&quot;addconfig fathom gatsby plugin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add/Config Fathom Gatsby plugin&lt;/h2&gt;&lt;p&gt;In this guide I’m going to use a Gatsby starter
&lt;a href=&quot;https://github.com/v4iv/gatsby-starter-business&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-starter-business&lt;/a&gt; which is a nice starter with some of the
relevant things I’d want to track. Things like the pricing page and
how many people submit a contact form.&lt;/p&gt;&lt;p&gt;In the &lt;code&gt;gatsby-config.js&lt;/code&gt; plugins array the config looks pretty
similar to this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  resolve: `gatsby-plugin-fathom`,
  options: {
    siteId: process.env.GATSBY_FATHOM_TRACKING_ID_MY_AWESOME_SITE,
    // or use the site ID in plaintext
    // siteId: &amp;#x27;PBZRRJHH&amp;#x27;,
  },
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the example I’m doing I’m hard-coding in the site ID but you can
use environment variables if you like.&lt;/p&gt;&lt;h2 id=&quot;push-to-netlify-and-test&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#push-to-netlify-and-test&quot; aria-label=&quot;push to netlify and test permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Push to Netlify and test&lt;/h2&gt;&lt;p&gt;For the purposes of the guide I build and push the site to Netlify
then check in the console on the browser that &lt;code&gt;fathom&lt;/code&gt; is available as
a global function.&lt;/p&gt;&lt;p&gt;I can now check my Fathom dashboard to see that the site has a
visitor.&lt;/p&gt;&lt;p&gt;Cool, cool! That’s Fathom Analytics configured for the site, now to
the custom events.&lt;/p&gt;&lt;h2 id=&quot;create-goals-in-fathom-analytics&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-goals-in-fathom-analytics&quot; aria-label=&quot;create goals in fathom analytics permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create goals in Fathom Analytics&lt;/h2&gt;&lt;p&gt;To track events in Fathom I’ll first need to set up a goal! This will
give a unique ID that I can pass to the Fathom global function that’s
on my configured site.&lt;/p&gt;&lt;p&gt;So, to get to the goal section of my site I’ll scroll to the bottom of
the configured site’s dashboard and click the &lt;em&gt;Show more data&lt;/em&gt; toggle.&lt;/p&gt;&lt;p&gt;This will reveal the &lt;em&gt;Goals&lt;/em&gt; section where I can configure goals. In
this example I’ll be adding goals for &lt;code&gt;about&lt;/code&gt;, &lt;code&gt;pricing&lt;/code&gt;, &lt;code&gt;blog&lt;/code&gt;,
&lt;code&gt;contact-us&lt;/code&gt; and &lt;code&gt;form-submit&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Each time I save the goal I’m given a JavaScript snippet to use, like:
&lt;code&gt;fathom(&amp;#x27;trackGoal&amp;#x27;, &amp;#x27;CYAZA98C&amp;#x27;, 0);&lt;/code&gt; , this is what I’m going to be
adding into my code example.&lt;/p&gt;&lt;h2 id=&quot;use-react-context-api-to-make-an-analytics-provider&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-react-context-api-to-make-an-analytics-provider&quot; aria-label=&quot;use react context api to make an analytics provider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use React Context API to make an analytics provider&lt;/h2&gt;&lt;p&gt;I’m going to use the React context API to create an analytics provider
to be used throughout the app.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { createContext, useContext, useEffect } from &amp;#x27;react&amp;#x27;

const AnalyticsContext = createContext({})

export const AnalyticsProvider = ({ children }) =&amp;gt; {
  useEffect(() =&amp;gt; {
    if (typeof window.fathom === &amp;#x27;undefined&amp;#x27;) {
      window.fathom = (x, y, z) =&amp;gt; {
        console.log(`I&amp;#x27;m a fake Fathom`, x, y, z)
      }
    }
  }, [])

  const logClicks = goalId =&amp;gt; {
    window.fathom(&amp;#x27;trackGoal&amp;#x27;, goalId, 0)
  }

  return (
    &amp;lt;AnalyticsContext.Provider value={logClicks}&amp;gt;
      {children}
    &amp;lt;/AnalyticsContext.Provider&amp;gt;
  )
}

export const useAnalytics = () =&amp;gt; {
  return useContext(AnalyticsContext)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example I’m defining one function to be available via the
context provider and passed in with &lt;code&gt;value&lt;/code&gt; but I could add in many
functions here for different event types.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook is for when I’m on the dev server and don’t want
to be submitting data to Fathom, I’ll instead get a console message.&lt;/p&gt;&lt;p&gt;As high up the component tree as possible, I’m going to add the
provider.&lt;/p&gt;&lt;h2 id=&quot;add-custom-event-tracking-for-fathom&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-custom-event-tracking-for-fathom&quot; aria-label=&quot;add custom event tracking for fathom permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add custom event tracking for Fathom&lt;/h2&gt;&lt;p&gt;In this example there’s a &lt;code&gt;Layout&lt;/code&gt; component I can add the provider
to, this wraps all of the components in the application so the
provider can be accessed throughout the site.&lt;/p&gt;&lt;p&gt;Then use in the areas I want to track a goal I’ll use the
&lt;code&gt;useAnalytics&lt;/code&gt; hook.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const NavBar = ({ toggleNavbar, isActive }) =&amp;gt; {
  const fa = useAnalytics()
  return (
    // other wrapping elements
    &amp;lt;Link
      onClick={() =&amp;gt; {
        fa(&amp;#x27;CDDZY97C&amp;#x27;)
      }}
      className=&amp;quot;navbar-item&amp;quot;
      to=&amp;quot;/about&amp;quot;
    &amp;gt;
      About
    &amp;lt;/Link&amp;gt;
    // other wrapping elements
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up&lt;/h2&gt;&lt;p&gt;Ok, time for me to review what I just did and what you’ll need to do
if you’re looking to do the same:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Set up Fathom account&lt;/li&gt;&lt;li&gt;Add and configure the Fathom Gatsby plugin&lt;/li&gt;&lt;li&gt;Push the configured site to Netlify to test configuration.&lt;/li&gt;&lt;li&gt;Add custom tracking code in the shape of a React Context API
Provider&lt;/li&gt;&lt;li&gt;Wrap the app in the &lt;code&gt;AnalyticsProvider&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Consume the analytics provider function to log the event to the
&lt;code&gt;fathom&lt;/code&gt; global function.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;🥁 Demo site: &lt;a href=&quot;https://gatsby-starter-business-fathom.netlify.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gatsby-starter-business-fathom.netlify.com&lt;/a&gt;&lt;/p&gt;&lt;p&gt;📈 Demo Fathom Dashboard:
&lt;a href=&quot;https://app.usefathom.com/share/nymdtplm/gatsby-starter-business&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://app.usefathom.com/share/nymdtplm/gatsby-starter-business&lt;/a&gt;&lt;/p&gt;&lt;p&gt;🤝 Affiliate link for \$10 of off your first month of Fathom
Analytics: &lt;a href=&quot;https://usefathom.com/ref/HG492L&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://usefathom.com/ref/HG492L&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h2&gt;&lt;p&gt;That’s all folks! If there is anything I have missed, or if there is a
better way to do something then please let me know.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[React Advanced - London 2019]]></title><description><![CDATA[React Advanced London going deep! Here's my recollection of my attendance at React Advanced London 2019
supported with videos from the event…]]></description><link>https://scottspence.com/2019/11/06/react-advanced-london-2019/</link><guid isPermaLink="false">https://scottspence.com/2019/11/06/react-advanced-london-2019/</guid><pubDate>Tue, 31 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;React Advanced London going deep!&lt;/p&gt;&lt;p&gt;Here’s my recollection of my attendance at React Advanced London 2019
supported with videos from the event.&lt;/p&gt;&lt;h2 id=&quot;ken-wheeler---react-performance&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#ken-wheeler---react-performance&quot; aria-label=&quot;ken wheeler   react performance permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ken Wheeler - React Performance&lt;/h2&gt;&lt;p&gt;Ken’s keynote didn’t disappoint! Ken talks about how performance fixes
aren’t prescriptive and it’s more like a puzzle to figure out.&lt;/p&gt;&lt;p&gt;To help with this he prescribed the IMDOPE system!&lt;/p&gt;&lt;h3 id=&quot;imdope-system&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#imdope-system&quot; aria-label=&quot;imdope system permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;IMDOPE System&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;I&lt;/strong&gt;dentify that a problem exists&lt;/li&gt;&lt;li&gt;&lt;strong&gt;M&lt;/strong&gt;easure your timings&lt;/li&gt;&lt;li&gt;&lt;strong&gt;D&lt;/strong&gt;evelop a plan&lt;/li&gt;&lt;li&gt;&lt;strong&gt;O&lt;/strong&gt;pen dev tools&lt;/li&gt;&lt;li&gt;&lt;strong&gt;P&lt;/strong&gt;lay around until its better&lt;/li&gt;&lt;li&gt;&lt;strong&gt;E&lt;/strong&gt;njoy newly performant app&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Ken detailed an animation running at 60 frames per second and how that
appears on the performance tab.&lt;/p&gt;&lt;p&gt;The user Timings API (which I’ve never heard of) lets you define
precise performance marking that you can name and display in dev
tools.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;performance.mark(&amp;#x27;mainthread-start&amp;#x27;)
# do expensive things for performance
performance.mark(&amp;#x27;mainthread-stop&amp;#x27;)
performance.measure(&amp;#x27;mainthread&amp;#x27;, &amp;#x27;mainthread-start&amp;#x27;, &amp;#x27;mainthread-stop&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;React does not control renders by default, very often problems
relating to performance are related to unnecessary renders.&lt;/p&gt;&lt;p&gt;React is &lt;em&gt;generally&lt;/em&gt; not great when you have a lot of components
rendering and re-rendering at the same time (cough React Memo!)&lt;/p&gt;&lt;p&gt;The React dev tools profiler got a mention and there was a demo of how
react will re-render all the things if you have many components in a
view using the React dev tools profiler.&lt;/p&gt;&lt;p&gt;There was an amusing part where when trying to demo the &lt;code&gt;useCallback&lt;/code&gt;
React API where Ken missed out the second argument and had to consult
the React docs to clarify.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;“as developers almost everything we do is building elaborate lists
of shit”&lt;/p&gt;&lt;p&gt;— Ken Wheeler&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;List should be virtualized, check out Brian Vaughn’s &lt;a href=&quot;https://github.com/bvaughn/react-window&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Window&lt;/a&gt; or
&lt;a href=&quot;https://github.com/bvaughn/react-virtualized&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Virtualized&lt;/a&gt; he went on to render lists with 10k plus items in
there and demoed the shoddy performance on a rendered list then with
react window.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Web Workers&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;A particularly interesting section for me (because I didn’t know it
was a thing), with web workers you can take expensive tasks off of the
main thread.&lt;/p&gt;&lt;p&gt;There are some downsides to this relating to serialization though.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;WASM&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;He finished up with an auto tune example made with Rust and a Google
audio worklet to process a stream of audio to do the Daft Punk “one
more time” vocoder example! Dope!&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-t8svxxtUTl8&quot; src=&quot;https://www.youtube.com/embed/t8svxxtUTl8?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;sean-wang---react-with-hooks-from-scratch&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#sean-wang---react-with-hooks-from-scratch&quot; aria-label=&quot;sean wang   react with hooks from scratch permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sean Wang - React (with hooks) from scratch&lt;/h2&gt;&lt;p&gt;Bonkers talk from Sean where he recreated React with Hooks and React
Concurrency (Fibre) in a &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox.io&lt;/a&gt; session.&lt;/p&gt;&lt;p&gt;The talk was a sequel to a previous talk on &lt;a href=&quot;https://www.swyx.io/speaking/react-hooks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React hooks from scratch&lt;/a&gt;
in 29 lines. He started with “we’re going to re-create concurrent
React in 130 lines of code!“.&lt;/p&gt;&lt;p&gt;At blazing fast speed he covered many concepts, a lot I was unfamiliar
with relating to React, topics covered:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;React Fiber&lt;/li&gt;&lt;li&gt;“Rendering”&lt;/li&gt;&lt;li&gt;Linked List Traversal&lt;/li&gt;&lt;li&gt;Reconciliation vs Commit&lt;/li&gt;&lt;li&gt;&lt;code&gt;useState&lt;/code&gt; hook&lt;/li&gt;&lt;li&gt;Work loop&lt;/li&gt;&lt;li&gt;Suspense&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;First, the POJO! (Plain Old JavaScript Object):&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const element = {
  type: &amp;#x27;h1&amp;#x27;,
  props: {
    children: &amp;#x27;Hello world&amp;#x27;,
  },
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then went on to define what a fiber was, which is an extension on the
POJO:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const element = {
  type: &amp;#x27;h1&amp;#x27;,
  props: {
    children: &amp;#x27;Hello world&amp;#x27;,
  },
  dom: domNode,
  parent: parentFiber,
  child: childFiber,
  sibling: null,
  alternate: currentFiber,
  effectTag: PLACEMENT,
  hooks: [],
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’ll be honest, the speed at which Sean went, although very concise
was quite though to follow at times.&lt;/p&gt;&lt;p&gt;He covered all the main sections along with code examples. TL;DR
suspense with time slicing is here.&lt;/p&gt;&lt;p&gt;The only dependency used in the code was Babel with this &lt;a href=&quot;https://codesandbox.io/s/reactadvanced-final-uwrx0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;fetch
example&lt;/a&gt; where the we’re using state and reading from a resource which
suspends (or caches) as needed.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-dFO4m7Y-yhs&quot; src=&quot;https://www.youtube.com/embed/dFO4m7Y-yhs?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;vojtech-miksu---what-a-drag&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#vojtech-miksu---what-a-drag&quot; aria-label=&quot;vojtech miksu   what a drag permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Vojtech Miksu - What a Drag&lt;/h2&gt;&lt;p&gt;Vojtech (Uber) goes through the history lesson about drag and drop and
the complexities that come with it.&lt;/p&gt;&lt;p&gt;He details the options available and why they implemented their own
&lt;a href=&quot;https://github.com/tajo/react-movable&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Movable&lt;/a&gt; Accessible drag and drop project.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-y_XkQ2qMTSA&quot; src=&quot;https://www.youtube.com/embed/y_XkQ2qMTSA?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Here’s the same talk from RSCONF 2019:&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-373pc0AbR9M&quot; src=&quot;https://www.youtube.com/embed/373pc0AbR9M?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;daniel-irvine---dont-let-your-unit-tests-slow-you-down&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#daniel-irvine---dont-let-your-unit-tests-slow-you-down&quot; aria-label=&quot;daniel irvine   dont let your unit tests slow you down permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Daniel Irvine - Don’t Let Your Unit Tests Slow You Down&lt;/h2&gt;&lt;p&gt;Six ideas that can help improve your testing.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Idea 1:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Always follow &lt;em&gt;Arrange Act Assert&lt;/em&gt;, get the variables in place,
render, expected result.&lt;/p&gt;&lt;p&gt;Keep tests simple&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Idea 2:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Test the &lt;em&gt;lifecycle&lt;/em&gt; of your components.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Idea 3:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Be aware of tests surface areas, good test pinpoint errors.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Idea 4:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Make a mess, then refactor.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Idea 5:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Get out of React components at every opportunity. Testing simple
functions, simple, React component, not so simple to test.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Idea 6:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Write your own test library! 😱&lt;/p&gt;&lt;p&gt;It will help you understand the DOM better and further your
learning!!!&lt;/p&gt;&lt;p&gt;Library’s lock you into &lt;em&gt;their&lt;/em&gt; way of testing things.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Main takeaway for me from this is:&lt;/strong&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;No tests are better than bad tests!&lt;/p&gt;&lt;/blockquote&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-1vDXRDQ9aJE&quot; src=&quot;https://www.youtube.com/embed/1vDXRDQ9aJE?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;After this talk I was off to the React native hall to go see some of
the lightening talks as I knew one of the speakers.&lt;/p&gt;&lt;h2 id=&quot;dave-nicholas---functions-vs-classes&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#dave-nicholas---functions-vs-classes&quot; aria-label=&quot;dave nicholas   functions vs classes permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dave Nicholas - Functions vs Classes&lt;/h2&gt;&lt;p&gt;He discussed the migration from classes over to functional components
at Tesco.&lt;/p&gt;&lt;h2 id=&quot;jamie-barton---teaching-and-sharing-awesome-content-101&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#jamie-barton---teaching-and-sharing-awesome-content-101&quot; aria-label=&quot;jamie barton   teaching and sharing awesome content 101 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Jamie Barton - Teaching and Sharing Awesome Content 101&lt;/h2&gt;&lt;p&gt;A non technical talk about teaching what you have learned as someone
will benefit from it.&lt;/p&gt;&lt;p&gt;That can be in the form of ANYTHING. It wasn’t quite as memorable as
Ken’s IMDOPE system but it was the message was what was important.&lt;/p&gt;&lt;p&gt;Jamie went on to talk about how the community can benefit from any
kind of sharing.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/a5977c43c2e8140e1898ffb67e75234f/5b4a1/anything.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:56.25%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;225\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20225\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M79%20107a13290%2013290%200%2001-3%2014c3%200%203-1%204-3%201-3%202-3%206-3s5%200%206%203c1%202%202%203%204%203%203%200%203%200-3-13-4-11-4-12-7-12-2%200-3%201-7%2011m32%202c0%2011%200%2012%202%2012s2-1%202-8c0-8%200-8%206%201%203%206%205%207%207%207h2v-13c0-12%200-12-2-12s-3%201-3%208v7l-5-8c-3-5-5-7-7-7s-2%200-2%2013m32-12l4%206c2%205%204%208%204%2012%200%205%201%206%203%206s2%200%202-5c0-4%201-6%203-10%206-9%206-10%203-10-2%200-3%201-5%205l-3%204-3-4c-2-4-4-5-5-5l-3%201m29%201c0%201%201%202%203%202l4%201v10c0%2010%200%2010%203%2010%202%200%202%200%202-10v-11h4c2%200%203%200%203-2s-1-2-9-2c-9%200-10%200-10%202m28%2011v12h3c2%200%202%200%202-6v-5h5l5%201v5c0%204%200%205%202%205s3-1%203-13V96h-3c-2%200-2%201-2%205v5h-10v-5c0-5%200-5-2-5h-3v13m34%200v12h5V96h-5v13m19%200c0%2012%200%2012%202%2012s3-1%203-8v-7l5%207c4%207%205%208%207%208s3-1%203-13V96h-2c-3%200-3%200-3%208v8l-5-8c-4-6-5-8-7-8h-3v13m39-12c-7%204-8%2015-2%2021%204%203%2010%204%2015%202%204-2%204-2%204-7v-6h-5c-5%200-5%200-5%203%200%202%200%202%203%202s2%203-1%204c-5%202-8-1-9-7%200-8%206-12%2011-7%202%202%206%202%206%200%200-5-11-8-17-5m-44%2051c-2%200-3%202%200%202v4l1%203%201%201%201%202c2%202%202%202%202%205l1%201c1-1%201%200%200%200l1%203%201%201%201%201c2%200%203%202%201%202-1%201%200%203%201%203%202%200%203-2%202-4l-2-3-1-2c1-1%200-1-1-2l-1-1c1%200%201-3-1-5l-2-4-2-1c-2%200-1-1%201-3v-1l-2-1c1-2%201-2-2-1\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/a5977c43c2e8140e1898ffb67e75234f/60a22/anything.webp 160w,/static/a5977c43c2e8140e1898ffb67e75234f/4c812/anything.webp 320w,/static/a5977c43c2e8140e1898ffb67e75234f/0ba47/anything.webp 640w,/static/a5977c43c2e8140e1898ffb67e75234f/6d405/anything.webp 831w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/a5977c43c2e8140e1898ffb67e75234f/69538/anything.png 160w,/static/a5977c43c2e8140e1898ffb67e75234f/72799/anything.png 320w,/static/a5977c43c2e8140e1898ffb67e75234f/6af66/anything.png 640w,/static/a5977c43c2e8140e1898ffb67e75234f/5b4a1/anything.png 831w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/a5977c43c2e8140e1898ffb67e75234f/6af66/anything.png&quot; alt=&quot;anything acronym&quot; title=&quot;anything acronym&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;YouTube video or video series&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Tutorials&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Hackathons, hosting or organising&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Indie Hackers, posting milestones&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Guides&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Something that resonated with me was the quite:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;“Write the guide you needed as a developer when trying to do this.”&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I have been doing this for a long time myself now and it’s something I
believe in a lot.&lt;/p&gt;&lt;h2 id=&quot;lunch&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lunch&quot; aria-label=&quot;lunch permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lunch&lt;/h2&gt;&lt;h2 id=&quot;siddharth-kshetrapal---design-systems-design-system&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#siddharth-kshetrapal---design-systems-design-system&quot; aria-label=&quot;siddharth kshetrapal   design systems design system permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Siddharth Kshetrapal - Design Systems Design System&lt;/h2&gt;&lt;p&gt;Sid gave a good overview of making design systems. Or designing design
systems.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;“When I started laying out a system last year I would just call them
gray, gray darker and gray darkest.”&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Basically there always a colour that’s not on there.&lt;/p&gt;&lt;p&gt;Then he came out with this gem!&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const theme = {
  colours: {
    grays: {
      100: &amp;#x27;#fff9f9&amp;#x27;
      200: &amp;#x27;#e6e6e6&amp;#x27;
      300: &amp;#x27;#999999&amp;#x27;
      400: &amp;#x27;#757575&amp;#x27;
      500: &amp;#x27;#242424&amp;#x27;
      700: &amp;#x27;#151515&amp;#x27;
      900: &amp;#x27;#111111&amp;#x27;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So you can add in more colours if you need them, add a 150, or add a
600 here.&lt;/p&gt;&lt;p&gt;Sid then went on to talks about how awesome styled-components was and
some nice touches for that:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import styled from &amp;#x27;styled-components&amp;#x27;

const FormLabel = styled.label(
  props =&amp;gt; `
  color: ${props.theme.colors.text.subtle}
  font-size: ${props.theme.fontSizes[2]}
`
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Looks pretty verbose so you could use &lt;code&gt;@styled-system/css&lt;/code&gt; to reduce
that:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import styled from &amp;#x27;styled-components&amp;#x27;
import css from &amp;#x27;@styled-system/css&amp;#x27;

const FormLabel = styled.label(
  css({
    color: &amp;#x27;text.subtle&amp;#x27;,
    fontSize: 2,
  })
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pretty neat stuff!&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-Dd-Y9K7IKmk&quot; src=&quot;https://www.youtube.com/embed/Dd-Y9K7IKmk?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;emma-brillhart---a-more-readable-react-codebase-using-typescript-graphql-and-hooks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#emma-brillhart---a-more-readable-react-codebase-using-typescript-graphql-and-hooks&quot; aria-label=&quot;emma brillhart   a more readable react codebase using typescript graphql and hooks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Emma Brillhart - A More Readable React Codebase Using TypeScript, GraphQL, and Hooks&lt;/h2&gt;&lt;p&gt;Emma’s talk centered around why TypeScript is awesome and how
readability enables faster onboarding for developers.&lt;/p&gt;&lt;p&gt;Using TypeScript on the client side give built in documentation,
better navigation, less technical debt.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-nkJbGgieALI&quot; src=&quot;https://www.youtube.com/embed/nkJbGgieALI?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Complete playlist of all the talks on YouTube &lt;a href=&quot;https://www.youtube.com/playlist?list=PLNBNS7NRGKMH7yfpYQD4TrFV25SMOCIPM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Check the &lt;a href=&quot;https://twitter.com/hashtag/ReactAdvanced&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hashtag&lt;/a&gt; on Twitter and also &lt;a href=&quot;https://twitter.com/search?q=reactadvanced%20spences10&amp;amp;f=live&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my coverage&lt;/a&gt; on Twitter.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/search?q=spences10%20reactadvanced&amp;amp;f=live&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://twitter.com/search?q=spences10%20reactadvanced&amp;amp;f=live&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Build a coding blog from scratch with Gatsby and MDX]]></title><description><![CDATA[I have been a Gatsby user since around  v0 May 2017 , at that time was
using a template called  Lumen  and it was just what I needed at the…]]></description><link>https://scottspence.com/2019/10/31/build-an-mdx-blog/</link><guid isPermaLink="false">https://scottspence.com/2019/10/31/build-an-mdx-blog/</guid><pubDate>Thu, 31 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have been a Gatsby user since around &lt;a href=&quot;https://github.com/spences10/blog.scottspence.me/tree/a470e8563e1a040527cf2094fc1b377550a88c77&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;v0 May 2017&lt;/a&gt;, at that time was
using a template called &lt;a href=&quot;https://github.com/alxshelepenok/gatsby-starter-lumen&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lumen&lt;/a&gt; and it was just what I needed at the
time. Since then I have have gone from using a template to creating my
blog.&lt;/p&gt;&lt;p&gt;Over the years I have made my own &lt;a href=&quot;https://lengstorf.com/progressive-disclosure-of-complexity/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Progressive Disclosure of
Complexity&lt;/a&gt; with Gatsby to where I am now.&lt;/p&gt;&lt;h2 id=&quot;what-does-that-mean&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-does-that-mean&quot; aria-label=&quot;what does that mean permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What does that mean?&lt;/h2&gt;&lt;p&gt;It means that although there are an awesome amount of Gatsby starters
and themes out there to get you up and running in minutes, this post
is going to focus on what you need to do to build your own blog.
Starting with the most basic “Hello World!” to deploying your code to
production.&lt;/p&gt;&lt;h2 id=&quot;what-youre-going-to-build&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-youre-going-to-build&quot; aria-label=&quot;what youre going to build permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What you’re going to build&lt;/h2&gt;&lt;p&gt;You’re going to build a developer blog with MDX support (for some
React components in Markdown goodness), so you will be able to add
your own React components into your Markdown posts.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;There’ll be:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Adding a Layout&lt;/li&gt;&lt;li&gt;Basic styling with styled-components&lt;/li&gt;&lt;li&gt;Code blocks with syntax highlighting&lt;/li&gt;&lt;li&gt;Copy code snippet to clipboard&lt;/li&gt;&lt;li&gt;Cover images for the posts&lt;/li&gt;&lt;li&gt;Configuring an SEO component&lt;/li&gt;&lt;li&gt;Deploying it to Netlify&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;whos-this-how-to-for&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#whos-this-how-to-for&quot; aria-label=&quot;whos this how to for permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Who’s this how-to for?&lt;/h2&gt;&lt;p&gt;People that may have used Gatsby before as a template and now want to
get more involved in how to make changes.&lt;/p&gt;&lt;p&gt;If you want to have code syntax highlighting.&lt;/p&gt;&lt;p&gt;If you want to use styled-components in an app.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;I really want to avoid this!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/c94426ee247944669175d7575b851f60/dba9a/draw-a-horse-quincy-tweet.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:133.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;531\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20531\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20266c0%20264%200%20265%202%20265s2-1%202-263L5%205c2-2%20388-1%20390%200l1%20264v262h5V0H0v266M38%2026l-1%209c0%207%200%207-3%209l-3%203%202%202c5%205%209%204%208-1l1-2c1%201%202%200%204-1s3-1%201%204c-1%202%203%202%205%200%203-2%202-2-1-4-3-1-3-1-2-3v-5c-1%202-1%202-3%200-3-2-2-3%201-2%202%200%203%200%203-2s0-2-4-2c-5%201-7-5-2-6%202-1%202-1-1-1l-5%202m112%2072c-1%202-1%202-3%200-2-1-2-1-4%201l-1%202-2-2c-3-4-4-1-2%204%203%204%207%206%207%203s2-2%203%200c3%203%205%202%205-3%201-7-1-9-3-5m-84%2024c0%2013%200%2013%203%2013%204%200%209-7%209-11%200-3-3-7-8-10-5-4-5-3-4%208m39-9l6%2019c2%205%208%203%207-3-1-3%200-2%202%203%203%205%204%207%206%207%201%200%202-1%202-13l-1-12c-2-1-2%200-3%207-1%206-2%206-4%200s-5-10-6-8l-1%206v6l-2-6c-2-6-6-10-6-6m-25%2011c0%2010%202%2014%204%2013v-11l3%204%205%204c2%200%201-4%200-5-3-1-5-5-4-6%203-4%200-9-6-9h-3l1%2010m15%200l1%2011c2%202%203%200%203-3%200-4%202-4%204%201%202%203%205%204%205%202%200-5-9-21-11-21l-2%2010m73-4c0%206-1%207-3%201l-3-5c-2%200-1%2019%201%2022s4%202%204-3c0-6%201-7%202%200%200%205%202%208%204%206%201-1%200-23-2-24-2-3-3-2-3%203m18-4v7l2%209c1%207%205%207%204%201l-1-4%204%204%205%204c2%200%203-2%201-3l-4-4c-3-3-3-3-2-5%203-2%202-5-1-8-2-2-7-3-8-1m16%201c-3%204-3%205%202%209s5%206%201%206-4%202%200%203c4%202%207%200%207-4%200-2-3-5-7-8-1-1-1-1%201-3%203-3%203-5%200-5l-4%202m12-1v22c1%201%2014%200%2014-2%200-1-2-2-7-2-4%200-4%200-4-3s1-4%204-4c6-2%205-5-1-4-3%200-3%200-3-2%200-1%201-2%203-2%204-1%203-3-2-4l-4%201m-71%202c-2%203-1%2020%201%2020l2-4c0-4%201-4%203%200%201%203%205%204%204%201-4-17-7-22-10-17m33%200c-2%202-1%2014%201%2016%205%206%2010%202%209-7-1-8-6-13-10-9m15%2065l-1%205-1%201c0%201%201%201%202-1l2-2%201%204c2%204%202%204%200%204l-4-2c-1-2-2-2-3%200v1c3-1%205%202%202%204s-4%206-1%2012c2%205%202%203%200-2v-6c1-3%207-7%209-6h1l2-1h2l7%201%205-1-9-1h-8l-2-5-2-5-1-2c-1-1-1%200-1%202m32%2021c1%2010-4%2014-18%2013a39%2039%200%2001-13-3l3%2022%201-3-2-10c0-9%201-6%203%204%200%206%202%2010%202%207l-1-10v-7c1%200%202%201%203%2011l2%205-1-8v-7l2%208%202%209c1%201%201%201%201-1l-2-9c0-7%200-7%202-6%202%200%202%201%204%209%201%207%203%2010%202%203-2-11-2-13-1-13l1%202%203%2015%201-2c-2-4-3-14-2-15%202-2%203-1%205%207l2%207%201-2c-3-6-4-13-3-14s2%201%203%207c0%205%201%209%202%209l-1-5v-21l-1-6v4m-52%2074l-3%205c-2%203-2%204%201%202s10-1%2011%201c1%204%201%206-1%208-2%203-2%203%200%205s2%202-1%205-4%205-2%2010c2%202%202%202%201-2%200-5%200-6%202-7l3-2%202-1h2l3-1h4c2-1%2012%200%2016%203h2c-1-2-9-5-15-5l-6-1c1-1-1-5-5-12l-3-3-3-2c0-2-1-3-3-2l-4-1h-1m52%2021l-8%204c-5%203-5%203-3%206%202%204%200%2010-4%2012-7%204-21%203-27-2-1-2-3-3-3-2l2%202c2%202%203%2012%203%2022%201%203%202%203%204%202s2-2%200-10v-9c2%200%204%2010%204%2016%200%202%201%203%202%203%203%201%204-1%203-4l-2-9c0-5%200-5%202-5%203%200%203%201%204%208l1%209c0%201%204%202%205%200v-3l-2-9c0-6%200-6%202-6l5%2016c-1%201%203%203%204%202l-1-12c-1-7-2-11-1-13l1-5c0-3%201-4%205-6%205-3%205-3%207%201%201%202%201%203%203%202h3c2%202%200-4-2-8-3-3-2-3-7-2m-100%206c3%204%203%2011%200%2015-3%203-12%204-19%203l-7-1%201%208v9l-1-9c0-8-1-9-3-11-3-2-4-2-2%201%202%201%202%205%203%2013%201%2012%202%2012%204%2010s2-2%201-8l-1-10c0-5%203%201%204%2010%201%208%201%208%204%208%202%200%202%200%202-3l-2-9c-1-6-1-6%202-6%202%200%204%206%204%2014%200%204%201%204%203%204%203%200%203%200%203-3l-3-15%202-1c2%200%205%2010%205%2015%200%202%203%204%204%202l-1-11-1-11c3-4%200-17-4-17l2%203m-21%2083c0%202-1%202-3%201-2%200-3%200-4%202s-3%202-7-2h-2v1c-2-1-1%202%201%203l2%201%201%201%201%202c2%202%202%202%202%200l-1-3v-1l2%204c2%204%209%206%209%202%201-2%201-2%201%200%201%202%201%204-1%207l-2%2012c-1%209-3%2012-6%207-2-3-3-1%200%203%201%202%202%203%204%203%203%200%204-2%204-8%200-4-1-4%207%204%202%203%203%204%205%203h3l-2-3c-4-4-7-13-7-18%200-7%202-7%202%200v6l2-6c2-5%203-6%203-1l1%207%201%205%202-3c0-2%201-2%201-1l1%202%201%202c0%204%202%202%202-2%201-3%201-2%201%202l1%206c1%200%204-11%204-16%200-6%202-6%209-2%205%202%205%203%204%201s-8-6-10-6c-5%200-5%200-5%205v5l-2-3-1-3-1%202-1%201-1-1c-2%201-2%200-2-1%200-3-2-3-2%200s0%203-1%200l-2-7c-2-3-2-3-2-1-1%202-1%202-5-1-3-3-4-7-1-7l-1-1-2-2c-1-2-3-2-3-1m162%2078c-5%202-7%208-3%2012%205%205%2012%201%2012-5%200-5-5-9-9-7m-71%201v3c0%201%200%202-2%203-3%200-3%203%200%206%202%202%203%201%203-1l1-2v2l1%202c2%200%204-1%204-4l1-2v-5l-2-3-1%203-1%204v-4c0-3-2-4-4-2m16%201l-1%202-1%201v7l1-1%202-1c1%200%202%200%201%201h-1l-1%201c1%203%206%202%209%200%203-3%203-5%200-5h-2l2-1c2%200%201-4-2-5s-5-1-7%201m87%201c-4%205-2%2010%205%2010%204%200%204%200%205-3l2-2v-5c-1-2-2-2-4-1l-4%201%201-1a303%20303%200%20001-2c-3%200-4%201-6%203m-138-1l-2%203h-1c-2-2-3-1-3%202%200%201%201%203%203%203l2%202c0%202%204%203%205%201%201-1%202-2%201-3l2-1%202-1-2-1-2-2c0-3-3-4-5-3m73%201l-5%201c-2%200-3%202-2%205%201%202%202%203%203%202%201%200%203%200%203%202h4c4-3%204-9%201-11-2-1-2-1-4%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/c94426ee247944669175d7575b851f60/60a22/draw-a-horse-quincy-tweet.webp 160w,/static/c94426ee247944669175d7575b851f60/4c812/draw-a-horse-quincy-tweet.webp 320w,/static/c94426ee247944669175d7575b851f60/0ba47/draw-a-horse-quincy-tweet.webp 640w,/static/c94426ee247944669175d7575b851f60/db2ac/draw-a-horse-quincy-tweet.webp 652w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/c94426ee247944669175d7575b851f60/69538/draw-a-horse-quincy-tweet.png 160w,/static/c94426ee247944669175d7575b851f60/72799/draw-a-horse-quincy-tweet.png 320w,/static/c94426ee247944669175d7575b851f60/6af66/draw-a-horse-quincy-tweet.png 640w,/static/c94426ee247944669175d7575b851f60/dba9a/draw-a-horse-quincy-tweet.png 652w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/c94426ee247944669175d7575b851f60/6af66/draw-a-horse-quincy-tweet.png&quot; alt=&quot;draw a horse quincy tweet&quot; title=&quot;draw a horse quincy tweet&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/ossia/status/588389121053200385&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;draw a horse Quincy tweet&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;requirements&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#requirements&quot; aria-label=&quot;requirements permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Requirements&lt;/h2&gt;&lt;p&gt;You’re going to need a basic web development setup: node, terminal
(bash, zsh or fish) and a text editor.&lt;/p&gt;&lt;p&gt;I do like to use &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; for these sort of guides to reduce
the barrier to entry but in this case I have found there are some
limitations with starting out from scratch on &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; which
doesn’t make this possible.&lt;/p&gt;&lt;p&gt;I have made a guide on getting set up for web development with
&lt;a href=&quot;http://blog.scottspence.me/wsl-bootstrap-2019&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Windows Web-Dev Bootstrap&lt;/a&gt; and covered the same process in &lt;a href=&quot;https://www.youtube.com/watch?v=eSAsdQuQ-1o&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ubuntu as
well&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Ok? Time to get started!&lt;/p&gt;&lt;h2 id=&quot;hello-world&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#hello-world&quot; aria-label=&quot;hello world permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hello World&lt;/h2&gt;&lt;p&gt;Kick this off with the Gatsby ‘hello world’, you’ll need to initialise
the project with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm init -y
git init
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I suggest that you commit this code to a git repository, so you should
start with a &lt;code&gt;.gitignore&lt;/code&gt; file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch .gitignore

echo &amp;quot;# Project dependencies
.cache
node_modules

# Build directory
public

# Other
.DS_Store
yarn-error.log&amp;quot; &amp;gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok now is a good time to do a &lt;code&gt;git init&lt;/code&gt; and if you’re using VSCode
you’ll see the changes reflected in the sidebar.&lt;/p&gt;&lt;h3 id=&quot;basic-hello-world&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#basic-hello-world&quot; aria-label=&quot;basic hello world permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;basic hello world&lt;/h3&gt;&lt;p&gt;Ok a Gatsby hello world, get started with the bare minimum! Install
the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby react react-dom
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You’re going to need to create a pages directory and add an index
file. You can do that in the terminal by typing the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# -p is to create parent directories too if needed
mkdir -p src/pages
touch src/pages/index.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now you can commence the hello word incantation! In the newly
created &lt;code&gt;index.js&lt;/code&gt; enter the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;

export default () =&amp;gt; {
  return &amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you need to add the Gatsby develop script to the &lt;code&gt;package.json&lt;/code&gt;
file, &lt;code&gt;-p&lt;/code&gt; specifies what port you want to run the project on and &lt;code&gt;-o&lt;/code&gt;
opens a new tab on your default browser, so in this case
&lt;code&gt;localhost:9988&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;dev&amp;quot;: &amp;quot;gatsby develop -p 9988 -o&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok it’s time to run the code! From the terminal type the npm script
command you just created:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note I’m using Yarn for installing all my dependencies and running
scripts, if you prefer you can use npm just bear in mind that the
content on here uses yarn, so swap out commands where needed&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;And with that the “Hello World” incantation is complete 🧙!&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-2vP3ZTDbN1g&quot; src=&quot;https://www.youtube.com/embed/2vP3ZTDbN1g?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;add-content&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-content&quot; aria-label=&quot;add content permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add content&lt;/h2&gt;&lt;p&gt;Ok, now you have the base your blog you’re going to want to add some
content, first up we’re going to get the convention out of the way.
For this how-to, the date format will be a logical way, the most
logical way for a date format is &lt;strong&gt;YYYYMMDD&lt;/strong&gt;, fight me!&lt;/p&gt;&lt;p&gt;So you’re going to structure your posts content in years, in each one
of those you’re going to have another folder relating to the post with
the (correct) date format for the beginning of the file followed by
the title of the post. You could drill into this further if you like
by separating out months and days depending on the volume of posts
going this may be a good approach. In this case and in the examples
provided the convention detailed will be used.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# create multiple directories using curly braces
mkdir -p posts/2019/{2019-06-01-hello-world,2019-06-10-second-post,2019-06-20-third-post}
touch posts/2019/2019-06-01-hello-world/index.mdx
touch posts/2019/2019-06-10-second-post/index.mdx
touch posts/2019/2019-06-20-third-post/index.mdx
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok that’s your posts set up now you need to add some content to them,
each file you have in here should have frontmatter. Frontmatter is a
way to assign properties to the contents, in this case a &lt;code&gt;title&lt;/code&gt;,
published &lt;code&gt;date&lt;/code&gt; and a &lt;code&gt;published&lt;/code&gt; flag (&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;).&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;---
title: Hello World - from mdx!
date: 2019-06-01
published: true
---

# h1 Heading

My first post!!

## h2 Heading

### h3 Heading
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;---
title: Second Post!
date: 2019-06-10
published: true
---

This is my second post!

#### h4 Heading

##### h5 Heading

###### h6 Heading
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;---
title: Third Post!
date: 2019-06-20
published: true
---

This is my third post!

&amp;gt; with a block quote!
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;gatsby-config-api&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#gatsby-config-api&quot; aria-label=&quot;gatsby config api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gatsby config API&lt;/h2&gt;&lt;p&gt;Ok, now you’re going to configure Gatsby so that it can read your
super awesome content you just created. So, first up you need to
create a &lt;code&gt;gatsby-config.js&lt;/code&gt; file, in the terminal create the file:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch gatsby-config.js
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;plugins&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#plugins&quot; aria-label=&quot;plugins permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Plugins&lt;/h2&gt;&lt;p&gt;And now you can add the plugins Gatsby needs to use for sourcing and
displaying the the files you just created.&lt;/p&gt;&lt;h3 id=&quot;gatsby-source-filesystem&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#gatsby-source-filesystem&quot; aria-label=&quot;gatsby source filesystem permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gatsby source filesystem&lt;/h3&gt;&lt;p&gt;The &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-source-filesystem/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-source-filesystem&lt;/a&gt; collects the files on the local
filesystem for use in Gatsby once configured.&lt;/p&gt;&lt;h3 id=&quot;gatsby-plugin-mdx&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#gatsby-plugin-mdx&quot; aria-label=&quot;gatsby plugin mdx permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gatsby plugin MDX&lt;/h3&gt;&lt;p&gt;The &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-mdx/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-plugin-mdx&lt;/a&gt; is what will be allowing us to write JSX in
our Markdown documents and the heart of how the content is displayed
in the blog.&lt;/p&gt;&lt;p&gt;Now is a good time to also add in dependent packages for the Gatsby
plugin MDX which are &lt;code&gt;@mdx-js/mdx&lt;/code&gt; and &lt;code&gt;@mdx-js/react&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;In the terminal install the dependencies:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react gatsby-source-filesystem
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now its time to configure &lt;code&gt;gatsby-config.js&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = {
  siteMetadata: {
    title: `The Localhost Blog`,
    description: `This is my coding blog where I write about my coding journey.`,
  },
  plugins: [
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        extensions: [`.mdx`, `.md`],
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/posts`,
        name: `posts`,
      },
    },
  ],
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;query-data-from-graphql&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#query-data-from-graphql&quot; aria-label=&quot;query data from graphql permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Query data from GraphQL&lt;/h2&gt;&lt;p&gt;Ok now you can see what the &lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-source-filesystem/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-source-filesystem&lt;/a&gt; and
&lt;a href=&quot;https://www.gatsbyjs.org/packages/gatsby-plugin-mdx/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-plugin-mdx&lt;/a&gt; have done for us. You can now go to the Gatsby
GraphQL GraphiQL explorer and check out the data:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  allMdx {
    nodes {
      frontmatter {
        title
        date
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-MPNJu24ad_s&quot; src=&quot;https://www.youtube.com/embed/MPNJu24ad_s?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;site-metadata&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#site-metadata&quot; aria-label=&quot;site metadata permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Site Metadata&lt;/h2&gt;&lt;p&gt;When you want to reuse common pieces of data across the site (for
example, your site title), you can store that data in &lt;code&gt;siteMetadata&lt;/code&gt;,
you touched on this when defining the &lt;code&gt;gatsby-config.js&lt;/code&gt;, now you’re
going to separate this out from the &lt;code&gt;module.exports&lt;/code&gt;, why? It will be
nicer to reason about once the config is filled with plugins. At the
top of &lt;code&gt;gatsby-config.js&lt;/code&gt; add a new object variable for the site
metadata:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const siteMetadata = {
  title: `The Localhost Blog`,
  description: `This is my coding blog where I write about my coding journey.`,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now query the Site Metadata with GraphQL.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  site {
    siteMetadata {
      title
      description
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;site-metadata-hook&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#site-metadata-hook&quot; aria-label=&quot;site metadata hook permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Site metadata hook&lt;/h2&gt;&lt;p&gt;Ok, so, that’s cool n’ all but how am I meant to use it? Well do some
of the code stuff and make a React hook so you can get your site data
in any component you need it.&lt;/p&gt;&lt;p&gt;Create a folder to keep all your hooks in and create a file for our
hook, in the terminal do:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src/hooks
touch src/hooks/useSiteMetadata.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, and in your newly created file were going to use the Gatsby
&lt;code&gt;useStaticQuery&lt;/code&gt; hook to make your own hook:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql, useStaticQuery } from &amp;#x27;gatsby&amp;#x27;

export const useSiteMetadata = () =&amp;gt; {
  const { site } = useStaticQuery(
    graphql`
      query SITE_METADATA_QUERY {
        site {
          siteMetadata {
            title
            description
          }
        }
      }
    `
  )
  return site.siteMetadata
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you can use this hook anywhere in your site, so do that now in
&lt;code&gt;src/pages/index.js&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;

export default () =&amp;gt; {
  const { title, description } = useSiteMetadata()
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;{title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{description}&amp;lt;/p&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-TfycpV4yyqY&quot; src=&quot;https://www.youtube.com/embed/TfycpV4yyqY?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;styling&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#styling&quot; aria-label=&quot;styling permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Styling&lt;/h2&gt;&lt;p&gt;You’re going to use styled-components for styling, styled-components
(for me) help with scoping styles in your components. Time to go over
the basics now.&lt;/p&gt;&lt;h3 id=&quot;install-styled-components&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-styled-components&quot; aria-label=&quot;install styled components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;install styled-components&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-plugin-styled-components styled-components babel-plugin-styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, what was all that I just installed?&lt;/p&gt;&lt;p&gt;The babel plugin is for automatic naming of components to help with
debugging.&lt;/p&gt;&lt;p&gt;The Gatsby plugin is for built-in server-side rendering support.&lt;/p&gt;&lt;h3 id=&quot;configure&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure&quot; aria-label=&quot;configure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure&lt;/h3&gt;&lt;p&gt;Ok, with that detailed explanation out of the way, configure them in
&lt;code&gt;gatsby-config.js&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;{1-4,7,9}&quot;&gt;const siteMetadata = {
  title: `The Localhost Blog`,
  description: `This is my coding blog where I write about my coding journey.`,
}

module.exports = {
  siteMetadata: siteMetadata,
  plugins: [
    `gatsby-plugin-styled-components`,
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        extensions: [`.mdx`, `.md`],
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/posts`,
        name: `posts`,
      },
    },
  ],
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, time to go over a styled component, in &lt;code&gt;index.js&lt;/code&gt; you’re going to
&lt;code&gt;import styled from &amp;#x27;styled-components&amp;#x27;&lt;/code&gt; and create a &lt;code&gt;StyledH1&lt;/code&gt;
variable.&lt;/p&gt;&lt;p&gt;So, you’re using the variable to wrap your &lt;code&gt;{title}&lt;/code&gt; that you’re
destructuring from the &lt;code&gt;useSiteMetadata&lt;/code&gt; hook you made previously.&lt;/p&gt;&lt;p&gt;For this example make it the now iconic Gatsby &lt;code&gt;rebeccapurple&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot; metastring=&quot;{2-3,5-7,10-16}&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;

const StyledH1 = styled.h1`
  color: rebeccapurple;
`

export default () =&amp;gt; {
  const { title, description } = useSiteMetadata()
  return (
    &amp;lt;&amp;gt;
      &amp;lt;StyledH1&amp;gt;{title}&amp;lt;/StyledH1&amp;gt;
      &amp;lt;p&amp;gt;{description}&amp;lt;/p&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is styled-components on a very basic level, basically create the
styling you want for your page elements you’re creating in the JSX.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-41aNkb2tLyg&quot; src=&quot;https://www.youtube.com/embed/41aNkb2tLyg?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;layout&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#layout&quot; aria-label=&quot;layout permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Layout&lt;/h2&gt;&lt;p&gt;Gatsby doesn’t apply any layouts by default but instead uses the way
you can compose React components for the layout, meaning it’s up to
you how you want to layout what your building with Gatsby. In this
guide were going to initially create a basic layout component that
you’ll add to as you go along. For more detail on layout components
take a look at the Gatsby &lt;a href=&quot;https://www.gatsbyjs.org/docs/layout-components/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;layout components&lt;/a&gt; page.&lt;/p&gt;&lt;p&gt;Ok, so now you’re going to refactor the home page
(&lt;code&gt;src/pages/index.js&lt;/code&gt;) a little and make some components for your blog
layout and header. In the terminal create a components directory and a
&lt;code&gt;Header&lt;/code&gt; and &lt;code&gt;Layout&lt;/code&gt; component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src/components
touch src/components/Header.js src/components/Layout.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to move the title and description from &lt;code&gt;src/pages/index.js&lt;/code&gt; to the
newly created &lt;code&gt;src/components/Header.js&lt;/code&gt; component, destructuring
props for the &lt;code&gt;siteTitle&lt;/code&gt; and &lt;code&gt;siteDescription&lt;/code&gt;, you’ll pass these
from the &lt;code&gt;Layout&lt;/code&gt; component to here. You’re going to add Gatsby Link
to this so users can click on the header to go back to the home page.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { Link } from &amp;#x27;gatsby&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

export const Header = ({ siteTitle, siteDescription }) =&amp;gt; (
  &amp;lt;Link to=&amp;quot;/&amp;quot;&amp;gt;
    &amp;lt;h1&amp;gt;{siteTitle}&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;{siteDescription}&amp;lt;/p&amp;gt;
  &amp;lt;/Link&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to the Layout component, this is going to be a basic wrapper
component for now, you’re going to use your site metadata hook for the
title and description and pass them to the header component and return
the children of the wrapper (&lt;code&gt;Layout&lt;/code&gt;).&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;
import { Header } from &amp;#x27;./Header&amp;#x27;

export const Layout = ({ children }) =&amp;gt; {
  const { title, description } = useSiteMetadata()
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Header siteTitle={title} siteDescription={description} /&amp;gt;
      {children}
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to add the slightest of styles for some alignment for
&lt;code&gt;src/components/Layout.js&lt;/code&gt;, create an &lt;code&gt;AppStyles&lt;/code&gt; styled component and
make it the main wrapper of your &lt;code&gt;Layout&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;
import { Header } from &amp;#x27;./Header&amp;#x27;

const AppStyles = styled.main`
  width: 800px;
  margin: 0 auto;
`

export const Layout = ({ children }) =&amp;gt; {
  const { title, description } = useSiteMetadata()
  return (
    &amp;lt;AppStyles&amp;gt;
      &amp;lt;Header siteTitle={title} siteDescription={description} /&amp;gt;
      {children}
    &amp;lt;/AppStyles&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now refactor your homepage (&lt;code&gt;src/pages/index.js&lt;/code&gt;) with &lt;code&gt;Layout&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

export default () =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Layout /&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-Ase7bjxtQ3w&quot; src=&quot;https://www.youtube.com/embed/Ase7bjxtQ3w?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;index-page-posts-query&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#index-page-posts-query&quot; aria-label=&quot;index page posts query permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Index page posts query&lt;/h2&gt;&lt;p&gt;Ok, now you can take a look at getting some of the posts you’ve
created add them to the index page of your blog. You’re going to do
that by creating a graphql query to list out the posts by title, order
by date and add an excerpt of the post.&lt;/p&gt;&lt;p&gt;The query will look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  allMdx {
    nodes {
      id
      excerpt(pruneLength: 250)
      frontmatter {
        title
        date
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you put that into the GraphiQL GUI though you’ll notice that the
posts aren’t in any given order, so now add a sort to this you’ll also
add in a filter for posts that are marked as published or not.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  allMdx(
    sort: { fields: [frontmatter___date], order: DESC }
    filter: { frontmatter: { published: { eq: true } } }
  ) {
    nodes {
      id
      excerpt(pruneLength: 250)
      frontmatter {
        title
        date
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On the homepage (&lt;code&gt;src/pages/index.js&lt;/code&gt;) you’re going to use the query
we just put together to get a list of published posts in date order;
add the following to the &lt;code&gt;index.js&lt;/code&gt; file:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { graphql } from &amp;#x27;gatsby&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

export default ({ data }) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Layout&amp;gt;
        {data.allMdx.nodes.map(({ excerpt, frontmatter }) =&amp;gt; (
          &amp;lt;&amp;gt;
            &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
            &amp;lt;p&amp;gt;{excerpt}&amp;lt;/p&amp;gt;
          &amp;lt;/&amp;gt;
        ))}
      &amp;lt;/Layout&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

export const query = graphql`
  query SITE_INDEX_QUERY {
    allMdx(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { published: { eq: true } } }
    ) {
      nodes {
        id
        excerpt(pruneLength: 250)
        frontmatter {
          title
          date
        }
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Woah! WTF was all that yo!?&lt;/p&gt;&lt;p&gt;Ok, you’re looping through the data passed into the component via the
GraphQL query. Gatsby &lt;code&gt;graphql&lt;/code&gt; runs the query (&lt;code&gt;SITE_INDEX_QUERY&lt;/code&gt;) at
runtime and gives us the results as props to your component via the
&lt;code&gt;data&lt;/code&gt; prop.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-2GDbxZ0mHbM&quot; src=&quot;https://www.youtube.com/embed/2GDbxZ0mHbM?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;slugs-and-paths&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#slugs-and-paths&quot; aria-label=&quot;slugs and paths permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Slugs and Paths&lt;/h2&gt;&lt;p&gt;Gatsby source filesystem will help with the creation of slugs (URL
paths for the posts you’re creating) in Gatsby node you’re going to
create the slugs for your posts.&lt;/p&gt;&lt;p&gt;First up you’re going to need to create a &lt;code&gt;gatsby-node.js&lt;/code&gt; file:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch gatsby-node.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will create the file path (URL) for each of the blog posts.&lt;/p&gt;&lt;p&gt;You’re going to be using the Gatsby Node API &lt;code&gt;onCreateNode&lt;/code&gt; and
destructuring out &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;actions&lt;/code&gt; and &lt;code&gt;getNode&lt;/code&gt; for use in creating
the file locations and associated value.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, actions, getNode }) =&amp;gt; {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to help visualise some of the data being passed into the
components you’re going to use &lt;a href=&quot;https://github.com/wesbos/dump&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dump.js&lt;/a&gt; for debugging the data.
Thanks to Wes Bos for the super handy &lt;a href=&quot;https://github.com/wesbos/dump&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dump.js&lt;/a&gt; component.&lt;/p&gt;&lt;p&gt;To get the component set up, create a &lt;code&gt;Dump.js&lt;/code&gt; file in your
&lt;code&gt;src\components&lt;/code&gt; folder and copypasta the code from the linked GitHub
page.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch src/components/Dump.js
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;

const Dump = props =&amp;gt; (
  &amp;lt;div
    style={{
      fontSize: 20,
      border: &amp;#x27;1px solid #efefef&amp;#x27;,
      padding: 10,
      background: &amp;#x27;white&amp;#x27;,
    }}
  &amp;gt;
    {Object.entries(props).map(([key, val]) =&amp;gt; (
      &amp;lt;pre key={key}&amp;gt;
        &amp;lt;strong style={{ color: &amp;#x27;white&amp;#x27;, background: &amp;#x27;red&amp;#x27; }}&amp;gt;
          {key} 💩
        &amp;lt;/strong&amp;gt;
        {JSON.stringify(val, &amp;#x27;&amp;#x27;, &amp;#x27; &amp;#x27;)}
      &amp;lt;/pre&amp;gt;
    ))}
  &amp;lt;/div&amp;gt;
)

export default Dump
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you can use the &lt;code&gt;Dump&lt;/code&gt; component anywhere in your project. To
demonstrate, use it with the index page &lt;code&gt;data&lt;/code&gt; to see the output.&lt;/p&gt;&lt;p&gt;So in the &lt;code&gt;src/pages/index.js&lt;/code&gt; you’re going to import the Dump
component and pass in the &lt;code&gt;data&lt;/code&gt; prop and see what the output looks
like.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { graphql } from &amp;#x27;gatsby&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import Dump from &amp;#x27;../components/Dump&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

export default ({ data }) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Layout&amp;gt;
        &amp;lt;Dump data={data} /&amp;gt;
        {data.allMdx.nodes.map(({ excerpt, frontmatter }) =&amp;gt; (
          &amp;lt;&amp;gt;
            &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
            &amp;lt;p&amp;gt;{excerpt}&amp;lt;/p&amp;gt;
          &amp;lt;/&amp;gt;
        ))}
      &amp;lt;/Layout&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

export const query = graphql`
  query SITE_INDEX_QUERY {
    allMdx(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { published: { eq: true } } }
    ) {
      nodes {
        id
        excerpt(pruneLength: 250)
        frontmatter {
          title
          date
        }
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-7eZZk7aJnUU&quot; src=&quot;https://www.youtube.com/embed/7eZZk7aJnUU?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;link-paths&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#link-paths&quot; aria-label=&quot;link paths permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Link Paths&lt;/h2&gt;&lt;p&gt;Now you’ve created the paths you can link to them with Gatsby Link.
First you’ll need to add the slug to your &lt;code&gt;SITE_INDEX_QUERY&lt;/code&gt; Then you
can add gatsby &lt;code&gt;Link&lt;/code&gt; to &lt;code&gt;src/pages/index.js&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;You’re also going to create some styled-components for wrapping the
list of posts and each individual post as well.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { graphql, Link } from &amp;#x27;gatsby&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

const IndexWrapper = styled.main``

const PostWrapper = styled.div``

export default ({ data }) =&amp;gt; {
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;IndexWrapper&amp;gt;
        {data.allMdx.nodes.map(
          ({ id, excerpt, frontmatter, fields }) =&amp;gt; (
            &amp;lt;PostWrapper key={id}&amp;gt;
              &amp;lt;Link to={fields.slug}&amp;gt;
                &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
                &amp;lt;p&amp;gt;{excerpt}&amp;lt;/p&amp;gt;
              &amp;lt;/Link&amp;gt;
            &amp;lt;/PostWrapper&amp;gt;
          )
        )}
      &amp;lt;/IndexWrapper&amp;gt;
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query SITE_INDEX_QUERY {
    allMdx(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { published: { eq: true } } }
    ) {
      nodes {
        id
        excerpt(pruneLength: 250)
        frontmatter {
          title
          date
        }
        fields {
          slug
        }
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;adding-a-blog-post-template&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#adding-a-blog-post-template&quot; aria-label=&quot;adding a blog post template permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding a Blog Post Template&lt;/h2&gt;&lt;p&gt;Now you have the links pointing to the blog posts you currently have
no file associated with the path, so clicking a link will give you a
404 and the built in gatsby 404 will list all the pages available in
the project, currently only the &lt;code&gt;/&lt;/code&gt; index/homepage.&lt;/p&gt;&lt;p&gt;So, for each one of your blog posts you’re going to use a template
that will contain, the information you need to make up your blog post.
To start, create a &lt;code&gt;templates&lt;/code&gt; directory and template file for that
with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir -p src/templates
touch src/templates/blogPostTemplate.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For now you’re going to scaffold out a basic template, you’ll be
adding data to this shortly:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from &amp;#x27;react&amp;#x27;

export default () =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;post here&amp;lt;/p&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To populate the template you’ll need to use Gatsby node to create your
pages.&lt;/p&gt;&lt;p&gt;Gatsby Node has many internal APIs available to us, for this example
you’re going to be using the &lt;code&gt;createPages&lt;/code&gt; API.&lt;/p&gt;&lt;p&gt;More details on Gatsby &lt;code&gt;createPages&lt;/code&gt; API can be found on the Gatsby
docs, details here:
&lt;a href=&quot;https://www.gatsbyjs.org/docs/node-apis/#createPages&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.gatsbyjs.org/docs/node-apis/#createPages&lt;/a&gt;&lt;/p&gt;&lt;p&gt;In your &lt;code&gt;gatsby-node.js&lt;/code&gt; file you’re going to add in the following in
addition to the &lt;code&gt;onCreateNode&lt;/code&gt; export you did earlier.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { createFilePath } = require(`gatsby-source-filesystem`)
const path = require(`path`)

exports.createPages = ({ actions, graphql }) =&amp;gt; {
  const { createPage } = actions
  const blogPostTemplate = path.resolve(
    &amp;#x27;src/templates/blogPostTemplate.js&amp;#x27;
  )

  return graphql(`
    {
      allMdx {
        nodes {
          fields {
            slug
          }
          frontmatter {
            title
          }
        }
      }
    }
  `).then(result =&amp;gt; {
    if (result.errors) {
      throw result.errors
    }

    const posts = result.data.allMdx.nodes

    // create page for each mdx file
    posts.forEach(post =&amp;gt; {
      createPage({
        path: post.fields.slug,
        component: blogPostTemplate,
        context: {
          slug: post.fields.slug,
        },
      })
    })
  })
}

exports.onCreateNode = ({ node, actions, getNode }) =&amp;gt; {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the part that you need to pay particular attention to right now is
the &lt;code&gt;.forEach&lt;/code&gt; loop where you’re using the &lt;code&gt;createPage&lt;/code&gt; function we
destructured from the &lt;code&gt;actions&lt;/code&gt; object.&lt;/p&gt;&lt;p&gt;This is where you pass the data needed by &lt;code&gt;blogPostTemplate&lt;/code&gt; you
defined earlier. You’re going to be adding more to the &lt;code&gt;context&lt;/code&gt; for
post navigation soon.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// create page for each mdx node
posts.forEach(post =&amp;gt; {
  createPage({
    path: post.fields.slug,
    component: blogPostTemplate,
    context: {
      slug: post.fields.slug,
    },
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-OyQfIvXr4YA&quot; src=&quot;https://www.youtube.com/embed/OyQfIvXr4YA?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;build-out-blog-post-template&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#build-out-blog-post-template&quot; aria-label=&quot;build out blog post template permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Build out Blog Post Template&lt;/h2&gt;&lt;p&gt;Now you’re going to take the context information passed to the
&lt;code&gt;blogPostTemplate.js&lt;/code&gt; to make the blog post page.&lt;/p&gt;&lt;p&gt;This is similar to the &lt;code&gt;index.js&lt;/code&gt; homepage whereas there’s GraphQL
data used to create the page but in this instance the template uses a
variable (also known as a parameter or an identifier) so you can query
data specific to that given variable.&lt;/p&gt;&lt;p&gt;Now quickly dig into that with a demo. In the GraphiQL GUI, create a
named query and define the variable you’re going to pass in:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;query PostBySlug($slug: String!) {
  mdx(fields: { slug: { eq: $slug } }) {
    frontmatter {
      title
      date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here you’re defining the variable as slug with the &lt;code&gt;$&lt;/code&gt; denoting that
it’s a variable, you also need to define the variable type as (in this
case) &lt;code&gt;String!&lt;/code&gt; the exclamation after the type means that it has to be
a string being passed into the query.&lt;/p&gt;&lt;p&gt;Using &lt;code&gt;mdx&lt;/code&gt; you’re going to filter on &lt;code&gt;fields&lt;/code&gt; where the &lt;code&gt;slug&lt;/code&gt;
matches the variable being passed into the query.&lt;/p&gt;&lt;p&gt;Running the query now will show an error as there’s no variable being
fed into the query. If you look to the bottom of the query pane you
should notice &lt;code&gt;QUERY VARIABLES&lt;/code&gt;, click on that to bring up the
variables pane.&lt;/p&gt;&lt;p&gt;This is where you can add in one of the post paths you created
earlier, if you have your dev server up and running go to one of the
posts and take the path and paste it into the quotes &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; and try
running the query again.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  &amp;quot;slug&amp;quot;: &amp;quot;/2019/2019-06-20-third-post/&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Time to use that data to make the post, you’re going to add &lt;code&gt;body&lt;/code&gt; to
the query and have that at the bottom of your page file.&lt;/p&gt;&lt;p&gt;Right now you’re going to add create a simple react component that
will display the data you have queried.&lt;/p&gt;&lt;p&gt;Destructuring the &lt;code&gt;frontmatter&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; from the GraphQL query,
you’ll get the Title and the Data from the frontmatter object and wrap
the &lt;code&gt;body&lt;/code&gt; in the &lt;code&gt;MDXRenderer&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { graphql } from &amp;#x27;gatsby&amp;#x27;
import { MDXRenderer } from &amp;#x27;gatsby-plugin-mdx&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

export default ({ data }) =&amp;gt; {
  const { frontmatter, body } = data.mdx
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
      &amp;lt;MDXRenderer&amp;gt;{body}&amp;lt;/MDXRenderer&amp;gt;
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query PostsBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      body
      frontmatter {
        title
        date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you haven’t done so already now would be a good time to restart
your dev server.&lt;/p&gt;&lt;p&gt;Now you can click on one of the post links and see your blog post
template in all it’s basic glory!&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-S7cnkRoCjsc&quot; src=&quot;https://www.youtube.com/embed/S7cnkRoCjsc?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;previous-and-next&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#previous-and-next&quot; aria-label=&quot;previous and next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Previous and Next&lt;/h2&gt;&lt;p&gt;Coolio! Now you have your basic ass blog where you can list available
post and click a link to see the full post in a predefined template.
Once you’re in a post you have to navigate back to the home page to
pick out a new post to read. In this section you’re going to work on
adding in some previous and next navigation.&lt;/p&gt;&lt;p&gt;Remember the &lt;code&gt;.forEach&lt;/code&gt; snippet you looked at earlier? That’s where
you’re going to pass some additional context to the page by selecting
out the previous and next posts.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// create page for each mdx node
posts.forEach((post, index) =&amp;gt; {
  const previous =
    index === posts.length - 1 ? null : posts[index + 1]
  const next = index === 0 ? null : posts[index - 1]

  createPage({
    path: post.fields.slug,
    component: blogPostTemplate,
    context: {
      slug: post.fields.slug,
      previous,
      next,
    },
  })
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So this should now match up with the query you have on the homepage
(&lt;code&gt;src/pages/index.js&lt;/code&gt;) except you currently have no filter or sort
applied here so do that now in &lt;code&gt;gatsby-node.js&lt;/code&gt; and apply the same
filters as on the homepage query:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { createFilePath } = require(`gatsby-source-filesystem`)
const path = require(`path`)

exports.createPages = ({ actions, graphql }) =&amp;gt; {
  const { createPage } = actions
  const blogPostTemplate = path.resolve(
    &amp;#x27;src/templates/blogPostTemplate.js&amp;#x27;
  )

  return graphql(`
    {
      allMdx(
        sort: { fields: [frontmatter___date], order: DESC }
        filter: { frontmatter: { published: { eq: true } } }
      ) {
        nodes {
          fields {
            slug
          }
          frontmatter {
            title
          }
        }
      }
    }
  `).then(result =&amp;gt; {
    if (result.errors) {
      throw result.errors
    }

    const posts = result.data.allMdx.nodes

    // create page for each mdx node
    posts.forEach((post, index) =&amp;gt; {
      const previous =
        index === posts.length - 1 ? null : posts[index + 1]
      const next = index === 0 ? null : posts[index - 1]

      createPage({
        path: post.fields.slug,
        component: blogPostTemplate,
        context: {
          slug: post.fields.slug,
          previous,
          next,
        },
      })
    })
  })
}

exports.onCreateNode = ({ node, actions, getNode }) =&amp;gt; {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you will be able to expose the &lt;code&gt;previous&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; objects
passed in as context from Gatsby node.&lt;/p&gt;&lt;p&gt;You can destructure &lt;code&gt;previous&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; from &lt;code&gt;pageContext&lt;/code&gt; and for
now pop them into your super handy &lt;code&gt;Dump&lt;/code&gt; component to take a look at
their contents.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { graphql } from &amp;#x27;gatsby&amp;#x27;
import { MDXRenderer } from &amp;#x27;gatsby-plugin-mdx&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import Dump from &amp;#x27;../components/Dump&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

export default ({ data, pageContext }) =&amp;gt; {
  const { frontmatter, body } = data.mdx
  const { previous, next } = pageContext
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;Dump previous={previous} /&amp;gt;
      &amp;lt;Dump next={next} /&amp;gt;
      &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
      &amp;lt;MDXRenderer&amp;gt;{body}&amp;lt;/MDXRenderer&amp;gt;
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query PostsBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      body
      frontmatter {
        title
        date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add in previous and next navigation, this is a couple of ternary
operations, if the variable is empty then return &lt;code&gt;null&lt;/code&gt; else render a
Gatsby &lt;code&gt;Link&lt;/code&gt; component with the page slug and the frontmatter title:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { graphql, Link } from &amp;#x27;gatsby&amp;#x27;
import { MDXRenderer } from &amp;#x27;gatsby-plugin-mdx&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import Dump from &amp;#x27;../components/Dump&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

export default ({ data, pageContext }) =&amp;gt; {
  const { frontmatter, body } = data.mdx
  const { previous, next } = pageContext
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;Dump previous={previous} /&amp;gt;
      &amp;lt;Dump next={next} /&amp;gt;
      &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
      &amp;lt;MDXRenderer&amp;gt;{body}&amp;lt;/MDXRenderer&amp;gt;
      {previous === false ? null : (
        &amp;lt;&amp;gt;
          {previous &amp;amp;&amp;amp; (
            &amp;lt;Link to={previous.fields.slug}&amp;gt;
              &amp;lt;p&amp;gt;{previous.frontmatter.title}&amp;lt;/p&amp;gt;
            &amp;lt;/Link&amp;gt;
          )}
        &amp;lt;/&amp;gt;
      )}
      {next === false ? null : (
        &amp;lt;&amp;gt;
          {next &amp;amp;&amp;amp; (
            &amp;lt;Link to={next.fields.slug}&amp;gt;
              &amp;lt;p&amp;gt;{next.frontmatter.title}&amp;lt;/p&amp;gt;
            &amp;lt;/Link&amp;gt;
          )}
        &amp;lt;/&amp;gt;
      )}
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query PostsBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      body
      frontmatter {
        title
        date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-AjLimYEwDOk&quot; src=&quot;https://www.youtube.com/embed/AjLimYEwDOk?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;code-blocks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#code-blocks&quot; aria-label=&quot;code blocks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code Blocks&lt;/h2&gt;&lt;p&gt;Now to add some syntax highlighting for adding code blocks to your
blog pages. To do that you’re going to add dependencies for
&lt;a href=&quot;https://github.com/FormidableLabs/prism-react-renderer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;prism-react-renderer&lt;/a&gt; and &lt;a href=&quot;https://github.com/FormidableLabs/react-live&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-live&lt;/a&gt; and you’ll also create the
files you’re going to need to use them:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add prism-react-renderer react-live
touch root-wrapper.js gatsby-ssr.js gatsby-browser.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You’ll come onto &lt;code&gt;react-live&lt;/code&gt; soon for now you’re going to get
&lt;code&gt;prism-react-render&lt;/code&gt; up and running for syntax highlighting for any
code you’re going to add to the blog, but before that you’re going to
go over the root wrapper concept.&lt;/p&gt;&lt;p&gt;So, to change the rendering of a page element, such as a heading or a
code block you’re going to need to use the &lt;code&gt;MDXProvider&lt;/code&gt;, the
&lt;code&gt;MDXProvider&lt;/code&gt; is a component you can use anywhere higher in the React
component tree than the MDX content you want to render.&lt;/p&gt;&lt;p&gt;Gatsby browser and a Gatsby SSR both have &lt;code&gt;wrapRootElement&lt;/code&gt; available
to them and that is as high up the tree as you can get so you’re going
to create the &lt;code&gt;root-wrapper.js&lt;/code&gt; file and add out elements you want to
override there and import it into both &lt;code&gt;gatsby-browser.js&lt;/code&gt; and
&lt;code&gt;gatsby-ssr.js&lt;/code&gt; so you’re not duplicating code.&lt;/p&gt;&lt;p&gt;Before you go any further I want to add that there is a top quality
&lt;a href=&quot;https://egghead.io/lessons/vue-js-introduction-to-mdx?pl=building-websites-with-mdx-and-gatsby-161e9529&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;egghead.io playlist&lt;/a&gt; resource for using MDX with Gatsby by Chris
&lt;a href=&quot;https://twitter.com/chrisbiscardi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chris Biscardi&lt;/a&gt; there’s a ton of useful information in there on MDX
in Gatsby.&lt;/p&gt;&lt;p&gt;Ok, first up you’re going to import the &lt;code&gt;root-wrapper.js&lt;/code&gt; file into
both &lt;code&gt;gatsby-browser.js&lt;/code&gt; and &lt;code&gt;gatsby-ssr.js&lt;/code&gt;, in both code modules
paste the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { wrapRootElement as wrap } from &amp;#x27;./root-wrapper&amp;#x27;

export const wrapRootElement = wrap
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now you can work on the code that will be used in both modules.
MDX allows you to control the rendering of page elements in your
markdown. &lt;code&gt;MDXProvider&lt;/code&gt; is used to give to give React components to
override the markdown page elements.&lt;/p&gt;&lt;p&gt;Quick demonstration, in &lt;code&gt;root-wrapper.js&lt;/code&gt; add the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { MDXProvider } from &amp;#x27;@mdx-js/react&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

const components = {
  h2: ({ children }) =&amp;gt; (
    &amp;lt;h2 style={{ color: &amp;#x27;rebeccapurple&amp;#x27; }}&amp;gt;{children}&amp;lt;/h2&amp;gt;
  ),
  &amp;#x27;p.inlineCode&amp;#x27;: props =&amp;gt; (
    &amp;lt;code style={{ backgroundColor: &amp;#x27;lightgray&amp;#x27; }} {...props} /&amp;gt;
  ),
}

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;MDXProvider components={components}&amp;gt;{element}&amp;lt;/MDXProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You’re now overriding any &lt;code&gt;h2&lt;/code&gt; in your rendered markdown along with
any &lt;code&gt;code&lt;/code&gt; blocks (that’s words wrapped in &lt;code&gt;`backticks`&lt;/code&gt;).&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-kN8ld7iLQso&quot; src=&quot;https://www.youtube.com/embed/kN8ld7iLQso?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Ok, now for the syntax highlighting, create a post with a block of
code in it:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir posts/2019-07-01-code-blocks
touch posts/2019-07-01-code-blocks/index.mdx
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Paste in some content:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;---
title: Code Blocks
date: 2019-07-01
published: true
---

## Yes! Some code!

Here is the `Dump` component!

```jsx
import React from &amp;#x27;react&amp;#x27;

const Dump = props =&amp;gt; (
  &amp;lt;div
    style={{
      fontSize: 20,
      border: &amp;#x27;1px solid #efefef&amp;#x27;,
      padding: 10,
      background: &amp;#x27;white&amp;#x27;,
    }}
  &amp;gt;
    {Object.entries(props).map(([key, val]) =&amp;gt; (
      &amp;lt;pre key={key}&amp;gt;
        &amp;lt;strong style={{ color: &amp;#x27;white&amp;#x27;, background: &amp;#x27;red&amp;#x27; }}&amp;gt;
          {key} 💩
        &amp;lt;/strong&amp;gt;
        {JSON.stringify(val, &amp;#x27;&amp;#x27;, &amp;#x27; &amp;#x27;)}
      &amp;lt;/pre&amp;gt;
    ))}
  &amp;lt;/div&amp;gt;
)

export default Dump
```
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, if you go to the &lt;a href=&quot;https://github.com/FormidableLabs/prism-react-renderer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;prism-react-renderer&lt;/a&gt; GitHub page and copy the
example code into &lt;code&gt;root-wrapper.js&lt;/code&gt; for the &lt;code&gt;pre&lt;/code&gt; element.&lt;/p&gt;&lt;p&gt;You’re going to copy the provided code for highlighting to validate it
works.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { MDXProvider } from &amp;#x27;@mdx-js/react&amp;#x27;
import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

const components = {
  h2: ({ children }) =&amp;gt; (
    &amp;lt;h2 style={{ color: &amp;#x27;rebeccapurple&amp;#x27; }}&amp;gt;{children}&amp;lt;/h2&amp;gt;
  ),
  &amp;#x27;p.inlineCode&amp;#x27;: props =&amp;gt; (
    &amp;lt;code style={{ backgroundColor: &amp;#x27;lightgray&amp;#x27; }} {...props} /&amp;gt;
  ),
  pre: props =&amp;gt; (
    &amp;lt;Highlight
      {...defaultProps}
      code={`
        (function someDemo() {
          var test = &amp;quot;Hello World!&amp;quot;;
          console.log(test);
        })();

        return () =&amp;gt; &amp;lt;App /&amp;gt;;
      `}
      language=&amp;quot;jsx&amp;quot;
    &amp;gt;
      {({
        className,
        style,
        tokens,
        getLineProps,
        getTokenProps,
      }) =&amp;gt; (
        &amp;lt;pre className={className} style={style}&amp;gt;
          {tokens.map((line, i) =&amp;gt; (
            &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
              {line.map((token, key) =&amp;gt; (
                &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/pre&amp;gt;
      )}
    &amp;lt;/Highlight&amp;gt;
  ),
}

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;MDXProvider components={components}&amp;gt;{element}&amp;lt;/MDXProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, cool! Now you want to replace the pasted in code example with
the props of the child component of the pre component, you can do that
with &lt;code&gt;props.children.props.children.trim()&lt;/code&gt; 🙃.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { MDXProvider } from &amp;#x27;@mdx-js/react&amp;#x27;
import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

const components = {
  pre: props =&amp;gt; (
    &amp;lt;Highlight
      {...defaultProps}
      code={props.children.props.children.trim()}
      language=&amp;quot;jsx&amp;quot;
    &amp;gt;
      {({
        className,
        style,
        tokens,
        getLineProps,
        getTokenProps,
      }) =&amp;gt; (
        &amp;lt;pre className={className} style={style}&amp;gt;
          {tokens.map((line, i) =&amp;gt; (
            &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
              {line.map((token, key) =&amp;gt; (
                &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/pre&amp;gt;
      )}
    &amp;lt;/Highlight&amp;gt;
  ),
}

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;MDXProvider components={components}&amp;gt;{element}&amp;lt;/MDXProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then to match the language, for now you’re going to add in a &lt;code&gt;matches&lt;/code&gt;
function to match the language class assigned to the code block.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { MDXProvider } from &amp;#x27;@mdx-js/react&amp;#x27;
import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

const components = {
  h2: ({ children }) =&amp;gt; (
    &amp;lt;h2 style={{ color: &amp;#x27;rebeccapurple&amp;#x27; }}&amp;gt;{children}&amp;lt;/h2&amp;gt;
  ),
  &amp;#x27;p.inlineCode&amp;#x27;: props =&amp;gt; (
    &amp;lt;code style={{ backgroundColor: &amp;#x27;lightgray&amp;#x27; }} {...props} /&amp;gt;
  ),
  pre: props =&amp;gt; {
    const className = props.children.props.className || &amp;#x27;&amp;#x27;
    const matches = className.match(/language-(?&amp;lt;lang&amp;gt;.*)/)
    return (
      &amp;lt;Highlight
        {...defaultProps}
        code={props.children.props.children.trim()}
        language={
          matches &amp;amp;&amp;amp; matches.groups &amp;amp;&amp;amp; matches.groups.lang
            ? matches.groups.lang
            : &amp;#x27;&amp;#x27;
        }
      &amp;gt;
        {({
          className,
          style,
          tokens,
          getLineProps,
          getTokenProps,
        }) =&amp;gt; (
          &amp;lt;pre className={className} style={style}&amp;gt;
            {tokens.map((line, i) =&amp;gt; (
              &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
                {line.map((token, key) =&amp;gt; (
                  &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
                ))}
              &amp;lt;/div&amp;gt;
            ))}
          &amp;lt;/pre&amp;gt;
        )}
      &amp;lt;/Highlight&amp;gt;
    )
  },
}

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;MDXProvider components={components}&amp;gt;{element}&amp;lt;/MDXProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/FormidableLabs/prism-react-renderer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;prism-react-renderer&lt;/a&gt; comes with additional themes over the default
theme which is &lt;a href=&quot;https://github.com/FormidableLabs/prism-react-renderer/blob/master/themes/duotoneDark.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;duotoneDark&lt;/a&gt; you’re going to use &lt;a href=&quot;https://github.com/FormidableLabs/prism-react-renderer/blob/master/themes/nightOwl.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;nightOwl&lt;/a&gt; in this
example, feel free to take a look at &lt;a href=&quot;https://github.com/FormidableLabs/prism-react-renderer/blob/master/themes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;the other examples&lt;/a&gt; if you like.&lt;/p&gt;&lt;p&gt;Import the &lt;code&gt;theme&lt;/code&gt; then use it in the props of the &lt;code&gt;Highlight&lt;/code&gt;
component.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { MDXProvider } from &amp;#x27;@mdx-js/react&amp;#x27;
import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import theme from &amp;#x27;prism-react-renderer/themes/nightOwl&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

const components = {
  pre: props =&amp;gt; {
    const className = props.children.props.className || &amp;#x27;&amp;#x27;
    const matches = className.match(/language-(?&amp;lt;lang&amp;gt;.*)/)

    return (
      &amp;lt;Highlight
        {...defaultProps}
        code={props.children.props.children.trim()}
        language={
          matches &amp;amp;&amp;amp; matches.groups &amp;amp;&amp;amp; matches.groups.lang
            ? matches.groups.lang
            : &amp;#x27;&amp;#x27;
        }
        theme={theme}
      &amp;gt;
        {({
          className,
          style,
          tokens,
          getLineProps,
          getTokenProps,
        }) =&amp;gt; (
          &amp;lt;pre className={className} style={style}&amp;gt;
            {tokens.map((line, i) =&amp;gt; (
              &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
                {line.map((token, key) =&amp;gt; (
                  &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
                ))}
              &amp;lt;/div&amp;gt;
            ))}
          &amp;lt;/pre&amp;gt;
        )}
      &amp;lt;/Highlight&amp;gt;
    )
  },
}

export const wrapRootElement = ({ element }) =&amp;gt; (
  &amp;lt;MDXProvider components={components}&amp;gt;{element}&amp;lt;/MDXProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-k6gI3jVxjKg&quot; src=&quot;https://www.youtube.com/embed/k6gI3jVxjKg?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Ok, now time to abstract this out into it’s own component so your
&lt;code&gt;root-wrapper.js&lt;/code&gt; isn’t so crowded.&lt;/p&gt;&lt;p&gt;Make a &lt;code&gt;Code.js&lt;/code&gt; component, move the code from &lt;code&gt;root-wrapper.js&lt;/code&gt; into
there&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;touch src/components/Code.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Remember this?&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Cool, cool! Now you want to replace the pasted in code example with
the props of the child component of the pre component, you can do
that with &lt;code&gt;props.children.props.children.trim()&lt;/code&gt; 🙃.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;If that ☝ makes no real amount of sense for you (I’ve had to read it
many, many times myself), don’t worry, now you’re going to dig into
that a bit more for the creation of the code block component.&lt;/p&gt;&lt;p&gt;So, for now in the &lt;code&gt;components&lt;/code&gt; you’re adding into the &lt;code&gt;MDXProvider&lt;/code&gt;,
take a look at the &lt;code&gt;props&lt;/code&gt; coming into the &lt;code&gt;pre&lt;/code&gt; element.&lt;/p&gt;&lt;p&gt;Comment out the code you added earlier and add in a &lt;code&gt;console.log&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;pre: props =&amp;gt; {
  console.log(&amp;#x27;=====================&amp;#x27;)
  console.log(props)
  console.log(&amp;#x27;=====================&amp;#x27;)
  return &amp;lt;pre /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if you pop open the developer tools of your browser you can see
the output.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{children: {…}}
  children:
    $$typeof: Symbol(react.element)
    key: null
    props: {parentName: &amp;quot;pre&amp;quot;, className: &amp;quot;language-jsx&amp;quot;, originalType: &amp;quot;code&amp;quot;, mdxType: &amp;quot;code&amp;quot;, children: &amp;quot;import React from &amp;#x27;react&amp;#x27;↵↵const Dump = props =&amp;gt; (…  &amp;lt;/pre&amp;gt;↵    ))}↵  &amp;lt;/div&amp;gt;↵)↵↵export default Dump↵&amp;quot;}
    ref: null
    type: ƒ (re....
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you drill into the props of that output you can see the &lt;code&gt;children&lt;/code&gt;
of those props, if you take a look at the contents of that you will
see that it is the code string for your code block, this is what
you’re going to be passing into the &lt;code&gt;Code&lt;/code&gt; component you’re about to
create. Other properties to note here are the &lt;code&gt;className&lt;/code&gt; and
&lt;code&gt;mdxType&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;So, take the code you used earlier for &lt;code&gt;Highlight&lt;/code&gt;, everything inside
and including the &lt;code&gt;return&lt;/code&gt; statement and paste it into the &lt;code&gt;Code.js&lt;/code&gt;
module you created earlier.&lt;/p&gt;&lt;p&gt;&lt;code&gt;Highlight&lt;/code&gt; requires several props:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;lt;Highlight
  {...defaultProps}
  code={codeString}
  language={language}
  theme={theme}
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;Code&lt;/code&gt; module should look something like this now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import theme from &amp;#x27;prism-react-renderer/themes/nightOwl&amp;#x27;
import React from &amp;#x27;react&amp;#x27;

const Code = ({ codeString, language }) =&amp;gt; {
  return (
    &amp;lt;Highlight
      {...defaultProps}
      code={codeString}
      language={language}
      theme={theme}
    &amp;gt;
      {({
        className,
        style,
        tokens,
        getLineProps,
        getTokenProps,
      }) =&amp;gt; (
        &amp;lt;pre className={className} style={style}&amp;gt;
          {tokens.map((line, i) =&amp;gt; (
            &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
              {line.map((token, key) =&amp;gt; (
                &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/pre&amp;gt;
      )}
    &amp;lt;/Highlight&amp;gt;
  )
}

export default Code
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Back to the &lt;code&gt;root-wrapper&lt;/code&gt; where you’re going to pass the &lt;code&gt;props&lt;/code&gt;
needed to the &lt;code&gt;Code&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;The first check you’re going to do is if the &lt;code&gt;mdxType&lt;/code&gt; is &lt;code&gt;code&lt;/code&gt; then
you can get the additional props you need to pass to your &lt;code&gt;Code&lt;/code&gt;
component.&lt;/p&gt;&lt;p&gt;You’re going to get &lt;code&gt;defaultProps&lt;/code&gt; and the &lt;code&gt;theme&lt;/code&gt; from
&lt;code&gt;prism-react-renderer&lt;/code&gt; so all that’s needed is the &lt;code&gt;code&lt;/code&gt; and
&lt;code&gt;language&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;codeString&lt;/code&gt; you can get from the &lt;code&gt;props&lt;/code&gt;, &lt;code&gt;children&lt;/code&gt; by
destructuring from the &lt;code&gt;props&lt;/code&gt; being passed into the &lt;code&gt;pre&lt;/code&gt; element.
The &lt;code&gt;language&lt;/code&gt; can either be the tag assigned to the meta property of
the backticks, like &lt;code&gt;js&lt;/code&gt;, &lt;code&gt;jsx&lt;/code&gt; or equally empty, so you check for
that with some JavaScript and also remove the &lt;code&gt;language-&lt;/code&gt; prefix, then
pass in the elements &lt;code&gt;{...props}&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;pre: ({ children: { props } }) =&amp;gt; {
  if (props.mdxType === &amp;#x27;code&amp;#x27;) {
    return (
      &amp;lt;Code
        codeString={props.children.trim()}
        language={
          props.className &amp;amp;&amp;amp; props.className.replace(&amp;#x27;language-&amp;#x27;, &amp;#x27;&amp;#x27;)
        }
        {...props}
      /&amp;gt;
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-m0tWxa9Ip5E&quot; src=&quot;https://www.youtube.com/embed/m0tWxa9Ip5E?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;Ok, now you’re back to where you were before abstracting out the
&lt;code&gt;Highlight&lt;/code&gt; component to it’s own module. Add some additional styles
with &lt;code&gt;styled-components&lt;/code&gt; and replace the &lt;code&gt;pre&lt;/code&gt; with a styled &lt;code&gt;Pre&lt;/code&gt; and
you can also add in some line numbers with a styled span and style
that as well.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import theme from &amp;#x27;prism-react-renderer/themes/nightOwl&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

export const Pre = styled.pre`
  text-align: left;
  margin: 1em 0;
  padding: 0.5em;
  overflow-x: auto;
  border-radius: 3px;

  &amp;amp; .token-line {
    line-height: 1.3em;
    height: 1.3em;
  }
  font-family: &amp;#x27;Courier New&amp;#x27;, Courier, monospace;
`

export const LineNo = styled.span`
  display: inline-block;
  width: 2em;
  user-select: none;
  opacity: 0.3;
`

const Code = ({ codeString, language, ...props }) =&amp;gt; {
  return (
    &amp;lt;Highlight
      {...defaultProps}
      code={codeString}
      language={language}
      theme={theme}
    &amp;gt;
      {({
        className,
        style,
        tokens,
        getLineProps,
        getTokenProps,
      }) =&amp;gt; (
        &amp;lt;Pre className={className} style={style}&amp;gt;
          {tokens.map((line, i) =&amp;gt; (
            &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
              &amp;lt;LineNo&amp;gt;{i + 1}&amp;lt;/LineNo&amp;gt;
              {line.map((token, key) =&amp;gt; (
                &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/Pre&amp;gt;
      )}
    &amp;lt;/Highlight&amp;gt;
  )
}

export default Code
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-PPH153kWpqc&quot; src=&quot;https://www.youtube.com/embed/PPH153kWpqc?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h3 id=&quot;copy-code-to-clipboard&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#copy-code-to-clipboard&quot; aria-label=&quot;copy code to clipboard permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Copy code to clipboard&lt;/h3&gt;&lt;p&gt;What if you had some way of getting that props code string into the
clipboard?&lt;/p&gt;&lt;p&gt;I had a look around and found the majority of the components available
for this sort of thing expected an input until &lt;a href=&quot;https://github.com/gatsbyjs/gatsby/blob/master/www/src/utils/copy-to-clipboard.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this&lt;/a&gt; in the Gatsby
source code. Which is creating the input for you 👌&lt;/p&gt;&lt;p&gt;So, create a &lt;code&gt;utils&lt;/code&gt; directory and the &lt;code&gt;copy-to-clipboard.js&lt;/code&gt; file and
add in the code from the Gatsby sourcue code.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src/utils
touch src/utils/copy-to-clipboard.js
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// https://github.com/gatsbyjs/gatsby/blob/master/www/src/utils/copy-to-clipboard.js

export const copyToClipboard = str =&amp;gt; {
  const clipboard = window.navigator.clipboard
  /*
   * fallback to older browsers (including Safari)
   * if clipboard API not supported
   */
  if (!clipboard || typeof clipboard.writeText !== `function`) {
    const textarea = document.createElement(`textarea`)
    textarea.value = str
    textarea.setAttribute(`readonly`, true)
    textarea.setAttribute(`contenteditable`, true)
    textarea.style.position = `absolute`
    textarea.style.left = `-9999px`
    document.body.appendChild(textarea)
    textarea.select()
    const range = document.createRange()
    const sel = window.getSelection()
    sel.removeAllRanges()
    sel.addRange(range)
    textarea.setSelectionRange(0, textarea.value.length)
    document.execCommand(`copy`)
    document.body.removeChild(textarea)

    return Promise.resolve(true)
  }

  return clipboard.writeText(str)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you’re going to want a way to trigger copying the code to the
clipboard.&lt;/p&gt;&lt;p&gt;Lets create a styled button but first add a &lt;code&gt;position: relative;&lt;/code&gt; to
the &lt;code&gt;Pre&lt;/code&gt; component which will let us position the styled button:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const CopyCode = styled.button`
  position: absolute;
  right: 0.25rem;
  border: 0;
  border-radius: 3px;
  margin: 0.25em;
  opacity: 0.3;
  &amp;amp;:hover {
    opacity: 1;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now you need to use the &lt;code&gt;copyToClipboard&lt;/code&gt; function in the
&lt;code&gt;onClick&lt;/code&gt; of the button:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import theme from &amp;#x27;prism-react-renderer/themes/nightOwl&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { copyToClipboard } from &amp;#x27;../utils/copy-to-clipboard&amp;#x27;

export const Pre = styled.pre`
  text-align: left;
  margin: 1rem 0;
  padding: 0.5rem;
  overflow-x: auto;
  border-radius: 3px;

  &amp;amp; .token-line {
    line-height: 1.3rem;
    height: 1.3rem;
  }
  font-family: &amp;#x27;Courier New&amp;#x27;, Courier, monospace;
  position: relative;
`

export const LineNo = styled.span`
  display: inline-block;
  width: 2rem;
  user-select: none;
  opacity: 0.3;
`

const CopyCode = styled.button`
  position: absolute;
  right: 0.25rem;
  border: 0;
  border-radius: 3px;
  margin: 0.25em;
  opacity: 0.3;
  &amp;amp;:hover {
    opacity: 1;
  }
`

const Code = ({ codeString, language }) =&amp;gt; {
  const handleClick = () =&amp;gt; {
    copyToClipboard(codeString)
  }

  return (
    &amp;lt;Highlight
      {...defaultProps}
      code={codeString}
      language={language}
      theme={theme}
    &amp;gt;
      {({
        className,
        style,
        tokens,
        getLineProps,
        getTokenProps,
      }) =&amp;gt; (
        &amp;lt;Pre className={className} style={style}&amp;gt;
          &amp;lt;CopyCode onClick={handleClick}&amp;gt;Copy&amp;lt;/CopyCode&amp;gt;
          {tokens.map((line, i) =&amp;gt; (
            &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
              &amp;lt;LineNo&amp;gt;{i + 1}&amp;lt;/LineNo&amp;gt;
              {line.map((token, key) =&amp;gt; (
                &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/Pre&amp;gt;
      )}
    &amp;lt;/Highlight&amp;gt;
  )
}

export default Code
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-j-EINXVe2WA&quot; src=&quot;https://www.youtube.com/embed/j-EINXVe2WA?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;react-live&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#react-live&quot; aria-label=&quot;react live permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;React live&lt;/h2&gt;&lt;p&gt;So with React Live you need to add two snippets to your &lt;code&gt;Code.js&lt;/code&gt;
component.&lt;/p&gt;&lt;p&gt;You’re going to import the components:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import {
  LiveEditor,
  LiveError,
  LivePreview,
  LiveProvider,
} from &amp;#x27;react-live&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then ypu’re going to check if &lt;code&gt;react-live&lt;/code&gt; has been added to the
language tag on your mdx file via the props:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;if (props[&amp;#x27;react-live&amp;#x27;]) {
  return (
    &amp;lt;LiveProvider code={codeString} noInline={true} theme={theme}&amp;gt;
      &amp;lt;LiveEditor /&amp;gt;
      &amp;lt;LiveError /&amp;gt;
      &amp;lt;LivePreview /&amp;gt;
    &amp;lt;/LiveProvider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s the full component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import Highlight, { defaultProps } from &amp;#x27;prism-react-renderer&amp;#x27;
import theme from &amp;#x27;prism-react-renderer/themes/nightOwl&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import {
  LiveEditor,
  LiveError,
  LivePreview,
  LiveProvider,
} from &amp;#x27;react-live&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { copyToClipboard } from &amp;#x27;../../utils/copy-to-clipboard&amp;#x27;

const Pre = styled.pre`
  position: relative;
  text-align: left;
  margin: 1em 0;
  padding: 0.5em;
  overflow-x: auto;
  border-radius: 3px;

  &amp;amp; .token-lline {
    line-height: 1.3em;
    height: 1.3em;
  }
  font-family: &amp;#x27;Courier New&amp;#x27;, Courier, monospace;
`

const LineNo = styled.span`
  display: inline-block;
  width: 2em;
  user-select: none;
  opacity: 0.3;
`

const CopyCode = styled.button`
  position: absolute;
  right: 0.25rem;
  border: 0;
  border-radius: 3px;
  margin: 0.25em;
  opacity: 0.3;
  &amp;amp;:hover {
    opacity: 1;
  }
`

export const Code = ({ codeString, language, ...props }) =&amp;gt; {
  if (props[&amp;#x27;react-live&amp;#x27;]) {
    return (
      &amp;lt;LiveProvider code={codeString} noInline={true} theme={theme}&amp;gt;
        &amp;lt;LiveEditor /&amp;gt;
        &amp;lt;LiveError /&amp;gt;
        &amp;lt;LivePreview /&amp;gt;
      &amp;lt;/LiveProvider&amp;gt;
    )
  }

  const handleClick = () =&amp;gt; {
    copyToClipboard(codeString)
  }

  return (
    &amp;lt;Highlight
      {...defaultProps}
      code={codeString}
      language={language}
      theme={theme}
    &amp;gt;
      {({
        className,
        style,
        tokens,
        getLineProps,
        getTokenProps,
      }) =&amp;gt; (
        &amp;lt;Pre className={className} style={style}&amp;gt;
          &amp;lt;CopyCode onClick={handleClick}&amp;gt;Copy&amp;lt;/CopyCode&amp;gt;
          {tokens.map((line, i) =&amp;gt; (
            &amp;lt;div {...getLineProps({ line, key: i })}&amp;gt;
              &amp;lt;LineNo&amp;gt;{i + 1}&amp;lt;/LineNo&amp;gt;
              {line.map((token, key) =&amp;gt; (
                &amp;lt;span {...getTokenProps({ token, key })} /&amp;gt;
              ))}
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/Pre&amp;gt;
      )}
    &amp;lt;/Highlight&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To test this, add &lt;code&gt;react-live&lt;/code&gt; next to the language on your &lt;code&gt;Dump&lt;/code&gt;
component, so you have added to the blog post you made:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;```jsx react-live
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you can edit the code directly, try changing a few things like
this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const Dump = props =&amp;gt; (
  &amp;lt;div
    style={{
      fontSize: 20,
      border: &amp;#x27;1px solid #efefef&amp;#x27;,
      padding: 10,
      background: &amp;#x27;white&amp;#x27;,
    }}
  &amp;gt;
    {Object.entries(props).map(([key, val]) =&amp;gt; (
      &amp;lt;pre key={key}&amp;gt;
        &amp;lt;strong style={{ color: &amp;#x27;white&amp;#x27;, background: &amp;#x27;red&amp;#x27; }}&amp;gt;
          {key} 💩
        &amp;lt;/strong&amp;gt;
        {JSON.stringify(val, &amp;#x27;&amp;#x27;, &amp;#x27; &amp;#x27;)}
      &amp;lt;/pre&amp;gt;
    ))}
  &amp;lt;/div&amp;gt;
)

render(&amp;lt;Dump props={[&amp;#x27;One&amp;#x27;, &amp;#x27;Two&amp;#x27;, &amp;#x27;Three&amp;#x27;, &amp;#x27;Four&amp;#x27;]} /&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-AlOdd-TvqHE&quot; src=&quot;https://www.youtube.com/embed/AlOdd-TvqHE?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;cover-image&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#cover-image&quot; aria-label=&quot;cover image permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cover Image&lt;/h2&gt;&lt;p&gt;Now to add a cover image to go with each post, you’ll need to install
a couple of packages to manage images in Gatsby.&lt;/p&gt;&lt;p&gt;install:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-transformer-sharp gatsby-plugin-sharp gatsby-remark-images gatsby-image
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now you should config &lt;code&gt;gatsby-config.js&lt;/code&gt; to include the newly added
packages. Remember to add &lt;code&gt;gatsby-remark-images&lt;/code&gt; to
&lt;code&gt;gatsby-plugin-mdx&lt;/code&gt; as both a &lt;code&gt;gatsbyRemarkPlugins&lt;/code&gt; option and as a
&lt;code&gt;plugins&lt;/code&gt; option.&lt;/p&gt;&lt;p&gt;config:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = {
  siteMetadata: siteMetadata,
  plugins: [
    `gatsby-plugin-styled-components`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-mdx`,
      options: {
        extensions: [`.mdx`, `.md`],
        gatsbyRemarkPlugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 590,
            },
          },
        ],
        plugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 590,
            },
          },
        ],
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: { path: `${__dirname}/posts`, name: `posts` },
    },
  ],
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add image to index query in &lt;code&gt;src/pages.index.js&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;cover {
  publicURL
  childImageSharp {
    sizes(
      maxWidth: 2000
      traceSVG: { color: &amp;quot;#639&amp;quot; }
    ) {
      ...GatsbyImageSharpSizes_tracedSVG
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fix up the date in the query too:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will show the date as full year, full month and the day as a
‘st’, ‘nd’, ‘rd’ and ‘th’. So if today’s date were 1970/01/01 it would
read 1970 January 1st.&lt;/p&gt;&lt;p&gt;Add &lt;code&gt;gatsby-image&lt;/code&gt; use that in a styled component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Image = styled(Img)`
  border-radius: 5px;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add some JavaScript to determine if there’s anything to render:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  !!frontmatter.cover ? (
    &amp;lt;Image sizes={frontmatter.cover.childImageSharp.sizes} /&amp;gt;
  ) : null
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s what the full module should look like now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { Link, graphql } from &amp;#x27;gatsby&amp;#x27;
import Img from &amp;#x27;gatsby-image&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;

const IndexWrapper = styled.main``

const PostWrapper = styled.div``

const Image = styled(Img)`
  border-radius: 5px;
`

export default ({ data }) =&amp;gt; {
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;IndexWrapper&amp;gt;
        {/* &amp;lt;Dump data={data}&amp;gt;&amp;lt;/Dump&amp;gt; */}
        {data.allMdx.nodes.map(
          ({ id, excerpt, frontmatter, fields }) =&amp;gt; (
            &amp;lt;PostWrapper key={id}&amp;gt;
              &amp;lt;Link to={fields.slug}&amp;gt;
                {!!frontmatter.cover ? (
                  &amp;lt;Image
                    sizes={frontmatter.cover.childImageSharp.sizes}
                  /&amp;gt;
                ) : null}
                &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
                &amp;lt;p&amp;gt;{excerpt}&amp;lt;/p&amp;gt;
              &amp;lt;/Link&amp;gt;
            &amp;lt;/PostWrapper&amp;gt;
          )
        )}
      &amp;lt;/IndexWrapper&amp;gt;
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query SITE_INDEX_QUERY {
    allMdx(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { published: { eq: true } } }
    ) {
      nodes {
        id
        excerpt(pruneLength: 250)
        frontmatter {
          title
          date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
          cover {
            publicURL
            childImageSharp {
              sizes(maxWidth: 2000, traceSVG: { color: &amp;quot;#639&amp;quot; }) {
                ...GatsbyImageSharpSizes_tracedSVG
              }
            }
          }
        }
        fields {
          slug
        }
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-9S5GNtql02w&quot; src=&quot;https://www.youtube.com/embed/9S5GNtql02w?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Additional resources:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;this helped me for my own blog:
&lt;a href=&quot;https://juliangaramendy.dev/custom-open-graph-images-in-gatsby-blog/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://juliangaramendy.dev/custom-open-graph-images-in-gatsby-blog/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;and the Gatsby docs:
&lt;a href=&quot;https://www.gatsbyjs.org/docs/working-with-images/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.gatsbyjs.org/docs/working-with-images/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;adding-an-seo-component-to-the-site&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#adding-an-seo-component-to-the-site&quot; aria-label=&quot;adding an seo component to the site permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding an SEO component to the site&lt;/h2&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-I9qQslUJknw&quot; src=&quot;https://www.youtube.com/embed/I9qQslUJknw?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;There’s a Gatsby &lt;a href=&quot;https://github.com/gatsbyjs/gatsby/issues/14125&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github PR on seo&lt;/a&gt; with some &lt;a href=&quot;https://github.com/gatsbyjs/gatsby/pull/10780#issuecomment-451048608&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;great notes from Andrew
Welch&lt;/a&gt; on SEO and a link to a presentation he did back in 2017.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Crafting Modern SEO with Andrew Welch:&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot;vimeo-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;vimeo-246846978&quot; src=&quot;https://player.vimeo.com/video/246846978?autoplay=false#t=0h0m0s&quot; frameBorder=&quot;0&quot; allow=&quot;autoplay; fullscreen&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;In the following comments of that PR, Gatsby’s &lt;a href=&quot;https://github.com/LekoArts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LekoArts&lt;/a&gt; details &lt;a href=&quot;https://github.com/LekoArts/gatsby-starter-prismic/blob/master/src/components/SEO/SEO.jsx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;his
own implementation&lt;/a&gt; which I have implemented &lt;a href=&quot;https://github.com/spences10/react-seo-component&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;as a React component&lt;/a&gt;,
you’re going to be configuring that now in this how-to.&lt;/p&gt;&lt;p&gt;First up, install and configure, &lt;code&gt;gatsby-plugin-react-helmet&lt;/code&gt; this is
used for server rendering data added with React Helmet.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn add gatsby-plugin-react-helmet react-helmet react-seo-component
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You’ll need to add the plugin to your &lt;code&gt;gatsby-config.js&lt;/code&gt;. If you
haven’t done so already now is a good time to also configure the
&lt;code&gt;gatsby-plugin-styled-components&lt;/code&gt; as well.&lt;/p&gt;&lt;h3 id=&quot;configure-seo-component-for-homepage&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure-seo-component-for-homepage&quot; aria-label=&quot;configure seo component for homepage permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure SEO Component for Homepage&lt;/h3&gt;&lt;p&gt;To visualise the data you’re going to need to get into the SEO
component use the &lt;code&gt;Dump&lt;/code&gt; component to begin with to validate the data.&lt;/p&gt;&lt;p&gt;The majority of the information needed for &lt;code&gt;src/pages/index.js&lt;/code&gt; can be
first added to the &lt;code&gt;gatsby-config.js&lt;/code&gt;, &lt;code&gt;siteMetadata&lt;/code&gt; object then
queried with the &lt;code&gt;useSiteMetadata&lt;/code&gt; hook. Some of the data added here
can then be used in &lt;code&gt;src/templates/blogPostTemplate.js&lt;/code&gt;, more on that
in the next section.&lt;/p&gt;&lt;p&gt;For now add the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const siteMetadata = {
  title: `The Localhost Blog`,
  description: `This is my coding blog where I write about my coding journey.`,
  image: `/default-site-image.jpg`,
  siteUrl: `https://thelocalhost.blog`,
  siteLanguage: `en-GB`,
  siteLocale: `en_gb`,
  twitterUsername: `@spences10`,
  authorName: `Scott Spence`,
}

module.exports = {
  siteMetadata: siteMetadata,
  plugins: [
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You don’t have to abstract out the &lt;code&gt;siteMetadata&lt;/code&gt; into it’s own
component here, it’s only a suggestion on how to manage it.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;image&lt;/code&gt; is going to be the default image for your site, you should
create a &lt;code&gt;static&lt;/code&gt; folder at the root of the project and add in an
image you want to be shown when the homepage of your site is shared on
social media.&lt;/p&gt;&lt;p&gt;For &lt;code&gt;siteUrl&lt;/code&gt; at this stage it doesn’t necessarily have to be valid,
add a dummy url for now and you can change this later.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;siteLanguage&lt;/code&gt; is your language of choice for the site, take a
look at &lt;a href=&quot;https://www.w3.org/International/articles/language-tags/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;w3 language tags&lt;/a&gt; for more info.&lt;/p&gt;&lt;p&gt;Facebook OpenGraph is the only place the &lt;code&gt;siteLocale&lt;/code&gt; is used and it
is different from language tags.&lt;/p&gt;&lt;p&gt;Add your &lt;code&gt;twitterUsername&lt;/code&gt; and your &lt;code&gt;authorName&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Update the &lt;code&gt;useSiteMetadata&lt;/code&gt; hook now to reflect the newly added
properties:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql, useStaticQuery } from &amp;#x27;gatsby&amp;#x27;

export const useSiteMetadata = () =&amp;gt; {
  const { site } = useStaticQuery(
    graphql`
      query SITE_METADATA_QUERY {
        site {
          siteMetadata {
            description
            title
            image
            siteUrl
            siteLanguage
            siteLocale
            twitterUsername
            authorName
          }
        }
      }
    `
  )
  return site.siteMetadata
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Begin with importing the &lt;code&gt;Dump&lt;/code&gt; component in &lt;code&gt;src/pages/index.js&lt;/code&gt; then
plug in the props as they are detailed in the docs of the
&lt;a href=&quot;https://github.com/spences10/react-seo-component&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-seo-component&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import Dump from &amp;#x27;../components/Dump&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;

export default ({ data }) =&amp;gt; {
  const {
    description,
    title,
    image,
    siteUrl,
    siteLanguage,
    siteLocale,
    twitterUsername,
  } = useSiteMetadata()
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;Dump
        title={title}
        description={description}
        image={`${siteUrl}${image}`}
        pathname={siteUrl}
        siteLanguage={siteLanguage}
        siteLocale={siteLocale}
        twitterUsername={twitterUsername}
      /&amp;gt;
      &amp;lt;IndexWrapper&amp;gt;
        {data.allMdx.nodes.map(
          ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check that all the props are displaying valid values then you can swap
out the &lt;code&gt;Dump&lt;/code&gt; component with the &lt;code&gt;SEO&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;The complete &lt;code&gt;src/pages/index.js&lt;/code&gt; should look like this now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql, Link } from &amp;#x27;gatsby&amp;#x27;
import Img from &amp;#x27;gatsby-image&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import SEO from &amp;#x27;react-seo-component&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;

const IndexWrapper = styled.main``

const PostWrapper = styled.div``

const Image = styled(Img)`
  border-radius: 5px;
`

export default ({ data }) =&amp;gt; {
  const {
    description,
    title,
    image,
    siteUrl,
    siteLanguage,
    siteLocale,
    twitterUsername,
  } = useSiteMetadata()
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;SEO
        title={title}
        description={description || `nothin’`}
        image={`${siteUrl}${image}`}
        pathname={siteUrl}
        siteLanguage={siteLanguage}
        siteLocale={siteLocale}
        twitterUsername={twitterUsername}
      /&amp;gt;
      &amp;lt;IndexWrapper&amp;gt;
        {/* &amp;lt;Dump data={data}&amp;gt;&amp;lt;/Dump&amp;gt; */}
        {data.allMdx.nodes.map(
          ({ id, excerpt, frontmatter, fields }) =&amp;gt; (
            &amp;lt;PostWrapper key={id}&amp;gt;
              &amp;lt;Link to={fields.slug}&amp;gt;
                {!!frontmatter.cover ? (
                  &amp;lt;Image
                    sizes={frontmatter.cover.childImageSharp.sizes}
                  /&amp;gt;
                ) : null}
                &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
                &amp;lt;p&amp;gt;{excerpt}&amp;lt;/p&amp;gt;
              &amp;lt;/Link&amp;gt;
            &amp;lt;/PostWrapper&amp;gt;
          )
        )}
      &amp;lt;/IndexWrapper&amp;gt;
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query SITE_INDEX_QUERY {
    allMdx(
      sort: { fields: [frontmatter___date], order: DESC }
      filter: { frontmatter: { published: { eq: true } } }
    ) {
      nodes {
        id
        excerpt(pruneLength: 250)
        frontmatter {
          title
          date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
          cover {
            publicURL
            childImageSharp {
              sizes(maxWidth: 2000, traceSVG: { color: &amp;quot;#639&amp;quot; }) {
                ...GatsbyImageSharpSizes_tracedSVG
              }
            }
          }
        }
        fields {
          slug
        }
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-O0jk9AqM_ls&quot; src=&quot;https://www.youtube.com/embed/O0jk9AqM_ls?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h3 id=&quot;configure-seo-component-for-blog-posts&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure-seo-component-for-blog-posts&quot; aria-label=&quot;configure seo component for blog posts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure SEO Component for Blog Posts&lt;/h3&gt;&lt;p&gt;This will be the same approach as with the homepage, import the &lt;code&gt;Dump&lt;/code&gt;
component and validate the props before swapping out the &lt;code&gt;Dump&lt;/code&gt;
component with the &lt;code&gt;SEO&lt;/code&gt; component.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import Dump from &amp;#x27;../components/Dump&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;

export default ({ data, pageContext }) =&amp;gt; {
  const {
    image,
    siteUrl,
    siteLanguage,
    siteLocale,
    twitterUsername,
    authorName,
  } = useSiteMetadata()
  const { frontmatter, body, fields, excerpt } = data.mdx
  const { title, date, cover } = frontmatter
  const { previous, next } = pageContext
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;Dump
        title={title}
        description={excerpt}
        image={
          cover === null
            ? `${siteUrl}${image}`
            : `${siteUrl}${cover.publicURL}`
        }
        pathname={`${siteUrl}${fields.slug}`}
        siteLanguage={siteLanguage}
        siteLocale={siteLocale}
        twitterUsername={twitterUsername}
        author={authorName}
        article={true}
        publishedDate={date}
        modifiedDate={new Date(Date.now()).toISOString()}
      /&amp;gt;
      &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
      ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add &lt;code&gt;fields.slug&lt;/code&gt;, &lt;code&gt;excerpt&lt;/code&gt; and &lt;code&gt;cover.publicURL&lt;/code&gt; to the
&lt;code&gt;PostsBySlug&lt;/code&gt; query and destructure them from &lt;code&gt;data.mdx&lt;/code&gt; and
&lt;code&gt;frontmatter&lt;/code&gt; respectively.&lt;/p&gt;&lt;p&gt;For the image you’ll need to do some logic as to weather the &lt;code&gt;cover&lt;/code&gt;
exists and default to the default site image if it doesn’t.&lt;/p&gt;&lt;p&gt;The complete &lt;code&gt;src/templates/blogPostTemplate.js&lt;/code&gt; should look like this
now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql, Link } from &amp;#x27;gatsby&amp;#x27;
import { MDXRenderer } from &amp;#x27;gatsby-plugin-mdx&amp;#x27;
import React from &amp;#x27;react&amp;#x27;
import SEO from &amp;#x27;react-seo-component&amp;#x27;
import { Layout } from &amp;#x27;../components/Layout&amp;#x27;
import { useSiteMetadata } from &amp;#x27;../hooks/useSiteMetadata&amp;#x27;

export default ({ data, pageContext }) =&amp;gt; {
  const {
    image,
    siteUrl,
    siteLanguage,
    siteLocale,
    twitterUsername,
    authorName,
  } = useSiteMetadata()
  const { frontmatter, body, fields, excerpt } = data.mdx
  const { title, date, cover } = frontmatter
  const { previous, next } = pageContext
  return (
    &amp;lt;Layout&amp;gt;
      &amp;lt;SEO
        title={title}
        description={excerpt}
        image={
          cover === null
            ? `${siteUrl}${image}`
            : `${siteUrl}${cover.publicURL}`
        }
        pathname={`${siteUrl}${fields.slug}`}
        siteLanguage={siteLanguage}
        siteLocale={siteLocale}
        twitterUsername={twitterUsername}
        author={authorName}
        article={true}
        publishedDate={date}
        modifiedDate={new Date(Date.now()).toISOString()}
      /&amp;gt;
      &amp;lt;h1&amp;gt;{frontmatter.title}&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;{frontmatter.date}&amp;lt;/p&amp;gt;
      &amp;lt;MDXRenderer&amp;gt;{body}&amp;lt;/MDXRenderer&amp;gt;
      {previous === false ? null : (
        &amp;lt;&amp;gt;
          {previous &amp;amp;&amp;amp; (
            &amp;lt;Link to={previous.fields.slug}&amp;gt;
              &amp;lt;p&amp;gt;{previous.frontmatter.title}&amp;lt;/p&amp;gt;
            &amp;lt;/Link&amp;gt;
          )}
        &amp;lt;/&amp;gt;
      )}
      {next === false ? null : (
        &amp;lt;&amp;gt;
          {next &amp;amp;&amp;amp; (
            &amp;lt;Link to={next.fields.slug}&amp;gt;
              &amp;lt;p&amp;gt;{next.frontmatter.title}&amp;lt;/p&amp;gt;
            &amp;lt;/Link&amp;gt;
          )}
        &amp;lt;/&amp;gt;
      )}
    &amp;lt;/Layout&amp;gt;
  )
}

export const query = graphql`
  query PostBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      frontmatter {
        title
        date(formatString: &amp;quot;YYYY MMMM Do&amp;quot;)
        cover {
          publicURL
        }
      }
      body
      excerpt
      fields {
        slug
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-a2fcgYIQRIU&quot; src=&quot;https://www.youtube.com/embed/a2fcgYIQRIU?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h3 id=&quot;build-site-and-validate-meta-tags&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#build-site-and-validate-meta-tags&quot; aria-label=&quot;build site and validate meta tags permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Build Site and Validate Meta Tags&lt;/h3&gt;&lt;p&gt;Add in the build script to &lt;code&gt;package.json&lt;/code&gt; and also a script for
serving the built site locally.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts&amp;quot;: {
  &amp;quot;dev&amp;quot;: &amp;quot;gatsby develop -p 9988 -o&amp;quot;,
  &amp;quot;build&amp;quot;: &amp;quot;gatsby build&amp;quot;,
  &amp;quot;serve&amp;quot;: &amp;quot;gatsby serve -p 9500 -o&amp;quot;
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now it’s time to run:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn build &amp;amp;&amp;amp; yarn serve
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will build the site and open a browser tab so you can see the
site as it will appear when it is on the internet. Validate meta tags
have been added to the build by selecting “View page source” (Crtl+u
in Windows and Linux) on the page and do a Ctrl+f to find them.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-c6bB9ddAgjc&quot; src=&quot;https://www.youtube.com/embed/c6bB9ddAgjc?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;adding-the-project-to-github&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#adding-the-project-to-github&quot; aria-label=&quot;adding the project to github permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adding the Project to GitHub&lt;/h2&gt;&lt;p&gt;Add your code to GitHub by either selecting the plus (+) icon next to
your avatar on GitHub or by going to directly to
&lt;a href=&quot;https://github.com/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/new&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Name your repository and click create repository, then you will be
given the instructions to link your local code to the repository you
created via the command line.&lt;/p&gt;&lt;p&gt;Depending on how you authenticate with GitHub will depend on what the
command looks like.&lt;/p&gt;&lt;p&gt;Some good resources for authenticating with GitHub via SSH are &lt;a href=&quot;https://egghead.io/lessons/javascript-how-to-authenticate-with-github-using-ssh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kent
Dodds Egghead.io video&lt;/a&gt; and also a how-to &lt;a href=&quot;https://www.cheatsheets.xyz/git/#how-to-authenticate-with-github-using-ssh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;on CheatSheets.xyz&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-r2eiJ8E_YT0&quot; src=&quot;https://www.youtube.com/embed/r2eiJ8E_YT0?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;deploy-to-netlify&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#deploy-to-netlify&quot; aria-label=&quot;deploy to netlify permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deploy to Netlify&lt;/h2&gt;&lt;p&gt;To deploy your site to Netlify, if you haven’t done so already you’ll
need to add the GitHub integration to your GitHub profile. If you got
to &lt;a href=&quot;https://app.netlify.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;app.netlify.com&lt;/a&gt; the wizard will walk you
through the process.&lt;/p&gt;&lt;p&gt;From here you can add your built site’s &lt;code&gt;public&lt;/code&gt; folder, drag ‘n drop
style directly to the Netlify global CDNs.&lt;/p&gt;&lt;p&gt;You, however are going to load your site via the Netlify CLI! In your
terminal, if you haven’t already got the CLI installed, run:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn global add netlify-cli
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then once the CLI is installed:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# authenticate via the CLI
netlify login
# initialise the site
netlify init
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Enter the details for your team, the site name is optional, the build
command will be &lt;code&gt;yarn build&lt;/code&gt; and directory to deploy is &lt;code&gt;public&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;You will be prompted to commit the changes and push them to GitHub
(with &lt;code&gt;git push&lt;/code&gt;), once you have done that your site will be published
and ready for all to see!&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-voWeHvIGB0g&quot; src=&quot;https://www.youtube.com/embed/voWeHvIGB0g?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;validate-metadata-with-heymeta&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#validate-metadata-with-heymeta&quot; aria-label=&quot;validate metadata with heymeta permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Validate Metadata with Heymeta&lt;/h2&gt;&lt;p&gt;Last up is validating the metadata for the OpenGraph fields, to do
that you’ll need to make sure that the &lt;code&gt;siteUrl&lt;/code&gt; reflecting what you
have in your Netlify dashboard.&lt;/p&gt;&lt;p&gt;If you needed to change the url you’ll need to commit and push the
changes to GitHub again.&lt;/p&gt;&lt;p&gt;Once your site is built with a valid url you can then test the
homepage and a blog page for the correct meta tags with
&lt;a href=&quot;http://heymeta.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;heymeta.com&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-JH1AVanYhwo&quot; src=&quot;https://www.youtube.com/embed/JH1AVanYhwo?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;OpenGraph checking tools:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.heymeta.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;heymeta&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://opengraphcheck.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;opengraphcheck&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://cards-dev.twitter.com/validator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twitter validator&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://developers.facebook.com/tools/debug/sharing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;facebook sharing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/post-inspector/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;linkedin inspector/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Additional resources:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/essential-meta-tags-social-media/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Essential Meta Tags for Social Media&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h2&gt;&lt;p&gt;That’s all folks! If there is anything I have missed, or if there is a
better way to do something then please let me know.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[JAMstack_conf London 2019]]></title><description><![CDATA[I've been wanting to go to a JAMstack conf since the first one was
scheduled for October 2018. This year when it was announced there
would…]]></description><link>https://scottspence.com/2019/07/19/jamstack-london-2019/</link><guid isPermaLink="false">https://scottspence.com/2019/07/19/jamstack-london-2019/</guid><pubDate>Fri, 19 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been wanting to go to a JAMstack conf since the first one was
scheduled for October 2018. This year when it was announced there
would be one in London I was super excited to get the opportunity to
go.&lt;/p&gt;&lt;p&gt;The conference was across two days with the first consisting of
workshops, lightning talks and welcome drinks. The second was the
keynote and conference talks either side of a lightning round with
some exciting announcements.&lt;/p&gt;&lt;h2 id=&quot;tuesday---2019-07-09&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#tuesday---2019-07-09&quot; aria-label=&quot;tuesday   2019 07 09 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tuesday - 2019-07-09&lt;/h2&gt;&lt;p&gt;First up was the workshop events where I was attending a workshop on
schema stitching with GraphQL using GraphCMS and Moltin&lt;/p&gt;&lt;h2 id=&quot;workshop&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#workshop&quot; aria-label=&quot;workshop permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Workshop&lt;/h2&gt;&lt;p&gt;Jesse was a great at going through the basics of the headless CMS and
why you should be using one. The workshop consisted of us defining our
CMS content model with pen and paper before creating them in the
GraphCMS UI for use with the Moltin eComerce API&lt;/p&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/notrab/status/1148587457866358784?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;h3 id=&quot;technical-difficulties&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#technical-difficulties&quot; aria-label=&quot;technical difficulties permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Technical difficulties&lt;/h3&gt;&lt;p&gt;There were issues on both the GraphCMS and the Moltin side, mainly
around the UI for Moltin. We all managed to breeze through these
keeping a good pace on the content.&lt;/p&gt;&lt;h3 id=&quot;graphql-schema-stitching&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#graphql-schema-stitching&quot; aria-label=&quot;graphql schema stitching permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GraphQL Schema Stitching&lt;/h3&gt;&lt;p&gt;Once we all got through the initial setup on our projects it was quite
satisfying to get to two schemas in one query. I still have a bit of
work to do on my project as we all ran out of time towards the end.
Jesse covered the main goal of the workshop which was to stitch the
two schemas together. The additional UI work I can pick up at a later
date.&lt;/p&gt;&lt;h2 id=&quot;lightning-talks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lightning-talks&quot; aria-label=&quot;lightning talks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lightning Talks&lt;/h2&gt;&lt;p&gt;After the workshops it was time for the lightening talks.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/jamiebradley234&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@jamiebradley234&lt;/a&gt; did a talk on the booming tech scene in
Middlesbrough.&lt;/p&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/kmelve/status/1148664935305699328?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/danfascia&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@danfascia&lt;/a&gt; did a great talk on how healthcare tech is benefiting
from JAMstack methodologies.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-n1ca0cQAr_4&quot; src=&quot;https://www.youtube.com/embed/n1ca0cQAr_4?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;wednesday---2019-07-10&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wednesday---2019-07-10&quot; aria-label=&quot;wednesday   2019 07 10 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wednesday - 2019-07-10&lt;/h2&gt;&lt;h2 id=&quot;talks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#talks&quot; aria-label=&quot;talks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Talks&lt;/h2&gt;&lt;p&gt;First up we had some apologies from Phill Hawksworth on behalf of
Chris Coyer as Chris couldn’t make it. We sent him a get well soon
message.&lt;/p&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/philhawksworth/status/1148929743342972928?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;h3 id=&quot;state-of-the-jamstack-nation---sarah-drasner&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#state-of-the-jamstack-nation---sarah-drasner&quot; aria-label=&quot;state of the jamstack nation   sarah drasner permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;State of the JAMstack Nation - Sarah Drasner&lt;/h3&gt;&lt;p&gt;Sarah gave a demo of how quickly you could set up a JAMstack site,
using Vue and Nuxt&lt;/p&gt;&lt;h3 id=&quot;netlify-analytics---matt-biilmann&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#netlify-analytics---matt-biilmann&quot; aria-label=&quot;netlify analytics   matt biilmann permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Netlify Analytics - Matt Biilmann&lt;/h3&gt;&lt;p&gt;Massive announcement for Netlify analytics I signed up there and then
for my blog. Obviously Netlify is used to build Netlify so Matt showed
off the continuous deployment for Netlify whilst putting the feature
live.&lt;/p&gt;&lt;h3 id=&quot;transforming-the-json---groq--sanity-cms---knut-melvær&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#transforming-the-json---groq--sanity-cms---knut-melv%C3%A6r&quot; aria-label=&quot;transforming the json   groq  sanity cms   knut melvær permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Transforming the Json - GROQ (&amp;amp; Sanity CMS) - Knut Melvær&lt;/h3&gt;&lt;p&gt;Knut showing off the advantages of using GROQ for querying your data.&lt;/p&gt;&lt;p&gt;Also it’s &lt;a href=&quot;https://www.sanity.io/blog/we-re-open-sourcing-groq-a-query-language-for-json-documents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;now open source&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;stackbit---ben-edwards&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#stackbit---ben-edwards&quot; aria-label=&quot;stackbit   ben edwards permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stackbit - Ben Edwards&lt;/h3&gt;&lt;p&gt;Ben announcing that Stackbit was coming out of beta. Stackbit is a
great all in one tool for making JAMstack sites with CMS integration.&lt;/p&gt;&lt;h3 id=&quot;code-sandbox---ives-van-horne&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#code-sandbox---ives-van-horne&quot; aria-label=&quot;code sandbox   ives van horne permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code Sandbox. - Ives van Horne&lt;/h3&gt;&lt;p&gt;Ives (Flip) went into how he made &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; whils being a
college student.&lt;/p&gt;&lt;p&gt;If you want something build cheaply, ask a student to build it for you
was the take home here for me.&lt;/p&gt;&lt;h3 id=&quot;why--how-smashing-magazine-moved-to-jamstack---vitaly-friedman&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#why--how-smashing-magazine-moved-to-jamstack---vitaly-friedman&quot; aria-label=&quot;why  how smashing magazine moved to jamstack   vitaly friedman permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why &amp;amp; How Smashing Magazine moved to JAMstack - Vitaly Friedman&lt;/h3&gt;&lt;p&gt;Brilliant talks from Vitaly on the transition of Smashing Mag from
monolith over to the JAMstack. Also great detail on the redesign.&lt;/p&gt;&lt;h3 id=&quot;weworklabs-moves-to-jamstack---ramin-bozorgzadeh&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#weworklabs-moves-to-jamstack---ramin-bozorgzadeh&quot; aria-label=&quot;weworklabs moves to jamstack   ramin bozorgzadeh permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;WeWorkLabs moves to JAMstack - Ramin Bozorgzadeh&lt;/h3&gt;&lt;p&gt;JAMstack helps me sleep at night!&lt;/p&gt;&lt;h3 id=&quot;css-houdini-today---una-kravets&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#css-houdini-today---una-kravets&quot; aria-label=&quot;css houdini today   una kravets permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CSS Houdini Today - Una Kravets&lt;/h3&gt;&lt;p&gt;Una was super jazzed about Houdini, you could do some pretty neat css
tricks with it.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://extra-css.netlify.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://extra-css.netlify.com/&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;serverless-functions---simona-cotin&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#serverless-functions---simona-cotin&quot; aria-label=&quot;serverless functions   simona cotin permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Serverless functions - Simona Cotin&lt;/h3&gt;&lt;p&gt;Simona detailed key usecases for serveless functions.&lt;/p&gt;&lt;h3 id=&quot;performance-optimizing-and-webpack-bashing---jake-archibald-and-surma&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#performance-optimizing-and-webpack-bashing---jake-archibald-and-surma&quot; aria-label=&quot;performance optimizing and webpack bashing   jake archibald and surma permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Performance optimizing and Webpack bashing - Jake Archibald and Surma&lt;/h3&gt;&lt;p&gt;Surma and Jake went through how to optimise a modern day minesweeper
game for mobile.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;“Should I worry about performance?”&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Answer: YES!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Hosted web fonts slow things down, because the browser has to load
from multiple servers. Optimize further by only including the
characters you need. Use css, assets, fonts directly in the HTML to
eliminate needing additional requests.&lt;/p&gt;&lt;p&gt;Here’s the repo: &lt;a href=&quot;https://github.com/GoogleChromeLabs/proxx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/GoogleChromeLabs/proxx&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;hot&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#hot&quot; aria-label=&quot;hot permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hot!&lt;/h3&gt;&lt;p&gt;Being in the UK we had the British weather to content with and the
venue although fitted with A/C units in the speaker hall the venue
outside of that was hot and sweaty! I spent the majority of my time
between talks situated directly in front of the A/C units.&lt;/p&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/spences10/status/1148927111526268928?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/peduarte/status/1148923305254096896?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class=&quot;twitter-tweet-mdx-embed&quot; style=&quot;overflow:auto&quot;&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-theme=&quot;light&quot; data-align=&quot;left&quot;&gt;&lt;a href=&quot;https://twitter.com/spences10/status/1148914884039577600?ref_src=twsrc%5Etfw&quot;&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;h2 id=&quot;thats-it-folks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thats-it-folks&quot; aria-label=&quot;thats it folks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;That’s it folks!&lt;/h2&gt;&lt;p&gt;This was a great event I met a lot of new people and several Twitter
friends. I can’t wait until the next one.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Convert the Gatsby default starter blog to use MDX]]></title><description><![CDATA[In this guide we're going to cover converting the Gatsby default blog
starter to use MDX. All the cool kids are using Gatsby and MDX in…]]></description><link>https://scottspence.com/2019/04/09/convert-gatsby-default-blog-to-mdx/</link><guid isPermaLink="false">https://scottspence.com/2019/04/09/convert-gatsby-default-blog-to-mdx/</guid><pubDate>Tue, 09 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this guide we’re going to cover converting the Gatsby default blog
starter to use MDX.&lt;/p&gt;&lt;p&gt;All the cool kids are using Gatsby and MDX in their blogs these days.
If you already have a blog that uses Gatsby but want to move onto the
new hotness then this is the guide for you.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-gck4RjaX5D4&quot; src=&quot;https://www.youtube.com/embed/gck4RjaX5D4?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;h2 id=&quot;versions&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#versions&quot; aria-label=&quot;versions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Versions:&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;This guide is being used with the following dependency versions.&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;gatsby: 2.3.5&lt;/li&gt;&lt;li&gt;react: 16.8.6&lt;/li&gt;&lt;li&gt;react-dom: 16.8.6&lt;/li&gt;&lt;li&gt;gatsby-mdx: 0.4.5&lt;/li&gt;&lt;li&gt;@mdx-js/mdx: 0.20.3&lt;/li&gt;&lt;li&gt;@mdx-js/tag: 0.20.3&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You can also check out the &lt;a href=&quot;https://codesandbox.io/s/lqp6p647q&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;example code&lt;/a&gt;.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;We’re going to need some links, which are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://codesandbox.io/docs/importing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox docs for importing projects&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://codesandbox.io/s/github&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox import wizard&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/gatsbyjs/gatsby-starter-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby starter blog&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;import-to-codesandbox&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#import-to-codesandbox&quot; aria-label=&quot;import to codesandbox permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Import to CodeSandbox&lt;/h2&gt;&lt;p&gt;For this example I’m going to be using the &lt;a href=&quot;https://github.com/gatsbyjs/gatsby-starter-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby starter blog&lt;/a&gt; and
importing it into CodeSandbox, looking at the docs it says you can do
this with the &lt;a href=&quot;https://codesandbox.io/s/github&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox import wizard&lt;/a&gt; linked, paste the link in
there and CodeSandbox will open the representation of the code on
GitHub.&lt;/p&gt;&lt;p&gt;Now we can go about moving from using Gatsby transformer remark over
to MDX.&lt;/p&gt;&lt;p&gt;Let’s take a look at what we’ll be changing for this example. But
first we’re going to need to import some dependencies to get MDX
running in out Gatsby project.&lt;/p&gt;&lt;p&gt;With the add dependency button in CodeSandbox add the following
dependencies:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;gatsby-mdx&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;@mdx-js/mdx&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;@mdx-js/tag&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We will also need to add dependencies for styled-components so may as
well add them now as well:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;gatsby-plugin-styled-components&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;styled-components&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;babel-plugin-styled-components&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Files to change:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;gatsby-node.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;gatsby-config.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;blog-post.js&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;gatsby-nodejs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#gatsby-nodejs&quot; aria-label=&quot;gatsby nodejs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;gatsby-node.js&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;First up we’re going to need to change &lt;code&gt;gatsby-node.js&lt;/code&gt; this is where
all the pages and data nodes are generated.&lt;/p&gt;&lt;p&gt;Change all markdown remark occurrences with MDX, that’s the initial
GraphQL query in create pages, then again in the result.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/initialGatsbyNode.png&quot; alt=&quot;initial gatsby node changes&quot;/&gt;&lt;/p&gt;&lt;p&gt;Then change the &lt;code&gt;node.internal.type&lt;/code&gt; in &lt;code&gt;onCreateNode&lt;/code&gt; from
&lt;code&gt;MarkdownRemark&lt;/code&gt; to &lt;code&gt;Mdx&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/lastGatsbyNode.png&quot; alt=&quot;last gatsby node changes&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;gatsby-configjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#gatsby-configjs&quot; aria-label=&quot;gatsby configjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;gatsby-config.js&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;Here we’re going to replace &lt;code&gt;gatsby-transformer-remark&lt;/code&gt; with
&lt;code&gt;gatsby-mdx&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/gatsbyConfig.png&quot; alt=&quot;replace transformer remark with gatsby-mdx&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;indexjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#indexjs&quot; aria-label=&quot;indexjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;Here we’re going to alter the &lt;code&gt;posts&lt;/code&gt; variable to take the &lt;code&gt;Mdx&lt;/code&gt;
edges.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/indexPageEdges.png&quot; alt=&quot;replace all markdown edges&quot;/&gt;&lt;/p&gt;&lt;p&gt;The &lt;code&gt;Mdx&lt;/code&gt; edges are taken from the page query, which is also altered
to use &lt;code&gt;allMdx&lt;/code&gt; in place of &lt;code&gt;allMarkdownRemark&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/indexPageQuery.png&quot; alt=&quot;index page query&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;blog-postjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#blog-postjs&quot; aria-label=&quot;blog postjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;blog-post.js&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;Now last on the list to get MDX working is the blog post template,
we’re going to need to import &lt;code&gt;MDXRenderer&lt;/code&gt; from &lt;code&gt;gatsby-mdx&lt;/code&gt; we’re
going to replace &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt; with this shortly.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/importMdxRenderer.png&quot; alt=&quot;MDX renderer&quot;/&gt;&lt;/p&gt;&lt;p&gt;Here’s where we use it, we’ll come onto &lt;code&gt;post.code.body&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/replaceDangerHtml.png&quot; alt=&quot;replace dangerously set html&quot;/&gt;&lt;/p&gt;&lt;p&gt;Again in the query we’re replacing &lt;code&gt;markdownRemark&lt;/code&gt; with &lt;code&gt;mdx&lt;/code&gt; and
this time also doing away with &lt;code&gt;html&lt;/code&gt; from the query and adding in
&lt;code&gt;code&lt;/code&gt; for &lt;code&gt;body&lt;/code&gt; which we’re using in our render method.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2019/convert-gatsby-default-blog-to-mdx/blogPostQuery.png&quot; alt=&quot;blog post query&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;now-were-using-mdx&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#now-were-using-mdx&quot; aria-label=&quot;now were using mdx permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Now we’re using MDX!&lt;/h2&gt;&lt;p&gt;So now we can create a &lt;code&gt;.mdx&lt;/code&gt; post, let’s do that.&lt;/p&gt;&lt;p&gt;Import the styled-components dependencies:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gatsby-plugin-styled-components
styled-components
babel-plugin-styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then configure them in &lt;code&gt;gatsby-config.js&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js:title=gatsby-config.js&quot;&gt;module.exports = {
  siteMetadata: {
    title: `Gatsby Starter Blog`,
    ...
    },
  },
  plugins: [
    `gatsby-plugin-styled-components`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
  ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can use styled-components, in &lt;code&gt;src/components&lt;/code&gt; make a new
component, I have called my one &lt;code&gt;butt.js&lt;/code&gt; call yours what you like.&lt;/p&gt;&lt;p&gt;We’re going to use this component in a &lt;code&gt;.mdx&lt;/code&gt; document, first the
component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import styled from &amp;#x27;styled-components&amp;#x27;

export const Butt = styled.button`
  background-color: red;
  height: 40px;
  width: 80px;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Spicy, right! 🌶&lt;/p&gt;&lt;p&gt;Now we can include this component in a &lt;code&gt;.mdx&lt;/code&gt; document so let’s go
ahead and create that, in &lt;code&gt;content/blog&lt;/code&gt; make a new directory, I’m
giving mine the imaginative name &lt;code&gt;first-mdx-post&lt;/code&gt;, in there create a
&lt;code&gt;index.mdx&lt;/code&gt; file and use the frontmatter from one of the other posts
as an example of what to use:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-mdx&quot;&gt;---
title: My First MDX Post!
date: &amp;#x27;2019-04-07T23:46:37.121Z&amp;#x27;
---

# make a site they said, it&amp;#x27;ll be fun they said

more content yo!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will render a &lt;code&gt;h1&lt;/code&gt; and a &lt;code&gt;p&lt;/code&gt; and we should see it render in our
CodeSandbox preview.&lt;/p&gt;&lt;p&gt;Now we can go ahead and import our beautifully crafted button:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-mdx&quot;&gt;---
title: My First MDX Post!
date: &amp;#x27;2019-04-07T23:46:37.121Z&amp;#x27;
---

import { Butt } from &amp;#x27;../../../src/components/button&amp;#x27;

# make a site they said, it&amp;#x27;ll be fun they said

more content yo!

&amp;lt;Butt&amp;gt;yoyoyo&amp;lt;/Butt&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up!&lt;/h2&gt;&lt;p&gt;So, that’s it, we’ve gone and converted the Gatsby starter blog from
using Markdown Remark over to using MDX.&lt;/p&gt;&lt;p&gt;I hope you have found it helpful.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Thanks for reading&lt;/strong&gt; 🙏&lt;/p&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Update Windows Subsystem Linux Ubuntu from 18.04 to 18.10]]></title><description><![CDATA[Already use WSL with Ubuntu? Want an Upgrade?? This is a guide that will cover upgrading Windows Subsystem Linux
(WSL) from the current LTS…]]></description><link>https://scottspence.com/2019/04/01/update-wsl-from-18.04-18.10/</link><guid isPermaLink="false">https://scottspence.com/2019/04/01/update-wsl-from-18.04-18.10/</guid><pubDate>Mon, 01 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;already-use-wsl-with-ubuntu-want-an-upgrade&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#already-use-wsl-with-ubuntu-want-an-upgrade&quot; aria-label=&quot;already use wsl with ubuntu want an upgrade permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Already use WSL with Ubuntu? Want an Upgrade??&lt;/h2&gt;&lt;p&gt;This is a guide that will cover upgrading Windows Subsystem Linux
(WSL) from the current LTS version to the latest ‘normal’ version
18.10.&lt;/p&gt;&lt;p&gt;I found this post on &lt;a href=&quot;https://dev.to&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dev.to&lt;/a&gt; this weekend detailing going from
version 18.04 to 18.10 on Ubuntu for Windows Subsystem Linux. You will
know form &lt;a href=&quot;https://thelocalhost.blog/wsl-bootstrap-2019#update-upgrade-and-autoremove&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;earlier posts from me&lt;/a&gt; that trying to go the update route
on WSL is time consuming and you’re basically better off starting
again.&lt;/p&gt;&lt;p&gt;I tried it myself and got in a bit of trouble, you can see by checking
out the comments on &lt;a href=&quot;https://dev.to/david_j_eddy/how-to-upgrade-wsl-ubuntu-18-04-to-18-10-203&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;David’s post&lt;/a&gt;&lt;/p&gt;&lt;p&gt;So from uninstalling my version of Ubuntu I went ahead and tried
again, if you have read the comment’s on &lt;a href=&quot;https://dev.to/david_j_eddy/how-to-upgrade-wsl-ubuntu-18-04-to-18-10-203&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;David’s post&lt;/a&gt; you’ll see
that I came up against an issue with being unable to reach the ‘snap
store’. I don’t know what that is or means but basically it stopped my
upgrade and I was left not knowing if I was fully upgraded or not.&lt;/p&gt;&lt;p&gt;Thankfully someone else had come across the same problem and asked on
&lt;a href=&quot;https://askubuntu.com/questions/1119301/your-system-is-unable-to-reach-the-snap-store&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stack Overflow&lt;/a&gt;, basically you need to uninstall Lxd with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo dpkg --force depends -P lxd; sudo dpkg --force depends -P lxd-client
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can go about updating Ubuntu with the &lt;code&gt;do-release-upgrade&lt;/code&gt;
command, if you do that right away you may see something along the
lines of:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:534px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/7d50b4fcaaff9385631fc85d31cd2418/a07a7/noLtsUpgrade.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:47.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;191\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20191\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%209l1%208c0-1%202%200%202%202l2%203v-3l1-3%201%202c0%202%200%202%201%201%203-3%207%202%205%205-2%202-8%201-10-2l-1-2v2l-1%203-1%203c0%203%200%204%202%203l4%201h3c1-2%202-1%202%203l1%204v1c-2%200-3-1-3-3%200-3-1-3-3%200%200%202-2%203-3%203-3%200-3%201-3%203%200%203%200%204%202%203%202%200%203%200%204%202%201%201%202%202%203%201l2-1c3%201%202%204%200%204-2%201-2%201%200%202l3%201h-3l-4-1H6l-4%201c-2%200-2%200-2%203s0%204%203%204c2%200%203%200%203%203v5l-2-1-1-2-1%202-1%201-1%205c0%203%200%204%201%203%201-2%204-3%205-1l-1%201c-3%201-4%204-2%205s4%200%204-1c0-3%203-4%205-3s5%200%207-3c1-1%201-1%201%202s0%203%201%202c1-2%205-3%205-1%201%202%200%203-2%203s-2%200-1%201h2l1%201c0%202-4%201-5-1h-1c0%202-4%203-6%201h-1c-2%202-11%201-12-1-1-1-1%203-1%2013s0%2013%201%2012l3-2h5l2%202c2%201%202%202%202%204%200%203%200%203-1%201-1-3-3-4-3-1s-6%204-8%201c-1-1-1%200-1%203v5h5l4%201%202%201c2%201%202%202%202%204%200%203%200%203-1%201-1-3-3-4-3-1l-1%203-1-4c0-5-3-4-3%201l-1%204v-4l-1-4c-2-1-2%200-2%206v7h4c3%200%203%200%202%201l-2%205-1%204v-4l-1-4c-2-1-2%202-2%2026v27h401V0H213v4c0%204%200%205%202%205%201%201%200%201-1%201-2%200-3-1-3-4l-1-4V1l-13-1-13%201%202%203c4%201%203%205%200%206-3%200-3%200-3-5V0h-11l1%204%201%205c1%201%201%201-1%201s-2-1-2-4l-1-5c-2-1-11-2-11%200l1%201c2%200%201%202-1%202h-2l2%201c3%201%203%203%201%205-1%202-1%202-3%201-2-2-1-3%201-2l2-1-2-1c-2-1-3-3-1-4%204-3-4-3-78-3H0v9m66%207v1l-2%201c-3%202-4%202-5%201h-6c-2-2-5-1-6%203l1%203%201-3c0-1%200-2%201-1%201%203%2010%206%2010%203h1l4%201c2%200%202%200%202-5s0-6-1-4m42%2019c0%204%201%205%203%205l3-1h1c0%202%205%201%206-1h1l3%202c3%200%203%200%203-3l-1-3c-1-1-1%200-1%202l-1%203-1-2-1-3c-1-1-1%200-1%201h-1l-3-2-1-1c0-3-4%200-4%203-1%204-2%204-3%200l-1-4-1%204m8%2011h-2l-1%204c-1%204-2%204-3%200l-1-4-1%204c0%204%201%205%203%205l3-1h1c0%202%205%201%206-1h1l3%202c3%200%203%200%203-3l-1-3c-1-1-1%200-1%202l-1%203-1-2-1-3c-1-1-1%200-1%201h-1l-2-2-2-2h-1M35%2093c-2%204-1%209%203%209%202%200%202%200%200-1-3-1-3-2%201-2h7c2-3%201-8-3-8l-2%202h-1c-1-3-4-2-5%200m81%2031c-2%202-1%205%201%206l4-2c1-1%201-1%201%201%200%203%201%204%202%202l3-1c3%200%203-1%203-3s0-2%201%200l1%202v-2c1-2%201-2%201%200s0%203%204%203c3%200%204%200%203-1h-1l-1-1%202-1c1-1%202%200%202%201l1%202%201-2%201-3%201%203%201%202%201-3c0-3-2-5-5-3h-16c-2-2-5-1-5%201h-1c-1-2-3-3-5-1m111%2012l-2%202c-3%201-2%206%201%207%202%200%203%200%203-2h1l3%202c3%200%202-2%200-2s-2%200%201-1c2-2%203-2%203%201%201%203%203%203%204-1%202-2%202-2%202%200s2%203%205%203c1-1%201-1-1-2l-2-1h1c2%200%204-2%202-3h-5c0-2-2-1-3%202v3l-1-3c-2-4-2-4-3-2h-1c0-2-4-1-5%201%200%201-1%201-1-2s-1-3-2-2M0%20164l1%2019c0-7%200-8%202-8%203%200%204-2%201-4v-1l2-1-2-1c-3%201-3%200-3-4s0-4%203-4c2%200%203-2%200-4v-1l2-1-2-1c-3%201-3%201-3-8l-1%2019m257-24c-2%203%200%205%205%205%203%200%203-1%203-3s0-2%201%200v2l1-2c1-2%201-2%201%200s0%203%204%203c3%200%204%200%203-1l-2-1-1-1h1c2%200%204-2%202-3h-13c-2-2-4-1-5%201M35%20169c-2%203%200%207%203%208%202%200%202%200%200-1-3-1-3-2%201-2h7c2-3%201-8-3-8l-2%202h-1c-2-3-4-2-5%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/7d50b4fcaaff9385631fc85d31cd2418/60a22/noLtsUpgrade.webp 160w,/static/7d50b4fcaaff9385631fc85d31cd2418/4c812/noLtsUpgrade.webp 320w,/static/7d50b4fcaaff9385631fc85d31cd2418/29722/noLtsUpgrade.webp 534w&quot; sizes=&quot;(max-width: 534px) 100vw, 534px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/7d50b4fcaaff9385631fc85d31cd2418/69538/noLtsUpgrade.png 160w,/static/7d50b4fcaaff9385631fc85d31cd2418/72799/noLtsUpgrade.png 320w,/static/7d50b4fcaaff9385631fc85d31cd2418/a07a7/noLtsUpgrade.png 534w&quot; sizes=&quot;(max-width: 534px) 100vw, 534px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/7d50b4fcaaff9385631fc85d31cd2418/a07a7/noLtsUpgrade.png&quot; alt=&quot;no lts upgrade&quot; title=&quot;no lts upgrade&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;This is setting the updater to to only check for Long Term Support
versions, we’re going to change that now by changing the prompt from
&lt;code&gt;lts&lt;/code&gt; to &lt;code&gt;normal&lt;/code&gt;, in bash use:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo nano /etc/update-manager/release-upgrades
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You should see the default release upgrader settings:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/0920e538b6e247b6658b4ae737dd6113/2e06c/defaultRelaeaseUpgrader.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:46.25%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;184\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20184\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M1%202c0%202%200%203%202%202%201%200%202%200%202%202l1%204c0%202%200%202-2%202H1v13c0%2012%200%2013%202%2012%202%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203l-2%203c-1%200-2%201-2%203s0%203%202%202c2%200%202%200%202%203%200%202-1%202-2%202-2%200-2%201-2%202%200%202%201%203%202%203%202%200%202%203%200%205-1%202-2%203-2%207v4h399V0H1v2\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/0920e538b6e247b6658b4ae737dd6113/60a22/defaultRelaeaseUpgrader.webp 160w,/static/0920e538b6e247b6658b4ae737dd6113/4c812/defaultRelaeaseUpgrader.webp 320w,/static/0920e538b6e247b6658b4ae737dd6113/0ba47/defaultRelaeaseUpgrader.webp 640w,/static/0920e538b6e247b6658b4ae737dd6113/e46b2/defaultRelaeaseUpgrader.webp 960w,/static/0920e538b6e247b6658b4ae737dd6113/af3f0/defaultRelaeaseUpgrader.webp 1280w,/static/0920e538b6e247b6658b4ae737dd6113/7ad36/defaultRelaeaseUpgrader.webp 1637w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/0920e538b6e247b6658b4ae737dd6113/69538/defaultRelaeaseUpgrader.png 160w,/static/0920e538b6e247b6658b4ae737dd6113/72799/defaultRelaeaseUpgrader.png 320w,/static/0920e538b6e247b6658b4ae737dd6113/6af66/defaultRelaeaseUpgrader.png 640w,/static/0920e538b6e247b6658b4ae737dd6113/d9199/defaultRelaeaseUpgrader.png 960w,/static/0920e538b6e247b6658b4ae737dd6113/21b4d/defaultRelaeaseUpgrader.png 1280w,/static/0920e538b6e247b6658b4ae737dd6113/2e06c/defaultRelaeaseUpgrader.png 1637w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/0920e538b6e247b6658b4ae737dd6113/6af66/defaultRelaeaseUpgrader.png&quot; alt=&quot;default release ugrader&quot; title=&quot;default release ugrader&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;You’ll need to set it to normal:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/f459e42150a391a68786a8b0a9562a03/fd8a5/normalRelaeaseUpgrader.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:45.62500000000001%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;184\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20184\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%203c0%202%200%202%201%200l3-2%201%202-1%203-2%201C0%206%200%207%200%2022c0%209%200%2015%201%2014l2-2c2%200%202%200%202%202l-1%202c0%201-1%202-2%201-2%200-2%200-2%205%200%204%200%204%201%202%201-1%201-2%203-1l1%202-1%202-2%201c-2-1-2%200-2%204s0%205%201%203c2-4%204-2%203%202l-2%202c-2-1-2%200-2%204s0%205%201%203l3-2%201%202-1%203-2%201c-2-1-2%200-2%204s0%205%201%203l3-2%201%202-1%203-2%201c-2-1-2%200-2%204s0%205%201%203l3-2%201%202-1%203-2%201c-2-1-2%200-2%204%200%203%200%204%201%203l2-2c2%200%202%200%202%202l-1%203-2%201c-2-1-2%200-2%204%200%203%200%204%201%203l2-2c2%200%202%200%202%202l-1%202-2%201c-2%200-2%201-2%205s0%204%201%202c1-1%201-2%203-1l1%202-1%202-2%201c-2-1-2%200-2%204%200%205%200%205%201%203s3-3%203-1v3c0%202%200%202-2%202-2-1-2%200-2%204s0%205%201%203l3-2%201%202-1%203-2%201c-2-1-2%200-2%204s0%205%201%203l3-2%201%202-1%203-2%201c-2-1-2%200-2%202s0%203%202%202c3-1%204%203%201%205s-3%203-3%209v7h401V0H0v3\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/f459e42150a391a68786a8b0a9562a03/60a22/normalRelaeaseUpgrader.webp 160w,/static/f459e42150a391a68786a8b0a9562a03/4c812/normalRelaeaseUpgrader.webp 320w,/static/f459e42150a391a68786a8b0a9562a03/0ba47/normalRelaeaseUpgrader.webp 640w,/static/f459e42150a391a68786a8b0a9562a03/e46b2/normalRelaeaseUpgrader.webp 960w,/static/f459e42150a391a68786a8b0a9562a03/af3f0/normalRelaeaseUpgrader.webp 1280w,/static/f459e42150a391a68786a8b0a9562a03/a3d21/normalRelaeaseUpgrader.webp 1659w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/f459e42150a391a68786a8b0a9562a03/69538/normalRelaeaseUpgrader.png 160w,/static/f459e42150a391a68786a8b0a9562a03/72799/normalRelaeaseUpgrader.png 320w,/static/f459e42150a391a68786a8b0a9562a03/6af66/normalRelaeaseUpgrader.png 640w,/static/f459e42150a391a68786a8b0a9562a03/d9199/normalRelaeaseUpgrader.png 960w,/static/f459e42150a391a68786a8b0a9562a03/21b4d/normalRelaeaseUpgrader.png 1280w,/static/f459e42150a391a68786a8b0a9562a03/fd8a5/normalRelaeaseUpgrader.png 1659w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/f459e42150a391a68786a8b0a9562a03/6af66/normalRelaeaseUpgrader.png&quot; alt=&quot;default release ugrader&quot; title=&quot;default release ugrader&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Now we can go and do the release upgrade command:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo do-release-upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;upgrade-time&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#upgrade-time&quot; aria-label=&quot;upgrade time permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Upgrade time!&lt;/h2&gt;&lt;p&gt;Now I was quite surprised that it didn’t &lt;em&gt;really&lt;/em&gt; take that long at
all for the upgrade to complete, you may get asked questions about
modified packages and weather you want to accept the maintainers or
keep your version, I will always go with the maintainers version of
any packages. You can do what you like with yours, I’m not your mum 😜&lt;/p&gt;&lt;h2 id=&quot;thats-it&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thats-it&quot; aria-label=&quot;thats it permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;That’s it&lt;/h2&gt;&lt;p&gt;You should now have your Ubuntu WSL version at 18.10 👏&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/659d8b8617efe423b8fb2548500b9806/ddc81/updateComlpete.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:38.75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;154\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20154\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M2%2076v75h27c26%200%2027%200%2026-2-2-2-3-9-1-12%201-3%205-3%207%200l2%203v-3c0-2%205-3%207-1%202%203%202%209-1%2011h-6l-3-1c-4%201-6-4-2-5%203-1%202-3-1-3-4%200-3%2010%202%2011l2%201%2053%201a330%20330%200%200154%201l116-1h116V0H2v76M54%205c-3%206%200%2015%205%2014%202-1%202-1%200-2-5-2-6-11-2-11%203%200%204%202%201%203-4%201-2%206%202%205l3%201h6c3-2%203-8%201-11-2-2-7-1-7%201v3l-2-3c-2-3-6-3-7%200m59-1v11c4%203%208%200%208-6%200-5-5-8-8-5m228%204c-1%201%200%204%203%204l2%201-3%201h-3c1%202%207%202%208%200%202-2%202-2%203%200l4%202c4%200%204-2%200-2-4-1-4-3%200-3%203%200%205-1%203-4-2-2-6-1-8%202s-2%203-5%201l-2-1%202-1%203-1c0-2-6-1-7%201M99%2026l-2%202-4%202c-1%201-1%201-3-1h-9l-5-1h-4v5l1%205%201-4%201-3%201%202%201%202%201-2%201-2%201%204%201%203%201-1h1c2%201%205%201%207-1h3l5%202h3v-7l-1-7-1%202M3%2032l1%206%201-4c0-5%201-5%203%200%202%204%204%205%204%202h2c3%204%208%202%208-3s-6-7-8-3c-2%202-2%202-2-1l-1-4-1%204v4l-2-4c-3-6-5-5-5%203m31-1v7h8c11%200%2013-3%206-8-3-2-3-4%201-2l2-1c-1-2-6-2-7%200-2%202%201%206%204%206l1%201c-1%201-3%202-7%202h-6v-5l-1-6-1%206m19%200v7h3c4%200%207-2%205-5v-4c0-3-1-4-4-4h-4v6M3%2053c0%207%200%207%203%207s6-2%206-5c1-4%203-3%204%201%200%203%201%204%203%204%203%200%204-2%201-2-2-1-2-2-2-4%200-4%200-4-2-4l-3%201-1-1c-1-2-2-3-5-3H3v6m129%201v6h3c4%200%206-2%206-7%200-4-2-6-6-6-3%200-3%200-3%207M3%2076v6h3l5-2c2-2%202-2%203%200s7%203%207%201l-2-1-3-1c-1-2-1-2%202-2s4%200%204-2c0-3-5-4-8-1-2%201-2%201-2-1%200-3-2-4-6-4H3v7m268-4c-3%207%203%2014%208%207%202-4%201-9-4-10-2%200-3%200-4%203M93%2074c-3%206%203%2011%207%207l2-2%201%202%201%201%201-4%201-4c1%200%203%203%203%205l1%203v-9c-2-2-7-1-7%201l-1%202-2-2c-1-3-6-3-7%200m109%2019c-2%204%200%2011%203%2011%204%200%205-2%205-6%200-7-5-10-8-5M29%20114l-2%202-3%202h-3c-3-4-8-2-8%203s5%207%208%203c1-1%201-1%203%201l5%201c2%200%203-1%203-7l-1-7-2%202m33%207c0%206%203%207%203%201%200-2%200-3%201-1%200%203%202%203%202%200l1-2%201%204%201%203%201-1h3l5%201c1-1%201-1-1-2-4-1-5-3-1-3%203%200%204-1%203-3s-5-3-7-1-2%202-2%200l-5-1h-5v5m51%2015c-3%203%200%2012%204%2012%202%200%204-3%204-7s-1-6-4-6l-4%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/659d8b8617efe423b8fb2548500b9806/60a22/updateComlpete.webp 160w,/static/659d8b8617efe423b8fb2548500b9806/4c812/updateComlpete.webp 320w,/static/659d8b8617efe423b8fb2548500b9806/0ba47/updateComlpete.webp 640w,/static/659d8b8617efe423b8fb2548500b9806/a6125/updateComlpete.webp 837w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/659d8b8617efe423b8fb2548500b9806/69538/updateComlpete.png 160w,/static/659d8b8617efe423b8fb2548500b9806/72799/updateComlpete.png 320w,/static/659d8b8617efe423b8fb2548500b9806/6af66/updateComlpete.png 640w,/static/659d8b8617efe423b8fb2548500b9806/ddc81/updateComlpete.png 837w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/659d8b8617efe423b8fb2548500b9806/6af66/updateComlpete.png&quot; alt=&quot;update complete&quot; title=&quot;update complete&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;If, like me, you uninstalled Ubuntu and tried to reinstall it and are
getting errors like this:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;/e0476cc0d2751828f40541b205165d16/derp-install.gif&quot; alt=&quot;error installing ubuntu&quot;/&gt;&lt;/p&gt;&lt;p&gt;Then what worked for me was to restart the &lt;code&gt;LxssManager&lt;/code&gt; via a
PowerShell console with admin rights.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Get-Service LxssManager | Restart-Service
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up!&lt;/h2&gt;&lt;p&gt;We went ahead an upgraded our WSL Ubuntu version from 18.04 to 18.10,
we removed Lxd which isn’t needed on WSL but is part of the Microsoft
Store version 🤷‍♂️&lt;/p&gt;&lt;p&gt;Then we changed the default behaviour of the release upgrader from
&lt;code&gt;lts&lt;/code&gt; to &lt;code&gt;normal&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Once we have done those two parts we can then go ahead and upgrade
Ubuntu with `do-release-upgrade.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Thanks for reading&lt;/strong&gt; 🙏&lt;/p&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Creating a Custom React Hook for Gatsby Site Metadata]]></title><description><![CDATA[Hooks ahoy! Ok, let's get it on with the new hotness in Reactland, React Hooks!
This is a guide covering using the Gatsby custom React hook…]]></description><link>https://scottspence.com/2019/03/24/custom-gatsby-metadata-hook/</link><guid isPermaLink="false">https://scottspence.com/2019/03/24/custom-gatsby-metadata-hook/</guid><pubDate>Sun, 24 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;hooks-ahoy&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#hooks-ahoy&quot; aria-label=&quot;hooks ahoy permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hooks ahoy!&lt;/h2&gt;&lt;p&gt;Ok, let’s get it on with the new hotness in Reactland, React Hooks!
This is a guide covering using the Gatsby custom React hook for
&lt;code&gt;StaticQuery&lt;/code&gt; which it is now replacing with &lt;code&gt;useStaticQuery&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;If you haven’t used Gatsby before &lt;code&gt;StaticQuery&lt;/code&gt; is just that, a way to
query data in a Gatsby component (i.e. a react component) or a Gatsby
page where the query input doesn’t change. This is a great use case
for data that doesn’t change a great deal, like your site metadata.&lt;/p&gt;&lt;h2 id=&quot;tldr&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;tl;dr&lt;/h2&gt;&lt;p&gt;Here’s me trying to &lt;a href=&quot;https://youtu.be/8ruJBKFrRCk?t=93&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;even&lt;/a&gt; with &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; whilst I convert some
of the Gatsby default starter that’s on &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; to use the
&lt;code&gt;useSiteMetadata&lt;/code&gt; custom hook.&lt;/p&gt;&lt;p&gt;Using &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; we take a look at implementing a custom react
hook for getting site metadata in Gatsby.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Here’s a video:&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-qWay-LjXwbk&quot; src=&quot;https://www.youtube.com/embed/qWay-LjXwbk?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;StaticQuery&lt;/code&gt; component uses the &lt;a href=&quot;https://reactjs.org/docs/render-props.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;render props&lt;/a&gt; pattern, which
means it takes in a function and returns/renders based off of that.&lt;/p&gt;&lt;p&gt;I have detailed this pattern before in a post about &lt;a href=&quot;http://localhost:8899/react-context-api-getting-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;using the react
context api&lt;/a&gt;, it’s a component that you pass a function to, to render
a component.&lt;/p&gt;&lt;p&gt;Think of it like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;lt;Component&amp;gt;
 {() =&amp;gt; ()}
&amp;lt;/Component&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first parenthesis is the arguments/variables and the second is
what gets rendered, so in the case of the Gatsby &lt;code&gt;StaticQuery&lt;/code&gt; you
pass a query with a &lt;code&gt;graphql&lt;/code&gt; tag and then the &lt;code&gt;data&lt;/code&gt; that comes back
from that is what is used in the render of that component. So you have
your wrapping component that returns and renders a child component,
like this.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;lt;WrappingComponent&amp;gt;
  {args =&amp;gt; &amp;lt;ComponentToRender propsForComponent={args.propNeeded} /&amp;gt;}
&amp;lt;/WrappingComponent&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s a cut down version of the &lt;code&gt;StaticQuery&lt;/code&gt; component being used in
the Gatsby default starter on &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I’ve taken out the styling to make it a bit shorter:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Layout = ({ children }) =&amp;gt; (
  &amp;lt;StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data =&amp;gt; (
      &amp;lt;&amp;gt;
        &amp;lt;Header siteTitle={data.site.siteMetadata.title} /&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
          &amp;lt;footer /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/&amp;gt;
    )}
  /&amp;gt;
)

export default Layout
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;StaticQuery&lt;/code&gt; takes in two props, the &lt;code&gt;query&lt;/code&gt; and what you want to
render with &lt;code&gt;render&lt;/code&gt;, this is where you can destructure the data you
need out of the &lt;code&gt;data&lt;/code&gt; prop returned from the query.&lt;/p&gt;&lt;p&gt;I was never really a fan of doing it that way so I adopted a similar
pattern but with the component contained on it’s own and then added to
the &lt;code&gt;StaticQuery&lt;/code&gt; separately. Like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Layout = ({ children, data }) =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;Header siteTitle={data.site.siteMetadata.title} /&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
      &amp;lt;footer /&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/&amp;gt;
)

export default props =&amp;gt; (
  &amp;lt;StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data =&amp;gt; &amp;lt;Layout data={data} {...props} /&amp;gt;}
  /&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I found this more acceptable because you didn’t have to have all the
code bunched into the &lt;code&gt;StaticQuery&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;That all make sense?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Good, now forget about all of that! It’s time to use the new
&lt;code&gt;useStaticQuery&lt;/code&gt; hotness in Gatsby. 💪&lt;/p&gt;&lt;h2 id=&quot;versions&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#versions&quot; aria-label=&quot;versions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Versions:&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;This guide is being used with the following dependency versions.&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;gatsby: 2.1.31&lt;/li&gt;&lt;li&gt;react: 16.8.4&lt;/li&gt;&lt;li&gt;react-dom: 16.8.4&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;You can also check out the &lt;a href=&quot;https://codesandbox.io/s/1vnvko0zqj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;example code&lt;/a&gt;.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;The &lt;a href=&quot;https://www.gatsbyjs.org/docs/use-static-query/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby documentation&lt;/a&gt; covers the use of it and also how to make
your own custom react hook to use &lt;code&gt;useStaticQuery&lt;/code&gt;, here’s the one I
use in the video.&lt;/p&gt;&lt;p&gt;&lt;em&gt;useSiteMetadata.js&lt;/em&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql, useStaticQuery } from &amp;#x27;gatsby&amp;#x27;

const useSiteMetadata = () =&amp;gt; {
  const { site } = useStaticQuery(
    graphql`
      query SITE_METADATA_QUERY {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )
  return site.siteMetadata
}

export default useSiteMetadata
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This can now be implemented in the rest of the code as a function
call:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { title, description, author } = useSiteMetadata()
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;lets-implement-it&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lets-implement-it&quot; aria-label=&quot;lets implement it permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s implement it!&lt;/h2&gt;&lt;p&gt;In the &lt;code&gt;layout&lt;/code&gt; component import the &lt;code&gt;useSiteMetadata&lt;/code&gt; hook then we
can go about removing the &lt;code&gt;StaticQuery&lt;/code&gt; component and destructuring
&lt;code&gt;title&lt;/code&gt; from the &lt;code&gt;useSiteMetadata&lt;/code&gt; hook.&lt;/p&gt;&lt;p&gt;It should look something like this, I have taken the styling out for
brevity:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;
import useSiteMetadata from &amp;#x27;./useSiteMetadata&amp;#x27;

import Header from &amp;#x27;./header&amp;#x27;
import &amp;#x27;./layout.css&amp;#x27;

const Layout = ({ children }) =&amp;gt; {
  const { title } = useSiteMetadata()
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Header siteTitle={title} /&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
        &amp;lt;footer&amp;gt;
          © {new Date().getFullYear()}, Built with
          {` `}
          &amp;lt;a href=&amp;quot;https://www.gatsbyjs.org&amp;quot;&amp;gt;Gatsby&amp;lt;/a&amp;gt;
        &amp;lt;/footer&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  )
}
Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here’s the comparison:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/9fafa/compareLayout.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:60%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;239\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20239\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20120v119h10c9%200%2010-1%2010-2l1-2%201%202c0%202%201%202%20189%202h190V0H0v120m0-55l1%2052v-12h29v6h44v-6h119v3c0%202%201%203%202%203l1-30V50h7c6%200%206%200%206%202s0%202%201%201v-2l2-1%203%201h-2l-1%201%201%201%202%201c1%201%201%201%201-1s0-3%202-3c3%200%203%202%201%205l9%201h9v-6h152v3l1%203v1l1%201h1v44l1%208c0%205%200%206-2%206-2%201-3%208%200%208l2%201%204%201%204%201V63l-1-51v13h-10l2%201%201%205c0%204-1%206-2%206l-2%202v3h-87v-2c1-2%200-3-1-3s-2%201-2%203l-1%202-2-1-2-2c-3%200-3%202%200%203%203%200%202%201-2%201l-4-3c0-2%200-2-1%201l-1%203v-3l-1-3v2l-1%202-2-1c0-2-1-2-12-2-7-1-9%200-9%202s-3%201-3-1%200-2-1%200-1%202-1%200c0-3-2-3-2%200s-8%203-8%200c-1-2-10-2-13%200%200%201-1%201-1-1-1-1-1-1-1%201s-3%203-3%200c-1-2-11-2-13%201-1%201-5%202-5%200s0-3-2-3l-2%202c0%201%200%202-4%202-9%200-5%202%204%202l9%201h-2l-1%201%202%201%201%201-9%201h-9l-1-6c-1-7-2-8-3-3v3h-43a176%20176%200%2001-44-2v-2c1-2%201-2-1-2-1%200-2%201-2%203s0%203-5%203-5%200-5-2l-1-3-1%201h-1c-1-1-1-1-1%201s-1%203-13%203c-13%200-14%200-13-4l-1-1-1%203-1%203h134l-1%203v2h-68l-69-1c-1-1%200-4%202-4%201-1-2-1-7-1l-9-1h4c4%200%204%200%204-2l-6-1-6%201-2-1c-1-1-1-1-1%201%200%201%201%202%203%202%201%201-2%201-8%201s-8-1-4-1c6%200%207%200%206-2l-2-2-5%201c-4%200-5%200-5%202-1%202-2%202-10%202H1V22L0%2065m0%200l1%2051v-12h29v-5H1l17-1h17v-5H18L1%2092h39v-5H26c-9%200-14%200-13%201h1l1%201c0%202-2%203-2%201h-1l-1%201v-2c0-2%200-2-5-2-6-1%206-1%2026-1%2013%200%2013%200%2013-3v-2H30c-14%200-15%200-15%202-1%202-1%202-2%201h-1l-1%201v-2l1-2c2%200%203%200%202-2l-2-1c-1%202-2%201-1-1%200-2%203-2%204%200%200%202%202%202%2018%202h17v-3c0-2%200-3-1-2H34C9%2074%200%2074%205%2073c4%200%205-1%205-2%201-2%205-2%205-1l-2%202c-1%201%206%201%2015%201h17v-5H32c-18%200-33%200-26-1%205%200%205%200%205-2v-2l1%202c0%202%201%202%2014%202h14v-5H1l17-1h17v-5H1l14-1h15v-5H1l12-1c12%200%2012%200%2012-3v-2H1V22L0%2065M38%203l2%202h4c1%201%200%201-3%201-4%200-4%200-4%203l1%204h61v-3l-1-4c-1-1%200-1%202-1l3-1c0-3-8-2-9%200%200%202-1%202-4%202s-3%200-2-2c2%200%202-1%201-1H77l1%202-6%201c-6%200-7%200-7-2l-1-2v2c-1%202-2%202-6%202s-4%200-1-1c5%200%204-3-1-3-4%200-5%200-5%202l-2%202c-2%200-2%200-1-1%204-1%202-3-4-3l-6%201m195%200c0%202%201%202%203%202h4c1%201%200%201-3%201-4%200-4%200-4%204v3h39V6h-5c-5%200-6%200-6-2l-1-2v2c-1%202-2%202-6%202-3%200-4%200-2-1h3l1-1c0-1-2-2-11-2l-12%201m54%201l1%201v5l1%202%2022%201h22l1-2c2-5%200-5-21-5-11%200-20%200-18-1h3l1-1c0-1-2-2-6-2s-6%201-6%202M115%207v3l1%202%208%201%208-1c-1-1%200-2%201-2V7c-1-1-15-2-18%200m195%2040v2h79v-2l1-3h-80v3M68%2053v2h125v-5H68v3m23%206v2h102v-5H91v3m-35%205v2l69%201h68v-5h-68c-62%200-69%200-69%202m26%205l-1%202c0%202%202%202%2056%202h57l-1-2v-3h-55l-56%201m-18%205v3l-1%202h131l-1-3v-2h-58a5469%205469%200%2001-71%200m330%2022c0%2017%200%2020%202%2020s2%206-1%206c-1%201%200%201%202%201h3V75h-6v21M48%2082c-1%204-3%204%2073%204h72v-2l1-3h-73l-73%201m-5%207l1%203h149v-2l1-3H43v2m-5%207v2h155v-5H38v3m-3%206v2h158v-5H35v3m52%2016l-1%203v2h29c33%200%2036%200%2036-3%200-2-2-3-2-1h-1c-1-2-3-2-30-2l-31%201M0%20184l1%2050v-6h10c9%200%209%200%209%203a522495%20522495%200%200192%203h84v-13H19v3l1%203H1v-49l-1-49v55m71%2015l1%201h1l2%201c2%200%202%200%200%201l28%201h31v-2c-1-3-8-4-7-1l-2%202-2-1-1-3-2%202-1%202-1-1c1-2-4-3-6-2h-5l-3%201c0%202-1%202-6%202l-6-1h5l4-1-3-1-4-1-2%202-2%202v-4l-1%202c-1%202-4%203-4%201s0-3-2-3l-2%201h-4l-3-1-3%201m191%200l3%202c2%200%202%200%200%201-1%201%2012%201%2029%201h30l1-2%202-3h-5l-4%202-2%202-2-2c0-3-4-2-4%200s0%202-1%201c0-2-4-3-6-2h-2l-7%201c0%202-11%203-11%201h5l4-1c0-2-9-2-10%200h-1v-2l-2%202c0%202%200%202-2%200s-8-3-8%200h-1c-1-2-6-3-6-1\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/60a22/compareLayout.webp 160w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/4c812/compareLayout.webp 320w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/0ba47/compareLayout.webp 640w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/e46b2/compareLayout.webp 960w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/af3f0/compareLayout.webp 1280w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/18d80/compareLayout.webp 1565w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/69538/compareLayout.png 160w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/72799/compareLayout.png 320w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/6af66/compareLayout.png 640w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/d9199/compareLayout.png 960w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/21b4d/compareLayout.png 1280w,/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/9fafa/compareLayout.png 1565w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/ea4dd0fb5890ca0f00a8d98e9f57a0df/6af66/compareLayout.png&quot; alt=&quot;compareLayout&quot; title=&quot;compareLayout&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;On now to the &lt;code&gt;seo&lt;/code&gt; component, same again, remove &lt;code&gt;StaticQuery&lt;/code&gt; and
use &lt;code&gt;useSiteMetadata&lt;/code&gt; in it’s place.&lt;/p&gt;&lt;p&gt;Here’s the comparison:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/0e2968ec8991f7a0c3f41e1b64986288/9f9a4/compareSEO.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:47.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;191\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20191\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2021v21h5l5%201H0v18h6l7%201H0v129h401V61h-4l-4-1%204-1%204%201V30c0-17%200-30-1-29h-3L199%200H0v21m252-7l-1%202-3%203h-9l-3-1c-3%200-4%200-3%203%200%204%204%205%206%203h9l27%201h27v-7h-50l1-2c0-3%200-4-1-2M55%2017c1%202%200%202-3%201l-7%201-6%201-3%201c0%202%2014%203%2031%203h8v-6h-9c-9%200-10%200-10-2-1-1-1-1-1%201m36%202v2l1%202%2020%201c15%200%2019-1%2019-2l1-1v-2H91m227%200v2l1%202c0%202%201%202%208%202s8%200%208-2l1-2c3-2-2-3-9-3l-9%201m-75%2015l2%201%201%201h-4c-4%200-6%202-6%204%200%203-3%202-3%200-1-2-13-2-12%200%200%202-1%202-7%202s-7%200-7-2l-1-2v2c0%202-1%202-5%202h-5l15%201c14%200%2014%200%2014%203s-18%203-18%200l-1-2v2c0%202-1%202-5%202-3%200-5%200-4%201l4%201c4%200%205%200%205%202l1%203v-3c0-2%200-2%2012-2%2010%200%2011%200%2011%202s1%202-21%202l-13%201%206%201%207%201h1l13-1h12v2c0%203%200%203-9%203s-10%200-10-2c-1-2-1-2-1%200s0%202-10%202l15%201c13%200%2024%200%2023%201-3%200-3%203%200%203l2-2c0-2%201-2%208-2l8%201h-8c-5%200-7%201-7%202l2%201c1%201-6%201-15%201-17%200-17%200-17-2l-1-2v2c0%202%200%202-10%202l-9%201h9c10%200%2010%200%2010%202%200%203%200%203-9%203l-9%201h9c8%200%209%200%209%202l1%203v-3c0-2%200-2%2014-2%2016%200%2016%200%2015%203%200%202-1%202-25%202l-15%201c9%200%2010%200%2010%202l1%203v-5h88a4105%204105%200%200029-1c-56%200-60%200-60-2%201-2-11-3-12-1h-6l-6-1%2072-1h73l-68-1h-67v-5h135l-59-1h-58v-5h58a1794%201794%200%2000-13-1h-70v-3l-1-2h71a916%20916%200%2000-73-4c0-2%201-2%2072-2a996%20996%200%2000-71-6%2011442%2011442%200%200098-2h-46v-3c0-3%200-3-3-3-2%200-3%200-3-2%200-1%200-2-5-1-3%200-2%202%201%202l2%201h-23v-1l2-1c0-1-1-2-3-2-3%200-4%201-4%202l1%201%201%201c0%202-4%200-5-2s-10-2-9%200l-2%202-2-2c0-2%200-2-1%200%200%202-1%202-1%201l-1-2-2-1-2%202M24%2039c-1%202%200%203%204%203h3c-2%200-3%207-2%208v1c-2%203-1%205%203%205h4l-4%201c-6%201-4%202%203%203l8-1h1c0%202-1%202-15%202H13l5%201c6%200%206%200%206%203%200%204%202%204%202%200v-3l1%203%201%203h23l25-1v-4l59-1%2061-1H47v-2c0-3%200-3%209-3%206%200%208%200%207-1-2-1%200-2%202-1l1-2c-1-3%200-3%201-3%202%200%202%200%201%201-2%203-1%204%205%204%208-1%2010%200%208%201-1%201%200%201%203%201%202%200%203%200%202-1-2-1-1-1%205-1l3-1h1c2%202%207%201%207-1l-5-1c-11%200-12%200-11-1l-2-2-2-2%201-2%2056-1%2057-1H41v-2c0-2%200-2-1-1v2l-2%201-2-2c0-1-1-2-6-2l-6%201m192%2032v2h15c14%200%2015-1%2015-2%200-2-1-3-15-3h-15v3m-10%2012c0%202-1%202-4%202l-5%201%206%201%206%201h-1c-2-1-2-1-2%201s-1%202-4%202l-5%201%205%201c4%200%204%200%204%202v2l1-3%2014-1c14%200%2014%200%2014%202v3h-38l17%201h16v2c0%204-14%204-14%201l-1-2v2c0%202%200%202-10%202l-9%201h9c10%200%2010%200%2010%202%200%203%200%203-10%203l-9%201h19v3l1%204v-7h178l-83-1h-83v-5h166l-80-1h-80l-1-3v-2h80a3014%203014%200%2000-74-2v-2c0-2%208-2%2077-2a1134%201134%200%20002-2h-75l1-2v-2h74a1074%201074%200%2000-73-3c1%201-2%201-19%201l-19-1h2l1-1c-1-2-4-2-4%200m5%204l-1%202c-1%202%201%202%2015%202%2015%201%2017%200%2016-3l-15-1h-15m-69%2038h-2c-1-1-12-1-12%201h-1l-1-2v2h-1c0-1-2-1-2%201l10%201%2022-1h1c2%202%2015%201%2015%200%200-2-7-3-7-1h-1c0-2-1-2-8-1l-9-1c0-1-2-1-4%201m186%200h-7l-2%201c0%202%201%202%203%202l12%201%209-1h4c7%201%2028%200%2029-1s2%200%203%201h9l5-1c0-2-4-3-5-2h-8l-12-1h-21c-10-1-17-1-19%201m-29%2048l-2%201c-2-1-3%200-3%201s1%202%203%202h46c3%200%204%200%204-2l-1-1h-2c0-2-2-1-2%201h-1c-1-2-2-2-12-3-6%200-8%200-7%201h-23m-63%202c0%202%201%202%206%202h24l1%201%201-3c0-2%200-2-1-1l-2%201-11-1h-16l-1-1-1%202\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/0e2968ec8991f7a0c3f41e1b64986288/60a22/compareSEO.webp 160w,/static/0e2968ec8991f7a0c3f41e1b64986288/4c812/compareSEO.webp 320w,/static/0e2968ec8991f7a0c3f41e1b64986288/0ba47/compareSEO.webp 640w,/static/0e2968ec8991f7a0c3f41e1b64986288/e46b2/compareSEO.webp 960w,/static/0e2968ec8991f7a0c3f41e1b64986288/af3f0/compareSEO.webp 1280w,/static/0e2968ec8991f7a0c3f41e1b64986288/9fbc2/compareSEO.webp 1560w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/0e2968ec8991f7a0c3f41e1b64986288/69538/compareSEO.png 160w,/static/0e2968ec8991f7a0c3f41e1b64986288/72799/compareSEO.png 320w,/static/0e2968ec8991f7a0c3f41e1b64986288/6af66/compareSEO.png 640w,/static/0e2968ec8991f7a0c3f41e1b64986288/d9199/compareSEO.png 960w,/static/0e2968ec8991f7a0c3f41e1b64986288/21b4d/compareSEO.png 1280w,/static/0e2968ec8991f7a0c3f41e1b64986288/9f9a4/compareSEO.png 1560w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/0e2968ec8991f7a0c3f41e1b64986288/6af66/compareSEO.png&quot; alt=&quot;compareSEO&quot; title=&quot;compareSEO&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;If you want to check out the code the example is available here:
&lt;a href=&quot;https://codesandbox.io/s/1vnvko0zqj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;example code&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up!&lt;/h2&gt;&lt;p&gt;That’s it! Wh have gone from using the awesome &lt;code&gt;StaticQuery&lt;/code&gt; render
props pattern used in Gatsby over to the even more awesome
&lt;code&gt;useStaticQuery&lt;/code&gt; React hooks, hook.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Thanks for reading&lt;/strong&gt; 🙏&lt;/p&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Testing MDX]]></title><description><![CDATA[Moving to the new hotness!! I've now moved this blog over to Gatsby MDX. You can see all the
changes
 on my repo here . From the pull I'm…]]></description><link>https://scottspence.com/2019/03/09/testing-mdx/</link><guid isPermaLink="false">https://scottspence.com/2019/03/09/testing-mdx/</guid><pubDate>Sat, 09 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;moving-to-the-new-hotness&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#moving-to-the-new-hotness&quot; aria-label=&quot;moving to the new hotness permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Moving to the new hotness!!&lt;/h2&gt;&lt;p&gt;I’ve now moved this blog over to Gatsby MDX. You can see all the
changes
&lt;a href=&quot;https://github.com/spences10/blog.scottspence.me/pull/1128/files&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;on my repo here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;From the pull I’m hoping you can glean that the majority of the work
is in replacing &lt;code&gt;gatsby-transformer-remark&lt;/code&gt; with &lt;code&gt;gatsby-mdx&lt;/code&gt;, there
are some additional files added, that pretty nifty &lt;code&gt;Code.js&lt;/code&gt; component
from LekoArts minimal starter blog, and the &lt;code&gt;wrap-root-element.js&lt;/code&gt;
module for (I think) the MDX rendering of the code.&lt;/p&gt;&lt;p&gt;Files changed:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;gatsby-browser.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;gatsby-config.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;gatsby-node.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;gatsby-ssr.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;src/pages/index.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;src/templates/blogPostTemplate.js&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Files added:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;src/components/Code.js&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;wrap-root-element.js&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Shout out to LekoArts, HagNerd and Chris Biscardi for their example
repositories:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/LekoArts/gatsby-starter-minimal-blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-starter-minimal-blog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/hagnerd/gatsby-starter-blog-mdx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gatsby-starter-blog-mdx&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/ChristopherBiscardi/christopherbiscardi.github.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;christopherbiscardi.github.com&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;things-i-still-havent-figured-out&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#things-i-still-havent-figured-out&quot; aria-label=&quot;things i still havent figured out permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Things I still haven’t figured out&lt;/h2&gt;&lt;h3 id=&quot;code-blocks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#code-blocks&quot; aria-label=&quot;code blocks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code blocks&lt;/h3&gt;&lt;p&gt;Code blocks are pretty, this is a &lt;code&gt;js&lt;/code&gt; block with the
&lt;code&gt;prism-react-renderer/themes/nightOwl&lt;/code&gt; theme:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const onClick = () =&amp;gt; {
  alert(&amp;#x27;clicked&amp;#x27;)
}
render(&amp;lt;button onClick={onClick}&amp;gt;Click Me!&amp;lt;/button&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And here is a &lt;code&gt;js react-live&lt;/code&gt; block, try editing the code:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; metastring=&quot;react-live&quot;&gt;const onClick = () =&amp;gt; {
  alert(&amp;#x27;clicked&amp;#x27;)
}
render(&amp;lt;button onClick={onClick}&amp;gt;Click Me!&amp;lt;/button&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Image for prosperity 👍&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/a242d/highlightVLive.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:43.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;173\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20173\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M6%2025v51c0%202%2018%202%20197%202h197V23H203C24%2023%206%2023%206%2025m-1%2083v24l1%2022h394v-47H203L5%20108\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/60a22/highlightVLive.webp 160w,/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/4c812/highlightVLive.webp 320w,/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/0ba47/highlightVLive.webp 640w,/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/79561/highlightVLive.webp 724w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/69538/highlightVLive.png 160w,/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/72799/highlightVLive.png 320w,/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/6af66/highlightVLive.png 640w,/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/a242d/highlightVLive.png 724w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/3b1ee37a5c2b58e0079a1c23bea2b7e4/6af66/highlightVLive.png&quot; alt=&quot;highlightVLive&quot; title=&quot;highlightVLive&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h3 id=&quot;mdx-is-a-bit-slow&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#mdx-is-a-bit-slow&quot; aria-label=&quot;mdx is a bit slow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mdx is a bit slow&lt;/h3&gt;&lt;h3 id=&quot;sometimes-renders-dont-update&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#sometimes-renders-dont-update&quot; aria-label=&quot;sometimes renders dont update permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sometimes renders don’t update&lt;/h3&gt;&lt;h3 id=&quot;not-working-yet&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#not-working-yet&quot; aria-label=&quot;not working yet permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Not working yet&lt;/h3&gt;&lt;ul class=&quot;contains-task-list&quot;&gt;&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled=&quot;&quot;/&gt; Autolink headers&lt;/li&gt;&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled=&quot;&quot;/&gt; Embed tweets&lt;/li&gt;&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled=&quot;&quot;/&gt; Embed videos&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Setting up multiple Git providers]]></title><description><![CDATA[Over the past couple of weeks now I have set up several development
machines at work and have had to also use two git accounts, GitHib and…]]></description><link>https://scottspence.com/2019/01/27/multiple-git-profiles/</link><guid isPermaLink="false">https://scottspence.com/2019/01/27/multiple-git-profiles/</guid><pubDate>Sun, 27 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the past couple of weeks now I have set up several development
machines at work and have had to also use two git accounts, GitHib and
Bitbucket.&lt;/p&gt;&lt;p&gt;To connect to both I use SSH as a preference, I have been using SSH in
place of HTTPS for quite some time now, if you want to connect
repeatedly without having to provide user name and password details
then SSH is a good option.&lt;/p&gt;&lt;p&gt;If you are unfamiliar with using SSH to authenticate with git then
take a look at my cheat sheets repository (&lt;a href=&quot;https://github.com/spences10/cheat-sheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ss10.me/cheat-sheets&lt;/a&gt;)
there are several sections covering SSH, notably:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/git.md#how-to-authenticate-with-github-using-ssh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How to Authenticate with GitHub Using SSH&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/git.md#use-multiple-ssh-keys&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Use multiple SSH Keys&lt;/a&gt; (what this post is covering)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/git.md#re-use-ssh-keys-from-one-machine-to-another&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Re Use SSH Keys from one Machine to Another&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I have come across this set-up a few times now and implemented it for
myself.&lt;/p&gt;&lt;p&gt;You’ll need to create a &lt;code&gt;config&lt;/code&gt; file in the &lt;code&gt;.ssh&lt;/code&gt; folder in your
home directory (Windows, Ubuntu or both if you use a &lt;a href=&quot;https://thelocalhost.blog/wsl-bootstrap-2019&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WSL set-up&lt;/a&gt;)
check with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ll ~/.ssh/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will list out the contents of the folder, if you get
&lt;code&gt;No such file or directory&lt;/code&gt; then you don’t have SSH configured.&lt;/p&gt;&lt;p&gt;Take a look at the &lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/git.md#how-to-authenticate-with-github-using-ssh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How to Authenticate with GitHub Using SSH&lt;/a&gt; section
on the cheat-sheets repo for details on that.&lt;/p&gt;&lt;p&gt;For this example let’s presume that we have already created our SSH
keys for Bitbucket and GitHub and authenticated with both Bitbucket
and GitHub.&lt;/p&gt;&lt;p&gt;Next create a &lt;code&gt;config&lt;/code&gt; file:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nano ~/.ssh/config
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will open a new file with nano that we can add the following to:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Bitbucket (default)
  Host bb
  HostName bitbucket.org
  User git
  IdentityFile ~/.ssh/id_default

# Github (secondary)
  Host gh
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_secondary
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Just remember that the &lt;code&gt;IdentityFile&lt;/code&gt; needs to match what you have
called your SSH keys.&lt;/p&gt;&lt;p&gt;Check current permissions with &lt;code&gt;stat&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# stat -c &amp;quot;%a %n&amp;quot; ~/.ssh/*
644 /home/scott/.ssh/config
700 /home/scott/.ssh/id_default
700 /home/scott/.ssh/id_default.pub
700 /home/scott/.ssh/id_secondary
700 /home/scott/.ssh/id_secondary.pub
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Change the &lt;code&gt;config&lt;/code&gt; file permissions as needed:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;chmod 644 ~/.ssh/config
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;multiple-users&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#multiple-users&quot; aria-label=&quot;multiple users permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Multiple users&lt;/h2&gt;&lt;p&gt;Ok now we should be able to push and pull to the respective GitHub and
Bitbucket repositories, &lt;em&gt;but&lt;/em&gt; unless you have the same username and
email address for GitHub and Bitbucket then we’re also going to need
to specify specific user details for the repositories we’re accessing,
otherwise the details specified in the &lt;code&gt;~/.gitconfig&lt;/code&gt; are what will be
used with commits.&lt;/p&gt;&lt;p&gt;In my case for work my default user account is Bitbucket so that is
what I have specified in the &lt;code&gt;~/.gitconfig&lt;/code&gt;, however for the GitHub
repos I work on I’ll need to specify my GitHub credentials on a repo
by repo basis.&lt;/p&gt;&lt;p&gt;Historically I have gone into the individual repo and manually set the
config details.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# from the root of the repo you want to specify the credentials
git config user.name &amp;#x27;Your Name&amp;#x27;
git config user.email &amp;#x27;your@email.com&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I have since found an ok solution here:
&lt;a href=&quot;https://stackoverflow.com/a/43654115/1138354&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/a/43654115/1138354&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Example:&lt;/p&gt;&lt;p&gt;Global config &lt;code&gt;~/.gitconfig&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
[user]
  name = play.user
  email = play.user@gmail.com

[includeIf &amp;quot;gitdir:~/work/&amp;quot;]
  path = ~/work/.gitconfig
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Work specific config &lt;code&gt;~/work/.gitconfig&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[user]
  name = work.user
  email = work.user@megacorp.ltd
&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title><![CDATA[Windows Web-dev bootstrap]]></title><description><![CDATA[From scratch to Create React App on Windows An opinionated guide on setting up a web development environment on
Windows 10 I have been a…]]></description><link>https://scottspence.com/2018/12/24/wsl-bootstrap-2019/</link><guid isPermaLink="false">https://scottspence.com/2018/12/24/wsl-bootstrap-2019/</guid><pubDate>Mon, 24 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;from-scratch-to-create-react-app-on-windows&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#from-scratch-to-create-react-app-on-windows&quot; aria-label=&quot;from scratch to create react app on windows permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;From scratch to Create React App on Windows&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;An opinionated guide on setting up a web development environment on
Windows 10&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I have been a professional web developer for 10 months now and used
both MacOs and Windows in that time. My preferred OS to use is
Windows, for no other reason than I prefer the keyboard layout.&lt;/p&gt;&lt;p&gt;With Windows/Linux I like to have my Ctrl key as the key to use for
copy paste operations and I can use my left pinky instead of my thumb.
Anyway, let’s leave the weak reasoning behind as that’s not the
purpose of this post!&lt;/p&gt;&lt;p&gt;If you don’t have a Windows machine then this post probably isn’t for
you, if this is different from what you use, it doesn’t make it bad.&lt;/p&gt;&lt;p&gt;Let’s see what Ken has to say about it:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/ken_wheeler/status/1075556283795824640&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://twitter.com/ken_wheeler/status/1075556283795824640&lt;/a&gt;&lt;/p&gt;&lt;p&gt;This is the refresh on &lt;a href=&quot;https://thelocalhost.blog/wsl-setup/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my guide from the start of 2018&lt;/a&gt; on setting up
a web development environment on a Windows machine.&lt;/p&gt;&lt;p&gt;This guide will cover installing Ubuntu but you can use some of the
other flavours of Linux available in the Windows store, the Debian
setup will be very similar to the Ubuntu one.&lt;/p&gt;&lt;h2 id=&quot;objective-of-this-post&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#objective-of-this-post&quot; aria-label=&quot;objective of this post permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Objective of this post&lt;/h2&gt;&lt;p&gt;To go from a fresh instance of Windows 10 to something you can develop
web apps with.&lt;/p&gt;&lt;p&gt;These instructions are for the &lt;strong&gt;Windows 10 Fall Creators Update and
later.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;What we’re going to cover:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#install-wsl&quot;&gt;Install WSL&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#enable-wsl-on-your-machine&quot;&gt;Enable WSL on your machine&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#update-upgrade-and-autoremove&quot;&gt;update, upgrade and autoremove&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#install-node-with-n&quot;&gt;Install Node (with &lt;code&gt;n&lt;/code&gt;)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#install-visual-studio-code&quot;&gt;Install Visual Studio Code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#install-windows-git&quot;&gt;Install Windows Git&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#install-a-terminal-hyper&quot;&gt;Install a Terminal (Hyper)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#install-fish-shell&quot;&gt;Install Fish Shell!&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#install-oh-my-fish&quot;&gt;Install Oh My Fish&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#fish-themes-with-omf&quot;&gt;Fish themes with OMF&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#configure&quot;&gt;Configure&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#git-config&quot;&gt;Git config&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#create-react-app&quot;&gt;Create React App&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#use-ssh-with-github&quot;&gt;Use SSH with GitHub&lt;/a&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;#wsl-ssh-config&quot;&gt;WSL SSH Config&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#windows-git-bash-ssh-config&quot;&gt;Windows Git Bash SSH Config&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#change-wsl-version&quot;&gt;Change WSL version&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;#wrap-up&quot;&gt;Wrap up!&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;install-wsl&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-wsl&quot; aria-label=&quot;install wsl permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install WSL&lt;/h2&gt;&lt;p&gt;You can install Ubuntu from &lt;a href=&quot;https://www.microsoft.com/en-gb/p/ubuntu/9nblggh4msv6?activetab=pivot:overviewtab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;the Microsoft store&lt;/a&gt; which will be the
first half of the install the second will be when ypu open the app.&lt;/p&gt;&lt;h2 id=&quot;enable-wsl-on-your-machine&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#enable-wsl-on-your-machine&quot; aria-label=&quot;enable wsl on your machine permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enable WSL on your machine&lt;/h2&gt;&lt;p&gt;The &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/install-win10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;official guidance&lt;/a&gt; covers it very well, but I’m going to add in
the shortcut keys here if you don’t want to be clicking around with
the mouse.&lt;/p&gt;&lt;p&gt;Before that however, if you haven’t selected PowerShell as your
default Command Prompt you can select it from the Taskbar settings
page located in the Personalisation section in the Settings, I suggest
doing that now:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/powershell.gif&quot; alt=&quot;powershell activation&quot;/&gt;&lt;/p&gt;&lt;p&gt;Whilst we’re at it we should also enable hidden folders and add files
extensions for known file types in Windows File Explorer.&lt;/p&gt;&lt;p&gt;Open the Windows File Explorer with Windows key+e then select View
from the ribbon. Then click the Options button on the far right, this
will bring up the Folder Options dialog, from here we want to select
the View tab and select the Radio button for Hidden files and folders
with the ‘Show hidden files, folders and drives’, uncheck the option
for ‘Hide extensions for known file types’ too. Click apply and Ok.&lt;/p&gt;&lt;p&gt;The reason we’re doing this is so that we can see the &lt;code&gt;.git&lt;/code&gt; folder in
project structures it’s also needed for files like &lt;code&gt;.env&lt;/code&gt; files which
are used for environment configuration.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/show-extensions.gif&quot; alt=&quot;show file extensions&quot;/&gt;&lt;/p&gt;&lt;p&gt;Use Windows key+x, this is the same as right-clicking the windows icon
on the desktop, this will open the quick link menu. From here you need
to select the Windows PowerShell (&lt;u&gt;A&lt;/u&gt;dmin) option, you can do
this by pressing &lt;strong&gt;a&lt;/strong&gt; on the keyboard. So Windows key+x then a, will
open the user account control (Admin) prompt, presuming you have admin
rights on your machine you’ll need to click yes to continue.&lt;/p&gt;&lt;p&gt;Copy the code here and paste it into the PowerShell window, Ctrl+v
will work in PowerShell, press enter to execute the command.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You will be prompted to restart your machine after this, which you
should do.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Check the link for a complete list of &lt;a href=&quot;https://support.microsoft.com/en-gb/help/12445/windows-keyboard-shortcuts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;windows keyboard shortcuts&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;After restarting you can open the Ubuntu program from the start menu
and the second install (of WSL on your system) should happen. Wait for
this to complete then you will be prompted to create a user and a
password for the account. You will need to remember the password
created for the user as you will be prompted for it to use &lt;code&gt;sudo&lt;/code&gt;
privileges.&lt;/p&gt;&lt;h2 id=&quot;update-upgrade-and-autoremove&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#update-upgrade-and-autoremove&quot; aria-label=&quot;update upgrade and autoremove permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;update, upgrade and autoremove&lt;/h2&gt;&lt;p&gt;At the time of writing this, the version I have linked of Ubuntu is
18.04.1&lt;/p&gt;&lt;p&gt;The linked app will install the latest stable Ubuntu release on
Windows.&lt;/p&gt;&lt;p&gt;You can check what version of Ubuntu you have installed with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lsb_release -a
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/lsb_release.png&quot; alt=&quot;lsb_release image&quot;/&gt;&lt;/p&gt;&lt;p&gt;If you want to use a specific LTS version of Ubuntu you can get them
from the Windows Store, here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/en-gb/p/ubuntu-1604-lts/9pjn388hp8c9?activetab=pivot:overviewtab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ubuntu 16.04 LTS&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/en-gb/p/ubuntu-1804-lts/9n9tngvndl3q?activetab=pivot:overviewtab&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ubuntu 18.04 LTS&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now we’re going to go ahead an update and upgrade all the things, the
three commands here will update and upgrade all the pre-installed
software that comes with the Ubuntu install.&lt;/p&gt;&lt;p&gt;The code below is three commands joined together with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;. The &lt;code&gt;-y&lt;/code&gt;
flag is to auto accept the changes that are going to be performed with
the upgrades. Auto remove will remove unused packages left behind from
upgrades.&lt;/p&gt;&lt;p&gt;Copy the below commands into your Ubuntu terminal, and run the
command:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt update &amp;amp;&amp;amp; sudo apt -y upgrade &amp;amp;&amp;amp; sudo apt autoremove
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;To go from 16.04 to 18.04 try &lt;code&gt;do-release-upgrade&lt;/code&gt; in the terminal.
be warned this takes considerably longer than just deleting the
current install of Ubuntu and starting again.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Now that the base has been installed and updated we need to install
the &lt;a href=&quot;https://packages.ubuntu.com/bionic/build-essential&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;build-essential&lt;/a&gt; package in order to compile and build other
packages, the following packages we’re going to install will all need
it.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install -y build-essential
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From here on in I’d suggest using two bash windows, one with sudo
enabled the other with standard permissions.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;i.e. open a terminal and don’t enter &lt;code&gt;sudo&lt;/code&gt; in there, instead use
the terminal that has been granted that permission.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The reason for this is that I have found if you install node as sudo
then each time you want to run an &lt;code&gt;npm install&lt;/code&gt; command you will need
to grant sudo permissions and it can all get a bit tedious. And you
really shouldn’t be installing npm packages with sudo permissions.&lt;/p&gt;&lt;h2 id=&quot;install-node-with-n&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-node-with-n&quot; aria-label=&quot;install node with n permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Node (with &lt;code&gt;n&lt;/code&gt;)&lt;/h2&gt;&lt;p&gt;Let’s get our run-time on! If you use Node.js you will eventually have
situations where you need to be able to switch Node versions, for this
you may have heard to nvm (&lt;a href=&quot;https://github.com/creationix/nvm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Node Version Manager&lt;/a&gt;) which by the way
you can still use in WSL.&lt;/p&gt;&lt;p&gt;The reason for me opting for n over nvm is that in the past I
experienced slow bash startup times whilst using nvm. Take a look at
this &lt;a href=&quot;https://github.com/Microsoft/WSL/issues/776&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WSL GitHub issue detailing it&lt;/a&gt; and the specific comment for the
&lt;a href=&quot;https://github.com/Microsoft/WSL/issues/776#issuecomment-266112578&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pros of using n&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Ok let’s install n, with &lt;a href=&quot;https://github.com/mklement0/n-install&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;n-install&lt;/a&gt;, the command doesn’t start with
sudo so use it in the bash window you have with no sudo privileges.🧐&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://git.io/n-install | bash
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will install the latest version of Node for us, follow the prompt
on the terminal screen to reload bash:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# mine looks like this
. /home/scott/.bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now check the versions of Node and npm we have installed with
&lt;code&gt;node -v &amp;amp;&amp;amp; npm -v&lt;/code&gt; in the terminal.&lt;/p&gt;&lt;h2 id=&quot;install-visual-studio-code&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-visual-studio-code&quot; aria-label=&quot;install visual studio code permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Visual Studio Code&lt;/h2&gt;&lt;p&gt;Install VSCode? What? This post is to set up WSL? Ok, so we’re going
to presume that this is going from nothing to being able to web dev,
so we’re going to need a text editor, and there’s nothing out there at
the moment that comes close to VSCode, if you already have a text
editor installed then skip to the next part.&lt;/p&gt;&lt;p&gt;Install the Windows version of VSCode from the &lt;a href=&quot;https://code.visualstudio.com/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Download section&lt;/a&gt; once
installed we can enable WSL in the settings, the quickest way to do
this is to open the integrated terminal in VSCode with the shortcut
keys Ctrl+’ 👈 that’s and apostrophe. You will be prompted to select
your default terminal, select WSL Bash.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/vscode-wsl-config.gif&quot; alt=&quot;vscode config&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;install-windows-git&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-windows-git&quot; aria-label=&quot;install windows git permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Windows Git&lt;/h2&gt;&lt;p&gt;There’s a bit of stumbling block getting &lt;a href=&quot;https://github.com/Microsoft/vscode/issues/9502&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git support for VSCode&lt;/a&gt;,
it’s well documented in the various issues mentioned in the linked
issue.&lt;/p&gt;&lt;p&gt;There are workarounds as well with things like &lt;a href=&quot;https://github.com/andy-5/wslgit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WSLGit&lt;/a&gt; which has it’s
own set of issues, this all stems from users (me included) not wanting
to have to install another binary for Git.&lt;/p&gt;&lt;p&gt;I have tried several variants when it comes to using Git with VSCode
and the path of least resistance was biting the bullet and installing
that additional binary, there’s an overhead with having to maintain
and configure SSH keys for both Windows and WSL Git but it’s a one
time setup.&lt;/p&gt;&lt;p&gt;Until the VSCode team incorporate &lt;a href=&quot;https://github.com/andy-5/wslgit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WSLGit&lt;/a&gt; into VSCode I think this is
the best option.&lt;/p&gt;&lt;p&gt;Install from &lt;a href=&quot;https://git-scm.com/download/win&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git-scm.com&lt;/a&gt; the link will start downloading the install
binary you can then open it and go through the install, you can keep
clicking next through the install, I have selected a few options that
I would like enabled.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/install-git.gif&quot; alt=&quot;windows git setup&quot;/&gt;&lt;/p&gt;&lt;p&gt;For now, that is all we need to do, when it comes to authenticating
with with GitHub using SSH we will use the Git Bash command line to
configure the Windows side of things.&lt;/p&gt;&lt;h2 id=&quot;install-a-terminal-hyper&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-a-terminal-hyper&quot; aria-label=&quot;install a terminal hyper permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install a Terminal (Hyper)&lt;/h2&gt;&lt;p&gt;Now we have bash on Windows it’s time to install a nice Terminal app,
because, let’s face it, the standard one is a bit basic.&lt;/p&gt;&lt;p&gt;Enter &lt;a href=&quot;http://hyper.is&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hyper&lt;/a&gt; an electron based terminal app that is super themeable
and configurable.&lt;/p&gt;&lt;p&gt;Download and install hyper for Windows, this will be the bare-bones
version, it’ll look something like this:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/basic_hyper.png&quot; alt=&quot;basic hyper&quot;/&gt;&lt;/p&gt;&lt;p&gt;You may notice that, this is the Windows Command prompt too, don’t
worry, we’re going to configure that right now.&lt;/p&gt;&lt;p&gt;Open up the &lt;code&gt;.hyper.js&lt;/code&gt; file located in the root of your user folder,
or from Hyper itself use the shortcut key Ctrl+, to pop open the
settings.&lt;/p&gt;&lt;p&gt;If the settings file (&lt;code&gt;.hyper.js&lt;/code&gt;) opens in Notepad then you can set
the default to be VSCode. In File Explorer (Use Windows key+e to open
it) navigate to the file, it’ll be in your User folder, right-click
the file and select Properties, then Change for ‘Opens with:’ and
select VSCode from the list.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/default-file-type.gif&quot; alt=&quot;default-file-type&quot;/&gt;&lt;/p&gt;&lt;p&gt;Now we can set WSL as the shell path in Hyper, open the &lt;code&gt;.hyper.js&lt;/code&gt;
settings file and search (Ctrl+f) for bash, we want to add the path to
the WSL shell into the &lt;code&gt;shell&lt;/code&gt; property defined in the file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// amend shell path
// WSL Bash
shell: &amp;#x27;C:\\Windows\\System32\\bash.exe&amp;#x27;,
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can also change the appearance of Hyper from here by specifying
font size and font family and also predefined themes, let’s quickly
add in the &lt;code&gt;hyper-adventure-time&lt;/code&gt; theme into the plugins section.&lt;/p&gt;&lt;p&gt;Open another Hyper tab with Ctrl+Shift+t, this will show the bash
terminal for WSL now.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/hyper-config.gif&quot; alt=&quot;hyper config&quot;/&gt;&lt;/p&gt;&lt;p&gt;Quick orientation with the Hyper terminal keyboard shortcuts:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;New tab = Ctrl+Shift+t&lt;/li&gt;&lt;li&gt;Close current tab = Ctrl+Shift+w&lt;/li&gt;&lt;li&gt;Cycle through tabs right = Ctrl+Shift+right arrow&lt;/li&gt;&lt;li&gt;Cycle through tabs left = Ctrl+Shift+left arrow&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now I’m going to configure some additional properties for Hyper, and
change the theme to something a bit more subtle.&lt;/p&gt;&lt;p&gt;I purchased Dank Mono, if you want a similar font as OSS check out
&lt;a href=&quot;https://github.com/tonsky/FiraCode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FiraCode&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here’s what I changed:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = {
  config: {
    fontSize: 18,
    fontFamily: &amp;#x27;&amp;quot;Dank Mono&amp;quot;,...&amp;#x27;,
    cursorShape: &amp;#x27;BEAM&amp;#x27;,
    cursorBlink: true,
    copyOnSelect: true,
    plugins: [&amp;#x27;hyper-altair&amp;#x27;],
  },
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/hyper-final-config.gif&quot; alt=&quot;final hyper config&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;install-fish-shell&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-fish-shell&quot; aria-label=&quot;install fish shell permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Fish Shell!&lt;/h2&gt;&lt;p&gt;Ok, time to install the Fish Shell! This is a completely optional
step, I like to use fish for the nice intellisense you get when
navigating file structures, there are also some neat themes you can
get with Oh My Fish&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt -y install fish
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/install-fish.gif&quot; alt=&quot;install fish&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;install-oh-my-fish&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-oh-my-fish&quot; aria-label=&quot;install oh my fish permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Oh My Fish&lt;/h3&gt;&lt;p&gt;Now we can install Oh My Fish (OMF) and get a nice terminal theme
going on too, remember we talked about running commands with the
correct permissions? Well this is one of those occasions, open a new
tab first then paste in the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://get.oh-my.fish | fish
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/install-omf.gif&quot; alt=&quot;install omf&quot;/&gt;&lt;/p&gt;&lt;h4 id=&quot;fish-themes-with-omf&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#fish-themes-with-omf&quot; aria-label=&quot;fish themes with omf permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fish themes with OMF&lt;/h4&gt;&lt;p&gt;After installing OMF you can pick a theme, here you may notice that
the text doesn’t fit in the screen on Hyper, a quick way to reset it
is to maximise the window then back again, I did this with the Windows
key+arrow up to maximise the Windows key+arrow down to restore it.&lt;/p&gt;&lt;p&gt;After installing omf I chose the theme agnoster, installed with
&lt;code&gt;omf install agnoster&lt;/code&gt; you can list out what is available and what you
have already installed by selecting &lt;code&gt;omf theme&lt;/code&gt; let’s change it once
more to the &lt;code&gt;one&lt;/code&gt; theme, adjust the size of the window first as things
are getting a bit cramped.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/omf-install-one.gif&quot; alt=&quot;omf one&quot;/&gt;&lt;/p&gt;&lt;p&gt;Have a play around there’s loads there, I prefer the one theme because
you can see what version of node you’re running on, over on the far
right. Here you can also see the intellisense for fish where it shows
agnoster as a previous selection, if I wanted to select agnoster I
could tab to complete the rest of the command.&lt;/p&gt;&lt;h2 id=&quot;configure&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#configure&quot; aria-label=&quot;configure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Configure&lt;/h2&gt;&lt;p&gt;So, now we have a swanky looking new terminal and a bare-bones VSCode
install it’s time to get things moving.&lt;/p&gt;&lt;p&gt;I have a &lt;a href=&quot;https://github.com/spences10/cheat-sheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cheat-sheets&lt;/a&gt; repo detailing a lot of the configuration
we’re about to go through here, if you find something useful along the
way please drop a PR with the suggestion.&lt;/p&gt;&lt;p&gt;First up, in place of typing out &lt;code&gt;fish&lt;/code&gt; each time I open a new
terminal, and not replacing bash which you can do, but I prefer to use
an alias. So what we’re going to do is open up the &lt;code&gt;.bashrc&lt;/code&gt; file and
edit it.&lt;/p&gt;&lt;p&gt;From a new terminal type in &lt;code&gt;nano ~/.bashrc&lt;/code&gt;, nano is a bash text
editor. Scroll (or Page) down to the bottom of the file and add in an
alias for fish, &lt;code&gt;alias f=fish&lt;/code&gt; then to exit nano Ctrl+x and confirm
changes with a &lt;code&gt;y&lt;/code&gt;. Reload the &lt;code&gt;.bashrc&lt;/code&gt; file like we did after using
n to install Node &lt;code&gt;. /home/scott/.bashrc&lt;/code&gt; but your username in place
of mine 😄, now we can use f instead of fish! Well done you saved
yourself typing three extra characters!!!.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/alias-fish.gif&quot; alt=&quot;alias fish in .bashrc&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;git-config&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#git-config&quot; aria-label=&quot;git config permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Git config&lt;/h2&gt;&lt;p&gt;Before we crack on with spinning up a Create React App instance we’re
going to need to configure Git, via the &lt;code&gt;.gitconfig&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;We’re going to use nano to add some settings for Git, both in WSL and
Windows, this is the extra config I mentioned earlier, apologies!&lt;/p&gt;&lt;p&gt;First up we’ll config our bash environment then move onto Git bash on
Windows.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# open up the .gitconfig file in WSL bash
# nano will create one if it doesn&amp;#x27;t exist
nano ~/.gitconfig
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It’s nearly identical config for both environments apart from Windows
uses the credential &lt;code&gt;manager&lt;/code&gt; helper and WSL will need the &lt;code&gt;cache&lt;/code&gt;
helper.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# needed in Git Bash for Windows
[credential]
  helper = manager
# needed in WSL
[credential]
  helper = cache
[color]
  ui = true

[user]
  name = yourGitHubUserName
  email = yourGitHub@email.com

[core]
  editor = code --wait
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Make your changes then Ctrl+x to exit and confirm with y, that’s the
first part of the Git config done.&lt;/p&gt;&lt;p&gt;In Git Bash for Windows do the same in the terminal, use nano to
create a &lt;code&gt;.gitconfig&lt;/code&gt; file and add the setting to it.&lt;/p&gt;&lt;h2 id=&quot;create-react-app&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#create-react-app&quot; aria-label=&quot;create react app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create React App&lt;/h2&gt;&lt;p&gt;Ok, we shall get create react app going so we can get Git configured
with GitHub using SSH and start making changes to commit to a GitHub
repo.&lt;/p&gt;&lt;p&gt;We’re going to use &lt;a href=&quot;https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;npx&lt;/a&gt; to make a starter React project with Create
React App. If you want to have your projects somewhere else now is the
time to navigate to that directory.&lt;/p&gt;&lt;p&gt;From the terminal enter:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# this will create a starter react project
# called create-react-app
npx create-react-app create-react-app
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is creating the project in my home (&lt;code&gt;~&lt;/code&gt;) folder, I’ve had to
speed the gif up to 20x faster, it does take a while.🙃&lt;/p&gt;&lt;p&gt;Wheeeeeeeeeeeeeeeeeeeee!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/npx-cra.gif&quot; alt=&quot;npx cra&quot;/&gt;&lt;/p&gt;&lt;p&gt;So, now that we have spun up a React app to work on we should make a
change and then add it to GitHub.&lt;/p&gt;&lt;p&gt;Navigate to the create-react-app folder in the terminal and open the
project. You can open VSCode with the &lt;code&gt;code .&lt;/code&gt; command, the &lt;code&gt;.&lt;/code&gt;
denotes the current folder in the terminal.&lt;/p&gt;&lt;p&gt;This will open VSCode at the root of the create-react-app project,
make sure everything is working as expected by running the start
script in npm.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want to see what scripts are available in the current project
you can also use &lt;code&gt;npm run&lt;/code&gt; which will list defined npm commands from
the &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;A window will open displaying the basic Create React App landing page,
we’re going to add a h1 to the &lt;code&gt;App.js&lt;/code&gt; module then commit it, via the
Source Control menu in VSCode.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Please bear in mind this is an up and running guide for a
development environment, I’m not going to be detailing developing in
React&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Whilst the terminal is busy starting up the create-react-page we can
open another tab in Hyper with Ctrl+Shift+t and open up VSCode with
the &lt;code&gt;code .&lt;/code&gt; command, navigate to the &lt;code&gt;App.js&lt;/code&gt; component and add a
&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag to it just above the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag with
&lt;code&gt;&amp;lt;h1&amp;gt;Hello React!&amp;lt;/h1&amp;gt;&lt;/code&gt; in it.&lt;/p&gt;&lt;p&gt;Now the landing page should show the newly added h1, we can confirm
that the file is changed in Git by doing a &lt;code&gt;git status&lt;/code&gt; from the
terminal. Then we can commit it from either the terminal or the IDE
(VSCode) my preference is to use VSCode as the visual diffing of files
is great.&lt;/p&gt;&lt;p&gt;Commit the changes with Ctrl+Enter if you have not selected the file
you want to commit you wil get a dialogue telling you there are no
staged changes to commit, you can select the files (in this case only
the &lt;code&gt;App.js&lt;/code&gt; file) by clicking the plus next to the file. Hitting
Ctrl+Enter again will commit the changes with a message, you can check
that there are no changes to commit with &lt;code&gt;git status&lt;/code&gt; from the
terminal or visually from the Source Control section in VSCode.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/cra-change.gif&quot; alt=&quot;cra change&quot;/&gt;&lt;/p&gt;&lt;p&gt;Ok, time to add our super sweet code changes to a repository on GitHub
for the world to see!&lt;/p&gt;&lt;p&gt;Next up we’re going to go through adding the local changes we’ve made
to a GitHub repository. If you haven’t got a GitHub account and are
following along now may be a good time to set one up.&lt;/p&gt;&lt;h2 id=&quot;use-ssh-with-github&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-ssh-with-github&quot; aria-label=&quot;use ssh with github permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use SSH with GitHub&lt;/h2&gt;&lt;p&gt;First up, we’re going to make a repository on GitHub and push the
changes we have made to it, here we’re going to click the + button in
the top right of the GitHub home page, enter a repository name and
GitHub will give you some defaults to choose from. As we have already
made change locally we can ignore the first several commands but we do
need the command to add the remote:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git remote add origin git@github.com:spences10/cra.git
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And to push the changes up to GitHub &lt;code&gt;git push -u origin master&lt;/code&gt; but
we’re going to get an error, as we haven’t set up SSH.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/make-repo.gif&quot; alt=&quot;make repo&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;wsl-ssh-config&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wsl-ssh-config&quot; aria-label=&quot;wsl ssh config permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;WSL SSH Config&lt;/h3&gt;&lt;p&gt;Open a new bash tab in Hyper and enter &lt;code&gt;ls -al ~/.ssh&lt;/code&gt; check that
there are no &lt;code&gt;rsa&lt;/code&gt; files before doing this.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;You’ll notice that we’re doing this in bash rather than Fish.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;If there’s nothing there then generate new keys with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# add your email address 👍
ssh-keygen -t rsa -b 4096 -C yourGitHub@email.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now &lt;code&gt;ls -al ~/.ssh&lt;/code&gt; will show two additional files:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# there should be a private and public key-pair
id_rsa
id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Start the SSH agent:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;eval &amp;quot;$(ssh-agent -s)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add RSA key to SSH with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-add ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now time to add the public SSH key to GitHub, in WSL were going to
copy pasta the public SSH key with &lt;code&gt;cat ~/.ssh/id_rsa.pub&lt;/code&gt; in Hyper
then we can copy from Hyper to a &lt;a href=&quot;https://github.com/settings/ssh/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;new SSH key&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Finally authenticate with GitHub:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -T git@github.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/ssh-config-wsl.gif&quot; alt=&quot;ssh config wsl&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;windows-git-bash-ssh-config&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#windows-git-bash-ssh-config&quot; aria-label=&quot;windows git bash ssh config permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Windows Git Bash SSH Config&lt;/h3&gt;&lt;p&gt;For Windows Git Bash we’re going to copy our SSH keys we’ve just
generated in WSL over to Windows Git Bash, there are some subtle
differences when authenticating with Windows Git Bash.&lt;/p&gt;&lt;p&gt;From Hyper, copy the SSH files from Linux to Windows:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cp ~/.ssh/* /c/Users/spenc/.ssh/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Start the SSH agent:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;eval `ssh-agent -s`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add the key to SSH agent:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-add ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Authenticate:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -T git@github.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/ssh-config-win.gif&quot; alt=&quot;ssh config win&quot;/&gt;&lt;/p&gt;&lt;p&gt;Now the additional set up for SSH is done we should be able to go back
to Hyper and push our change to GitHub.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2018/wsl-bootstrap-2019/final-push-github.gif&quot; alt=&quot;final push github&quot;/&gt;&lt;/p&gt;&lt;p&gt;Also you may have noticed that the SSH Key 🔑 token went from black to
green on the settings screen there this indicates that you have
authenticated.&lt;/p&gt;&lt;h2 id=&quot;change-wsl-version&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#change-wsl-version&quot; aria-label=&quot;change wsl version permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Change WSL version&lt;/h2&gt;&lt;p&gt;If you want to use a different version of Ubuntu, Debian or any of the
other available distributions of Linux from teh Windows store with
Hyper you will need to change the default version from PowerShell:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# list available versions
wslconfig /l
# set default
wslconfig /setdefault Debian
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;wrap-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#wrap-up&quot; aria-label=&quot;wrap up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Wrap up!&lt;/h2&gt;&lt;p&gt;That’s it! We have gone from scratch to a functioning web development
environment. There are several other personal things I’m now going to
add to my install now which is aliases for both Git and Fish shell. If
you are interested in them I have a &lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/fish.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cheat-sheet for Fish&lt;/a&gt; with a list
of all my aliases I use, the same for my &lt;code&gt;.gitconfig&lt;/code&gt; you can find
that in my &lt;a href=&quot;https://github.com/spences10/dotfiles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dotfiles&lt;/a&gt; repo&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Thanks for reading&lt;/strong&gt; 🙏&lt;/p&gt;&lt;p&gt;Please take a look at my other content if you enjoyed this.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Turning a job hunt into a dev project]]></title><description><![CDATA[Cliffs/TL;DR I made a  recruiter FAQ  on my personal site for recruiters and
created an  online CV . Preamble Apologies up front about this…]]></description><link>https://scottspence.com/2018/11/30/job-hunt-dev-project/</link><guid isPermaLink="false">https://scottspence.com/2018/11/30/job-hunt-dev-project/</guid><pubDate>Fri, 30 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;cliffstldr&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#cliffstldr&quot; aria-label=&quot;cliffstldr permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cliffs/TL;DR&lt;/h2&gt;&lt;p&gt;I made a &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;recruiter FAQ&lt;/a&gt; on my personal site for recruiters and
created an &lt;a href=&quot;https://cv.scottspence.me/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;online CV&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;preamble&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#preamble&quot; aria-label=&quot;preamble permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Preamble&lt;/h2&gt;&lt;p&gt;Apologies up front about this post if it comes across as entitled or
ranty and I’m sure a lot of people will disagree with my approach.&lt;/p&gt;&lt;p&gt;I’m going to try my hardest to not get too cynical here, so, first up
let’s get this out there to start with. I think technical recruitment
is in a very bad state! It has been for a long while (since 2010 at
the very least).&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Let’s call it job hunting/talent finding fatigue, as we as
developers have fatigues in other areas, however this isn’t one of
our own making.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Starting out on a job hunt and getting your CV out there will generate
a lot of calls where the most irrelevant keyword on your CV will
generate unwanted calls from what at times appear to be desperate
recruiters.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Urgent position to fill: Team Lead, 6+ year experience - immediate
start £900 a day, 3 month contract.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, that’s a bit harsh! it’s the truth, Ruth! It all sounds a bit
cliché now as well.&lt;/p&gt;&lt;p&gt;Being a developer I began to notice patterns with each call I got, the
same questions kept getting asked over and over. Also as a developer I
want to keep things &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DRY&lt;/a&gt; to save myself (and the recruiter) a bit of
time.&lt;/p&gt;&lt;p&gt;So to this end I decided to add an &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FAQ&lt;/a&gt; section to my personal
portfolio, this was a list of all the questions I had been asked on
the many calls previously, so, rather than have the recruiter have me
on the phone for ten minutes just to qualify me for the role they
could do the &lt;em&gt;vast&lt;/em&gt; majority of that with the provided &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FAQ&lt;/a&gt;, almost
like a reverse job spec, all they have to do is READ the &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FAQ&lt;/a&gt;! Then
check off my wants and needs from the list I have already provided.&lt;/p&gt;&lt;p&gt;For some reason though, a lot of recruiters would insist on talking to
me, taking time out of my day, they’d then proceed to ask the same
questions every other recruiter would ask. This would qualify them to
me as someone that didn’t value my time and they’d lose any
credibility they may have had with me.&lt;/p&gt;&lt;p&gt;So, I made a site, a portfolio, that listed all you could want to know
about me. I added the About, which covers my back-story and coding
history, how I got into it and where I am now. There’s also a Now
section and a Uses section. They are what I’m doing now, in my life
ans the things I use, like code editor and hardware.&lt;/p&gt;&lt;p&gt;The pages of the portfolio are all in markdown generated by Gatsby, so
when there was a question asked that was not on the list I could add
it quickly. Using Netlify made this even simpler, because it was a Git
push and the changes would be live in minutes,&lt;/p&gt;&lt;p&gt;Making a site, this is more for prospective employers rather than
recruiters and although the majority of recruiters will talk to you as
though they are the ones considering you for the role they’re only the
first stage in what can be a quite lengthy process.&lt;/p&gt;&lt;p&gt;So, let’s forget about recruiters for now and concentrate on the one
main thing you need to get out there if you’re looking for a job, your
CV.&lt;/p&gt;&lt;p&gt;Making a [CV], I went to the effort to make a basic site using my
favourite tech stack &lt;strong&gt;&lt;a href=&quot;https://jamstack.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;teh JAMStack behbeh!&lt;/a&gt;&lt;/strong&gt; I used the
&lt;a href=&quot;https://jsonresume.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JSONresume&lt;/a&gt; tool to detail all the roles I had held then used the
JSONresume as a guide for how I should make the individual components
for the [CV].&lt;/p&gt;&lt;p&gt;If you want to get started with your own JSON Resume you can run the
npm command &lt;code&gt;npx resume-cli init&lt;/code&gt; to kick-start your own.&lt;/p&gt;&lt;p&gt;Feel free to &lt;a href=&quot;https://github.com/spences10/cv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;use my CV&lt;/a&gt; as a template for your own as well, all you
need to do is generate your CV and push it to now.sh.&lt;/p&gt;&lt;p&gt;This was my full employment history and quite long and as I was
looking for a job in a new field the vast majority of it was not
pertinent to a my job search, this is why I decided rather than blast
out my [CV] everywhere I’d post out the list of answers to the
questions recruiters always asked me when calling me. So rather than
have them crawl through my mostly irrelevant job history they could
get the answers to the questions they wanted answering. The [CV] was
there if they wanted more detail on me, all they had to do was READ!&lt;/p&gt;&lt;p&gt;In my mind the &lt;a href=&quot;https://scottspence.me&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;personal portfolio&lt;/a&gt; and the [CV] site were a good
indication of my current skill level with styling and preferred stack,
in reality no one cares as long as it looks nice and recruiters even
less so because it doesn’t answer the questions they want to ask.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/ptve31bchle6hgg6wuaq.gif&quot; alt=&quot;build-it&quot;/&gt;&lt;/p&gt;&lt;p&gt;This wasn’t field of dreams though! So, how do I get recruiters to my
page? Well, rather than have a CV in MS Word format that I would post
onto every job site I could find, I had, a, link to my &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FAQ&lt;/a&gt; on a MS
Word doc! 🙃&lt;/p&gt;&lt;p&gt;On the MS Word doc I would have all the search terms a recruiter would
search for, JavaScript, React, HTML, CSS and so on at the bottom of
the document. At the top was a greeting:&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/11a27b76e59cb7c0015d28592c76c4c8/9888a/jobsite-cv.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:63.74999999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;256\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20256\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M201%2031l2%203%203%202h-6l4%201c2%200%203%201%203%202l1%201%201-1%202-1%203-2h1c0%202%201%202%203%202s3-1%203-4-2-4-5-1h-2c0-2-1-2-3-2-3%200-3%200-3%203%200%201%200%202-1%201l-2-3-2-1h4c0-1-1-2-3-2s-3%200-3%202M26%2054v3c-3%201%201%202%2013%202h14v-3l-1-2H32l-2%201v-1c2-1%201-2-2-2-2%200-2%200-2%202m130%2070l-1%203c0%203%200%203%204%203h66c6%200%206%200%205-3%200-2%200-2-1%200h-1c0-1-1-2-2-1l-2-1c-2-1-4-1-4%202h-1c-1-2-7-1-8%200h-2c-1-2-26-2-27%200l-1%201v-2h-4l-1-1c0-1-3-1-4%201%200%202-3%203-3%201l-8-2h-4l-1-1m-14%2022v4l-1-3-1-2c0%202-3%203-3%201-1-1-12-2-13-1s0%203%202%203v1c-2%201-1%201%203%201s5%200%205-2h1c0%203%208%203%208%200v-2l1%202%202%202%201-1v-1l1%201%201%201%201-1v-1l1%201%206%201%206-1%201-1%201%201c-1%201%200%201%202%201s3%200%202-1l-1-2%202%201c2%202%2011%203%2010%201-1-1%200-1%201-1l1%201c-1%201%200%201%202%201%206%200%205-5%200-5-4%200-5%200-5%202l-2%202v-2l-1-2c-11-1-25%200-26%201l-1%201v-1c0-1-1-2-2-1l-3-1c0-3-2-1-2%202m-68%2032l-4%201c0-2-4%200-5%202-1%201-1%201-1-1v-2l-1%202c-1%202-2%202-2%201-1-3-4-2-4%200s0%202-1%200-1-2-1%200l-1-1c-1-2-1-2-1%200h-1l-2-2v6h3v-1l1%201h3c1%201%202%201%203-1h1c0%201%201%202%202%201h2l1-2c0-2%200-2%201%200%200%203%202%203%203%201h2l6%201h5l2%201%201-1h9l2-1%202-2v-3l-1%202c0%202%200%202-1%201%200-2-8-2-9%200-1%201-1%201-1-1h-1c0%203-1%202-3%200-1-2-1-2-3%200h-3l-2-2h-1m49%203c0%202%200%202-1%200%200-2-1-2-11-2-9%200-11%201-11%202%200%203%203%204%205%203h4c2-2%203-3%203-1l3%201h11v-1l1%201%201%201%201-4c0-3%200-3-1-1l-1%203v-5l-1%202c-1%202-1%202-1%200%200-3-2-3-2%201m-73%207c-2%201-1%204%200%203l1%201c-1%201%202%201%209%201%206%200%209%200%208-1l-2-2h4c1-1%201-1%201%201s0%202%207%202l6-1c-1-1%200-1%201-1l1%201c-1%201%201%201%203%201l5-1h1c1%201%2018%202%2020%201h1v-1l1-1%201%201%207%201c4%200%206%200%205-1l1-1c1%201%201%200%201-1%200-2-5-3-6-1l-1%201v-1c1-1-1-1-6-1l-11-1c-3%200-3%200-3%203v3l-1-3c-1-3-1-3-1-1h-1c-1-2-10-1-12%201h-1c0-2-10-3-12-2h-8c-3-1-3%200-4%201-1%202-1%202-1%200v-2l-1%202c-1%202-1%202-2%201-2-2-10-3-11-2m35%208l1%204c1%201%201%201-1%201l-1-2c0-2-1-2-6-2h-8c-2-1-2-1-2%201l-1%203-1-1h-1l-2-1c-1-3-6-2-6%201%200%202%203%203%203%200h1c0%202%2019%203%2020%201h1l7%201%208-1h1c0%202%207%201%207-1h1c0%203%2025%203%2027%200%201-2%202-2%202-1%201%201%200%202-1%202a307%20307%200%200052%200l1-3-1-2-1%202h-1l-19-1-19-1h-1c-1%201-6%202-7%201h-3l-4-1c-1-2-3%200-3%202h-1c-1-2-6-2-6%200h-1c0-2-10-1-12%201h-1c0-2-2-3-9-2l-5-1h-8m-36%2010c0%203%202%204%209%204l8-1h1c0%203%202%202%202-1v-2l1%203c1%202%201%202%201%200v-2l2%202c1%202%202%202%203%201h3c0%202%208-1%208-3%200-1%200-2-8-2h-9c-2-1-2-1-2%201v3l-1-3-1-1-4%201c-4-1-5%200-5%201-1%202-1%202-1%200%200-3%200-3-1-1l-1%203v-3c0-2%200-2-1-1h-1c-1-2-3-1-3%201m53%200c0%202%200%202-1%201-2-3-13-1-13%203%200%202%208%201%209-1l1-1c0%202%202%203%209%203%204%200%205%200%206-2h2v-2l1%202c1%201%201%201%201-2%200-2%200-3-1-2h-4l-5%201h-2c1-2%200-2-1-2l-2%202m-59%2019c0%202-1%203-2%203-1%201-2%200-2-1h2l1-1c0-2-4-1-5%202%200%202%200%202%205%202%204%200%205-1%205-2h1c0%203%202%202%202%200s0-2%201%201l1%203%201-3c2-3%202-3%202-1%200%201%201%202%205%202l4-1-2-1v-1h1l1-1c0-2-4-1-4%201-1%202-3%201-3-2v-3l-1%201c0%202%200%202-5%202l-6-1-1-2-1%203m194%2017c0%202-1%202-4%202-5%200-6%201-5%203h27l3%201c3-1%204-5%201-5l-2%201h-9c0%201-10%200-10-2h-1m-136%203c0%203%200%203%201%202h1c-1%202%201%202%2034%202a329%20329%200%200035-2c-1%200-2%200-1-1%202-1%201-2-4-2-3%200-4%200-4%202v1c-1%200-2-1-1-2l-9-1h-11c-7-1-13%200-13%202l-1%201-1-2h-1l-1-1h-2l-2-1c0-1-1-1-1%201h-1c0-2-2-1-2%201-1%202-3%203-3%201a3650%203650%200%2001-13%200\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/11a27b76e59cb7c0015d28592c76c4c8/60a22/jobsite-cv.webp 160w,/static/11a27b76e59cb7c0015d28592c76c4c8/4c812/jobsite-cv.webp 320w,/static/11a27b76e59cb7c0015d28592c76c4c8/0ba47/jobsite-cv.webp 640w,/static/11a27b76e59cb7c0015d28592c76c4c8/e46b2/jobsite-cv.webp 960w,/static/11a27b76e59cb7c0015d28592c76c4c8/40d0b/jobsite-cv.webp 1198w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/11a27b76e59cb7c0015d28592c76c4c8/0913d/jobsite-cv.jpg 160w,/static/11a27b76e59cb7c0015d28592c76c4c8/cb69c/jobsite-cv.jpg 320w,/static/11a27b76e59cb7c0015d28592c76c4c8/c08c5/jobsite-cv.jpg 640w,/static/11a27b76e59cb7c0015d28592c76c4c8/6a068/jobsite-cv.jpg 960w,/static/11a27b76e59cb7c0015d28592c76c4c8/9888a/jobsite-cv.jpg 1198w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/jpeg&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/11a27b76e59cb7c0015d28592c76c4c8/c08c5/jobsite-cv.jpg&quot; alt=&quot;jobsite-cv&quot; title=&quot;jobsite-cv&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;It was a friendly hello and something different to what must be very
repetitive.&lt;/p&gt;&lt;p&gt;I used Google analytics’s, on the &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FAQ&lt;/a&gt; and the [CV] to see how much
traffic they were getting, the &lt;a href=&quot;https://scottspence.me/faq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FAQ&lt;/a&gt; a lot more than the [CV], so, I
could glean from that, that the recruiters were getting the answers to
their questions without having to pick up the phone. Win Win, right?&lt;/p&gt;&lt;p&gt;The stats weren’t great however, with a bounce rate of around 3
seconds 😲 you could see the vast majority of recruiters would rather
pick up the phone than READ the information provided.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Convert the Gatsby default starter to styled-components]]></title><description><![CDATA[Let's go through getting styled-components working with the Gatsby
default starter. In this example we're going to use the Gatsby default…]]></description><link>https://scottspence.com/2018/11/29/gatsby-starter-to-styled-components/</link><guid isPermaLink="false">https://scottspence.com/2018/11/29/gatsby-starter-to-styled-components/</guid><pubDate>Thu, 29 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s go through getting styled-components working with the Gatsby
default starter.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-O5sWySCr668&quot; src=&quot;https://www.youtube.com/embed/O5sWySCr668?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;In this example we’re going to use the Gatsby default starter you get
with &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox&lt;/a&gt; and add in styled-components, so first up, open a
&lt;a href=&quot;https://codesandbox.io/s/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;new CodeSandbox&lt;/a&gt; and select Gatsby from the SERVER TEMPLATES.&lt;/p&gt;&lt;h2 id=&quot;1-dependencies&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#1-dependencies&quot; aria-label=&quot;1 dependencies permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Dependencies&lt;/h2&gt;&lt;p&gt;In the dependencies section of the CodeSandbox editor you’ll need to
add the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gatsby-plugin-styled-components
styled-components
babel-plugin-styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;2-config&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#2-config&quot; aria-label=&quot;2 config permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Config&lt;/h2&gt;&lt;p&gt;Now we need to change &lt;code&gt;gatsby-config.js&lt;/code&gt; to incorporate the new
dependencies we’ve just added. It doesn’t have any configuration
options so it can just go in as an extra line on the config, in this
case I’m adding it after the &lt;code&gt;gatsby-plugin-sharp&lt;/code&gt; plugin:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;#x27;gatsby-transformer-sharp&amp;#x27;,
&amp;#x27;gatsby-plugin-sharp&amp;#x27;,
&amp;#x27;gatsby-plugin-styled-components&amp;#x27;,
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Don’t forget the comma at the end 👍&lt;/p&gt;&lt;h2 id=&quot;3-global-style&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#3-global-style&quot; aria-label=&quot;3 global style permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Global Style&lt;/h2&gt;&lt;p&gt;Now that we’re ready to rock n’ roll with styled-components we need to
remove the currently applied styled in the default starter and apply
our own.&lt;/p&gt;&lt;p&gt;In the &lt;code&gt;src/components/layout.js&lt;/code&gt; component there’s an import for
&lt;code&gt;layout.css&lt;/code&gt; this is the CSS reset for the starter if we remove the
import from here we’ll see the styles for border and font be reset. We
can now delete the &lt;code&gt;layout.css&lt;/code&gt; file and create out own CSS reset
using the &lt;code&gt;createGlobalStyle&lt;/code&gt; function from styled-components.&lt;/p&gt;&lt;p&gt;Create a new folder &lt;code&gt;theme&lt;/code&gt;, in this example it’s in &lt;code&gt;src/theme&lt;/code&gt; and
add a &lt;code&gt;globalStyle.js&lt;/code&gt; file in there.&lt;/p&gt;&lt;p&gt;This will export a &lt;code&gt;GlobalStyle&lt;/code&gt; component for us to use throughout
the app.&lt;/p&gt;&lt;p&gt;Let’s add in a Google font and reset the &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;margin&lt;/code&gt;, for
visual feedback we’re going to add the font directly to the body
element.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { createGlobalStyle } from &amp;#x27;styled-components&amp;#x27;

export const GlobalStyle = createGlobalStyle`
  @import url(&amp;#x27;https://fonts.googleapis.com/css?family=Kodchasan:400,700&amp;#x27;);
  body {
    padding: 0;
    margin: 0;
    font-family: Kodchasan;
  }
  a {
    text-decoration: none;
  }
  ul {
    margin: 0 auto;
    list-style-type: none;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now we can use the export component here to apply styles globally
in the app. So we need to have this as high up the component tree as
possible, in this case that is in the &lt;code&gt;layout.js&lt;/code&gt; component as it
wraps all the pages in this project.&lt;/p&gt;&lt;p&gt;In &lt;code&gt;layout.js&lt;/code&gt; import the &lt;code&gt;GlobalStyle&lt;/code&gt; component.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import Header from &amp;#x27;./header&amp;#x27;
import { GlobalStyle } from &amp;#x27;../theme/globalStyle&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then add it in with the other components being rendered.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;render={data =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;GlobalStyle /&amp;gt;
    &amp;lt;Helmet
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok! Global styled applied, we should now see the font change and the
margin around the body of the page change.&lt;/p&gt;&lt;p&gt;Time to use styled-components!&lt;/p&gt;&lt;h2 id=&quot;4-use-styled-components&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#4-use-styled-components&quot; aria-label=&quot;4 use styled components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. Use styled-components&lt;/h2&gt;&lt;p&gt;Now let’s convert all the inline styles used in the starter to
styled-components.&lt;/p&gt;&lt;p&gt;This is the actual styling part, which is moving the existing styles
to styled components, working from top to bottom of the file
structure, changing:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;src/components/header.js
src/components/layout.js
src/pages/index.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;header.js&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import { Link } from &amp;#x27;gatsby&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

const HeaderWrapper = styled.div`
  background: rebeccapurple;
  margin-bottom: 1.45rem;
`

const Headline = styled.div`
  margin: 0 auto;
  max-width: 960;
  padding: 1.45rem 1.0875rem;
  h1 {
    margin: 0;
  }
`

const StyledLink = styled(Link)`
  color: white;
  textdecoration: none;
`

const Header = ({ siteTitle }) =&amp;gt; (
  &amp;lt;HeaderWrapper&amp;gt;
    &amp;lt;Headline&amp;gt;
      &amp;lt;h1&amp;gt;
        &amp;lt;StyledLink to=&amp;quot;/&amp;quot;&amp;gt;{siteTitle}&amp;lt;/StyledLink&amp;gt;
      &amp;lt;/h1&amp;gt;
    &amp;lt;/Headline&amp;gt;
  &amp;lt;/HeaderWrapper&amp;gt;
)

export default Header
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;layout.js&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;
import Helmet from &amp;#x27;react-helmet&amp;#x27;
import { StaticQuery, graphql } from &amp;#x27;gatsby&amp;#x27;

import styled from &amp;#x27;styled-components&amp;#x27;

import Header from &amp;#x27;./header&amp;#x27;
import { GlobalStyle } from &amp;#x27;../theme/globalStyle&amp;#x27;

const ContentWrapper = styled.div`
  margin: 0 auto;
  maxwidth: 960;
  padding: 0px 1.0875rem 1.45rem;
  paddingtop: 0;
`

const Layout = ({ children }) =&amp;gt; (
  &amp;lt;StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data =&amp;gt; (
      &amp;lt;&amp;gt;
        &amp;lt;GlobalStyle /&amp;gt;
        &amp;lt;Helmet
          title={data.site.siteMetadata.title}
          meta={[
            { name: &amp;#x27;description&amp;#x27;, content: &amp;#x27;Sample&amp;#x27; },
            { name: &amp;#x27;keywords&amp;#x27;, content: &amp;#x27;sample, something&amp;#x27; },
          ]}
        &amp;gt;
          &amp;lt;html lang=&amp;quot;en&amp;quot; /&amp;gt;
        &amp;lt;/Helmet&amp;gt;
        &amp;lt;Header siteTitle={data.site.siteMetadata.title} /&amp;gt;
        &amp;lt;ContentWrapper&amp;gt;{children}&amp;lt;/ContentWrapper&amp;gt;
      &amp;lt;/&amp;gt;
    )}
  /&amp;gt;
)

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;index.js&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import { Link } from &amp;#x27;gatsby&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

import Layout from &amp;#x27;../components/layout&amp;#x27;
import Image from &amp;#x27;../components/image&amp;#x27;

const ImgWrapper = styled.div`
  max-width: 300px;
  margin-bottom: 1.45rem;
`

const IndexPage = () =&amp;gt; (
  &amp;lt;Layout&amp;gt;
    &amp;lt;h1&amp;gt;Hi people&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Welcome to your new Gatsby site.&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;Now go build something great.&amp;lt;/p&amp;gt;
    &amp;lt;ImgWrapper&amp;gt;
      &amp;lt;Image /&amp;gt;
    &amp;lt;/ImgWrapper&amp;gt;
    &amp;lt;Link to=&amp;quot;/page-2/&amp;quot;&amp;gt;Go to page 2&amp;lt;/Link&amp;gt;
  &amp;lt;/Layout&amp;gt;
)

export default IndexPage
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;5-done&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#5-done&quot; aria-label=&quot;5 done permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Done&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Thanks for reading&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Here’s the &lt;a href=&quot;https://codesandbox.io/s/yp3z16yw11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;example code&lt;/a&gt; we worked on if you need reference. 👀👌&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Get your GraphCMS data into Gatsby]]></title><description><![CDATA[Let's set up Gatsby to pull data from GraphCMS. This will be a walk-through of setting up some basic data on the
headless CMS, GraphCMS and…]]></description><link>https://scottspence.com/2018/11/25/graphcms-to-gatsby/</link><guid isPermaLink="false">https://scottspence.com/2018/11/25/graphcms-to-gatsby/</guid><pubDate>Sun, 25 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s set up Gatsby to pull data from GraphCMS.&lt;/p&gt;&lt;div class=&quot;youtube-mdx-embed&quot; style=&quot;position:relative;width:100%;padding-top:56.25%&quot;&gt;&lt;iframe title=&quot;youTube-S9JeASI5tck&quot; src=&quot;https://www.youtube.com/embed/S9JeASI5tck?&amp;amp;autoplay=false&amp;amp;start=0&quot; frameBorder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;This will be a walk-through of setting up some basic data on the
headless CMS, GraphCMS and then querying that data in Gatsby.&lt;/p&gt;&lt;h2 id=&quot;1-set-up-graphcms&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#1-set-up-graphcms&quot; aria-label=&quot;1 set up graphcms permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Set up GraphCMS&lt;/h2&gt;&lt;p&gt;Set yourself up with a GraphCMS account at
&lt;a href=&quot;https://app.graphcms.com/signup&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://app.graphcms.com/signup&lt;/a&gt; and select the developer plan.&lt;/p&gt;&lt;h2 id=&quot;2-define-data&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#2-define-data&quot; aria-label=&quot;2 define data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Define Data&lt;/h2&gt;&lt;p&gt;Create a new project and add in some data to query.&lt;/p&gt;&lt;p&gt;Select the &lt;strong&gt;Create new project&lt;/strong&gt; option, call it what you like, in
this example it’s going to be a list of projects, so I’m calling it
&lt;em&gt;Project List&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;In the side bar select the Schema and create a model, in this case
&lt;strong&gt;Project&lt;/strong&gt;. In the project model we’re going to have a &lt;em&gt;Title&lt;/em&gt; and a
&lt;em&gt;Description&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Select the fields from the tray on the right by clicking the
&lt;strong&gt;FIELDS&lt;/strong&gt; tab and dragging and dropping them into the &lt;strong&gt;Project&lt;/strong&gt;
model we created.&lt;/p&gt;&lt;h2 id=&quot;3-configure-the-graphcms-public-api&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#3-configure-the-graphcms-public-api&quot; aria-label=&quot;3 configure the graphcms public api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Configure the GraphCMS public API&lt;/h2&gt;&lt;p&gt;In the GraphCMS settings set the &lt;strong&gt;Public API Permissions&lt;/strong&gt; to
&lt;strong&gt;READ&lt;/strong&gt; scroll down to &lt;strong&gt;Endpoints&lt;/strong&gt; and copy the URL for use in
configuring Gatsby.&lt;/p&gt;&lt;p&gt;That’s it for the CMS configuration, now to pull that data into our
Gatsby frontend!&lt;/p&gt;&lt;h2 id=&quot;4-configure-gatsby&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#4-configure-gatsby&quot; aria-label=&quot;4 configure gatsby permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. Configure Gatsby&lt;/h2&gt;&lt;p&gt;In you Gatsby project install &lt;code&gt;gatsby-source-graphql&lt;/code&gt; and configure it
in &lt;code&gt;gatsby-config.js&lt;/code&gt; the configuration should looks something like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  resolve: &amp;#x27;gatsby-source-graphql&amp;#x27;,
  options: {
    typeName: &amp;#x27;GRAPHCMS&amp;#x27;,
    fieldName: &amp;#x27;graphCmsData&amp;#x27;,
    url: &amp;#x27;https://api-euwest.graphcms.com/v1/projectid/master&amp;#x27;,
  }
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example we’re using &lt;a href=&quot;https://codesandbox.io/dashboard/recent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; for our text editor and
the Gatsby Default Starter you get when selecting Gatsby from the
SERVER TEMPLATES available to you in &lt;a href=&quot;https://codesandbox.io/dashboard/recent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;5-query-the-data-in-gatsby-graphiql&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#5-query-the-data-in-gatsby-graphiql&quot; aria-label=&quot;5 query the data in gatsby graphiql permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Query the data in Gatsby GraphiQL&lt;/h2&gt;&lt;p&gt;Now that the endpoint is set up we will be able to query the data with
Gatsby’s GraphiQL UI, we can shape the query we want to use to display
the data here.&lt;/p&gt;&lt;p&gt;In the preview of our app in &lt;a href=&quot;https://codesandbox.io/dashboard/recent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codesandbox.io&lt;/a&gt; if you add &lt;code&gt;___grapgql&lt;/code&gt;
to the end of the url it will bring up the Gatsby GraphiQL UI, here we
can shape the data we want to query.&lt;/p&gt;&lt;p&gt;If we open up some curly brackets &lt;code&gt;{}&lt;/code&gt; and Cmd+space we’ll see the
available fields where we can pick out the &lt;code&gt;graphCmsData&lt;/code&gt; field we
defined in the &lt;code&gt;gatsby-source-graphql&lt;/code&gt; plugin.&lt;/p&gt;&lt;p&gt;Selecting the fields we created in GraphCMS then running the query
will display our defined data.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
  graphCmsData {
    projects {
      id
      status
      title
      description
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;6-display-the-data&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#6-display-the-data&quot; aria-label=&quot;6 display the data permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;6. Display the Data&lt;/h2&gt;&lt;p&gt;Use the &lt;code&gt;graphql&lt;/code&gt; gatsby export to query the data from the GraphCMS
endpoint.&lt;/p&gt;&lt;p&gt;In &lt;code&gt;pages/index.js&lt;/code&gt; add the &lt;code&gt;graphql&lt;/code&gt; export the the &lt;code&gt;gatsby&lt;/code&gt; imports.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql, Link } from &amp;#x27;gatsby&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At the very bottom define the query:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const query = graphql`
  {
    graphCmsData {
      projects {
        id
        status
        title
        description
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You will then be able to access the &lt;code&gt;data&lt;/code&gt; prop in the &lt;code&gt;IndexPage&lt;/code&gt;
component, we’ll need to de-structure the &lt;code&gt;data&lt;/code&gt; prop out in the
arguments of the component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const IndexPage = ({ data }) =&amp;gt; (
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can access the &lt;code&gt;data&lt;/code&gt; passed into the component, we just need a
way to visualise it! Luckily for use there’s a handy component from
Wes Bos that we can use called &lt;a href=&quot;https://github.com/wesbos/dump&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dump&lt;/a&gt;, so create a new &lt;code&gt;dump.js&lt;/code&gt;
component in &lt;code&gt;components&lt;/code&gt; then import it into the &lt;code&gt;index.js&lt;/code&gt; file, and
add in the component to see what’s inside the props:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const IndexPage = ({ data }) =&amp;gt; (
  &amp;lt;Layout&amp;gt;
    &amp;lt;h1&amp;gt;Hi people&amp;lt;/h1&amp;gt;
    &amp;lt;Dump data={data} /&amp;gt;
    &amp;lt;p&amp;gt;Welcome to your new Gatsby site.&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;Now go build something great.&amp;lt;/p&amp;gt;
    &amp;lt;div style={{ maxWidth: &amp;#x27;300px&amp;#x27;, marginBottom: &amp;#x27;1.45rem&amp;#x27; }}&amp;gt;
      &amp;lt;Image /&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;Link to=&amp;quot;/page-2/&amp;quot;&amp;gt;Go to page 2&amp;lt;/Link&amp;gt;
  &amp;lt;/Layout&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The output should be the same as the result of the Gatsby GraphiQL
query we created:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;data 💩{
 &amp;quot;graphCmsData&amp;quot;: {
  &amp;quot;projects&amp;quot;: [
   {
    &amp;quot;id&amp;quot;: &amp;quot;cjoxa812txqoh0932hz0bs345&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;PUBLISHED&amp;quot;,
    &amp;quot;title&amp;quot;: &amp;quot;Project 1&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;Description 1&amp;quot;
   },
   {
    &amp;quot;id&amp;quot;: &amp;quot;cjoxa8cctxqqj0932710u39db&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;PUBLISHED&amp;quot;,
    &amp;quot;title&amp;quot;: &amp;quot;Project 2&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;Description 2&amp;quot;
   },
   {
    &amp;quot;id&amp;quot;: &amp;quot;cjoxa8pbqxqt309324z9bcddv&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;PUBLISHED&amp;quot;,
    &amp;quot;title&amp;quot;: &amp;quot;Project 3&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;Description 3&amp;quot;
   },
   {
    &amp;quot;id&amp;quot;: &amp;quot;cjoxa959vxqvz0932g1jn5ss3&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;PUBLISHED&amp;quot;,
    &amp;quot;title&amp;quot;: &amp;quot;Project 4&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;Description 4&amp;quot;
   }
  ]
 }
}
&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title><![CDATA[Using the React Context API  -  getting started]]></title><description><![CDATA[Let's use the React Context API to change theme in an app! But first, some  context ! 🤣 Ok terrible puns aside let's have a look at what…]]></description><link>https://scottspence.com/2018/09/08/react-context-api/</link><guid isPermaLink="false">https://scottspence.com/2018/09/08/react-context-api/</guid><pubDate>Sat, 08 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let’s use the React Context API to change theme in an app!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/zmp2k4r128poj1gsws61.gif&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;but-first-some-context-🤣&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#but-first-some-context-%F0%9F%A4%A3&quot; aria-label=&quot;but first some context 🤣 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But first, some &lt;strong&gt;context&lt;/strong&gt;! 🤣&lt;/h2&gt;&lt;p&gt;Ok terrible puns aside let’s have a look at what the React Context API
is for and what it does. There’s a great one liner from the &lt;a href=&quot;https://reactjs.org/docs/context.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React
docs&lt;/a&gt;…&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Context provides a way to pass data through the component tree
without having to pass props down manually at every level.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Or in other words, you can use the React Context API to avoid &lt;a href=&quot;https://blog.kentcdodds.com/prop-drilling-bb62e02cb691&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;prop
drilling&lt;/a&gt; if you need more detail on the concept then please do check
out the links provided.&lt;/p&gt;&lt;p&gt;I’ve previously gone over implementing the React Context API in &lt;a href=&quot;https://thelocalhost.blog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my
Gatsby blog&lt;/a&gt; which I documented as I did it; you can see &lt;a href=&quot;https://thelocalhost.blog/react-context-api-with-gatsby&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;how that
went here&lt;/a&gt;.&lt;/p&gt;&lt;blockquote&gt;&lt;h3 id=&quot;explain-the-context-api-to-me&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#explain-the-context-api-to-me&quot; aria-label=&quot;explain the context api to me permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Explain the Context API to me.&lt;/h3&gt;&lt;p&gt;A great resource on explaining the API can be found from
&lt;a href=&quot;https://twitter.com/leighchalliday&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@leighchalliday&lt;/a&gt; with a &lt;a href=&quot;https://www.youtube.com/watch?v=yzQ_XulhQFw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;great usecase&lt;/a&gt; on the subject.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;what-were-doing&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-were-doing&quot; aria-label=&quot;what were doing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we’re doing…&lt;/h2&gt;&lt;p&gt;For this post we’re going to extend the example we created for
&lt;a href=&quot;https://medium.com/styled-components/styled-components-getting-started-c9818acbcbbd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components getting started&lt;/a&gt; as it has the majority of the code
we’ll need to get started with the React Context API.&lt;/p&gt;&lt;p&gt;We’re going to extend that example to manage the theme state of the
example application.&lt;/p&gt;&lt;p&gt;So in summary:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Scaffold out basic CreateReact App&lt;/li&gt;&lt;li&gt;Use styled-components 💅 for styling&lt;/li&gt;&lt;li&gt;Add themes to switch between with the React Context API&lt;/li&gt;&lt;li&gt;Use the React Context API!&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;what-well-need&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-well-need&quot; aria-label=&quot;what well need permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we’ll need…&lt;/h2&gt;&lt;p&gt;All we’ll be needing is an internet connection and a modern web
browser! Because we’re going to do all of this online in the awesome
&lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox&lt;/a&gt;!&lt;/p&gt;&lt;p&gt;If you have a GitHub account or not, CodeSandbox will let you get
started &lt;a href=&quot;https://codesandbox.io/s/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;coding straight away&lt;/a&gt;!&lt;/p&gt;&lt;h3 id=&quot;versions&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#versions&quot; aria-label=&quot;versions permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Versions:&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;This guide is being used with the following dependency versions.&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;react: 16.4.2&lt;/li&gt;&lt;li&gt;react-dom: 16.4.2&lt;/li&gt;&lt;li&gt;react-scripts: 1.1.4&lt;/li&gt;&lt;li&gt;styled-components: 3.4.5&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2 id=&quot;lets-start&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lets-start&quot; aria-label=&quot;lets start permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s start&lt;/h2&gt;&lt;p&gt;So let’s go over theming the basic create react app again, this time
instead of adding state into to the component we will use the React
Context API to manage the state for us. There will be people that will
argue that this is a bit overkill for a theme switch but it is given
as an example of &lt;a href=&quot;https://reactjs.org/docs/context.html#when-to-use-context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;when to use the Context API&lt;/a&gt; in the React
documentation so I will let you decide on the validity of that point.
For this example, I hope it will give you a clearer picture of how to
use the Context API in an application.&lt;/p&gt;&lt;h3 id=&quot;dependencies&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#dependencies&quot; aria-label=&quot;dependencies permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dependencies&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://codesandbox.io/s/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Open a React CodeSandbox&lt;/a&gt; and add &lt;code&gt;styled-components&lt;/code&gt; as a
dependency:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/d49drafvtvz3ws2br9vs.gif&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;file-structure&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#file-structure&quot; aria-label=&quot;file structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;File structure&lt;/h3&gt;&lt;p&gt;Another area for &lt;a href=&quot;https://en.wiktionary.org/wiki/bikeshedding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bikeshedding&lt;/a&gt; is file structure, in this scenario
we’re adding folders for &lt;code&gt;components&lt;/code&gt;, &lt;code&gt;contexts&lt;/code&gt; and the &lt;code&gt;theme&lt;/code&gt;
please feel free to structure your files how you see fit, this is how
we’re going to do it for this example ❤️&lt;/p&gt;&lt;p&gt;Add the directories into the &lt;code&gt;src&lt;/code&gt; folder so we can add in some
components, the file structure should look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;context-demo/
├─ public/
├─ src/
│  └─ components/
│  └─ contexts/
│  └─ theme/
└─ package.json
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;scaffold-out-a-basic-create-react-app&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#scaffold-out-a-basic-create-react-app&quot; aria-label=&quot;scaffold out a basic create react app permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Scaffold out a basic Create React App&lt;/h2&gt;&lt;p&gt;Ok, so, what we’re going to do is add in an &lt;code&gt;App.js&lt;/code&gt; component to the
&lt;code&gt;components&lt;/code&gt; folder then use that in the &lt;code&gt;src/index.js&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;App.js&lt;/code&gt; component can be a &lt;a href=&quot;https://reactjs.org/docs/state-and-lifecycle.html#the-data-flows-down&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stateless functional component&lt;/a&gt; as
for this example as we’re going to be handling state with the Context
API.&lt;/p&gt;&lt;p&gt;Here you can see my sketchy typing as I create the directories and add
in the &lt;code&gt;App.js&lt;/code&gt; component.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/oyxpggt00q754iv1azp0.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;We can then remove the &lt;code&gt;style.css&lt;/code&gt; file and reference in
&lt;code&gt;src/index.js&lt;/code&gt; as we’re going to be styling with styled-components 💅
and then use our &lt;code&gt;App.js&lt;/code&gt; component:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/yyne3q36jc0zca2ld89u.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Ok, so the reason why I have abstracted the &lt;code&gt;App.js&lt;/code&gt; component out of
the &lt;code&gt;src/index.js&lt;/code&gt; file is so that when we come to using the Context
API we can add it to the highest level in our app, which is
&lt;code&gt;src/index.js&lt;/code&gt;.&lt;/p&gt;&lt;h3 id=&quot;what-about-the-rest&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-about-the-rest&quot; aria-label=&quot;what about the rest permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about the rest?&lt;/h3&gt;&lt;p&gt;So this isn’t really the Create React App, as we’re using CodeSandbox
instead, I have gone over the basic styling used in the
&lt;a href=&quot;https://medium.com/styled-components/styled-components-getting-started-c9818acbcbbd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components getting started&lt;/a&gt; post so it’s time to refer to that
to mimic the styles we need.&lt;/p&gt;&lt;p&gt;That means what we’re going to do, rather than go into depth on the
styling of each of the component parts that make up the basic Create
React App appearance, we’re going to re-use components, so there’s
going to be a bit of copy pasting involved now.&lt;/p&gt;&lt;p&gt;The Create React App boilerplate code has one file that we go over
styling in the &lt;a href=&quot;https://medium.com/styled-components/styled-components-getting-started-c9818acbcbbd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components getting started&lt;/a&gt; post which is the
&lt;code&gt;App.js&lt;/code&gt; file, the others are left or deleted, the basic style of
&lt;code&gt;App.js&lt;/code&gt; is:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;App.css&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-title {
  font-size: 1.5em;
}

.App-intro {
  font-size: large;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;use-styled-components-for-styling&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-styled-components-for-styling&quot; aria-label=&quot;use styled components for styling permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use styled components for styling&lt;/h2&gt;&lt;p&gt;Now we’re going to recreate the styles from the &lt;code&gt;App.css&lt;/code&gt; file with
styled-components, let’s list them out here and go through them:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;AppWrapper
AppHeader
AppTitle
rotate360
AppLogo
# We&amp;#x27;re adding our own styles for
AppIntro
Underline
StyledHyperLink
Button
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;AppWrapper&lt;/code&gt; is the top level wrapper which in a larger component
could be used for layout with CSS Grid or Flexbox, in our case we’re
going to align the text center.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/uc08zkkf4ay1hq8pkt3w.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Straightforward enough, right? Now the majority of the rest of the
components will use the styled-components &lt;a href=&quot;https://www.styled-components.com/docs/advanced#theming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;ThemeProvider&lt;/code&gt;&lt;/a&gt; which is
what we’re going to pass our theme to from the Context API.&lt;/p&gt;&lt;h2 id=&quot;add-themes-to-switch-between-with-the-react-context-api&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-themes-to-switch-between-with-the-react-context-api&quot; aria-label=&quot;add themes to switch between with the react context api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add themes to switch between with the React Context API&lt;/h2&gt;&lt;p&gt;Ok, we need to define some themes to pass to the &lt;code&gt;ThemeProvider&lt;/code&gt;,
we’re going to define several theme aspects we want to change, these
are going to be:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;primary // colour
secondary // colour
danger // colour
fontHeader // font
fontBody // font
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Create a file to contain the theme object in the &lt;code&gt;theme&lt;/code&gt; directory and
call it &lt;code&gt;globalStyle.js&lt;/code&gt; and add in the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { injectGlobal } from &amp;#x27;styled-components&amp;#x27;

export const themes = {
  theme1: {
    primary: &amp;#x27;#ff0198&amp;#x27;,
    secondary: &amp;#x27;#01c1d6&amp;#x27;,
    danger: &amp;#x27;#e50000&amp;#x27;,
    fontHeader: &amp;#x27;Old Standard TT, sans, sans-serif&amp;#x27;,
    fontBody: &amp;#x27;Nunito, sans-serif&amp;#x27;,
  },

  theme2: {
    primary: &amp;#x27;#6e27c5&amp;#x27;,
    secondary: &amp;#x27;#ffb617&amp;#x27;,
    danger: &amp;#x27;#ff1919&amp;#x27;,
    fontHeader: &amp;#x27;Enriqueta, sans-serif&amp;#x27;,
    fontBody: &amp;#x27;Exo 2, sans, sans-serif&amp;#x27;,
  },

  theme3: {
    primary: &amp;#x27;#f16623&amp;#x27;,
    secondary: &amp;#x27;#2e2e86&amp;#x27;,
    danger: &amp;#x27;#cc0000&amp;#x27;,
    fontHeader: &amp;#x27;Kaushan Script, sans, sans-serif&amp;#x27;,
    fontBody: &amp;#x27;Headland One, sans-serif&amp;#x27;,
  },
}

injectGlobal`
  @import url(&amp;#x27;
    https://fonts.googleapis.com/css?family=
    Old+Standard+TT:400,700|
    Nunito:400,700&amp;#x27;|
    Enriqueta:400,700|
    Exo+2:400,700|
    Kaushan+Script:400,700|
    Headland+One:400,700|
  &amp;#x27;);

  body {
    padding: 0;
    margin: 0;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/qnxbteccbaw92jbwsq9c.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Ok, so nothing really happening there apart from setting up the styles
for use later.&lt;/p&gt;&lt;p&gt;You will notice that &lt;code&gt;injectGlobal&lt;/code&gt; is being used here, this is where
we’re setting the fonts for use throughout the app, &lt;code&gt;injectGlobal&lt;/code&gt;
&lt;a href=&quot;https://stackoverflow.com/a/42899789/1138354&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;should be used once&lt;/a&gt; in an app to set global styles like this.&lt;/p&gt;&lt;p&gt;Onwards! Let us now focus on getting the basic app styles into the
&lt;code&gt;App.js&lt;/code&gt; component. We can now start using the &lt;code&gt;ThemeProvider&lt;/code&gt; in
&lt;code&gt;App.js&lt;/code&gt;. To do this, for now, to get some visual feedback we’re going
to apply one of the themes from the &lt;code&gt;themes&lt;/code&gt; object in
&lt;code&gt;globalStyle.js&lt;/code&gt; this is so, as we are adding in components we can see
the theme being applied.&lt;/p&gt;&lt;p&gt;We can do this now with the &lt;code&gt;AppHeader&lt;/code&gt; which is a styled div:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppHeader = styled.div`
  height: 12rem;
  padding: 1rem;
  color: ${({ theme }) =&amp;gt; theme.dark};
  background-color: ${({ theme }) =&amp;gt; theme.primary};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You will notice here that we’re beginning to use the
styled-components, &lt;code&gt;theme&lt;/code&gt; props but, if we paste this code in now
there won’t be any change until the &lt;code&gt;ThemeProvider&lt;/code&gt; is passed the
&lt;code&gt;theme&lt;/code&gt; object so we’re going to wrap &lt;code&gt;App.js&lt;/code&gt; with the
&lt;code&gt;ThemeProvider&lt;/code&gt; component so that any component encapsulated by the
&lt;code&gt;ThemeProvider&lt;/code&gt; is able to receive &lt;code&gt;theme&lt;/code&gt; props.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/nuyaw29uoex6qcluf8va.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;AppTitle&lt;/code&gt; is going to be a h1 so:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppTitle = styled.h1`
  font-family: ${({ theme }) =&amp;gt; theme.fontHeader};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the spinning React logo we can use the asset used previously in
the &lt;a href=&quot;https://codesandbox.io/s/x26q7l9vyq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components getting started example&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We can add it in with the imports at the top of the &lt;code&gt;App.js&lt;/code&gt; component
and add it into the &lt;code&gt;AppLogo&lt;/code&gt; styled component as an &lt;code&gt;img&lt;/code&gt; tag:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const logo = `https://user-images.githubusercontent.com/
    234708/37256552-32635a02-2554-11e8-8fe3-8ab5bd969d8e.png`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;keyframes&lt;/code&gt; helper will need to be imported alongside the
&lt;code&gt;ThemeProvider&lt;/code&gt; for the animation on the react logo.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const rotate360 = keyframes`
  from { 
    transform: rotate(0deg); 
  }
  to { 
    transform: rotate(360deg); 
  }
`

const AppLogo = styled.img`
  animation: ${rotate360} infinite 5s linear;
  height: 80px;
  &amp;amp;:hover {
    animation: ${rotate360} infinite 1s linear;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/pxe3fb5zqvprvtjthq5b.gif&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;shared-components&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#shared-components&quot; aria-label=&quot;shared components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shared components&lt;/h3&gt;&lt;p&gt;Shared components are covered in the &lt;a href=&quot;https://medium.com/styled-components/styled-components-getting-started-c9818acbcbbd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components getting
started&lt;/a&gt; guide if you need more information, for this example we’re
going to bring in the final couple of components as shared ones for
the &lt;code&gt;StyledHyperLink&lt;/code&gt; and &lt;code&gt;Button&lt;/code&gt; in &lt;code&gt;src/Shared.js&lt;/code&gt; add the
following:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;src/Shared.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import styled, { css } from &amp;#x27;styled-components&amp;#x27;

export const Button = styled.button`
  padding: 0.5rem 1rem;
  margin: 0.5rem 1rem;
  color: ${({ theme }) =&amp;gt; theme.primary};
  font-size: 1rem;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  border: 2px solid ${props =&amp;gt; props.border};
  background-color: Transparent;
  text-transform: uppercase;
  border-radius: 4px;
  transition: all 0.1s;
  &amp;amp;:hover {
    transform: translateY(1px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
  }
  ${props =&amp;gt;
    props.primary &amp;amp;&amp;amp;
    css`
      background: ${({ theme }) =&amp;gt; theme.primary};
      border: 2px solid ${({ theme }) =&amp;gt; theme.primary};
      color: white;
    `};
  ${props =&amp;gt;
    props.danger &amp;amp;&amp;amp;
    css`
      background: ${({ theme }) =&amp;gt; theme.danger};
      border: 2px solid ${({ theme }) =&amp;gt; theme.danger};
      color: white;
    `};
  &amp;amp;:hover {
    transform: translateY(2px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
  }
`

export const StyledHyperLink = styled.a`
  cursor: pointer;
  &amp;amp;:visited,
  &amp;amp;:active {
    color: ${({ theme }) =&amp;gt; theme.primary};
  }
  &amp;amp;:hover {
    color: ${({ theme }) =&amp;gt; theme.secondary};
  }
  color: ${({ theme }) =&amp;gt; theme.primary};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then import the components like any other:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/ipi1kdmy83ieiw6sppog.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;The last three components for now, &lt;code&gt;AppIntro&lt;/code&gt;, &lt;code&gt;Underline&lt;/code&gt; and
&lt;code&gt;StyledHyperLink&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppIntro = styled.p`
  color: ${({ theme }) =&amp;gt; theme.dark};
  font-size: large;
  code {
    font-size: 1.3rem;
  }
  font-family: ${({ theme }) =&amp;gt; theme.fontBody};
`

const Underline = styled.span`
  border-bottom: 4px solid ${({ theme }) =&amp;gt; theme.secondary};
`

const StyledHyperLink = SHL.extend`
  text-decoration: none;
  font-family: ${({ theme }) =&amp;gt; theme.fontBody};
  color: ${({ theme }) =&amp;gt; theme.fontDark};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/smm6hpg2w71sxm6nf3ln.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Add them in under the &lt;code&gt;AppLogo&lt;/code&gt; styled component and then we can add
the rest of the components into the &lt;code&gt;App&lt;/code&gt; function &lt;code&gt;return&lt;/code&gt;, so, ready
for another &lt;a href=&quot;#&quot; title=&quot;Copy Paste! yes 🙃&quot;&gt;copy pasta&lt;/a&gt;? Here:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;AppIntro&amp;gt;
  Bootstrapped with{&amp;#x27; &amp;#x27;}
  &amp;lt;Underline&amp;gt;
    &amp;lt;code&amp;gt;
      &amp;lt;StyledHyperLink
        href={`https://github.com/facebook/create-react-app`}
        target=&amp;quot;_blank&amp;quot;
        rel=&amp;quot;noopener&amp;quot;
      &amp;gt;
        create-react-app
      &amp;lt;/StyledHyperLink&amp;gt;
    &amp;lt;/code&amp;gt;
  &amp;lt;/Underline&amp;gt;.
&amp;lt;/AppIntro&amp;gt;
&amp;lt;AppIntro&amp;gt;
  Components styled with{&amp;#x27; &amp;#x27;}
  &amp;lt;Underline&amp;gt;
    &amp;lt;code&amp;gt;
      &amp;lt;StyledHyperLink
        href={`https://www.styled-components.com`}
        target=&amp;quot;_blank&amp;quot;
        rel=&amp;quot;noopener&amp;quot;
      &amp;gt;
        styled-components
      &amp;lt;/StyledHyperLink&amp;gt;
    &amp;lt;/code&amp;gt;
  &amp;lt;/Underline&amp;gt;{&amp;#x27; &amp;#x27;}
  &amp;lt;span role=&amp;quot;img&amp;quot; aria-label=&amp;quot;nail polish&amp;quot;&amp;gt;
    💅
  &amp;lt;/span&amp;gt;
&amp;lt;/AppIntro&amp;gt;
&amp;lt;AppIntro&amp;gt;
  Fonts picked with{&amp;#x27; &amp;#x27;}
  &amp;lt;Underline&amp;gt;
    &amp;lt;code&amp;gt;
      &amp;lt;StyledHyperLink
        href={`https://fontjoy.com/`}
        target=&amp;quot;_blank&amp;quot;
        rel=&amp;quot;noopener&amp;quot;
      &amp;gt;
        fontjoy.com
      &amp;lt;/StyledHyperLink&amp;gt;
    &amp;lt;/code&amp;gt;
  &amp;lt;/Underline&amp;gt;
&amp;lt;/AppIntro&amp;gt;
&amp;lt;Button&amp;gt;Normal Button&amp;lt;/Button&amp;gt;
&amp;lt;Button primary&amp;gt;Primary Button&amp;lt;/Button&amp;gt;
&amp;lt;Button danger&amp;gt;Danger Button&amp;lt;/Button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Sorry for the code wall! Right paste that in under the closing
&lt;code&gt;&amp;lt;/AppHeader&amp;gt;&lt;/code&gt; tag and we should have the base of what we’re going to
theme!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/zfcnihvmyvb9my5dn11x.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Ok? How’s it looking?&lt;/p&gt;&lt;p&gt;Now we have a basic React app that uses styled-components!&lt;/p&gt;&lt;h2 id=&quot;use-the-react-context-api&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-the-react-context-api&quot; aria-label=&quot;use the react context api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use the React Context API&lt;/h2&gt;&lt;p&gt;Now for the main event! Here we’re going to cover:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Making the theme context.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Using the context API with a component.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Consuming the Context API in multiple components.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So, passing state needlessly through components is what we can use the
Context API to avoid. If we take a look at the &lt;a href=&quot;https://codesandbox.io/s/x26q7l9vyq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components
getting started example&lt;/a&gt; we can see the state being managed in the
&lt;code&gt;App.js&lt;/code&gt; component and the &lt;code&gt;handleThemeChange&lt;/code&gt; function has to be
passed to the &lt;code&gt;ThemeSelect&lt;/code&gt; component much the same way as any props
would need to be passed down. That is a simplified example but it’s
quite easy to imagine if that component lived on a footer component or
a menu item there would be several other components that would need to
have the state passed through them that would not actually need that
state or props. Make sense?&lt;/p&gt;&lt;p&gt;&lt;strong&gt;example&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;App&amp;gt;               {/* state begins here */}
  &amp;lt;Header&amp;gt;          {/* through here */}
    &amp;lt;Navigation&amp;gt;    {/* and here */}
      &amp;lt;ThemeSelect&amp;gt; {/* to be used here */}
    &amp;lt;/Navigation&amp;gt;
  &amp;lt;/Header&amp;gt;
  &amp;lt;Footer/&amp;gt;
&amp;lt;/App&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;add-the-site-theme-context&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-the-site-theme-context&quot; aria-label=&quot;add the site theme context permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add the site theme context&lt;/h3&gt;&lt;p&gt;In our &lt;code&gt;src/contexts/&lt;/code&gt; directory we’re going to make our
&lt;code&gt;SiteThemeContext.js&lt;/code&gt;, import React and define and export our context:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;

export const SiteThemeContext = React.createContext()
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;so-what-is-a-context&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#so-what-is-a-context&quot; aria-label=&quot;so what is a context permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So what is a context?&lt;/h3&gt;&lt;p&gt;A context is made up of two things, a provider and a consumer, you
have a single provider which will sit up as high as possible in the
component tree so that multiple consumers can get the state and props
from the provider.&lt;/p&gt;&lt;p&gt;Hopefully you recall the point at which we abstracted the
&lt;code&gt;function App&lt;/code&gt; component out of the &lt;code&gt;src/index.js&lt;/code&gt; file, this is so we
could add in the context provider at the highest level of the app, in
the &lt;code&gt;src/index.js&lt;/code&gt; file. This means that any consumer within the app,
no matter how deep into the component tree it is, it can get the state
and props from that top level.&lt;/p&gt;&lt;p&gt;Now to create a provider, the provider is a regular React component,
so:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;

export const SiteThemeContext = React.createContext()

export class SiteThemeProvider extends React.Component {
  render() {
    return (
      &amp;lt;SiteThemeContext.Provider value={}&amp;gt;
        {this.props.children}
      &amp;lt;/SiteThemeContext.Provider&amp;gt;
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is being returned by &lt;code&gt;&amp;lt;SiteThemeProvider&amp;gt;&lt;/code&gt; is the
&lt;code&gt;&amp;lt;SiteThemeContext.Provider&amp;gt;&lt;/code&gt; and the children of that component, the
one prop you have to provide the the provider is a &lt;code&gt;value&lt;/code&gt; prop. This
is the variable that the consumer has access to. The consumer being
&lt;code&gt;&amp;lt;SiteThemeContext.Consumer&amp;gt;&lt;/code&gt; (more on this shortly).&lt;/p&gt;&lt;p&gt;So what we can do now is have what is passed into &lt;code&gt;value&lt;/code&gt; be an object
&lt;code&gt;value={{}}&lt;/code&gt; so it can store multiple properties of the state and the
functions that are defined in &lt;code&gt;SiteThemeContext&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The state for the context needs to be the &lt;code&gt;theme&lt;/code&gt; so we need to import
the theme from &lt;code&gt;src/theme/globalStyle&lt;/code&gt; and add that to the state,
we’re going to default the theme (and state) to &lt;code&gt;theme1&lt;/code&gt; and add a
copy of that into the &lt;code&gt;value&lt;/code&gt; prop by spreading into state &lt;code&gt;...❤️&lt;/code&gt;, it
should look like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;

import { themes } from &amp;#x27;../theme/globalStyle&amp;#x27;

export const SiteThemeContext = React.createContext()

export class SiteThemeProvider extends React.Component {
  state = {
    theme: themes[&amp;#x27;theme1&amp;#x27;],
  }

  render() {
    return (
      &amp;lt;SiteThemeContext.Provider
        value={{
          ...this.state,
        }}
      &amp;gt;
        {this.props.children}
      &amp;lt;/SiteThemeContext.Provider&amp;gt;
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, it’s been a while since I’ve added a gif, time for another one!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/n2qbxs7cbf7w5opqcri2.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;And bring in the &lt;code&gt;themes&lt;/code&gt; and add state:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/y6n32p1gshah5ex747mu.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Now we can add in a function to the provider to change the theme state
based on what has been selected via the &lt;code&gt;handleThemeChange&lt;/code&gt; event
value:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;handleThemeChange = e =&amp;gt; {
  const key = e.target.value
  const theme = themes[key]
  this.setState({ theme })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This can then be consumed by any provider that wants to use it, we’re
going to need to add it into the &lt;code&gt;value&lt;/code&gt; prop, like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;

import { themes } from &amp;#x27;../theme/globalStyle&amp;#x27;

export const SiteThemeContext = React.createContext()

export class SiteThemeProvider extends React.Component {
  state = {
    theme: themes[&amp;#x27;theme1&amp;#x27;],
  }

  handleThemeChange = e =&amp;gt; {
    const key = e.target.value
    const theme = themes[key]
    this.setState({ theme })
  }

  render() {
    return (
      &amp;lt;SiteThemeContext.Provider
        value={{
          ...this.state,
          handleThemeChange: this.handleThemeChange,
        }}
      &amp;gt;
        {this.props.children}
      &amp;lt;/SiteThemeContext.Provider&amp;gt;
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, that is the site theme context component covered, pretty straight
forward, right?&lt;/p&gt;&lt;p&gt;What I should mention is that the &lt;code&gt;e&lt;/code&gt; in the &lt;code&gt;handleThemeChange&lt;/code&gt;
function is going to be the event from the theme select box that we’re
about to make.&lt;/p&gt;&lt;p&gt;Let’s go through adding in the function and adding that to the state:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/3bh3bwi4ekb24uowvm65.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;And now we can add the theme provider to &lt;code&gt;src/index.js&lt;/code&gt; so anything
lower in the dependency tree can access it via a consumer.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/p8nibx8ecfildi92jscm.gif&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;add-the-theme-select&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-the-theme-select&quot; aria-label=&quot;add the theme select permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add the theme select&lt;/h3&gt;&lt;p&gt;Now we want a want to call the &lt;code&gt;handleThemeChange&lt;/code&gt; function that is
part of the &lt;code&gt;SiteThemeProvider&lt;/code&gt; via the &lt;code&gt;SiteThemeContext&lt;/code&gt;! I’m sure
this all making perfect sense right now (🤣) so let’s get right in
there and define the component that we’re going to use to consume the
&lt;code&gt;SiteThemeContext.Provider&lt;/code&gt; with a &lt;code&gt;ThemeSelect&lt;/code&gt; component!&lt;/p&gt;&lt;p&gt;In the &lt;code&gt;src/components&lt;/code&gt; directory add a new &lt;code&gt;ThemeSelect.js&lt;/code&gt;
component, this is where we are going to consume the site theme
context with a consumer.&lt;/p&gt;&lt;p&gt;The child of a consumer isn’t a component it’s a function, so what
we’re going to need to do is have the theme select inside the return
of that function.&lt;/p&gt;&lt;p&gt;Let’s first set up the styled-components that will make up the select,
which is a select box, some options and a wrapper.&lt;/p&gt;&lt;p&gt;First we’ll do it without the consumer then we’ll add it in.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;ThemeSelect.js&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

import { themes } from &amp;#x27;../theme/globalStyle&amp;#x27;

const SelectWrapper = styled.div`
  margin: 0rem 0.5rem 0rem 0.25rem;
  padding: 0rem 0.5rem 0rem 0.25rem;
`

const Select = styled.select`
  margin: 1.5rem 0.5rem;
  padding: 0.25rem 0.5rem;
  font-family: ${({ theme }) =&amp;gt; theme.fontBody};
  border: 2px solid ${({ theme }) =&amp;gt; theme.secondary};
  box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
  background: ${({ theme }) =&amp;gt; theme.foreground};
  border-radius: 4px;
`

export const SelectOpt = styled.option`
  font-family: ${({ theme }) =&amp;gt; theme.fontBody};
`

const ThemeSelect = props =&amp;gt; {
  return (
    &amp;lt;SelectWrapper&amp;gt;
      &amp;lt;Select&amp;gt;
        {Object.keys(themes).map((theme, index) =&amp;gt; {
          return (
            &amp;lt;SelectOpt key={index} value={theme}&amp;gt;
              Theme {index + 1}
            &amp;lt;/SelectOpt&amp;gt;
          )
        })}
      &amp;lt;/Select&amp;gt;
    &amp;lt;/SelectWrapper&amp;gt;
  )
}

export default ThemeSelect
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/43e15llsi8uhlmi1z1ut.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;So from this we can list the this themes available to us in the
&lt;code&gt;themes&lt;/code&gt; object. But that’s it, the function to handle the theme
change lives on the &lt;code&gt;SiteThemeProvider&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Back to the &lt;code&gt;SiteThemeContext.Consumer&lt;/code&gt; as I mentioned earlier the
child of a consumer is a function &lt;code&gt;() =&amp;gt; ()&lt;/code&gt; the first section is the
&lt;code&gt;value&lt;/code&gt; from the provider (&lt;code&gt;&amp;lt;SiteThemeContext.Provider&amp;gt;&lt;/code&gt;) so let’s
take a quick look at what we’ve previously defined in the provider:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;value={{
  ...this.state,
  handleThemeChange: this.handleThemeChange
}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Available from &lt;code&gt;SiteThemeContext.Provider&lt;/code&gt; is the state and a function
so any of those items we can extract and pass to the provider, or to
put it another way the consumer can access those values.&lt;/p&gt;&lt;p&gt;Here we can use destructuring to pull the &lt;code&gt;handleThemeChange&lt;/code&gt; function
we need to change the theme.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;

import { SiteThemeContext } from &amp;#x27;../contexts/SiteThemeContext&amp;#x27;

const ThemeSelect = props =&amp;gt; {
  return (
    &amp;lt;SiteThemeContext.Consumer&amp;gt;
      {({ handleThemeChange }) =&amp;gt; ()}
    &amp;lt;/SiteThemeContext.Consumer&amp;gt;
  )
}

export default ThemeSelect
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/1qq4hc2zqa50t0t2vi5v.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Currently this isn’t going to change the theme because we have that
hardcoded into the styled-components &lt;code&gt;ThemeProvider&lt;/code&gt;, what we want to
do is use a consumer for the currently selected theme in the
&lt;code&gt;SiteThemeContext&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Before that we’ll also need to add in the &lt;code&gt;onChange&lt;/code&gt; event we want to
use to pass the event (&lt;code&gt;e&lt;/code&gt;) to the &lt;code&gt;handleThemeChange&lt;/code&gt; function on
&lt;code&gt;SiteThemeContext&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Then in the &lt;code&gt;App&lt;/code&gt; component we can import our
&lt;code&gt;&amp;lt;SiteThemeContext.Consumer&amp;gt;&lt;/code&gt; to consume the &lt;code&gt;theme&lt;/code&gt; on the
&lt;code&gt;SiteThemeContext&lt;/code&gt; state and pass that to the styled-components
&lt;code&gt;ThemeProvider&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/jn5u8bzuvufpa56c9ta7.gif&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;want-to-know-more&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#want-to-know-more&quot; aria-label=&quot;want to know more permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Want to know more?&lt;/h3&gt;&lt;p&gt;As mentioned at the start of this article a great resource is
&lt;a href=&quot;https://twitter.com/leighchalliday&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@leighchalliday&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/channel/UCWPY8W-FAZ2HdDiJp2RC_sQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;his YouTube channel&lt;/a&gt; where you can find his
&lt;a href=&quot;https://www.youtube.com/watch?v=yzQ_XulhQFw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;great usecase&lt;/a&gt; for the React Context API.&lt;/p&gt;&lt;p&gt;There’s also the &lt;a href=&quot;https://spectrum.chat/react&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React community on spectrum&lt;/a&gt; and &lt;a href=&quot;https://spectrum.chat/styled-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components
on spectrum&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://codesandbox.io/s/5vl16n5oxp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Example code&lt;/a&gt; of the walkthrough is available on &lt;a href=&quot;https://codesandbox.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CodeSandbox&lt;/a&gt;.&lt;/p&gt;&lt;h3 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h3&gt;&lt;p&gt;If there is anything I have missed, or if there is a better way to do
something then please let me know.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Making a CI pipeline with Travis CI]]></title><description><![CDATA[I thought I'd set up this blog with some sort of build pipeline, the
intention was to have a good Continuous Integration pipeline so that
if…]]></description><link>https://scottspence.com/2018/05/28/travis-ci/</link><guid isPermaLink="false">https://scottspence.com/2018/05/28/travis-ci/</guid><pubDate>Mon, 28 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I thought I’d set up this blog with some sort of build pipeline, the
intention was to have a good Continuous Integration pipeline so that
if there were any issues when building the site that I wouldn’t push a
broken build. No one wants to see that 😿&lt;/p&gt;&lt;p&gt;I’m feeling my way around with this and I’m presuming it’s far from
perfect or ideal even, but I have it as a functional work-flow.&lt;/p&gt;&lt;h3 id=&quot;what-im-using&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-im-using&quot; aria-label=&quot;what im using permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What I’m using&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Zeit’s now&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Gatsby&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Travis DUH!&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;how-the-set-up-works&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#how-the-set-up-works&quot; aria-label=&quot;how the set up works permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How the set-up works&lt;/h3&gt;&lt;p&gt;I have my GitHub project set up with two branches &lt;code&gt;master&lt;/code&gt; and
&lt;code&gt;development&lt;/code&gt;, changes are made on feature branch of &lt;code&gt;development&lt;/code&gt;
then pushed into &lt;code&gt;development&lt;/code&gt; then up to &lt;code&gt;master&lt;/code&gt; once I’m happy the
change is ok to go to production.&lt;/p&gt;&lt;p&gt;Using &lt;a href=&quot;https://zeit.co/now&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Zeit’s now&lt;/a&gt; you can define a different url for each of your
environments. I have a &lt;code&gt;.now.sh&lt;/code&gt; url for &lt;code&gt;development&lt;/code&gt; and a
sub-domain of my &lt;code&gt;scottspence.me&lt;/code&gt; domain for &lt;code&gt;master&lt;/code&gt;/production.&lt;/p&gt;&lt;h3 id=&quot;the-set-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-set-up&quot; aria-label=&quot;the set up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The set-up&lt;/h3&gt;&lt;p&gt;There are a few parts to setting this up, the first is adding your
repository to &lt;a href=&quot;https://travis-ci.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://travis-ci.org/&lt;/a&gt; then adding your &lt;code&gt;NOW_TOKEN&lt;/code&gt; from
&lt;a href=&quot;https://zeit.co/account/tokens&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://zeit.co/account/tokens&lt;/a&gt; to the repository settings page on
Travis-ci&lt;/p&gt;&lt;p&gt;The &lt;a href=&quot;https://zeit.co/docs/examples/travis&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;guide here&lt;/a&gt; covers it for using now, the part I found
particularly painful was generating the secure variable for the
&lt;code&gt;.travis.yml&lt;/code&gt; file because I don’t have Ruby installed and I struggled
to set it up on my OpenSUSE WSL install, so instead I used a Cloud9
machine in the end.&lt;/p&gt;&lt;h4 id=&quot;the-flow&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-flow&quot; aria-label=&quot;the flow permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;the flow&lt;/h4&gt;&lt;p&gt;Issue is “Add self hosted Fonts #75” I’ll make a branch from git and
give it a name to reflect the issue number
&lt;code&gt;dev/75/add-self-hosted-fonts&lt;/code&gt; I’ll make my changes locally then push
to the &lt;code&gt;development&lt;/code&gt; branch.&lt;/p&gt;&lt;p&gt;Once I have merged these changes into the &lt;code&gt;development&lt;/code&gt; branch then I
can view them om the &lt;code&gt;.now.sh&lt;/code&gt; url configured in my &lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;&lt;p&gt;My &lt;code&gt;travis.yml&lt;/code&gt; looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;sudo: false

language: node_js

cache:
  directories:
    - node_modules

notifications:
  email: false

node_js:
  - &amp;#x27;9&amp;#x27;

before_script:
  - npm prune

script:
  - npm i -g now@canary
  - npm run clean
  - npm run build
  - npm run deploy

after_script:
  - if [ &amp;quot;$TRAVIS_BRANCH&amp;quot; = &amp;quot;development&amp;quot; ]; then npm run alias:dev;
    fi
  - if [ &amp;quot;$TRAVIS_BRANCH&amp;quot; = &amp;quot;master&amp;quot; ]; then npm run alias:prod; fi
  - if [ &amp;quot;$TRAVIS_BRANCH&amp;quot; = &amp;quot;master&amp;quot; ]; then npm run release; fi
  - npm run cleanup

env:
global:
  secure: lngmfinghashvariable!
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;My &lt;code&gt;package.json&lt;/code&gt; looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &amp;quot;now&amp;quot;: {
    &amp;quot;name&amp;quot;: &amp;quot;scottblog&amp;quot;
  },
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;clean&amp;quot;: &amp;quot;rm -rf .cache/ &amp;amp;&amp;amp; rm -rf scottblog/ &amp;amp;&amp;amp; rm -rf public/&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;gatsby build &amp;amp;&amp;amp; mv public scottblog&amp;quot;,
    &amp;quot;deploy:now&amp;quot;: &amp;quot;npm run clean &amp;amp;&amp;amp; npm run build &amp;amp;&amp;amp; now scottblog/&amp;quot;,
    &amp;quot;dev&amp;quot;: &amp;quot;npm run clean &amp;amp;&amp;amp; gatsby develop&amp;quot;,
    &amp;quot;format&amp;quot;: &amp;quot;pretty-quick&amp;quot;,
    &amp;quot;precommit&amp;quot;: &amp;quot;pretty-quick --staged&amp;quot;,
    &amp;quot;deploy&amp;quot;: &amp;quot;now scottblog/ --token $NOW_TOKEN&amp;quot;,
    &amp;quot;alias:dev&amp;quot;: &amp;quot;now alias blog-scottspence.now.sh --token $NOW_TOKEN&amp;quot;,
    &amp;quot;alias:prod&amp;quot;: &amp;quot;now alias blog.scottspence.me --token $NOW_TOKEN&amp;quot;,
    &amp;quot;cleanup&amp;quot;: &amp;quot;now rm scottblog --safe --yes --token $NOW_TOKEN&amp;quot;,
    &amp;quot;release&amp;quot;: &amp;quot;release-it&amp;quot;
  },
&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title><![CDATA[Use the React Context API with Gatsby]]></title><description><![CDATA[I'm a bit late to the party using the new  React Context API , I did
get to use it the other day at work, I also  made a snippet  to…]]></description><link>https://scottspence.com/2018/05/22/react-context-api-with-gatsby/</link><guid isPermaLink="false">https://scottspence.com/2018/05/22/react-context-api-with-gatsby/</guid><pubDate>Tue, 22 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m a bit late to the party using the new &lt;a href=&quot;https://reactjs.org/docs/context.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Context API&lt;/a&gt;, I did
get to use it the other day at work, I also &lt;a href=&quot;https://github.com/spences10/settings/blob/35ba1ca3e9871c3ea6344ca2274ebbd327a18bed/globalVs.code-snippets#L74-L112&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;made a snippet&lt;/a&gt; to
scaffold out a component for it.&lt;/p&gt;&lt;p&gt;I had followed a couple of guides explaining how to use it and neither
of them as good as this great explanation of &lt;a href=&quot;https://www.youtube.com/watch?v=yzQ_XulhQFw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;how to use it&lt;/a&gt; from
&lt;a href=&quot;https://twitter.com/leighchalliday&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@leighchalliday&lt;/a&gt;, thank you Leigh 🙏 It’s a great use case which
helped me understand how to use it.&lt;/p&gt;&lt;p&gt;So, after doing this in a CRA project I decided to use it on one of my
Gatsby projects. With Gatsby the layout is slightly different where
you can have multiple layouts for differing sections of your app, so
this lends well for passing context.&lt;/p&gt;&lt;p&gt;One thing to bear in mind is that this is for my specific use case so
I’ll apologise upfront now if any of this is confusing, I’m trying to
get this documented to help me understand it too 👍&lt;/p&gt;&lt;p&gt;With Gatsby if you want to use the React 16.3 then you will need to
install the Gatsby React next plugin:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;npm install gatsby-plugin-react-next
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Gatsby uses React 16.2 I believe so you will need to use this plugin.&lt;/p&gt;&lt;p&gt;Another thing you may need to do is:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm i react react-dom
npm un react react-dom
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This may be because I was trying to use it in an old project, I’ve had
to do this on three projects now as I was getting &lt;code&gt;createContext&lt;/code&gt; is
not a function errors until I did this.&lt;/p&gt;&lt;p&gt;One other thing you may want to consider if it appears nothing is
working try using the &lt;code&gt;npm ci&lt;/code&gt; command. This is the npm 6+ version of
deleting your &lt;code&gt;node_modules&lt;/code&gt; folder and reinstalling. 🤓&lt;/p&gt;&lt;p&gt;So let’s go through one of my favourite use cases at the moment and
add theming support to a Gatsby site and use the React context API to
manage the theme.&lt;/p&gt;&lt;p&gt;You can see how theme a React app without the React Context API in my
&lt;a href=&quot;https://scottspence.me/styled-components-getting-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components 💅 getting started&lt;/a&gt; post.&lt;/p&gt;&lt;p&gt;For illustration I’ll go over it here now, you add the &lt;code&gt;ThemeProvider&lt;/code&gt;
at the highest level in the application structure so that all
descendants/children of the app can access it.&lt;/p&gt;&lt;p&gt;I have already done this for my &lt;a href=&quot;https://scottspence.me&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;personal site&lt;/a&gt; and now I’m going to
do it &lt;a href=&quot;#&quot; title=&quot;this site, 👀&quot;&gt;here&lt;/a&gt; so let’s go through it together.&lt;/p&gt;&lt;h2 id=&quot;lets-make-a-component&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lets-make-a-component&quot; aria-label=&quot;lets make a component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s make a component!&lt;/h2&gt;&lt;p&gt;Ok, so everything in React is a component, that’s why I like it so
much - so let’s make a &lt;code&gt;SomethingContext.js&lt;/code&gt; component, as I want to
do the &lt;a href=&quot;#&quot; title=&quot;things being using the styled components `ThemeProvider`&quot;&gt;things&lt;/a&gt; with the styled-components 💅&lt;/p&gt;&lt;p&gt;Let’s start by giving it an imaginative name:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;touch src/layouts/components/BlogThemeContext.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There we go 👍&lt;/p&gt;&lt;p&gt;Ok, the ‘things’ I want to do with the Context API are:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;change the styled-components &lt;code&gt;ThemeProvider&lt;/code&gt;&lt;/li&gt;&lt;li&gt;rotate the site hero patterns&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Now to scaffold out the context component, I have already mentioned
the &lt;a href=&quot;https://github.com/spences10/settings/blob/71dc76fb8e11c176f4517431be57c021fb72411a/globalVs.code-snippets#L74-L111&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VS Code snippet&lt;/a&gt; for my own personal use which is the basic
structure for the &lt;code&gt;Context&lt;/code&gt; which is in two parts, a &lt;code&gt;Provider&lt;/code&gt; and a
&lt;code&gt;Consumer&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Let’s create the &lt;code&gt;Context&lt;/code&gt; and the &lt;code&gt;Consumer&lt;/code&gt; in this component.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Using the snippet it should look something like this:&lt;/strong&gt;&lt;/p&gt;&lt;h6 id=&quot;srclayoutscomponentsblogthemecontextjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#srclayoutscomponentsblogthemecontextjs&quot; aria-label=&quot;srclayoutscomponentsblogthemecontextjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;src/layouts/components/BlogThemeContext.js&lt;/code&gt;&lt;/h6&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
// Context is made up of two things
// Provider - Single as close to top level as possible
// Consumer - Multiple have multiple consumers
export const BlogThemeContext = React.createContext()

export class BlogThemeProvider extends React.Component {
  state = {
    item1: 1,
    item2: 2,
  }

  // add function here
  functionHere = () =&amp;gt; {
    this.setState({
      item1: 2,
      item2: 3,
    })
  }
  render() {
    return (
      &amp;lt;BlogThemeContext.Provider
        value={{
          ...this.state,
          functionHere: this.functionHere,
        }}
      &amp;gt;
        {this.props.children}
      &amp;lt;/BlogThemeContext.Provider&amp;gt;
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the &lt;code&gt;props&lt;/code&gt; passed into the &lt;code&gt;&amp;lt;BlogThemeContext.Provider&amp;gt;&lt;/code&gt; is the
state and the methods contained in &lt;code&gt;BlogThemeProvider&lt;/code&gt; these can then
be accessed throughout the app by using the
&lt;code&gt;&amp;lt;BlogThemeContext.Consumer&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Now let’s add the &lt;code&gt;BlogThemeProvider&lt;/code&gt; at the top level of our app so
that the state and functions of the provider can are accessible for
the children of the &lt;code&gt;layout/index.js&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This is what it looks like before adding the context provider, you’ll
notice that the styled-components &lt;code&gt;ThemeProvider&lt;/code&gt; is a top level
component here.&lt;/p&gt;&lt;h6 id=&quot;srclayoutsindexjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#srclayoutsindexjs&quot; aria-label=&quot;srclayoutsindexjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;src/layouts/index.js&lt;/code&gt;&lt;/h6&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const TemplateWrapper = ({ children }) =&amp;gt; (
  &amp;lt;ThemeProvider theme={theme}&amp;gt;
    &amp;lt;PageContainer&amp;gt;
      &amp;lt;Helmet title={nameContent} meta={siteMeta} /&amp;gt;
      &amp;lt;Header /&amp;gt;
      &amp;lt;Main&amp;gt;{children()}&amp;lt;/Main&amp;gt;
      &amp;lt;Footer /&amp;gt;
    &amp;lt;/PageContainer&amp;gt;
  &amp;lt;/ThemeProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we already have the styled-components &lt;code&gt;ThemeProvider&lt;/code&gt; which
receives a &lt;code&gt;theme&lt;/code&gt; object, and we want to manage the theme in our
context provider. So let’s import the existing theme from the
&lt;code&gt;globalStyle&lt;/code&gt; module into &lt;code&gt;BlogThemeContext&lt;/code&gt; and add &lt;code&gt;theme&lt;/code&gt; to the
state of the &lt;code&gt;BlogThemeProvider&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;

import { theme } from &amp;#x27;../../theme/globalStyle&amp;#x27;

// Context is made up of two things
// Provider - Single as close to top level as possible
// Consumer - Multiple have multiple consumers
export const BlogThemeContext = React.createContext()

export class BlogThemeProvider extends React.Component {
  state = {
    theme,
  }

  // add function here
  functionHere = () =&amp;gt; {
    this.setState({
      item1: 2,
      item2: 3,
    })
  }
  render() {
    return (
      &amp;lt;BlogThemeContext.Provider
        value={{
          ...this.state,
          functionHere: this.functionHere,
        }}
      &amp;gt;
        {this.props.children}
      &amp;lt;/BlogThemeContext.Provider&amp;gt;
    )
  }
}

BlogThemeProvider.propTypes = {
  children: PropTypes.any,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;While we’re here let’s also add the function to handle the theme
changing by replacing the dummy &lt;code&gt;functionHere&lt;/code&gt; function in the snippet
and also bring in the themes we want to switch between.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import PropTypes from &amp;#x27;prop-types&amp;#x27;

import { theme1, theme2 } from &amp;#x27;../../theme/globalStyle&amp;#x27;

export const BlogThemeContext = React.createContext()

export class BlogThemeProvider extends React.Component {
  state = {
    theme,
  }

  handleThemeChange = e =&amp;gt; {
    let theme = e.target.value
    theme === &amp;#x27;theme1&amp;#x27; ? (theme = theme1) : (theme = theme2)
    this.setState({ theme })
  }
  render() {
    return (
      &amp;lt;BlogThemeContext.Provider
        value={{
          ...this.state,
          handleThemeChange: this.handleThemeChange,
        }}
      &amp;gt;
        {this.props.children}
      &amp;lt;/BlogThemeContext.Provider&amp;gt;
    )
  }
}

BlogThemeProvider.propTypes = {
  children: PropTypes.any,
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;use-the-contextconsumer&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-the-contextconsumer&quot; aria-label=&quot;use the contextconsumer permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use the &lt;code&gt;Context.Consumer&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;So, now, let’s use it, right? The way to use is much like with the
styled-component &lt;code&gt;ThemeProvider&lt;/code&gt;, import your &lt;code&gt;&amp;lt;ThemeSelectProvider&amp;gt;&lt;/code&gt;
then you can use the &lt;code&gt;&amp;lt;ThemeSelectContext.Consumer&amp;gt;&lt;/code&gt; to access the
functions and state of the &lt;code&gt;BlogThemeContext&lt;/code&gt; via the
&lt;code&gt;&amp;lt;ThemeSelectProvider&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;The child of a consumer is a function, so rather than have your app
being returned like you would with a normal React component like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;Wrapper&amp;gt;
  &amp;lt;Child /&amp;gt;
&amp;lt;/Wrapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So you need to embed a function like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;Wrapper&amp;gt;{() =&amp;gt; &amp;lt;Child /&amp;gt;}&amp;lt;/Wrapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So you’re returning the (in this example, &lt;code&gt;&amp;lt;Child /&amp;gt;&lt;/code&gt;) app as the
result of the &lt;code&gt;&amp;lt;Context.Consumer&amp;gt;&lt;/code&gt; function, here we can also get any
of the properties or state from the Context, in my use case here I
want to get the &lt;code&gt;theme&lt;/code&gt; prop out of the Context provider &lt;code&gt;value&lt;/code&gt;
(&lt;code&gt;&amp;lt;BlogThemeProvider&amp;gt;&lt;/code&gt;) so we’ll use ES6 destructuring to pull out the
&lt;code&gt;theme&lt;/code&gt; object.&lt;/p&gt;&lt;p&gt;The styled-components &lt;code&gt;ThemeProvider&lt;/code&gt; can now use the &lt;code&gt;theme&lt;/code&gt; object
supplied by the &lt;code&gt;&amp;lt;BlogThemeContext.Consumer&amp;gt;&lt;/code&gt; so it’s safe to remove
the import from &lt;code&gt;globalStyle&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const TemplateWrapper = ({ children }) =&amp;gt; (
  &amp;lt;BlogThemeProvider&amp;gt;
    &amp;lt;BlogThemeContext.Consumer&amp;gt;
      {({ theme }) =&amp;gt; (
        &amp;lt;ThemeProvider theme={theme}&amp;gt;
          &amp;lt;PageContainer&amp;gt;
            &amp;lt;Helmet title={nameContent} meta={siteMeta} /&amp;gt;
            &amp;lt;Header /&amp;gt;
            &amp;lt;Main&amp;gt;{children()}&amp;lt;/Main&amp;gt;
            &amp;lt;Footer /&amp;gt;
          &amp;lt;/PageContainer&amp;gt;
        &amp;lt;/ThemeProvider&amp;gt;
      )}
    &amp;lt;/BlogThemeContext.Consumer&amp;gt;
  &amp;lt;/BlogThemeProvider&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There’s also a template &lt;code&gt;src/template/blog-posts.js&lt;/code&gt; which Gatsby uses
to generate the posts in this blog, let’s make it the same, let’s wrap
the app in the return function for the context consumer, before it
looked like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Template = ({ data, pathContext }) =&amp;gt; {
  const { markdownRemark: post } = data
  const { frontmatter, html } = post
  const { title, date } = frontmatter
  const { next, prev } = pathContext

  return (
    &amp;lt;PostWrapper border={({ theme }) =&amp;gt; theme.primary.light}&amp;gt;
      &amp;lt;Helmet title={`${title} - blog.scottspence.me`} /&amp;gt;
      &amp;lt;Title&amp;gt;{title}&amp;lt;/Title&amp;gt;
      &amp;lt;TitleDate&amp;gt;{date}&amp;lt;/TitleDate&amp;gt;
      ....
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now it looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Template = ({ data, pathContext }) =&amp;gt; {
  const { markdownRemark: post } = data
  const { frontmatter, html } = post
  const { title, date } = frontmatter
  const { next, prev } = pathContext

  return (
    &amp;lt;BlogThemeProvider&amp;gt;
      &amp;lt;BlogThemeContext.Consumer&amp;gt;
        {({ theme }) =&amp;gt; (
          &amp;lt;PostWrapper border={({ theme }) =&amp;gt; theme.primary.light}&amp;gt;
            &amp;lt;Helmet title={`${title} - blog.scottspence.me`} /&amp;gt;
            &amp;lt;Title&amp;gt;{title}&amp;lt;/Title&amp;gt;
            &amp;lt;TitleDate&amp;gt;{date}&amp;lt;/TitleDate&amp;gt;
            ....
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;add-a-themeselect-component&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#add-a-themeselect-component&quot; aria-label=&quot;add a themeselect component permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add a ThemeSelect component&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;ThemeSelect&lt;/code&gt; component is a select component I have used several
times now, &lt;a href=&quot;https://github.com/spences10/scottspence.me/blob/master/src/components/ThemeSelect.js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here’s the source&lt;/a&gt; from my personal site, it’s what we’re
going to use to handle the theme change, it will use the
&lt;code&gt;handleThemeChange&lt;/code&gt; method in the &lt;code&gt;BlogThemeContext&lt;/code&gt; so we better use
a Context consumer to access the method:&lt;/p&gt;&lt;h6 id=&quot;srclayoutscomponentsfooterjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#srclayoutscomponentsfooterjs&quot; aria-label=&quot;srclayoutscomponentsfooterjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;code&gt;src/layouts/components/Footer.js&lt;/code&gt;&lt;/h6&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&amp;lt;BlogThemeContext.Consumer&amp;gt;
  {({ handleThemeChange }) =&amp;gt; (
    &amp;lt;ThemeSelectWrapper&amp;gt;
      &amp;lt;ThemeSelect handleThemeChange={handleThemeChange} /&amp;gt;
    &amp;lt;/ThemeSelectWrapper&amp;gt;
  )}
&amp;lt;/BlogThemeContext.Consumer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now if we have a look at the &lt;code&gt;state&lt;/code&gt; in the React dev tools we can see
the font changing with the selection of the theme change, much like in
the &lt;a href=&quot;https://scottspence.me/styled-components-getting-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;styled-components 💅 getting started&lt;/a&gt; post.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/r1b8qgu6lm5xjjondse7.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;Ok, success 💯 👌 now onto the background switching/transition thingy.&lt;/p&gt;&lt;h2 id=&quot;switch-hero-background-patterns&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#switch-hero-background-patterns&quot; aria-label=&quot;switch hero background patterns permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Switch hero (background patterns)&lt;/h2&gt;&lt;p&gt;So, right now to switch between &lt;a href=&quot;https://twitter.com/steveschoger&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Steve Schoger&lt;/a&gt;’s awesome &lt;a href=&quot;http://www.heropatterns.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hero
patterns&lt;/a&gt; I have a function sitting in the &lt;code&gt;globalStyle&lt;/code&gt; module which
returns a random HERO pattern:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const randoHero = () =&amp;gt; {
  const keys = Object.keys(HERO)
  return HERO[keys[(keys.length * Math.random()) &amp;lt;&amp;lt; 0]]
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This function sets the background on the &lt;code&gt;body&lt;/code&gt; each reload with a
random key from the &lt;code&gt;HERO&lt;/code&gt; object, now I’m going to move that to the
&lt;code&gt;componentDidMount()&lt;/code&gt; of &lt;code&gt;BlogThemeContext.Provider&lt;/code&gt; so (for now) it
selects a random key from the object every ten seconds:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export class BlogThemeProvider extends React.Component {
  state = {
    theme: theme1,
    background: HERO[0]
  }

  handleThemeChange = e =&amp;gt; {
    let theme = e.target.value
    theme === &amp;#x27;theme1&amp;#x27; ? (theme = theme1) : (theme = theme2)
    this.setState({ theme })
  }

  componentDidMount() {
    this.interval = setInterval(() =&amp;gt; {
      const keys = Object.keys(HERO)
      const background =
        HERO[keys[(keys.length * Math.random()) &amp;lt;&amp;lt; 0]]

      this.setState({ background })
    }, 10 * 1000)
  }

  render() {
  ....
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to find somewhere in the app that can change the background! As I
mentioned before the background for the page was set on the &lt;code&gt;body&lt;/code&gt; via
styled-components &lt;code&gt;injectGlobal&lt;/code&gt; I now want to access the &lt;code&gt;background&lt;/code&gt;
prop from Context so I have moved this to &lt;code&gt;src/layouts/index.js&lt;/code&gt;. I
already have the Context consumer added for the &lt;code&gt;theme&lt;/code&gt; so let’s
destructure the &lt;code&gt;background&lt;/code&gt; prop out as well:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const TemplateWrapper = ({ children }) =&amp;gt; (
  &amp;lt;BlogThemeProvider&amp;gt;
    &amp;lt;BlogThemeContext.Consumer&amp;gt;
      {({ theme, background }) =&amp;gt; (
        &amp;lt;ThemeProvider theme={theme}&amp;gt;
          &amp;lt;PageContainer background={background}&amp;gt;
            &amp;lt;Helmet title={nameContent} meta={siteMeta} /&amp;gt;
            &amp;lt;Header /&amp;gt;
            &amp;lt;Main&amp;gt;{children()}&amp;lt;/Main&amp;gt;
            &amp;lt;Footer /&amp;gt;
          &amp;lt;/PageContainer&amp;gt;
          ....
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now use the &lt;code&gt;background&lt;/code&gt; prop in the main wrapper &lt;code&gt;PageContainer&lt;/code&gt;&lt;/p&gt;&lt;p&gt;We’re passing the both the background image and colour as
styled-component props now.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const PageContainer = styled.div`
  background-color: ${props =&amp;gt; props.theme.background};
  background-image: url(&amp;quot;${props =&amp;gt; props.background}&amp;quot;);
  background-attachment: fixed;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s it! We have used the React Context API to access state and use
it at (two) different points in the app.&lt;/p&gt;&lt;h2 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h2&gt;&lt;p&gt;Thanks you for looking at all the code walls!&lt;/p&gt;&lt;p&gt;If you have any feedback &lt;a href=&quot;https://scottspence.me/contact&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;please get in touch&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You can find all the source code to this on my repo for this project
here: &lt;a href=&quot;https://thelocalhost.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://thelocalhost.io/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[styled-components 💅 getting started]]></title><description><![CDATA[We're going to style the basic create react app with styled-components
to look something like this: But first, preamble✨: I have always…]]></description><link>https://scottspence.com/2018/04/03/styled-components/</link><guid isPermaLink="false">https://scottspence.com/2018/04/03/styled-components/</guid><pubDate>Tue, 03 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re going to style the basic create react app with styled-components
to look something like this:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/5dwv10zpqa13wb4pr47l.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;But first, preamble✨: I have always struggled with styling sites, it
seems to be an aspect of starting web development that is either an
afterthought or glossed over. Up until December last year I didn’t
really like styling anything at all with CSS, it was a chore rather
than something I enjoyed doing.&lt;/p&gt;&lt;p&gt;This was until I started using styled-components, when I joined a
build to learn project for a &lt;a href=&quot;https://medium.com/chingu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chingu&lt;/a&gt; voyage (&lt;a href=&quot;https://github.com/chingu-voyage3/grad.then/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;grad.then()&lt;/code&gt;&lt;/a&gt; if
you’re interested) we decided to use a CSS-in-JS package, &lt;a href=&quot;https://twitter.com/mar_biletska&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Marina&lt;/a&gt; who
was on my team was such an inspiration for me watching how components
were styled and really gave me the confidence to start using
styled-components.&lt;/p&gt;&lt;h6 id=&quot;me-with-css-before&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#me-with-css-before&quot; aria-label=&quot;me with css before permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;me with css before&lt;/h6&gt;&lt;p&gt;&lt;img src=&quot;https://media.giphy.com/media/2rj8VysAig8QE/giphy.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;I want to share what I have learned so far by going through styling a
basic react application.&lt;/p&gt;&lt;p&gt;There’s some basic CSS concepts in this post that I was not aware of
before starting out with styled-components that I presume are assumed
in styling web pages.&lt;/p&gt;&lt;p&gt;Styling the body element of a site is assumed, so for when you are
starting out with a blank canvas there are some defaults for all
modern web browsers you add to your site, like leaving font size at
16px (or 1rem) or &lt;code&gt;box-sizing:&lt;/code&gt; &lt;code&gt;border-box;&lt;/code&gt; there’s some packages
out there to take care of this for you as well.&lt;/p&gt;&lt;h3 id=&quot;install-styled-components&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-styled-components&quot; aria-label=&quot;install styled components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install styled-components&lt;/h3&gt;&lt;p&gt;Ok let’s bootstrap the basic react application you get when using
&lt;a href=&quot;https://github.com/facebook/create-react-app#create-react-app-&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Create React App&lt;/a&gt; with &lt;a href=&quot;https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;npx&lt;/code&gt;&lt;/a&gt;, if you already have Create React App
installed globally then you can use the command without &lt;code&gt;npx&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-react-app style-with-styled-components
cd style-with-styled-components/
npm i styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now we have the basic app we can style, thankfully &lt;a href=&quot;https://github.com/gaearon&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dan&lt;/a&gt; has
kindly provided the starting styles for us so let’s begin my using
them with styled-components.&lt;/p&gt;&lt;p&gt;The way the CRA CSS is laid out, assumes that you will have a
corresponding CSS file for each component, which can help with
maintaining the CSS and lends to the React idea of having all your
files separated into their component parts.&lt;/p&gt;&lt;p&gt;We can start with the &lt;code&gt;App.js&lt;/code&gt; file and it’s accompanying &lt;code&gt;App.css&lt;/code&gt;
file. Let’s take a look at the &lt;code&gt;App.js&lt;/code&gt; first:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { Component } from &amp;#x27;react&amp;#x27;
import logo from &amp;#x27;./logo.svg&amp;#x27;
import &amp;#x27;./App.css&amp;#x27;
class App extends Component {
  render() {
    return (
      &amp;lt;div className=&amp;quot;App&amp;quot;&amp;gt;
        &amp;lt;header className=&amp;quot;App-header&amp;quot;&amp;gt;
          &amp;lt;img src={logo} className=&amp;quot;App-logo&amp;quot; alt=&amp;quot;logo&amp;quot; /&amp;gt;
          &amp;lt;h1 className=&amp;quot;App-title&amp;quot;&amp;gt;Welcome to React&amp;lt;/h1&amp;gt;
        &amp;lt;/header&amp;gt;
        &amp;lt;p className=&amp;quot;App-intro&amp;quot;&amp;gt;
          To get started, edit &amp;lt;code&amp;gt;src/App.js&amp;lt;/code&amp;gt; and save to
          reload.
        &amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }
}
export default App
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In styled-components we’d create components for each of these elements
that replace the aforementioned &lt;code&gt;className&lt;/code&gt;‘s. Ok we can start by
migrating our styles into components, let’s do one component first to
get an idea of where we’re going with this.&lt;/p&gt;&lt;p&gt;First, import &lt;code&gt;styled&lt;/code&gt; into the &lt;code&gt;App.js&lt;/code&gt; module:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import styled from &amp;#x27;styled-components&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let’s look at &lt;code&gt;&amp;lt;div className=&amp;quot;App&amp;quot;&amp;gt;&lt;/code&gt;, it’s the top level div for
this component and is what I like to call the wrapper for the
component. So let’s give it an imaginative name AppWrapper.&lt;/p&gt;&lt;p&gt;Referring to the App.css there is &lt;code&gt;text-align: center;&lt;/code&gt; which belongs
to this, so:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppWrapper = styled.div`
  text-align: center;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So here we have defined the &lt;code&gt;AppWrapper&lt;/code&gt; const as a &lt;code&gt;styled.div&lt;/code&gt;
followed by back ticks inside of the back ticks we can write any
regular CSS with the exact same CSS syntax you wold in a normal &lt;code&gt;.css&lt;/code&gt;
file.&lt;/p&gt;&lt;p&gt;Now that we have our &lt;code&gt;AppWrapper&lt;/code&gt; we can replace the top level div on
the &lt;code&gt;App.js&lt;/code&gt; component.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { Component } from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;
import logo from &amp;#x27;./logo.svg&amp;#x27;
import &amp;#x27;./App.css&amp;#x27;
class App extends Component {
  render() {
    return (
      &amp;lt;AppWrapper&amp;gt;
        &amp;lt;header className=&amp;quot;App-header&amp;quot;&amp;gt;
          &amp;lt;img src={logo} className=&amp;quot;App-logo&amp;quot; alt=&amp;quot;logo&amp;quot; /&amp;gt;
          &amp;lt;h1 className=&amp;quot;App-title&amp;quot;&amp;gt;Welcome to React&amp;lt;/h1&amp;gt;
        &amp;lt;/header&amp;gt;
        &amp;lt;p className=&amp;quot;App-intro&amp;quot;&amp;gt;
          To get started, edit &amp;lt;code&amp;gt;src/App.js&amp;lt;/code&amp;gt; and save to
          reload.
        &amp;lt;/p&amp;gt;
      &amp;lt;/AppWrapper&amp;gt;
    )
  }
}
export default App
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;styled-components-all-the-things&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#styled-components-all-the-things&quot; aria-label=&quot;styled components all the things permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;styled-components all the things&lt;/h3&gt;&lt;p&gt;So let’s do that for the remaining four CSS classes, and take a look,
I’ll define them underneath the &lt;code&gt;AppWrapper&lt;/code&gt; here:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const rotate360 = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`
const AppLogo = styled.img`
  animation: ${rotate360} infinite 120s linear;
  height: 80px;
`
const AppHeader = styled.div`
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
`
const AppTitle = styled.h1`
  font-size: 1.3em;
`
const AppIntro = styled.p`
  font-size: large;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So first off we’ve created a variable for the React svg &lt;a href=&quot;https://www.styled-components.com/docs/basics#animations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;animation&lt;/a&gt;,
you’ll need to import the &lt;code&gt;keyframes&lt;/code&gt; helper from styled-components
like so:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import styled, { keyframes } from &amp;#x27;styled-components&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;this can now be used throughout the &lt;code&gt;App.js&lt;/code&gt; component and we can add
an on &lt;code&gt;hover&lt;/code&gt; selector to any of our styled-components within this
module. Here we’re going to add it to the &lt;code&gt;AppLogo&lt;/code&gt; to keep the super
sweet rotating React logo.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppLogo = styled.img`
  animation: ${rotate360} infinite 120s linear;
  height: 80px;
  &amp;amp;:hover {
    animation: ${rotate360} infinite 1.5s linear;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, our app shouldn’t look any different as we haven’t added in our
styled-components to the app &lt;code&gt;render()&lt;/code&gt; method, so let’s do that now.&lt;/p&gt;&lt;p&gt;Let’s also change the intro text. You can add a wrapper for the
&lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; tags something like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const CodeWrapper = styled.code`
  font-size: 1.3rem;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But if you prefer you can nest selectors within the component, like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppIntro = styled.p`
  color: ${props =&amp;gt; props.theme.dark};
  font-size: large;
  code {
    font-size: 1.3rem;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s have a look at the &lt;code&gt;render()&lt;/code&gt; method now…&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;render() {
  return (
    &amp;lt;AppWrapper&amp;gt;
      &amp;lt;AppHeader&amp;gt;
        &amp;lt;AppLogo src={logo} alt=&amp;quot;logo&amp;quot; /&amp;gt;
        &amp;lt;AppTitle&amp;gt;Welcome to React&amp;lt;/AppTitle&amp;gt;
      &amp;lt;/AppHeader&amp;gt;
      &amp;lt;AppIntro&amp;gt;
        Bootstrapped with &amp;lt;code&amp;gt;create-react-app&amp;lt;/code&amp;gt;.
      &amp;lt;/AppIntro&amp;gt;
      &amp;lt;AppIntro&amp;gt;
        Components styled with &amp;lt;code&amp;gt;styled-components&amp;lt;/code&amp;gt;{&amp;#x27; &amp;#x27;}
        &amp;lt;EmojiWrapper aria-label=&amp;quot;nail polish&amp;quot;&amp;gt;&amp;lt;/EmojiWrapper&amp;gt;
      &amp;lt;/AppIntro&amp;gt;
    &amp;lt;/AppWrapper&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now all the classes originally used in &lt;code&gt;App.js&lt;/code&gt; have been replaced so
there’s no need for the &lt;code&gt;import &amp;#x27;./App.css&amp;#x27;&lt;/code&gt; mapping, remove that
aaaaand! Still no change!! Which is a good thing because at the moment
we’re swapping out the &lt;code&gt;.css&lt;/code&gt; files for styled-components.&lt;/p&gt;&lt;p&gt;Cool, we have now replaced all the css with styled-components, now we
can take a look at &lt;code&gt;injectGlobal&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Let’s take a look at how the &lt;code&gt;App.js&lt;/code&gt; file should look before we move
on:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { Component } from &amp;#x27;react&amp;#x27;
import styled, { keyframes } from &amp;#x27;styled-components&amp;#x27;
import logo from &amp;#x27;./logo.svg&amp;#x27;

const AppWrapper = styled.div`
  text-align: center;
`

const rotate360 = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`

const AppLogo = styled.img`
  animation: ${rotate360} infinite 120s linear;
  height: 80px;
  &amp;amp;:hover {
    animation: ${rotate360} infinite 1.5s linear;
  }
`

const AppHeader = styled.div`
  background-color: #222;
  height: 12rem;
  padding: 1rem;
  color: white;
`

const AppTitle = styled.h1`
  font-weight: 900;
`

const AppIntro = styled.p`
  font-size: large;
  code {
    font-size: 1.3rem;
  }
`

const EmojiWrapper = styled.span.attrs({
  role: &amp;#x27;img&amp;#x27;,
})``

class App extends Component {
  render() {
    return (
      &amp;lt;AppWrapper&amp;gt;
        &amp;lt;AppHeader&amp;gt;
          &amp;lt;AppLogo src={logo} alt=&amp;quot;logo&amp;quot; /&amp;gt;
          &amp;lt;AppTitle&amp;gt;Welcome to React&amp;lt;/AppTitle&amp;gt;
        &amp;lt;/AppHeader&amp;gt;
        &amp;lt;AppIntro&amp;gt;
          Bootstrapped with &amp;lt;code&amp;gt;create-react-app&amp;lt;/code&amp;gt;.
        &amp;lt;/AppIntro&amp;gt;
        &amp;lt;AppIntro&amp;gt;
          Components styled with &amp;lt;code&amp;gt;styled-components&amp;lt;/code&amp;gt;{&amp;#x27; &amp;#x27;}
          &amp;lt;EmojiWrapper aria-label=&amp;quot;nail polish&amp;quot; /&amp;gt;
        &amp;lt;/AppIntro&amp;gt;
      &amp;lt;/AppWrapper&amp;gt;
    )
  }
}

export default App
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;style-the-body-with-injectglobal&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#style-the-body-with-injectglobal&quot; aria-label=&quot;style the body with injectglobal permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Style the body with injectGlobal&lt;/h3&gt;&lt;p&gt;For styling the body of our react app we currently have the
&lt;code&gt;index.css&lt;/code&gt; file that is being imported into the mounting point of our
app in the &lt;code&gt;index.js&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;To style the body we can use &lt;a href=&quot;https://www.styled-components.com/docs/api#injectglobal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;injectGlobal&lt;/code&gt;&lt;/a&gt; from styled-components
which adds the styles directly to the stylesheet.&lt;/p&gt;&lt;p&gt;To do this you bring in the &lt;code&gt;injectGolabl&lt;/code&gt; named export from
styled-components and add your styles between the back ticks.&lt;/p&gt;&lt;p&gt;The current &lt;code&gt;index.css&lt;/code&gt; looks like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;body {
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s add a &lt;code&gt;theme&lt;/code&gt; folder in the &lt;code&gt;src&lt;/code&gt; directory and add a
&lt;code&gt;globalStyle.js&lt;/code&gt; file where we can keep all our styles we want to use
throughout the app, keeping the styles on one place will make changes
simpler.&lt;/p&gt;&lt;p&gt;In &lt;code&gt;src/theme/globalStyle.js&lt;/code&gt; we’ll need to import the &lt;code&gt;injectGlobal&lt;/code&gt;
named export from styled-components and add the &lt;code&gt;index.css&lt;/code&gt; styles
into it:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { injectGlobal } from &amp;#x27;styled-components&amp;#x27;

injectGlobal`
  body {
    padding: 0;
    margin: 0;
    font-family: sans-serif;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now we’re adding the body style to the stylesheet directly so
there is no need for the &lt;code&gt;index.css&lt;/code&gt; file mapping that is in
&lt;code&gt;index.js&lt;/code&gt; it should look like this now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27; import ReactDOM from &amp;#x27;react-dom&amp;#x27;

import App from &amp;#x27;./App&amp;#x27;

import registerServiceWorker from &amp;#x27;./registerServiceWorker&amp;#x27;

ReactDOM.render(&amp;lt;App /&amp;gt;, document.getElementById(&amp;#x27;root&amp;#x27;))

registerServiceWorker()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We should still have our nice &lt;code&gt;sans-serif&lt;/code&gt; font going on, but let’s
add in some nice Roboto for the body and Montserrat for the heading in
our &lt;code&gt;globalStyle.js&lt;/code&gt; module. We can import Google fonts with an
&lt;code&gt;@import&lt;/code&gt; in &lt;code&gt;injectGlobal&lt;/code&gt; and apply Roboto to the body:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;injectGlobal`
  @import url(‘https://fonts.googleapis.com/css?family=Montserrat|Roboto&amp;#x27;);
 
  body {
    padding: 0;
    margin: 0;
    font-family: Roboto, sans-serif;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool now we can add our imported font for or app header, and there’s
the option if we want all our &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;’s to use the same font we can add
that to the injectGlobal in our &lt;code&gt;globalStyle.js&lt;/code&gt; module.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;injectGlobal`
  @import url(‘https://fonts.googleapis.com/css?family=Montserrat:400,900|Roboto&amp;#x27;);
  body {
    padding: 0;
    margin: 0;
    font-family: Roboto, sans-serif;
  }
  h1 {
    font-family: Montserrat;
  }
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we can adjust the weight on the &lt;code&gt;AppTitle&lt;/code&gt; component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppTitle = styled.h1`
  font-weight: 900;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To add the additional styles for fonts like Montserrat and Roboto you
can specify them in the &lt;code&gt;@import url()&lt;/code&gt; you’ll notice that Montserrat
has &lt;code&gt;:400,900&lt;/code&gt; after it that is specifying the styles regular (400)
and black (900), you can import as many as you like from Google fonts
(CDN) but the more you import the longer it will take to load them, if
you have a lot of fonts and styles you want in your app then consider
adding them to a folder in the project, like:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import Montserrat from &amp;#x27;./fonts/Montserrat-Regular.ttf&amp;#x27;

injectGlobal`@font-face { font-family: Montserrat; src: url(${Montserrat}); }`
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;theming&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#theming&quot; aria-label=&quot;theming permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Theming&lt;/h3&gt;&lt;p&gt;Themes are often used to change the look and feel of a wide range of
things at once. For example, you may have a night and day mode like in
Twitter. You can create your own themes in styled-components too.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://thepracticaldev.s3.amazonaws.com/i/gwn8czgagns1n1545zgn.png&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;use-the-styled-components-themeprovider&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-the-styled-components-themeprovider&quot; aria-label=&quot;use the styled components themeprovider permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use the styled-components ThemeProvider&lt;/h3&gt;&lt;p&gt;Now say we want to have several components in our app that use a CSS
colour property &lt;code&gt;color: #6e27c5&lt;/code&gt; instead of hard coding it through the
app for every component that uses it we can use the styled-components
&lt;code&gt;ThemeProvider&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;For this we will need to import the &lt;code&gt;ThemeProvider&lt;/code&gt; named export from
styled-components, then define a &lt;code&gt;theme&lt;/code&gt; object where our colour is
going to live:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const theme = {
  primary: &amp;#x27;#6e27c5&amp;#x27;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s add the newly created &lt;code&gt;theme&lt;/code&gt; to the &lt;code&gt;globalStyle&lt;/code&gt; module we
created previously.&lt;/p&gt;&lt;p&gt;To make the theme object available throughout the app component we’ll
wrap our app component in the &lt;code&gt;ThemeProvider&lt;/code&gt; and import our awesome
theme for use in the &lt;code&gt;ThemeProvider&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { Component } from &amp;#x27;react&amp;#x27;
import styled, { keyframes, ThemeProvider } from &amp;#x27;styled-components&amp;#x27;
import logo from &amp;#x27;./logo.svg&amp;#x27;
import { theme } from &amp;#x27;./theme/globalStyle&amp;#x27;

// our styled-components

class App extends Component {
  render() {
    return (
      &amp;lt;ThemeProvider theme={theme}&amp;gt;
        {/* all children can access the theme object */}
      &amp;lt;/ThemeProvider&amp;gt;
    )
  }
}
export default App
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the &lt;code&gt;theme&lt;/code&gt; properties can be used as props in our
styled-components, let’s change the &lt;code&gt;background-color:&lt;/code&gt; in the
&lt;code&gt;AppHeader&lt;/code&gt; component, whilst we’re at it let’s add a &lt;code&gt;dark: #222&lt;/code&gt;
property to our &lt;code&gt;theme&lt;/code&gt; object and use that for the &lt;code&gt;color&lt;/code&gt; property:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const AppHeader = styled.div`
  height: 12rem;
  padding: 1rem;
  color: ${props =&amp;gt; props.theme.dark};
  background-color: ${props =&amp;gt; props.theme.primary};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can change our app theme globally&lt;/p&gt;&lt;h3 id=&quot;ok-cool-can-you-change-theme&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#ok-cool-can-you-change-theme&quot; aria-label=&quot;ok cool can you change theme permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ok cool, can you change theme?&lt;/h3&gt;&lt;p&gt;This is what I was thinking and it turns out you can, there’s a great
&lt;a href=&quot;https://stackoverflow.com/a/42899979/1138354&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stack Overflow answer&lt;/a&gt; from &lt;a href=&quot;https://twitter.com/mxstbr&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Max&lt;/a&gt; on it.&lt;/p&gt;&lt;p&gt;It got me thinking if you can switch between themes rather than define
them for different sections like in the SO answer.&lt;/p&gt;&lt;p&gt;I started off by defining two themes (with imaginative names) in the
&lt;code&gt;globalStyle.js&lt;/code&gt; module:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const theme1 = {
  primary: &amp;#x27;#ff0198&amp;#x27;,
  secondary: &amp;#x27;#01c1d6&amp;#x27;,
  danger: &amp;#x27;#eb238e&amp;#x27;,
  light: &amp;#x27;#f4f4f4&amp;#x27;,
  dark: &amp;#x27;#222&amp;#x27;,
}

export const theme2 = {
  primary: &amp;#x27;#6e27c5&amp;#x27;,
  secondary: &amp;#x27;#ffb617&amp;#x27;,
  danger: &amp;#x27;#f16623&amp;#x27;,
  light: &amp;#x27;#f4f4f4&amp;#x27;,
  dark: &amp;#x27;#222&amp;#x27;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we need a way to switch between the two &lt;code&gt;theme&lt;/code&gt; objects, let’s use
a select box for them, let’s create a components folder and in there
make a &lt;code&gt;ThemeSelect.js&lt;/code&gt; component, we can worry about refactoring the
&lt;code&gt;App.js&lt;/code&gt; component when I’m not here :&lt;/p&gt;&lt;h4 id=&quot;themeselectjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#themeselectjs&quot; aria-label=&quot;themeselectjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ThemeSelect.js&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &amp;#x27;react&amp;#x27;
import styled from &amp;#x27;styled-components&amp;#x27;

const Select = styled.select`
  margin: 2rem 0.5rem;
  padding: 0rem 0.5rem;
  font-family: Roboto;
  font-size: 1rem;
  border: 1px solid ${props =&amp;gt; props.theme.light};
  box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
  background: ${props =&amp;gt; props.theme.light};
  border-radius: 2px;
`

export const SelectOpt = styled.option`
  font-family: Roboto;
  font-size: 1rem;
`

class ThemeSelect extends React.Component {
  render() {
    return (
      &amp;lt;div&amp;gt;
        &amp;lt;Select onChange={e =&amp;gt; this.props.handleThemeChange(e)}&amp;gt;
          &amp;lt;SelectOpt value=&amp;quot;theme1&amp;quot;&amp;gt;Theme 1&amp;lt;/SelectOpt&amp;gt;
          &amp;lt;SelectOpt value=&amp;quot;theme2&amp;quot;&amp;gt;Theme 2&amp;lt;/SelectOpt&amp;gt;
        &amp;lt;/Select&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }
}

export default ThemeSelect
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You’ve probably noticed the
&lt;code&gt;onChange={e =&amp;gt; this.props.handleThemeChange(e)&lt;/code&gt; event, we’re going to
add that method to the &lt;code&gt;App.js&lt;/code&gt; component along with some state to
manage what theme is selected.&lt;/p&gt;&lt;h4 id=&quot;appjs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#appjs&quot; aria-label=&quot;appjs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;App.js&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { Component } from &amp;#x27;react&amp;#x27;
import styled, { keyframes, ThemeProvider } from &amp;#x27;styled-components&amp;#x27;

import logo from &amp;#x27;./logo.svg&amp;#x27;

import { theme1, theme2 } from &amp;#x27;./theme/globalStyle&amp;#x27;
import ThemeSelect from &amp;#x27;./components/ThemeSelect&amp;#x27;

// our lovely styled-components here

class App extends Component {
  state = {
    theme: theme1,
  }
  handleThemeChange = e =&amp;gt; {
    let theme = e.target.value
    theme === &amp;#x27;theme1&amp;#x27; ? (theme = theme1) : (theme = theme2)
    this.setState({ theme })
  }
  render() {
    return (
      &amp;lt;ThemeProvider theme={this.state.theme}&amp;gt;
        &amp;lt;AppWrapper&amp;gt;
          &amp;lt;AppHeader&amp;gt;
            &amp;lt;AppLogo src={logo} alt=&amp;quot;logo&amp;quot; /&amp;gt;
            &amp;lt;AppTitle&amp;gt;Welcome to React&amp;lt;/AppTitle&amp;gt;
          &amp;lt;/AppHeader&amp;gt;
          &amp;lt;AppIntro&amp;gt;
            Bootstrapped with &amp;lt;code&amp;gt;create-react-app&amp;lt;/code&amp;gt;.
          &amp;lt;/AppIntro&amp;gt;
          &amp;lt;AppIntro&amp;gt;
            Components styled with &amp;lt;code&amp;gt;styled-components&amp;lt;/code&amp;gt;{&amp;#x27; &amp;#x27;}
            &amp;lt;EmojiWrapper aria-label=&amp;quot;nail polish&amp;quot; /&amp;gt;
          &amp;lt;/AppIntro&amp;gt;
          &amp;lt;ThemeSelect handleThemeChange={this.handleThemeChange} /&amp;gt;
        &amp;lt;/AppWrapper&amp;gt;
      &amp;lt;/ThemeProvider&amp;gt;
    )
  }
}

export default App
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To summarise what we have done with &lt;code&gt;App.js&lt;/code&gt; here is, add some state
to default to theme1 where the two themes are imported as named
exports of the &lt;code&gt;globalStyle.js&lt;/code&gt; module.&lt;/p&gt;&lt;p&gt;Add a method to handle the change of the &lt;code&gt;ThemeSelect.js&lt;/code&gt; component
&lt;code&gt;handleThemeChange&lt;/code&gt; this is where we can switch between the two
&lt;code&gt;theme&lt;/code&gt; objects.&lt;/p&gt;&lt;p&gt;Let’s try it out, we should be able to switch between the two themes
we’ve defined now.&lt;/p&gt;&lt;h3 id=&quot;extending-styled-components&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#extending-styled-components&quot; aria-label=&quot;extending styled components permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Extending styled-components&lt;/h3&gt;&lt;p&gt;So far our app hasn’t got many styled-components that are similar but
what if we were to add some buttons…&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export const Button = styled.button`
  font-size: 1rem;
  border-radius: 5px;
  padding: 0.25rem 1rem;
  margin: 0 1rem;
  background: transparent;
  color: ${props =&amp;gt; props.theme.primary};
  border: 2px solid ${props =&amp;gt; props.theme.primary};
  ${props =&amp;gt;
    props.primary &amp;amp;&amp;amp;
    css`
      background: ${props =&amp;gt; props.theme.primary};
      color: white;
    `};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here I’ve added a &lt;code&gt;Button&lt;/code&gt; component to the &lt;code&gt;globalStyle.js&lt;/code&gt; for us to
use in the &lt;code&gt;App.js&lt;/code&gt; component. For the sake of convenience we’re going
to add it here, you may find if you have a lot of similar components
that you are reusing throughout your app that it may be a good idea to
add them all to a &lt;code&gt;components&lt;/code&gt; folder.&lt;/p&gt;&lt;p&gt;We can import the &lt;code&gt;Button&lt;/code&gt; as you would any other component and use it
in the module, as we’re extending it this means we only need to apply
the specific styles we want for that button. But first in the &lt;code&gt;App.js&lt;/code&gt;
component we can specify a normal and a primary button:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;button&amp;gt;Normal Button&amp;lt;/button&amp;gt; &amp;lt;button primary&amp;gt;Primary Button&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to specify another button with the same css as the imported button
we can extend it, like in this example we’ll make the button take up
40% of the screen width and make the corners more rounded:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const BigButt = Button.extend`
  height: 3rem;
  font-size: 2rem;
  width: 40vw;
  border-radius: 30px;
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s also apply the theme for an underline on &lt;code&gt;create-react-app&lt;/code&gt; and
&lt;code&gt;styled-components&lt;/code&gt; by adding in an &lt;code&gt;Underline&lt;/code&gt; styled-component:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Underline = styled.span`
  border-bottom: 4px solid ${props =&amp;gt; props.theme.secondary};
`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can switch the theme and have it applied to our components
using the theme, pretty neat, right?&lt;/p&gt;&lt;p&gt;I have put all of the examples we have gone over here in a working
example for you to play around with the theming and styled-components,
enjoy.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://codesandbox.io/s/x26q7l9vyq?from-embed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://codesandbox.io/s/x26q7l9vyq?from-embed&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;want-to-know-more&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#want-to-know-more&quot; aria-label=&quot;want to know more permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Want to know more?&lt;/h3&gt;&lt;p&gt;A great resource for getting started with styled-components which
really helped me is &lt;a href=&quot;https://twitter.com/simonswiss&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Simon Vrachliotis&lt;/a&gt;’s &lt;a href=&quot;https://egghead.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;egghead.io&lt;/a&gt;
styled-components &lt;a href=&quot;https://egghead.io/playlists/styled-components-4169206d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;playlist&lt;/a&gt; which is a great foundation for starting
out with styled-components 👌 the first lesson is for pro members but
the rest are currently available to watch for free.&lt;/p&gt;&lt;p&gt;There’s also the &lt;a href=&quot;https://spectrum.chat/?t=54887141-57a9-4386-807c-ed950c4d5132&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;spectrum.chat&lt;/a&gt; community and of course &lt;a href=&quot;https://stackoverflow.com/questions/tagged/styled-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Stack
Overflow&lt;/a&gt;.&lt;/p&gt;&lt;h3 id=&quot;thanks-for-reading-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thanks-for-reading-&quot; aria-label=&quot;thanks for reading  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks for reading 🙏&lt;/h3&gt;&lt;p&gt;If there is anything I have missed, or if you have a better way to do
something then please let me know.&lt;/p&gt;&lt;p&gt;Find me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to make time for 100 days of code]]></title><description><![CDATA[Life moves pretty fast. If you don’t stop and look around once in a
while, you could miss it. — Ferris Bueller. I'm going to go over steps I…]]></description><link>https://scottspence.com/2018/02/27/make-time-for-100doc/</link><guid isPermaLink="false">https://scottspence.com/2018/02/27/make-time-for-100doc/</guid><pubDate>Tue, 27 Feb 2018 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p&gt;Life moves pretty fast. If you don’t stop and look around once in a
while, you could miss it. — Ferris Bueller.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I’m going to go over steps I have taken the help me with learning to
code (&lt;a href=&quot;https://scottspence.me/#hi-im-scott&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;again&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;But fist, &lt;strong&gt;preamble:&lt;/strong&gt;&lt;/p&gt;&lt;h3 id=&quot;lets-pick-up-a-new-skill-get-a-new-job-all-in-a-few-months&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lets-pick-up-a-new-skill-get-a-new-job-all-in-a-few-months&quot; aria-label=&quot;lets pick up a new skill get a new job all in a few months permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s pick up a new skill, get a new job, all in a few months.&lt;/h3&gt;&lt;p&gt;That was the overriding message I got when I started out in
freeCodeCamp it’s a fun and exciting time and you will see a lot of
articles along the lines of ‘hey look at me I was a school teacher
before, now I’m earning \$100k as a engineer for x startup’&lt;/p&gt;&lt;p&gt;I don’t mean this in a mean spirited or passive aggressive way, but if
you’re starting out in web development and you surround yourself with
other people that want to achieve, they will, you know, achieve! 🙃&lt;/p&gt;&lt;p&gt;There’s a bit of expectation vs reality here, if you are the kind of
person that can memorize the masses of information out there relating
to your chosen field then you’re onto a winner, as for myself it’s
repetition, repetition, repetition until it becomes habit, there’s a
lot to be said about habits.&lt;/p&gt;&lt;p&gt;Forming habits takes time though, on &lt;a href=&quot;https://github.com/spences10/100-days-of-code/commit/7dbefb608862401d4cb9e6ed11f539b44bedcdae&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;20161230&lt;/a&gt; was when I decided to
take part in the &lt;span&gt;#100DaysOfCode&lt;/span&gt; challenge I couldn’t give
you an idea of how I felt then but reviewing the log entries I seemed
pretty confused and a little frustrated with it all.&lt;/p&gt;&lt;p&gt;That’s not to say it hasn’t been an enriching and life changing
experience for me.&lt;/p&gt;&lt;p&gt;Along the way I have met some truly awesome, inspiring people, happy
to help with any issues or problems you may have. The support I found
not just in the &lt;span&gt;#100DaysOfCode&lt;/span&gt; community but the web dev
community as a whole is truly amazing.&lt;/p&gt;&lt;h3 id=&quot;patience&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#patience&quot; aria-label=&quot;patience permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Patience&lt;/h3&gt;&lt;p&gt;Patience is needed, instant gratification doesn’t work here, well at
least not for me. This will soon come to light if you start to compare
yourself to how other people (your cohorts) are progressing. You may
start to wonder why you are not progressing as fast as they appear to
be progressing, this will probably add to any anxiety you may have
about if you can do this thing or not. Do not concern yourself with
this and instead use that energy to focus on what you need to do,
code.&lt;/p&gt;&lt;p&gt;Different people progress at different rates and learn in different
ways.&lt;/p&gt;&lt;p&gt;Myself personally, I have found that I’m a visual learner (I’ve known
this for a long time actually) where to be able to ‘join up’
concepts/paradigms I need to see them in action. This is why I will
always gush about courses by Wes Bos or Kent C. Dodds as they (among
many others) are great at explaining complex subject simply and
visually with their awesome &lt;a href=&quot;https://egghead.io/instructors/kentcdodds&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;content on egghead.io&lt;/a&gt; and wesbos.com.&lt;/p&gt;&lt;p&gt;YMMV however, so, find what works for you, find it and stick with it.&lt;/p&gt;&lt;p&gt;I have discovered recently that splitting my time between projects
wasn’t really helping me so I decided to work on one particular
project each time I sat down to code.&lt;/p&gt;&lt;p&gt;The first time I did this I was struggling for hours with little to
nothing show for it, it felt futile and I was getting anxious about
not moving on, it was at this point when I would usually switch
context and work on something else - I found though that pushing that
little bit more was all I needed.&lt;/p&gt;&lt;p&gt;This was such psychological win for me, and gave me the confidence to
do more.&lt;/p&gt;&lt;p&gt;This has paid dividends as I now have 6+ demos of projects I have made
on &lt;a href=&quot;https://scottspence.me/#portfolio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my portfolio&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;busy-work&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#busy-work&quot; aria-label=&quot;busy work permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Busy work&lt;/h3&gt;&lt;p&gt;I’s easy to get distracted, things like apps for slack and email and
Twitter should not be opened, this will eat up your time. You have a
set amount of time to get something done, this will come to light when
you have finished reading your Twitter updates and Slack messages only
to realise you have fifteen minutes left to complete the task you set
out to do.&lt;/p&gt;&lt;p&gt;Soon into starting &lt;span&gt;#100DaysOfCode&lt;/span&gt; I noticed this, what I
did was turn off all my phone notifications - if you need to check
something then check it, don’t let your phone dictate where your
attention needs to be directed.&lt;/p&gt;&lt;p&gt;I turned off all browser notifications for Slack and Gmail. My phone
is left in another room on do not disturb whilst I work. Whilst in do
not disturb mode my phone will not make a noise unless someone on my
stared contacts list calls me. I pick up the phone in the afternoon to
check missed calls listen to voice mails and return any calls if
needed.&lt;/p&gt;&lt;h3 id=&quot;make-time&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#make-time&quot; aria-label=&quot;make time permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make time&lt;/h3&gt;&lt;p&gt;Saying that you don’t have the time to do 1-2 hours of coding a day
isn’t going to help, it’s though, but it’s not about having the time
it’s about making the time to do this. If it’s important to you, you
will make time. You’re the only one that can make these things happen.&lt;/p&gt;&lt;h3 id=&quot;balance&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#balance&quot; aria-label=&quot;balance permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Balance&lt;/h3&gt;&lt;p&gt;This weight gain is a mixture of illness at the start of 2017 and bad
diet choices thereafter. In the past I consciously opted for ‘healthy’
foods spending that little extra time deciding what to eat.&lt;/p&gt;&lt;p&gt;Whilst being ill at the start of 2017 I developed a bit of an
addiction to cereals (granola) 😬 it was quick and easy and I got a
quick boost from it.&lt;/p&gt;&lt;p&gt;Quick and easy soon became the norm after that 🙃 I have identified
this now and am making an effort to reduce this whilst also making
time for my development.&lt;/p&gt;&lt;p&gt;It’s a balance though 😀&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/349fdf64fd8046a361b7bcf639250909/b4098/weight-gain.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:74.37499999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;299\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20299\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M25%20141v129h356V13H25v128m91%20135c-1%202%200%204%201%202%201-1%201-1%202%201%203%202%202%203-1%203l-3-1-1-1-1%201h-4l-1-1v3c1%202%205%202%205%200l1%201c1%202%203%203%203%201h1l5%201c4%200%204%200%204-2v-2l1%202c1%202%202%203%202%201l-2-4c-2-2-2-2-3%200-1%201-1%201-2-1v-3c1%201%201%201%201-1s-2-3-4-1h-1c0-3-2-2-3%201m49-2l-1%204h1c1-1%202-1%203%201h2l1-1v3h-1l-1%202-1-1c-1-3-3-3-3%200v4l6-1c4%200%206%201%207%202%201%202%205-1%205-3s0-2%201%200c1%203%209%202%209-1s-5-3-5%200h-1c0-3-6-3-6%200-1%202-1%202-1%200s-1-2-3-2c-4%201-5-1-3-3s0-4-3-4h-6m70%200v3l-1%201c1%201%207%201%207-1v-1l1%203c0%202-1%202-6%202l-6%202h-1c0-2-1-2-3-2s-2%201-2%203c0%201%200%202%209%202%2010%200%2013-1%2011-2s-2-1%200-4c4-5%202-7-5-5-3%200-3%200-2-1v-1l-2%201m-102%208v5c-1%203-5%204-6%202h-3v-2c-2%201-3%206-1%206l1-1h1l5%201c5%200%205%200%205-2%200-4%202-5%207-5%204-1%205-1%205-3%200-1-1-2-7-2l-7%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/349fdf64fd8046a361b7bcf639250909/60a22/weight-gain.webp 160w,/static/349fdf64fd8046a361b7bcf639250909/4c812/weight-gain.webp 320w,/static/349fdf64fd8046a361b7bcf639250909/0ba47/weight-gain.webp 640w,/static/349fdf64fd8046a361b7bcf639250909/79303/weight-gain.webp 816w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/349fdf64fd8046a361b7bcf639250909/69538/weight-gain.png 160w,/static/349fdf64fd8046a361b7bcf639250909/72799/weight-gain.png 320w,/static/349fdf64fd8046a361b7bcf639250909/6af66/weight-gain.png 640w,/static/349fdf64fd8046a361b7bcf639250909/b4098/weight-gain.png 816w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/349fdf64fd8046a361b7bcf639250909/6af66/weight-gain.png&quot; alt=&quot;compare&quot; title=&quot;compare&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h3 id=&quot;tools&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#tools&quot; aria-label=&quot;tools permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tools&lt;/h3&gt;&lt;p&gt;Some tools I use to help me ‘get on’ with what I’ve set out to do, a
while back I started using &lt;strong&gt;Todoist&lt;/strong&gt;, this is great for when you’re
scrolling through your Twitter feed and find a link to a really neat
looking tutorial or post you want to read but don’t want to go down
the rabbit hole of working out where to document it, I will add it to
Todoist and come back to it when I get the capacity to work on it.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;WakaTime&lt;/strong&gt; is a great tool for quantifying your coding, pretty handy
when doing &lt;span&gt;#100DaysOfCode&lt;/span&gt;, you get that instant feedback
on how you’re doing for the day.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/8581ce35405d8dd3124ca0fdb229c5f0/75b1f/wakatime-stats.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:33.75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;134\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20134\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M2%2016v27l1%2026h193V16l-97-1-97%201m201%2026v27h193V15H203v27m30-4l-2%205-2%203v1l2%204%203%205%201%202%206-6%206-6-6-6-7-5-1%203M2%20104l1%2027h193V77H2v27m201%200v27h193V77H203v27m94-15c0%206%201%208%205%208s10%205%2011%2010c0%203%200%203%205%203%204%200%204%200%204-3%200-6-6-14-12-17-5-2-13-3-13-1m-3%201h-1c-3%200-3%200-2%201s1%201-1%201h-1v1h-2c-2%200-4%203-3%204l-1%201v1h-1v1c0%202%200%202-1%201s-1-1-1%202v1c-1-2-1-2-1%200-2%205-1%205%203%205s4-1%204-6h1l1-3h1l1-1v-1l3-1c-1-1-1-1%200%200%203%200%204-1%203-5%200-2-1-3-2-3v1\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/8581ce35405d8dd3124ca0fdb229c5f0/60a22/wakatime-stats.webp 160w,/static/8581ce35405d8dd3124ca0fdb229c5f0/4c812/wakatime-stats.webp 320w,/static/8581ce35405d8dd3124ca0fdb229c5f0/0ba47/wakatime-stats.webp 640w,/static/8581ce35405d8dd3124ca0fdb229c5f0/e46b2/wakatime-stats.webp 960w,/static/8581ce35405d8dd3124ca0fdb229c5f0/af3f0/wakatime-stats.webp 1280w,/static/8581ce35405d8dd3124ca0fdb229c5f0/f6ed9/wakatime-stats.webp 1699w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/8581ce35405d8dd3124ca0fdb229c5f0/69538/wakatime-stats.png 160w,/static/8581ce35405d8dd3124ca0fdb229c5f0/72799/wakatime-stats.png 320w,/static/8581ce35405d8dd3124ca0fdb229c5f0/6af66/wakatime-stats.png 640w,/static/8581ce35405d8dd3124ca0fdb229c5f0/d9199/wakatime-stats.png 960w,/static/8581ce35405d8dd3124ca0fdb229c5f0/21b4d/wakatime-stats.png 1280w,/static/8581ce35405d8dd3124ca0fdb229c5f0/75b1f/wakatime-stats.png 1699w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/8581ce35405d8dd3124ca0fdb229c5f0/6af66/wakatime-stats.png&quot; alt=&quot;compare&quot; title=&quot;compare&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;RescueTime&lt;/strong&gt;, is handy for helping you identify your productivity
black holes and give you a nice breakdown of where your time is spent
on your computer and mobile.&lt;/p&gt;&lt;h3 id=&quot;life-hacks&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#life-hacks&quot; aria-label=&quot;life hacks permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Life hacks&lt;/h3&gt;&lt;p&gt;They just used to be called handy tips, now we need to call them hacks
so we can think they’re cheating the system. In reality it’s some
helpful rules to aid you if you need to find the extra time.&lt;/p&gt;&lt;p&gt;Get up early, I’ve taken to getting up an hour earlier than I used to
to squeeze an hour and a half out of the morning, I have a MI band
that I have set to vibrate to wake me at that time so I do not disturb
my wife.&lt;/p&gt;&lt;p&gt;Go to bed early, sleep is important kids, anyone that says otherwise
obviously doesn’t get enough sleep 🙃&lt;/p&gt;&lt;p&gt;Have a mobile phone? Download podcasts, download video tutorials and
try to carve a bit of time out of your day to consume these, on your
way to work on the train on your lunch break. All great ways to fill
‘empty time’. Whilst you’re out running or at the gym, great times to
listen to podcasts.&lt;/p&gt;&lt;h3 id=&quot;good-luck-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#good-luck-&quot; aria-label=&quot;good luck  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Good luck 👍&lt;/h3&gt;&lt;p&gt;When I finished my last (VBA) contract in October I used that time to
fully immerse myself in web development.&lt;/p&gt;&lt;p&gt;At the time (which was good timing actually) I started a build to
learn project with two other remote developers, one in Egypt and one
in Serbia. We were all participating in the &lt;a href=&quot;https://medium.com/chingu&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chingu&lt;/a&gt; Voyage, this has
been a real eye opener for me and has given me the confidence to get
all &lt;a href=&quot;https://scottspence.me/#portfolio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my portfolio&lt;/a&gt; projects ready for potential employers to view.&lt;/p&gt;&lt;p&gt;Whilst taking part in the b2l Chingu project I got to treat this time
as a full time job which my WakaTime stats will attest. This was one
of the triggers for me that I should start applying for jobs as a
junior dev.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Windows Subsystem Linux setup]]></title><description><![CDATA[I'm a Windows user, I have been a Linux user as well but I have found
that Windows is a bit less  neckbeardy  for me, both
have their pros…]]></description><link>https://scottspence.com/2018/01/13/wsl-bootstrap/</link><guid isPermaLink="false">https://scottspence.com/2018/01/13/wsl-bootstrap/</guid><pubDate>Sat, 13 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m a Windows user, I have been a Linux user as well but I have found
that Windows is a bit less &lt;a href=&quot;http://theoatmeal.com/blog/fix_computer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;neckbeardy&lt;/a&gt; for me, both
have their pros and cons. One of the big cons with Windows for me was
when I started learning web development.&lt;/p&gt;&lt;p&gt;That was until Windows Subsystem Linux came along 🙏&lt;/p&gt;&lt;p&gt;I love it, you can have a bash shell in Windows and run all your node
apps through it too and with the Windows 10 Fall Creators Update WSL
is really straightforward to set up.&lt;/p&gt;&lt;p&gt;Quick backstory on why I’m posting this: I nuked my laptop the other
day as I was having issues with bash on Windows. Related partly to
using &lt;a href=&quot;https://github.com/Microsoft/WSL/issues/776&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;nvm&lt;/a&gt; with WSL and generally getting frustrated with
how my computer was performing. I realise now I over reacted.&lt;/p&gt;&lt;p&gt;So I have had to set up my development environment again from scratch,
luckily for me I keep all my settings and config information in a
GitHub &lt;a href=&quot;https://github.com/spences10/settings&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;repo&lt;/a&gt; in the event of me getting a new computer
or to recover from a catastrophic event [like a nuked computer].&lt;/p&gt;&lt;p&gt;Here’s how I set up &lt;em&gt;my&lt;/em&gt; Windows Subsystem Linux for my development
environment.&lt;/p&gt;&lt;p&gt;This is my opinionated view on my specif setup and usage of WSL and
this is my step by step guide for the next time I have to spin up a
development environment from scratch on Windows.&lt;/p&gt;&lt;p&gt;So, after installing &lt;a href=&quot;https://www.microsoft.com/store/productId/9NBLGGH4MSV6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WSL&lt;/a&gt; from the Microsoft Store and
adding your default user, fist thing is to update and upgrade all the
things.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt update
sudo apt -y upgrade
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you’ve not used any Linux distributions before the &lt;code&gt;-y&lt;/code&gt; in the
upgrade statement is to default the answer to yes for any prompts that
are displayed in the terminal. You might not want to do this, as there
may be some programs you don’t want to update but I do.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/d9fdf06ee6eadf39561e9293149c669e/6a6e9/upgrade-yes.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:26.875%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;108\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20108\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%204c0%204%200%205%202%204%202%200%202%200%202%202s0%203-2%203c-1-1-2%200-2%201l2%202%202%202c0%201%200%202-1%201v1l-1%201c-2-1-2%200-2%201l2%202c1%200%202%200%202%202l-1%202c-2-1-3%200-3%203l1%202h1l1%202c1%201%200%201-1%201l-2-1v18c0%2016%200%2017%202%2017l2%201H2c-2%200-2%200-2%203l1%204%203%201c5%201%209%201%2010-1%202-1%202-1%202%201%200%203-2%205-3%203H2l-2%204c0%202%200%202%201%201%201-2%201-2%202-1v4c-2%200-3%200-3%202l1%201c1%200%202%201%201%202%200%202%200%202%201%201%201-2%204-3%203%200h2l-2%202c-6-1-6%200-6%205v5h401V0H278a894%20894%200%2000-119%204h-11c-1-1-2%200-3%201-3%202-4%203-5%200h-1c-2%201-7%200-7-2h3c0-2%2010-2%2013-1h5c1-2-1-2-21-2l-23%201%202%201%202%201h-2v1l-6%201c-6%200-7%200-7-2l1-2%201%201h1l2%201h1l1-2h2c1-1-1-1-6-1-8%200-8%201-8%203l-1%202-1-3c0-2-1-2-6-2-4%200-6%200-5%201h1l1%202-1%202-1-1h-7c0%202-2%201-2-1V1l1%201h3l2-1c1-1-1-1-5-1-6%200-7%200-6%202h-2v3l-1-2c0-2%200-3-1-2l-1%201-1%201-1-1V0c-1%200-2%201-1%202l-1%203c-1%200-2-1-2-3l-2-2c-2%200-3%200-2%201l-2%203c-2%201-2%201-3-1%200-2%200-2-2%200-1%201-1%201-1-1V0l-1%203v3l-1-3c-1-3-1-3-3-2v2l-1%201c-1%201-1%200-1-1l1-2c1-1%200-1-1-1l-2%202-1%201-1-1V0l-3%203%201%201c1%201%200%201-3%201-3-1-4%200-5%201-1%202-2-1-2-4%201-2%200-2-10-2H0v4m37%2013c-2%202-1%205%201%203h5c0%202%202%203%203%201h2l2-1h1l1-1h1l5%201h3l1-1h3l1%201h1c2%201%202%201%202-1s-1-2-6-2h-6c-2%201-18%201-18-1%200-1-1-1-2%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/d9fdf06ee6eadf39561e9293149c669e/60a22/upgrade-yes.webp 160w,/static/d9fdf06ee6eadf39561e9293149c669e/4c812/upgrade-yes.webp 320w,/static/d9fdf06ee6eadf39561e9293149c669e/0ba47/upgrade-yes.webp 640w,/static/d9fdf06ee6eadf39561e9293149c669e/40616/upgrade-yes.webp 826w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/d9fdf06ee6eadf39561e9293149c669e/69538/upgrade-yes.png 160w,/static/d9fdf06ee6eadf39561e9293149c669e/72799/upgrade-yes.png 320w,/static/d9fdf06ee6eadf39561e9293149c669e/6af66/upgrade-yes.png 640w,/static/d9fdf06ee6eadf39561e9293149c669e/6a6e9/upgrade-yes.png 826w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/d9fdf06ee6eadf39561e9293149c669e/6af66/upgrade-yes.png&quot; alt=&quot;upgrade image&quot; title=&quot;upgrade image&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;You wont have these messages 👆&lt;/p&gt;&lt;h3 id=&quot;build-tools&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#build-tools&quot; aria-label=&quot;build tools permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Build tools&lt;/h3&gt;&lt;p&gt;To compile and install native addons from npm you may also need to
install build tools, I need this for Gatsby images which uses &lt;code&gt;sharp&lt;/code&gt;
which in turn uses &lt;code&gt;node-gyp&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install -y build-essential
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;install-node&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-node&quot; aria-label=&quot;install node permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install node&lt;/h3&gt;&lt;p&gt;Installing node via the instructions given on the nodejs.org site
doesn’t give the correct permissions for me, so when trying to
&lt;code&gt;npm install&lt;/code&gt; anything I get errors, I found using &lt;a href=&quot;https://github.com/Microsoft/WSL/issues/776#issuecomment-266112578&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;using &lt;code&gt;n&lt;/code&gt;&lt;/a&gt;
helps:&lt;/p&gt;&lt;h3 id=&quot;install-node-with-n&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-node-with-n&quot; aria-label=&quot;install node with n permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install node with &lt;code&gt;n&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;As it’s a fresh install then we can go ahead and use &lt;a href=&quot;https://github.com/mklement0/n-install&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;n-install&lt;/a&gt; with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://git.io/n-install | bash
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will install the latest stable version of node 👍&lt;/p&gt;&lt;p&gt;Once the script is complete restart bash with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;. /home/my_user_name/.bashrc # the n prompt displays this for you to copy pasta
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check your node and npm versions:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node -v &amp;amp;&amp;amp; npm -v
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;install-fish-&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-fish-&quot; aria-label=&quot;install fish  permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install fish 🐟🐚&lt;/h3&gt;&lt;p&gt;Fish is now my go to shell purely for the auto complete/intellisense
👌 there’s also some nice themes you can get for it too.&lt;/p&gt;&lt;p&gt;There’s two options here, one is to use the standard package that come
pre installed with the Ubuntu install or you can use the Fish &lt;a href=&quot;#&quot; title=&quot;Personal Package Archive&quot;&gt;PPA&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Use the standard package:&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt -y install fish
sudo apt -y upgrade &amp;amp;&amp;amp; sudo apt -y autoremove
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Use the Fish shell &lt;a href=&quot;#&quot; title=&quot;Personal Package Archive&quot;&gt;PPA&lt;/a&gt;:&lt;/strong&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt-add-repository ppa:fish-shell/release-2
sudo apt update &amp;amp;&amp;amp; sudo apt -y install fish
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;install-oh-my-fish--omf&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-oh-my-fish--omf&quot; aria-label=&quot;install oh my fish  omf permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Oh My Fish | OMF&lt;/h3&gt;&lt;p&gt;Oh My Fish is like a package manager for Fish enabling the instal of
packages and themes.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://get.oh-my.fish | fish
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;install-omf-theme&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#install-omf-theme&quot; aria-label=&quot;install omf theme permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install OMF theme&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;omf install clearance
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;the-start-of-the-beginning&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-start-of-the-beginning&quot; aria-label=&quot;the start of the beginning permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The start of the beginning&lt;/h3&gt;&lt;p&gt;Ok, so that is a basic setup for WSL, you’ll probably want to get Git
set up now, I have been using SSH over HTTPS for a while now on WSL.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;At the time of writing this WSL Git integration with VSCode doesn’t
work so I have added a Git install to my windows machine, you can
omit this and go full Git via the terminal but I really like the
VSCode git integration.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;To get SSH set up on your machine take a look at this &lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/git.md#how-to-authenticate-with-github-using-ssh&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;handy SSH
setup&lt;/a&gt;. I say SSH instead of HTTPS 1. because I had all sorts of
issues with the Git credential manager and the keyring manager in the
end it was actually quicker to create an SSH key and authenticate with
GitHub - the guide I linked walks you through it.&lt;/p&gt;&lt;h3 id=&quot;move-your-dotfiles&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#move-your-dotfiles&quot; aria-label=&quot;move your dotfiles permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Move your dotfiles&lt;/h3&gt;&lt;p&gt;If you have all your &lt;a href=&quot;https://github.com/spences10/dotfiles&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dotfiles&lt;/a&gt; backed up in a GitHub repo then now is
a good time to add them to your WSL folder, the last times I did this
I manually set the permissions after moving each of the the files but
have since discovered &lt;a href=&quot;https://www.tecmint.com/rsync-local-remote-file-synchronization-commands/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;rsync&lt;/code&gt;&lt;/a&gt; to move all the files.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;rsync -avzh /mnt/c/Users/dotfiles/ ~/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That will copy the contents of my &lt;code&gt;dotfiles&lt;/code&gt; folder to the &lt;code&gt;~/&lt;/code&gt; (home)
directory in WSL, you can check them with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ls -la ~/
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:581px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/7499ad1ca9beabe2915014e11a7368d4/92d15/bash-wrong-perms.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:52.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;210\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20210\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20105v105h401V0H0v105m246-3l1%2012h18l20-1%205-10-3%204-2%205v-5c0-5%200-5-3-5-2%200-3%200-2-1l5-9c-1%200-1-1-4%205l-1%204-1-5v-5h-33v11m7%2028c0%202%200%202%201%201l1-2v4c0%201-2%202-5%202h-4v17l1%2017h10c11%200%2012%200%2015-7%203-5%201-5-1%200l-2%205-1-5v-5h-8c-7%200-8%200-7-2l3-5%201-3h11c8%200%2010%200%2012-2l5-9-3%204c-3%205-3%205-3-4%200-7%200-8-2-8l-2%202c0%202%200%202%201%201l1-2v4c0%201-4%202-11%202h-10l1-3c0-4%200-4-2-4l-2%202\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/7499ad1ca9beabe2915014e11a7368d4/60a22/bash-wrong-perms.webp 160w,/static/7499ad1ca9beabe2915014e11a7368d4/4c812/bash-wrong-perms.webp 320w,/static/7499ad1ca9beabe2915014e11a7368d4/39daa/bash-wrong-perms.webp 581w&quot; sizes=&quot;(max-width: 581px) 100vw, 581px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/7499ad1ca9beabe2915014e11a7368d4/69538/bash-wrong-perms.png 160w,/static/7499ad1ca9beabe2915014e11a7368d4/72799/bash-wrong-perms.png 320w,/static/7499ad1ca9beabe2915014e11a7368d4/92d15/bash-wrong-perms.png 581w&quot; sizes=&quot;(max-width: 581px) 100vw, 581px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/7499ad1ca9beabe2915014e11a7368d4/92d15/bash-wrong-perms.png&quot; alt=&quot;bash files wrong permissions&quot; title=&quot;bash files wrong permissions&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I copied across my &lt;code&gt;.gitconfig&lt;/code&gt;, &lt;code&gt;.gitignore&lt;/code&gt; and &lt;code&gt;.npmrc&lt;/code&gt; dotfiles
pictured here and you can see that the permissions are not consistent
with the &lt;code&gt;.bashrc&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;So, the only way I know how to change the file permissions is with
&lt;code&gt;chmod&lt;/code&gt; to get the ordinals of a similar file use &lt;code&gt;stat&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;stat -c &amp;quot;%a %n&amp;quot; ~/.*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will list out all everything that begins with a &lt;code&gt;.&lt;/code&gt; here’s mine:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;777 /home/scott/.
755 /home/scott/..
600 /home/scott/.bash_history
644 /home/scott/.bash_logout
644 /home/scott/.bashrc
777 /home/scott/.cache
777 /home/scott/.config
777 /home/scott/.gitconfig
777 /home/scott/.gitignore
777 /home/scott/.local
777 /home/scott/.npm
777 /home/scott/.npmrc
644 /home/scott/.profile
644 /home/scott/.sudo_as_admin_successful
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I only want to change &lt;code&gt;.gitconfig&lt;/code&gt;, &lt;code&gt;.gitignore&lt;/code&gt; and &lt;code&gt;.npmrc&lt;/code&gt; here so
I’m going to do this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;chmod 644 .gitconfig .gitignore .npmrc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now my files look like this. 👍&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:572px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/dad0b2d87dfb1eba5a9fc5320da452ce/a805e/bash-dotfiles.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:67.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;270\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20270\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20135v135h401V0H0v135m244-31v11h19l21-1%204-9-3%204-2%205v-5c0-5%200-5-2-5h-3l3-4%202-6c-1-1-2%200-3%203-2%205-3%205-2%200v-4h-34v11m7%2026v5c3%201%200%203-4%202h-3v57h11c8%200%2010%200%2012-2l5-9c-1%200-1-1-4%205l-1%204-1-5%201-6%205-8c0-2-2%200-3%203-2%205-3%205-3%200v-5h13c16%200%2017%200%2019-6%203-6%202-6-1%200l-2%205-1-5v-5h-16l3-4%202-6c-1-1-2%200-3%203-2%205-3%205-2%200%200-4%200-4-3-4s-4-1-2-2l4-9-3%204-1%204-1-4v-4h-10l-8-1v-7h-3m5%2071v4h-12v11h10c13%200%2014%200%2016-6%203-6%202-6-1%200l-3%205v-10h-4c-4%200-5%200-2-3h1l4%201c4%200%204-1%204-3l1-2c1-1-2-1-6-1h-8v4m-5%2019l-1%204c0%203%200%203-3%203s-3%200-3%206v5h10l12-1c2%200%206-7%206-8%200-2-2%200-4%203l-1%205-1-5v-5h-7c-7%200-9-1-5-2%202-1%201-5-1-6l-2%201\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/dad0b2d87dfb1eba5a9fc5320da452ce/60a22/bash-dotfiles.webp 160w,/static/dad0b2d87dfb1eba5a9fc5320da452ce/4c812/bash-dotfiles.webp 320w,/static/dad0b2d87dfb1eba5a9fc5320da452ce/a64e8/bash-dotfiles.webp 572w&quot; sizes=&quot;(max-width: 572px) 100vw, 572px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/dad0b2d87dfb1eba5a9fc5320da452ce/69538/bash-dotfiles.png 160w,/static/dad0b2d87dfb1eba5a9fc5320da452ce/72799/bash-dotfiles.png 320w,/static/dad0b2d87dfb1eba5a9fc5320da452ce/a805e/bash-dotfiles.png 572w&quot; sizes=&quot;(max-width: 572px) 100vw, 572px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/dad0b2d87dfb1eba5a9fc5320da452ce/a805e/bash-dotfiles.png&quot; alt=&quot;bash files permissions&quot; title=&quot;bash files permissions&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Ok now were up and running with an up to date Ubuntu install, node and
fish terminal. Of course there’s still the case of installing all your
global npm packages you want for development now.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Git ` — allow-unrelated-histories`]]></title><description><![CDATA[How to combine two separate unrelated Git repositories into one with
single history timeline. Just adding a quick note on this… I had a…]]></description><link>https://scottspence.com/2017/06/30/git-allow-unrelated-histories/</link><guid isPermaLink="false">https://scottspence.com/2017/06/30/git-allow-unrelated-histories/</guid><pubDate>Fri, 30 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;How to combine two separate unrelated Git repositories into one with
single history timeline.&lt;/p&gt;&lt;p&gt;Just adding a quick note on this…&lt;/p&gt;&lt;p&gt;I had a project that started off as it’s own project but it ended up
needing to go into an already existing project, so I thought ok add it
as a new branch on the existing project with &lt;code&gt;git remote add origin&lt;/code&gt;
then push the changes up to the origin then all is well with the
world. That was until I tried to compare the branches…&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/5602c54638703c110ed8325946dd4e07/20c85/git-compare.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:20.625%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;82\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2082\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M198%2045l-1%201c-1-1-3%200-3%201h-2l-3-1c-2%200-3%200-3%202s0%202%201%201h2c1%201%201%201%201-1%201-1%201%200%201%201v3c1%200%202-1%202-3%201-2%202-2%202-1l2%202%202-2h1c0%201%201%202%203%202s3-1%203-2h1l2%202c1%200%202%200%201%201v1c1%202%203%200%203-3v-3h-7l-7-1h-1\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/5602c54638703c110ed8325946dd4e07/60a22/git-compare.webp 160w,/static/5602c54638703c110ed8325946dd4e07/4c812/git-compare.webp 320w,/static/5602c54638703c110ed8325946dd4e07/0ba47/git-compare.webp 640w,/static/5602c54638703c110ed8325946dd4e07/e46b2/git-compare.webp 960w,/static/5602c54638703c110ed8325946dd4e07/5375e/git-compare.webp 999w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/5602c54638703c110ed8325946dd4e07/69538/git-compare.png 160w,/static/5602c54638703c110ed8325946dd4e07/72799/git-compare.png 320w,/static/5602c54638703c110ed8325946dd4e07/6af66/git-compare.png 640w,/static/5602c54638703c110ed8325946dd4e07/d9199/git-compare.png 960w,/static/5602c54638703c110ed8325946dd4e07/20c85/git-compare.png 999w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/5602c54638703c110ed8325946dd4e07/6af66/git-compare.png&quot; alt=&quot;compare&quot; title=&quot;compare&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;There isn’t anything to compare? Bit misleading there as there is but
the commit histories are different. How do you get around it, well the
first Google result was a bit sparse with the details but then I found
this which was more helpful. I needed to merge the disparate branches
which is now disabled by default in git but can be enabled with the
—allow-unrelated-histories flag.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git merge origin use-ts-bot --allow-unrelated-histories
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This brought up, understandably, a few conflicts with the branch I
wanted to merge with the origin.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Auto-merging package.json
CONFLICT (add/add): Merge conflict in package.json
Auto-merging package-lock.json
CONFLICT (add/add): Merge conflict in package-lock.json
Auto-merging README.md
CONFLICT (add/add): Merge conflict in README.md
Auto-merging .gitignore
CONFLICT (add/add): Merge conflict in .gitignore
Automatic merge failed; fix conflicts and then commit the result.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To get around this I just took the latest version of the &lt;code&gt;use-ts-bot&lt;/code&gt;
branch from my GitHub account and then and used that in place of the
&lt;code&gt;origin&lt;/code&gt; conflicts as what I’m working on will ultimately replace the
master branch, so it was just a copy pasta into my VSCode then
recommit the changes files. Phew! I now have a branch I can compare
with the master that I will one day make a PR for 😅&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/8e5004783656e0f79dadb8b730fc43ae/75609/git-compare-after.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:73.75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;296\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20296\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M9%2036v7l1%206h65V36l-33-1-33%201m345%20254v5h25v-11h-25v6m1%200v4h23v-9h-23v5\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/8e5004783656e0f79dadb8b730fc43ae/60a22/git-compare-after.webp 160w,/static/8e5004783656e0f79dadb8b730fc43ae/4c812/git-compare-after.webp 320w,/static/8e5004783656e0f79dadb8b730fc43ae/0ba47/git-compare-after.webp 640w,/static/8e5004783656e0f79dadb8b730fc43ae/e46b2/git-compare-after.webp 960w,/static/8e5004783656e0f79dadb8b730fc43ae/fd213/git-compare-after.webp 994w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/8e5004783656e0f79dadb8b730fc43ae/69538/git-compare-after.png 160w,/static/8e5004783656e0f79dadb8b730fc43ae/72799/git-compare-after.png 320w,/static/8e5004783656e0f79dadb8b730fc43ae/6af66/git-compare-after.png 640w,/static/8e5004783656e0f79dadb8b730fc43ae/d9199/git-compare-after.png 960w,/static/8e5004783656e0f79dadb8b730fc43ae/75609/git-compare-after.png 994w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/8e5004783656e0f79dadb8b730fc43ae/6af66/git-compare-after.png&quot; alt=&quot;git compare after&quot; title=&quot;git compare after&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Moving from beginner to (slightly more) advanced git with aliases.]]></title><description><![CDATA[Speed up your git workflow with git aliases, this is a brief
introduction on using aliases 👌🚀👍 The more you work with Git the more…]]></description><link>https://scottspence.com/2017/06/01/beginner-to-git-aliases/</link><guid isPermaLink="false">https://scottspence.com/2017/06/01/beginner-to-git-aliases/</guid><pubDate>Thu, 01 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Speed up your git workflow with git aliases, this is a brief
introduction on using aliases 👌🚀👍&lt;/p&gt;&lt;p&gt;The more you work with Git the more familiar you become with the
commands used in your every day workflow for your projects or your
team’s projects.&lt;/p&gt;&lt;p&gt;Commands like naming and creating feature branches making pull
requests or pushing your changes if you have the requisite
permissions.&lt;/p&gt;&lt;p&gt;So still used by me on a daily basis, and everyone else that uses git
[I presume] is the &lt;code&gt;git add .&lt;/code&gt; command, then
&lt;code&gt;git commit -m &amp;#x27;my awesome feature&amp;#x27;&lt;/code&gt; and &lt;code&gt;git push&lt;/code&gt; or
&lt;code&gt;git push origin &amp;lt;branch&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;In my short time using Git I have always just typed out the full
commands [usually with &lt;a href=&quot;https://github.com/spences10/cheat-sheets/blob/master/git.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my cheatsheet&lt;/a&gt; close to hand]
and thought nothing more of it, that is how you use the tool, right?&lt;/p&gt;&lt;p&gt;Well that was what I foolishly presumed until I learned about
dotfiles, I learned about &lt;code&gt;.&lt;/code&gt; files from listening to the
&lt;a href=&quot;http://www.toolsday.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;toolsday.io&lt;/a&gt; podcast with &lt;a href=&quot;http://twitter.com/chrisdhanaraj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Chris&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/una&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Una&lt;/a&gt; a
great channel for learning about tooling 👍 the podcast was about &lt;a href=&quot;http://www.toolsday.io/episodes/git.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git
Tools&lt;/a&gt; give it a listen it’s a great show.&lt;/p&gt;&lt;p&gt;This was a pretty cool learning experience for me and I now have a
pretty efficient git workflow 🚀&lt;/p&gt;&lt;p&gt;Let’s go over &lt;code&gt;.gitconfig&lt;/code&gt;, do you remember having to enter your email
address and name when first setting up Git on your computer? That
information is stored in your &lt;code&gt;.gitconfig&lt;/code&gt; file, your file will be
located in your user folder on Windows
&lt;code&gt;C:\Users\yourusername\.gitconfig&lt;/code&gt; or &lt;code&gt;~/.gitconfig&lt;/code&gt; on Linux/Mac&lt;/p&gt;&lt;p&gt;If you navigate to the file in the text editor of your choice and pop
it open you’ll see your details under the &lt;code&gt;[user]&lt;/code&gt; flag, here’s mine:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[user]
  name = spences10
  email = spences10apps@gmail.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I’m not sure what other configuration options you may have in yours so
we’re just going to concentrate on the aliases, aliases can be used so
that you can shorten the commands [or make them longer if you like]
but I’m all for reducing key strokes, even if it is one or two less.&lt;/p&gt;&lt;p&gt;So let’s review the common commands I mentioned at the start:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add .
git commit -m &amp;#x27;my awesome feature&amp;#x27;
git push
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So with aliases we can shorten these down a bit:&lt;/p&gt;&lt;p&gt;In your &lt;code&gt;.gitconfig&lt;/code&gt; file if there’s not already one there add in the
&lt;code&gt;[aliases]&lt;/code&gt; section, I have mine above my user details, then add in
some aliases:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[alias]
  a = add .
  c = commit -am
  p = push

[user]
  name = spences10
  email = spences10apps@gmail.com
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now we can shorten down our workflow for adding a change to one of
our repos:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add .
git commit -m &amp;#x27;my awesome feature&amp;#x27;
git push
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Will become:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git a
git c &amp;#x27;my awesome feature&amp;#x27;
git p
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It’s not a massive reduction in what you’re typing but you’ll be
amazed at how quickly you become accustomed to it and start adding
more an more.&lt;/p&gt;&lt;p&gt;Here’s my current list of aliases:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[alias]
  a = add .
  b = branch
  c = commit -am
  cl = clone
  co = checkout
  d = diff
  f = fetch
  i = init
  o = open # see: https://github.com/paulirish/git-open ♥
  p = push
  pt = push --tags
  s = status
  t = tag
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A new one I have found out whilst making this post is
&lt;code&gt;clone --depth 1&lt;/code&gt; which clones only the HEAD of the repository instead
of the whole repository, so say if you were cloning react you’d just
get the master version rather than the other 38 branches included in
the repository. Pretty neat 👍 so that could be aliased into something
a lot shorter &lt;code&gt;git cl1d&lt;/code&gt;?&lt;/p&gt;&lt;p&gt;You’ll no doubt notice the link I have in there for &lt;code&gt;o = open&lt;/code&gt; that
little gem belongs to &lt;a href=&quot;https://github.com/paulirish&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Paul Irish&lt;/a&gt; it’s an npm package that will
pop open a browser tab to the current repository you are in, pretty
neat right?&lt;/p&gt;&lt;p&gt;I’m sure there are many, many more ways to configure Git if you take a
look at &lt;a href=&quot;https://github.com/paulirish/dotfiles/blob/master/.gitconfig&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Paul Irish&lt;/a&gt;’s dotfiles repo for his &lt;code&gt;.gitconfig&lt;/code&gt; you’ll
see there is a lot of ways to configure Git, I’m still learning and
finding new ways to do things.&lt;/p&gt;&lt;p&gt;If there is anything I have missed, or if you have a better way to dom
something then please let me know 👍&lt;/p&gt;&lt;p&gt;Get me on &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://github.com/spences10/ama&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Ask Me Anything&lt;/a&gt; on GitHub&lt;/p&gt;&lt;p&gt;If you like this post or if it has helped you in any way then please
give it a like and don’t forget to share it on social media 🙌&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Just starting out with Git and GitHub? It gets easier, honest!]]></title><description><![CDATA[No doubt you have heard of Git or GitHub for source control, but
 what is source control? “Revision control (also known as version control…]]></description><link>https://scottspence.com/2017/05/31/gets-better-with-git/</link><guid isPermaLink="false">https://scottspence.com/2017/05/31/gets-better-with-git/</guid><pubDate>Wed, 31 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;No doubt you have heard of Git or GitHub for source control, but
&lt;strong&gt;what is source control?&lt;/strong&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;“Revision control (also known as version control, source control or
(source) code management (SCM)) is the management of multiple
revisions of the same unit of information.”&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Cool story br0! In other words: Source control allows distributed work
in teams of any size, at different locations, while avoiding conflicts
in source code changes.&lt;/p&gt;&lt;p&gt;Really!? Thanks for clearing that up!&lt;/p&gt;&lt;p&gt;Lets look at it this way…&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In its simplest term it’s like a “Save As”. You want the new file
without getting rid of the changes on the old one. It’s an everyday
situation, except on a software project there is the potential for a
lot of changes.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/lindakatcodes/status/869086021220261888&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://twitter.com/lindakatcodes/status/869086021220261888&lt;/a&gt;&lt;/p&gt;&lt;p&gt;A familiar sentiment for anyone starting out with Git&lt;/p&gt;&lt;h2 id=&quot;concepts&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#concepts&quot; aria-label=&quot;concepts permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Concepts&lt;/h2&gt;&lt;p&gt;There are some basic concepts about version control I’ll quickly go
over here, these terms used in many SCM systems some relevant to Git
and GitHub some to other systems.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Repository/repo:&lt;/strong&gt; The database storing the files.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Branch:&lt;/strong&gt; Create a separate copy of a repo for use on your computer.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Revert/rollback:&lt;/strong&gt; Go back to a previously saved version of the
codebase/repo.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Push:&lt;/strong&gt; Push is an access level on the repo, if you have no push
access you will need to make a pull request.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pull:&lt;/strong&gt; If you have no Push access you can make a pull request which
will notify the repo owner you want to merge your changes into their
code.&lt;/p&gt;&lt;p&gt;If you are just starting out then your most used commands will
probably be :&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add .
git commit -m &amp;#x27;some informative message&amp;#x27;
git push origin master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Those commands have served me well in my early days of learning how to
get my code back up to GitHub.&lt;/p&gt;&lt;p&gt;&lt;code&gt;video: https://www.youtube.com/watch?v=CDeG4S-mJts&lt;/code&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Git and GitHub&lt;/strong&gt; Git and GitHub are two separate things, Git is a
free and open source version control system whilst GitHub uses Git
technology to host your repositories on the GitHub.com servers.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Git and GitHub were a bit confusing for me when I first started out
with them, I was familiar with VCS before but that was in the shape of
Microsoft’s Visual SourceSafe and Team Foundation Server where you
have a nice GUI to guide you through the check-in and check-out
process, for those the process was:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check-out:&lt;/strong&gt; make a copy of the repository you wanted to make
changes to on your machine, once you have made your change then,
Check-in your changes.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check-in:&lt;/strong&gt; add your changes back to the repository with an
accompanying message detailing the change you have made.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;With Git it’s a bit less fancy, all via the command line, but pretty
much the same as with VSS and TFS.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Clone the repository: Make a copy of the repo on your machine.&lt;/li&gt;&lt;li&gt;Make changes.&lt;/li&gt;&lt;li&gt;Once the changes are made then add them back with accompanying
commit messages.&lt;/li&gt;&lt;li&gt;Push the changes back to the repo on Github.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The documentation on GitHub is fantastic for anything you want to
achieve and in this post I have referenced some the documentation.&lt;/p&gt;&lt;p&gt;It can get a bit overwhelming though, especially if you get out of
sync, i.e. forget to pull a change made on the remote then try to
check your changes in before pulling the changes into your local
version. I’m by no means confident if things go a bit wrong but I have
developed a “&lt;a href=&quot;https://gist.github.com/SethRobertson/1540906/68feeabfe906ec1eb893e4fa45f402795ed6e62c#commit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Commit Often Perfect Later&lt;/a&gt;” approach so if you do break
something you din’t lose too much of you valuable time trying to work
out what went wrong where.&lt;/p&gt;&lt;p&gt;If you take a look at a repo you have cloned from GitHub you will see
there is a file called &lt;code&gt;.git&lt;/code&gt; this is like a little database of all
the changes you have made on your machine and it contains all the
information it needs to connect to GitHub and make the changes it
needs to make to the master repo [or whatever branch you’re pushing
the changes to].&lt;/p&gt;&lt;p&gt;I made a cheat sheet &lt;a href=&quot;https://gist.github.com/spences10/5c492e197e95158809a83650ff97fc3a#useful-git-commands&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gist&lt;/a&gt; which I used every time I went near Git,
it has now turned into a &lt;a href=&quot;https://github.com/spences10/cheat-sheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;repo&lt;/a&gt; of other cheat sheets I still use on a
daily basis.&lt;/p&gt;&lt;p&gt;In it I cover these situations:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Make a new project on your machine that you want to add to GitHub?
Look here.&lt;/li&gt;&lt;li&gt;Cloning a repo from someone else’s GitHub and pushing it to a repo
on my GitHub, or “I didn’t make a fork, what do I do now!”&lt;/li&gt;&lt;li&gt;You have a fork which you need to update before making any changes.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Workflow will be different for differing situations, for me as a noob
developer I have tried to document anything I have come across with
Git so I can reference back to it for that one time I need it but
can’t remember what I did at 21:45 on a Wednesday just to get the code
checked into GitHub.&lt;/p&gt;&lt;p&gt;There are many GUIs that integrate with Git for use with GitHub the
official GitHub one is pretty nice but I quickly got into situations
that the GUI couldn’t get me out of so I have stuck with the terminal
since, well there is VSCode though which has a beautiful Git UI that I
use daily, but there are some things that I still use the terminal
for:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git status
git checkout &amp;lt;branch-name&amp;gt;
git [push] tags
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All pretty handy, there is probably extensions out there to help with
these but for now I’m pretty comfortable doing it via the command
line.&lt;/p&gt;&lt;p&gt;Any tips or tricks you use in Git you’d like to share? Please feel
free to leave a comment or better still add to the repo via a pull
request.&lt;/p&gt;&lt;p&gt;If any of this has helped you in any way feel free to like the article
and share it on social media.&lt;/p&gt;&lt;p&gt;Many thanks.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Twitter bot playground]]></title><description><![CDATA[How to build and deploy a multifunctional Twitter bot! This is a reference for me and anyone else that's interested in
Twitter bots in…]]></description><link>https://scottspence.com/2017/05/23/twitter-bot-playground/</link><guid isPermaLink="false">https://scottspence.com/2017/05/23/twitter-bot-playground/</guid><pubDate>Tue, 23 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;How to build and deploy a multifunctional Twitter bot!&lt;/p&gt;&lt;p&gt;This is a reference for me and anyone else that’s interested in
Twitter bots in JavaScript.&lt;/p&gt;&lt;p&gt;All of the examples here use the &lt;a href=&quot;https://www.npmjs.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;npm&lt;/a&gt; package &lt;a href=&quot;https://www.npmjs.com/package/twit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twit&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;We’ll go through setting up a simple bot so each of these examples can
be run with it.&lt;/p&gt;&lt;p&gt;I’m going to assume that you have &lt;code&gt;nodejs&lt;/code&gt; installed along with &lt;code&gt;npm&lt;/code&gt;
and that you are comfortable with the terminal.&lt;/p&gt;&lt;p&gt;If you are not familiar node or do not have your environment set up to
use it take a look at the &lt;a href=&quot;https://github.com/spences10/twitter-bot-bootstrap#twitter-bot-bootstrap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;README.md&lt;/a&gt; on
my &lt;a href=&quot;https://github.com/spences10/twitter-bot-bootstrap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter bot bootstrap&lt;/a&gt; repo which details
getting a Twitter application set up and a development environment
with c9.&lt;/p&gt;&lt;p&gt;A great resource is &lt;a href=&quot;https://github.com/amandeepmittal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aman Mittal’s&lt;/a&gt; &lt;a href=&quot;https://github.com/amandeepmittal/awesome-twitter-bots&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Awesome
Twitter bots&lt;/a&gt; repo which has resources and bot
examples.&lt;/p&gt;&lt;p&gt;A lot of this information is already out there I’m hoping this is all
the information someone will need to get started with their own
Twitter bot. I’m doing this for my own learning and hopefully other
people will get something out of this as well.&lt;/p&gt;&lt;h2 id=&quot;set-up-the-bot&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#set-up-the-bot&quot; aria-label=&quot;set up the bot permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set up the bot&lt;/h2&gt;&lt;p&gt;Before touching the terminal or writing any code we’ll need to create
a &lt;a href=&quot;https://apps.twitter.com/app/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter app&lt;/a&gt; to get our API keys, we’ll need them all:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Consumer Key (API Key)
Consumer Secret (API Secret)
Access Token
Access Token Secret
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Keep the keys somewhere safe so you can use them again when you need
them, we’re going to be using them in the &lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;.env&lt;/a&gt; file we’re
going to create.&lt;/p&gt;&lt;p&gt;We’re using &lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;dotenv&lt;/a&gt; so that if at some point in the future we
want to add our bot to GitHub the Twitter API keys are not added to
GitHub for all to see.&lt;/p&gt;&lt;p&gt;Starting from scratch, create a new folder via the terminal and
initialise the &lt;code&gt;package.json&lt;/code&gt; via &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt; we’ll need &lt;code&gt;twit&lt;/code&gt;
and &lt;code&gt;dotenv&lt;/code&gt; for all these examples.&lt;/p&gt;&lt;p&gt;I’ll be using &lt;code&gt;yarn&lt;/code&gt; for all these examples, you can use &lt;code&gt;npm&lt;/code&gt; if you
prefer.&lt;/p&gt;&lt;p&gt;Terminal commands:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir tweebot-play
cd tweebot-play
yarn init -y
yarn add twit dotenv
touch .env .gitignore index.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you take a look at the &lt;code&gt;package.json&lt;/code&gt; that was created it should
look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tweebot-play&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;author&amp;quot;: &amp;quot;Scott Spence &amp;lt;spences10apps@gmail.com&amp;gt; (https://spences10.github.io/)&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;dotenv&amp;quot;: &amp;quot;^4.0.0&amp;quot;,
    &amp;quot;twit&amp;quot;: &amp;quot;^2.2.5&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Add an &lt;code&gt;npm&lt;/code&gt; script to the &lt;code&gt;package.json&lt;/code&gt; to kick off the bot when
we’re testing and looking for output:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node index.js&amp;quot;
  },
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It should look something like this now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;tweebot-play&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node index.js&amp;quot;
  },
  &amp;quot;author&amp;quot;: &amp;quot;Scott Spence &amp;lt;spences10apps@gmail.com&amp;gt; (https://spences10.github.io/)&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;dotenv&amp;quot;: &amp;quot;^4.0.0&amp;quot;,
    &amp;quot;twit&amp;quot;: &amp;quot;^2.2.5&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can add the following pointer to the bot in &lt;code&gt;index.js&lt;/code&gt;, like
so:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;require(&amp;#x27;./src/bot&amp;#x27;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So when we use &lt;code&gt;yarn start&lt;/code&gt; to run the bot it calls the &lt;code&gt;index.js&lt;/code&gt;
file which runs the &lt;code&gt;bot.js&lt;/code&gt; file from the &lt;code&gt;src&lt;/code&gt; folder we’re going to
create.&lt;/p&gt;&lt;p&gt;Now we add our API keys to the &lt;code&gt;.env&lt;/code&gt; file, it should look something
like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;CONSUMER_KEY=AmMSbxxxxxxxxxxNh4BcdMhxg
CONSUMER_SECRET=eQUfMrHbtlxxxxxxxxxxkFNNj1H107xxxxxxxxxx6CZH0fjymV
ACCESS_TOKEN=7xxxxx492-uEcacdl7HJxxxxxxxxxxecKpi90bFhdsGG2N7iII
ACCESS_TOKEN_SECRET=77vGPTt20xxxxxxxxxxxZAU8wxxxxxxxxxx0PhOo43cGO
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the &lt;code&gt;.gitignore&lt;/code&gt; file we need to add &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Dependency directories
node_modules

# env files
.env
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then init git:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git init
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, now we can start to configure the bot, we’ll need a &lt;code&gt;src&lt;/code&gt; folder a
&lt;code&gt;bot.js&lt;/code&gt; file and a &lt;code&gt;config.js&lt;/code&gt; file.&lt;/p&gt;&lt;p&gt;Terminal:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir src
cd src
touch config.js bot.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we can set up the bot config, open the &lt;code&gt;config.js&lt;/code&gt; file and add
the following:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;require(&amp;#x27;dotenv&amp;#x27;).config()

module.exports = {
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  access_token: process.env.ACCESS_TOKEN,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET,
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, that’s the bot config done now we can set up the bot, each of the
examples detailed here will have the same three lines of code:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)

const bot = new Twit(config)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, that’s it out bot is ready to go, do a test with &lt;code&gt;yarn start&lt;/code&gt; from
the terminal, we should get this for output:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn start
yarn start v0.23.4
$ node index.js
Done in 0.64s.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bot is now configured and ready to go!🚀&lt;/p&gt;&lt;h2 id=&quot;post-statuses&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#post-statuses&quot; aria-label=&quot;post statuses permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Post Statuses&lt;/h2&gt;&lt;p&gt;Firstly post statuses, with &lt;code&gt;.post(&amp;#x27;statuses/update&amp;#x27;...&lt;/code&gt; bot will post
a hello world! status.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;statuses/update&amp;#x27;,
  {
    status: &amp;#x27;hello world!&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} tweeted!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;work-with-users&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#work-with-users&quot; aria-label=&quot;work with users permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Work with users&lt;/h2&gt;&lt;p&gt;To get a list of followers ids use &lt;code&gt;.get(&amp;#x27;followers/ids&amp;#x27;...&lt;/code&gt; and
include the account that you want the followers of, in this example
we’re using &lt;a href=&quot;https://twitter.com/DroidScott&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;@DroidScott&lt;/code&gt;&lt;/a&gt;, you can use any account you
like. We can then log them out to the console in this example.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;followers/ids&amp;#x27;,
  {
    screen_name: &amp;#x27;DroidScott&amp;#x27;,
    count: 5,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can specify with the &lt;code&gt;count&lt;/code&gt; parameter how many results you get up
to 100 at a time.&lt;/p&gt;&lt;p&gt;Or to get a detailed list you can use &lt;code&gt;.get(&amp;#x27;followers/list&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Here we print off a list of &lt;code&gt;user.screen_name&lt;/code&gt;’s up to 200 per call.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;followers/list&amp;#x27;,
  {
    screen_name: &amp;#x27;DroidScott&amp;#x27;,
    count: 200,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      data.users.forEach(user =&amp;gt; {
        console.log(user.screen_name)
      })
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To follow back a follower we can use &lt;code&gt;.post(&amp;#x27;friendships/create&amp;#x27;...&lt;/code&gt;
here the bot is following back the user &lt;code&gt;MarcGuberti&lt;/code&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A bot should only follow users that follow the bot.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;friendships/create&amp;#x27;,
  {
    screen_name: &amp;#x27;MarcGuberti&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like with followers you can get a list of accounts that your bot is
following back.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;friends/ids&amp;#x27;,
  {
    screen_name: &amp;#x27;DroidScott&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And also a detailed list.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;friends/list&amp;#x27;,
  {
    screen_name: &amp;#x27;DroidScott&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Get friendship status, this is useful for following new followers,
this will give us the relation of a specific user. So you can run
through your followers list and follow back any users that do not have
the &lt;code&gt;following&lt;/code&gt; connection.&lt;/p&gt;&lt;p&gt;Let’s take a look at the relation between our bot and
&lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;@spences10&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;friendships/lookup&amp;#x27;,
  {
    screen_name: &amp;#x27;spences10&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the user follows the bot, then relationship will be:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[ { name: &amp;#x27;Scott Spence 🌯😴💻♻&amp;#x27;,
    screen_name: &amp;#x27;spences10&amp;#x27;,
    id: 4897735439,
    id_str: &amp;#x27;4897735439&amp;#x27;,
    connections: [ &amp;#x27;followed_by&amp;#x27; ] } ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the user and the bot are following each other, the relationship
will be:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[ { name: &amp;#x27;Scott Spence 🌯😴💻♻&amp;#x27;,
    screen_name: &amp;#x27;spences10&amp;#x27;,
    id: 4897735439,
    id_str: &amp;#x27;4897735439&amp;#x27;,
    connections: [ &amp;#x27;following&amp;#x27;, &amp;#x27;followed_by&amp;#x27; ] } ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And if there is no relationship then:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[ { name: &amp;#x27;Scott Spence 🌯😴💻♻&amp;#x27;,
    screen_name: &amp;#x27;spences10&amp;#x27;,
    id: 4897735439,
    id_str: &amp;#x27;4897735439&amp;#x27;,
    connections: [ &amp;#x27;none&amp;#x27; ] } ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Direct Message a user with &lt;code&gt;bot.post(&amp;#x27;direct_messages/new&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;A bot should only DM a user that is following the bot account&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;direct_messages/new&amp;#x27;,
  {
    screen_name: &amp;#x27;spences10&amp;#x27;,
    text: &amp;#x27;Hello from bot!&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;interact-with-tweets&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#interact-with-tweets&quot; aria-label=&quot;interact with tweets permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Interact with tweets&lt;/h2&gt;&lt;p&gt;To get a list of tweets in the bots time line use
&lt;code&gt;.get(statuses/home_timeline&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;statuses/home_timeline&amp;#x27;,
  {
    count: 1,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To be more granular you can pull out specific information on each
tweet.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;statuses/home_timeline&amp;#x27;,
  {
    count: 5,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      data.forEach(t =&amp;gt; {
        console.log(t.text)
        console.log(t.user.screen_name)
        console.log(t.id_str)
        console.log(&amp;#x27;\n&amp;#x27;)
      })
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To retweet use &lt;code&gt;.post(&amp;#x27;statuses/retweet/:id&amp;#x27;...&lt;/code&gt; and pass in a tweet
id to retweet.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;statuses/retweet/:id&amp;#x27;,
  {
    id: &amp;#x27;860828247944253440&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} retweet success!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To unretweet just use &lt;code&gt;.post(&amp;#x27;statuses/unretweet/:id&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;statuses/unretweet/:id&amp;#x27;,
  {
    id: &amp;#x27;860828247944253440&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} unretweet success!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To like a tweet use &lt;code&gt;.post(&amp;#x27;favorites/create&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;favorites/create&amp;#x27;,
  {
    id: &amp;#x27;860897020726435840&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} tweet liked!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To unlike a post use &lt;code&gt;.post(&amp;#x27;favorites/destroy&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;favorites/destroy&amp;#x27;,
  {
    id: &amp;#x27;860897020726435840&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} tweet unliked!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To reply to a tweet is much the same a posting a tweet but you need to
include the &lt;code&gt;in_reply_to_status_id&lt;/code&gt; parameter, but that’s not enough
as you will also need to put in the screen name of the person you are
replying to.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;statuses/update&amp;#x27;,
  {
    status: &amp;#x27;@spences10 I reply to you yes!&amp;#x27;,
    in_reply_to_status_id: &amp;#x27;860900406381211649&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} tweeted!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally if you want to delete a tweet use
&lt;code&gt;.post(&amp;#x27;statuses/destroy/:id&amp;#x27;...&lt;/code&gt; passing the tweet id you want to
delete.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.post(
  &amp;#x27;statuses/destroy/:id&amp;#x27;,
  {
    id: &amp;#x27;860900437993676801&amp;#x27;,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(`${data.text} tweet deleted!`)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;use-twitter-search&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-twitter-search&quot; aria-label=&quot;use twitter search permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Twitter search&lt;/h2&gt;&lt;p&gt;To use search use &lt;code&gt;.get(&amp;#x27;search/tweets&amp;#x27;,...&lt;/code&gt; there are quite a few
search parameters for search.&lt;/p&gt;&lt;p&gt;&lt;code&gt;q: &amp;#x27;&amp;#x27;&lt;/code&gt; the Q is for query so to search for mango use &lt;code&gt;q: &amp;#x27;mango&amp;#x27;&lt;/code&gt; we
can also limit the results returned with &lt;code&gt;count: n&lt;/code&gt; so let’s limit it
the count to in the example:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;search/tweets&amp;#x27;,
  {
    q: &amp;#x27;mango&amp;#x27;,
    count: 5,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(data.statuses)
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Like we did with the timeline we will pull out specific items from the
&lt;code&gt;data.statuses&lt;/code&gt; returned, like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;search/tweets&amp;#x27;,
  {
    q: &amp;#x27;mango&amp;#x27;,
    count: 5,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      data.statuses.forEach(s =&amp;gt; {
        console.log(s.text)
        console.log(s.user.screen_name)
        console.log(&amp;#x27;\n&amp;#x27;)
      })
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The search API returns for relevance and not completeness, if you want
to search for an exact phrase you’ll need to wrap the query in quotes
&lt;code&gt;&amp;quot;purple pancakes&amp;quot;&lt;/code&gt; if you want to search for one of two words then
use &lt;code&gt;OR&lt;/code&gt; like &lt;code&gt;&amp;#x27;tabs OR spaces&amp;#x27;&lt;/code&gt; if you want to search for both use
&lt;code&gt;AND&lt;/code&gt; like &lt;code&gt;&amp;#x27;tabs AND spaces&amp;#x27;&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;If you want to search for a tweet without another word use &lt;code&gt;-&lt;/code&gt; like
&lt;code&gt;donald -trump&lt;/code&gt; you can use it multiple times as well, like
&lt;code&gt;donald -trump -duck&lt;/code&gt;&lt;/p&gt;&lt;p&gt;You can search for tweets with emoticons, like &lt;code&gt;q: &amp;#x27;sad :(&amp;#x27;&lt;/code&gt; try it!&lt;/p&gt;&lt;p&gt;Of course look for hashtags &lt;code&gt;q: &amp;#x27;#towie&amp;#x27;&lt;/code&gt;. Look for tweets to a user
&lt;code&gt;q: &amp;#x27;to:@stephenfry&amp;#x27;&lt;/code&gt; or from a user &lt;code&gt;q: &amp;#x27;from:@stephenfry&amp;#x27;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;You can filter out indecent tweets with the &lt;code&gt;filter:safe&lt;/code&gt; parameter
you can also use it to filter for &lt;code&gt;media&lt;/code&gt; tweets which will return
tweets containing video. You can specify for &lt;code&gt;images&lt;/code&gt; to view tweets
with images and you can specify &lt;code&gt;links&lt;/code&gt; for tweets with links.&lt;/p&gt;&lt;p&gt;If you want tweets from a certain website you can specify with the
&lt;code&gt;url&lt;/code&gt; parameter like &lt;code&gt;url:asda&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;search/tweets&amp;#x27;,
  {
    q:
      &amp;#x27;from:@dan_abramov url:facebook filter:images since:2017-01-01&amp;#x27;,
    count: 5,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      data.statuses.forEach(s =&amp;gt; {
        console.log(s.text)
        console.log(s.user.screen_name)
        console.log(&amp;#x27;\n&amp;#x27;)
      })
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Last few now, there’s the &lt;code&gt;result_type&lt;/code&gt; parameter that will return
&lt;code&gt;recent&lt;/code&gt;, &lt;code&gt;popular&lt;/code&gt; or &lt;code&gt;mixed&lt;/code&gt; results.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;geocode&lt;/code&gt; parameter that take the format latitude longitude then
radius in miles &lt;code&gt;&amp;#x27;51.5033640,-0.1276250,1mi&amp;#x27;&lt;/code&gt; example:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;bot.get(
  &amp;#x27;search/tweets&amp;#x27;,
  {
    q: &amp;#x27;bacon&amp;#x27;,
    geocode: &amp;#x27;51.5033640,-0.1276250,1mi&amp;#x27;,
    count: 5,
  },
  (err, data, response) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      data.statuses.forEach(s =&amp;gt; {
        console.log(s.text)
        console.log(s.user.screen_name)
        console.log(&amp;#x27;\n&amp;#x27;)
      })
    }
  }
)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;use-twitter-stream-api&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#use-twitter-stream-api&quot; aria-label=&quot;use twitter stream api permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Twitter Stream API&lt;/h2&gt;&lt;p&gt;There are two ways to use the Stream API first there’s
&lt;code&gt;.stream(&amp;#x27;statuses/sample&amp;#x27;)&lt;/code&gt; example:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const stream = bot.stream(&amp;#x27;statuses/sample&amp;#x27;)

stream.on(&amp;#x27;tweet&amp;#x27;, t =&amp;gt; {
  console.log(`${t.text}\n`)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will give you a random sampling of tweets.&lt;/p&gt;&lt;p&gt;For more specific information use &lt;code&gt;.stream(&amp;#x27;statuses/filter&amp;#x27;)...&lt;/code&gt; then
pass some parameters, use &lt;code&gt;track:&lt;/code&gt; to specify a search string:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;var stream = bot.stream(&amp;#x27;statuses/filter&amp;#x27;, {
  track: &amp;#x27;bot&amp;#x27;,
})

stream.on(&amp;#x27;tweet&amp;#x27;, function (t) {
  console.log(t.text + &amp;#x27;\n&amp;#x27;)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can also use multiple words in the &lt;code&gt;track&lt;/code&gt; parameter, tis will get
you results with either &lt;code&gt;twitter&lt;/code&gt; or &lt;code&gt;bot&lt;/code&gt; in them.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const stream = bot.stream(&amp;#x27;statuses/filter&amp;#x27;, {
  track: &amp;#x27;twitter, bot&amp;#x27;,
})

stream.on(&amp;#x27;tweet&amp;#x27;, t =&amp;gt; {
  console.log(`${t.text}\n`)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want both words then remove the comma &lt;code&gt;,&lt;/code&gt; you can think of
spaces as &lt;code&gt;AND&lt;/code&gt; and commas as &lt;code&gt;OR&lt;/code&gt;&lt;/p&gt;&lt;p&gt;You can also use the &lt;code&gt;follow:&lt;/code&gt; parameter which lets you input the ids
of specific users, example:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const stream = bot.stream(&amp;#x27;statuses/filter&amp;#x27;, {
  follow: &amp;#x27;4897735439&amp;#x27;,
})

stream.on(&amp;#x27;tweet&amp;#x27;, t =&amp;gt; {
  console.log(`${t.text}\n`)
})
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;tweet-media-files&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#tweet-media-files&quot; aria-label=&quot;tweet media files permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tweet media files&lt;/h2&gt;&lt;p&gt;This &lt;a href=&quot;https://egghead.io/lessons/node-js-tweet-media-files-with-twit-js&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;egghead.io&lt;/a&gt; video is a great resource for
this section thanks to &lt;a href=&quot;https://egghead.io/instructors/hannah-davis&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hannah Davis&lt;/a&gt; for the awesome
content!&lt;/p&gt;&lt;p&gt;This will be a request to get the &lt;a href=&quot;https://www.nasa.gov/multimedia/imagegallery/iotd.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NASA image of the day&lt;/a&gt;
and tweet it.&lt;/p&gt;&lt;p&gt;For this we will need references to &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;fs&lt;/code&gt; for working
with the file system.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const request = require(&amp;#x27;request&amp;#x27;)
const fs = require(&amp;#x27;fs&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)

const bot = new Twit(config)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;First up get the photo from the NASA api, for this we will need to
create a parameter object inside our &lt;code&gt;getPhoto&lt;/code&gt; function that will be
passed to the node HTTP client &lt;code&gt;request&lt;/code&gt; for the image:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function getPhoto() {
  const parameters = {
    url: &amp;#x27;https://api.nasa.gov/planetary/apod&amp;#x27;,
    qs: {
      api_key: process.env.NASA_KEY,
    },
    encoding: &amp;#x27;binary&amp;#x27;,
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;parameters&lt;/code&gt; specify an &lt;code&gt;api_key&lt;/code&gt; for this you can &lt;a href=&quot;https://api.nasa.gov/index.html#apply-for-an-api-key&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;apply for an
API key&lt;/a&gt; or you can use the &lt;code&gt;DEMO_KEY&lt;/code&gt; this API key can be
used for initially exploring APIs prior to signing up, but it has much
lower rate limits, so you’re encouraged to signup for your own API
key.&lt;/p&gt;&lt;p&gt;In the example you can see that I have configured my key with the rest
of my &lt;code&gt;.env&lt;/code&gt; variables.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;CONSUMER_KEY=AmMSbxxxxxxxxxxNh4BcdMhxg
CONSUMER_SECRET=eQUfMrHbtlxxxxxxxxxxkFNNj1H107xxxxxxxxxx6CZH0fjymV
ACCESS_TOKEN=7xxxxx492-uEcacdl7HJxxxxxxxxxxecKpi90bFhdsGG2N7iII
ACCESS_TOKEN_SECRET=77vGPTt20xxxxxxxxxxxZAU8wxxxxxxxxxx0PhOo43cGO

NASA_KEY=DEMO_KEY
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now to use the &lt;code&gt;request&lt;/code&gt; to get the image:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function getPhoto() {
  const parameters = {
    url: &amp;#x27;https://api.nasa.gov/planetary/apod&amp;#x27;,
    qs: {
      api_key: process.env.NASA_KEY,
    },
    encoding: &amp;#x27;binary&amp;#x27;,
  }
  request.get(parameters, (err, respone, body) =&amp;gt; {
    body = JSON.parse(body)
    saveFile(body, &amp;#x27;nasa.jpg&amp;#x27;)
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the &lt;code&gt;request&lt;/code&gt; we pass in our parameters and parse the body as JOSN
so we can save it with the &lt;code&gt;saveFile&lt;/code&gt; function which we’ll go over
now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function saveFile(body, fileName) {
  const file = fs.createWriteStream(fileName)
  request(body)
    .pipe(file)
    .on(&amp;#x27;close&amp;#x27;, err =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(&amp;#x27;Media saved!&amp;#x27;)
        console.log(body)
      }
    })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;request(body).pipe(file).on(&amp;#x27;close&amp;#x27;...&lt;/code&gt; is what saves the file from
the &lt;code&gt;file&lt;/code&gt; variable which has the name passed to it &lt;code&gt;nasa.jpg&lt;/code&gt; from
the &lt;code&gt;getPhoto&lt;/code&gt; function.&lt;/p&gt;&lt;p&gt;Calling &lt;code&gt;getPhoto()&lt;/code&gt; should now save the NASA image of the day to the
root of your project.&lt;/p&gt;&lt;p&gt;Now we can share it on Twitter 😎&lt;/p&gt;&lt;p&gt;Two parts to this, first save the file.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function saveFile(body, fileName) {
  const file = fs.createWriteStream(fileName)
  request(body)
    .pipe(file)
    .on(&amp;#x27;close&amp;#x27;, err =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(&amp;#x27;Media saved!&amp;#x27;)
        const descriptionText = body.title
        uploadMedia(descriptionText, fileName)
      }
    })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then &lt;code&gt;uploadMedia&lt;/code&gt; to upload media to Twitter before we can post it,
this had me stumped for a bit as I have my files in a &lt;code&gt;src&lt;/code&gt; folder, if
you have your bot files nested in folders then you will need to do the
same if you are struggling with &lt;code&gt;file does not exist&lt;/code&gt; errors:&lt;/p&gt;&lt;p&gt;Add a &lt;code&gt;require&lt;/code&gt; to &lt;code&gt;path&lt;/code&gt; then use &lt;code&gt;join&lt;/code&gt; with the relevant relative
file path.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const path = require(&amp;#x27;path&amp;#x27;)
//...
const filePath = path.join(__dirname, &amp;#x27;../&amp;#x27; + fileName)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Complete function here:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function uploadMedia(descriptionText, fileName) {
  console.log(`uploadMedia: file PATH ${fileName}`)
  bot.postMediaChunked(
    {
      file_path: fileName,
    },
    (err, data, respone) =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(data)
        const params = {
          status: descriptionText,
          media_ids: data.media_id_string,
        }
        postStatus(params)
      }
    }
  )
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then with the &lt;code&gt;params&lt;/code&gt; we created in &lt;code&gt;uploadMedia&lt;/code&gt; we can post with a
straightforward &lt;code&gt;.post(&amp;#x27;statuses/update&amp;#x27;...&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function postStatus(params) {
  bot.post(&amp;#x27;statuses/update&amp;#x27;, params, (err, data, respone) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(&amp;#x27;Status posted!&amp;#x27;)
    }
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Call the &lt;code&gt;getPhoto()&lt;/code&gt; function top post to Twitter… super straight
forward, right 😀 no, I know it wasn’t. Here’s the complete module:&lt;/p&gt;&lt;details&gt;&lt;summary&gt;Click to expand&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const request = require(&amp;#x27;request&amp;#x27;)
const fs = require(&amp;#x27;fs&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)
const path = require(&amp;#x27;path&amp;#x27;)

const bot = new Twit(config)

function getPhoto() {
  const parameters = {
    url: &amp;#x27;https://api.nasa.gov/planetary/apod&amp;#x27;,
    qs: {
      api_key: process.env.NASA_KEY,
    },
    encoding: &amp;#x27;binary&amp;#x27;,
  }
  request.get(parameters, (err, respone, body) =&amp;gt; {
    body = JSON.parse(body)
    saveFile(body, &amp;#x27;nasa.jpg&amp;#x27;)
  })
}

function saveFile(body, fileName) {
  const file = fs.createWriteStream(fileName)
  request(body)
    .pipe(file)
    .on(&amp;#x27;close&amp;#x27;, err =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(&amp;#x27;Media saved!&amp;#x27;)
        const descriptionText = body.title
        uploadMedia(descriptionText, fileName)
      }
    })
}

function uploadMedia(descriptionText, fileName) {
  const filePath = path.join(__dirname, `../${fileName}`)
  console.log(`file PATH ${filePath}`)
  bot.postMediaChunked(
    {
      file_path: filePath,
    },
    (err, data, respone) =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(data)
        const params = {
          status: descriptionText,
          media_ids: data.media_id_string,
        }
        postStatus(params)
      }
    }
  )
}

function postStatus(params) {
  bot.post(&amp;#x27;statuses/update&amp;#x27;, params, (err, data, respone) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(&amp;#x27;Status posted!&amp;#x27;)
    }
  })
}

getPhoto()
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;h2 id=&quot;make-a-markov-bot&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#make-a-markov-bot&quot; aria-label=&quot;make a markov bot permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make a Markov bot&lt;/h2&gt;&lt;p&gt;This is pretty neat, again from the &lt;a href=&quot;https://egghead.io/lessons/node-js-make-a-bot-that-sounds-like-you-with-rita-js?series=create-your-own-twitter-bots&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;egghead.io&lt;/a&gt;
series it uses &lt;a href=&quot;https://www.npmjs.com/package/rita&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;rita&lt;/a&gt; natural language toolkit. It also uses
&lt;code&gt;csv-parse&lt;/code&gt; as we’re going to be reading out our Twitter archive to
make the bot sound like us tweeting.&lt;/p&gt;&lt;p&gt;First of all, to set up the &lt;a href=&quot;https://support.twitter.com/articles/20170160&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter archive&lt;/a&gt;, you’ll
need to request your data from the Twitter settings page. You’ll be
emailed a link to download your archive, then when you have downloaded
the archive extract out the &lt;code&gt;tweets.csv&lt;/code&gt; file, we’ll then put that in
it’s own folder, so from the root of your project:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd src
mkdir twitter-archive
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We’ll move our &lt;code&gt;tweets.csv&lt;/code&gt; there to be accessed by the bot we’re
going to go over now.&lt;/p&gt;&lt;p&gt;Use &lt;code&gt;fs&lt;/code&gt; to set up a read stream…&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const filePath = path.join(__dirname, &amp;#x27;./twitter-archive/tweets.csv&amp;#x27;)

const tweetData = fs
  .createReadStream(filePath)
  .pipe(
    csvparse({
      delimiter: &amp;#x27;,&amp;#x27;,
    })
  )
  .on(&amp;#x27;data&amp;#x27;, row =&amp;gt; {
    console.log(row[5])
  })
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When you run this from the console you should get the output from your
Twitter archive.&lt;/p&gt;&lt;p&gt;Now clear out things like &lt;code&gt;@&lt;/code&gt; and &lt;code&gt;RT&lt;/code&gt; to help with the natural
language processing we’ll set up two functions &lt;code&gt;cleanText&lt;/code&gt; and
&lt;code&gt;hasNoStopWords&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;cleanText&lt;/code&gt; will tokenize the text delimiting it on space &lt;code&gt;&amp;#x27; &amp;#x27;&lt;/code&gt; filter
out the stop words then &lt;code&gt;.join(&amp;#x27; &amp;#x27;)&lt;/code&gt; back together with a space and
&lt;code&gt;.trim()&lt;/code&gt; any whitespace that may be at the start of the text.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function cleanText(text) {
  return rita.RiTa.tokenize(text, &amp;#x27; &amp;#x27;)
    .filter(hasNoStopWords)
    .join(&amp;#x27; &amp;#x27;)
    .trim()
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The tokenized text can then be fed into the &lt;code&gt;hasNoStopWords&lt;/code&gt; function
to be sanitized for use in &lt;code&gt;tweetData&lt;/code&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function hasNoStopWords(token) {
  const stopwords = [&amp;#x27;@&amp;#x27;, &amp;#x27;http&amp;#x27;, &amp;#x27;RT&amp;#x27;]
  return stopwords.every(sw =&amp;gt; !token.includes(sw))
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we have the data cleaned we can tweet it, so replace
&lt;code&gt;console.log(row[5])&lt;/code&gt; with
&lt;code&gt;inputText = inputText + &amp;#x27; &amp;#x27; + cleanText(row[5])&lt;/code&gt; then we can use
&lt;code&gt;rita.RiMarkov(3)&lt;/code&gt; the 3 being the number of words to take into
consideration. Then use &lt;code&gt;markov.generateSentences(1)&lt;/code&gt; with 1 being the
number of sentences being generated. We’ll also use &lt;code&gt;.toString()&lt;/code&gt; and
&lt;code&gt;.substring(0, 140)&lt;/code&gt; to truncate the result down to 140 characters.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const tweetData =
  fs.createReadStream(filePath)
  .pipe(csvparse({
    delimiter: &amp;#x27;,&amp;#x27;
  }))
  .on(&amp;#x27;data&amp;#x27;, function (row) {
    inputText = `${inputText} ${cleanText(row[5])}`
  })
  .on(&amp;#x27;end&amp;#x27;, function(){
    const markov = new rita.RiMarkov(3)
    markov.loadText(inputText)
    const sentence = markov.generateSentences(1)
      .toString()
      .substring(0, 140)
  }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can tweet this with the bot using &lt;code&gt;.post(&amp;#x27;statuses/update&amp;#x27;...&lt;/code&gt;
passing in the &lt;code&gt;sentence&lt;/code&gt; variable as the &lt;code&gt;status&lt;/code&gt; logging out when
there is a tweet.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const tweetData =
  fs.createReadStream(filePath)
    .pipe(csvparse({
      delimiter: &amp;#x27;,&amp;#x27;
    }))
    .on(&amp;#x27;data&amp;#x27;, row =&amp;gt; {
      inputText = `${inputText} ${cleanText(row[5])}`
    })
    .on(&amp;#x27;end&amp;#x27;, () =&amp;gt; {
      const markov = new rita.RiMarkov(3)
      markov.loadText(inputText)
      const sentence = markov.generateSentences(1)
        .toString()
        .substring(0, 140)
      bot.post(&amp;#x27;statuses/update&amp;#x27;, {
        status: sentence
      }, (err, data, response) =&amp;gt; {
        if (err) {
          console.log(err)
        } else {
          console.log(&amp;#x27;Markov status tweeted!&amp;#x27;, sentence)
        }
      })
    })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you want your sentences to be closer to the input text you can
increase the words to consider in &lt;code&gt;rita.RiMarkov(6)&lt;/code&gt; and if you want
to make it gibberish then lower the number.&lt;/p&gt;&lt;p&gt;Here’s the completed module:&lt;/p&gt;&lt;details&gt;&lt;summary&gt;Click to expand&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const fs = require(&amp;#x27;fs&amp;#x27;)
const csvparse = require(&amp;#x27;csv-parse&amp;#x27;)
const rita = require(&amp;#x27;rita&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)
const path = require(&amp;#x27;path&amp;#x27;)

let inputText = &amp;#x27;&amp;#x27;

const bot = new Twit(config)

const filePath = path.join(__dirname, &amp;#x27;../twitter-archive/tweets.csv&amp;#x27;)

const tweetData =
  fs.createReadStream(filePath)
    .pipe(csvparse({
      delimiter: &amp;#x27;,&amp;#x27;
    }))
    .on(&amp;#x27;data&amp;#x27;, row =&amp;gt; {
      inputText = `${inputText} ${cleanText(row[5])}`
    })
    .on(&amp;#x27;end&amp;#x27;, () =&amp;gt; {
      const markov = new rita.RiMarkov(10)
      markov.loadText(inputText)
      const sentence = markov.generateSentences(1)
        .toString()
        .substring(0, 140)
      bot.post(&amp;#x27;statuses/update&amp;#x27;, {
        status: sentence
      }, (err, data, response) =&amp;gt; {
        if (err) {
          console.log(err)
        } else {
          console.log(&amp;#x27;Markov status tweeted!&amp;#x27;, sentence)
        }
      })
    })
}

function hasNoStopWords(token) {
  const stopwords = [&amp;#x27;@&amp;#x27;, &amp;#x27;http&amp;#x27;, &amp;#x27;RT&amp;#x27;]
  return stopwords.every(sw =&amp;gt; !token.includes(sw))
}

function cleanText(text) {
  return rita.RiTa.tokenize(text, &amp;#x27; &amp;#x27;)
    .filter(hasNoStopWords)
    .join(&amp;#x27; &amp;#x27;)
    .trim()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;h2 id=&quot;retrieve-and-tweet-data-from-google-sheets&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#retrieve-and-tweet-data-from-google-sheets&quot; aria-label=&quot;retrieve and tweet data from google sheets permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Retrieve and Tweet data from Google sheets&lt;/h2&gt;&lt;p&gt;If you want to tweet a list of links you can use
&lt;a href=&quot;https://www.npmjs.com/package/tabletop&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;tabletop&lt;/code&gt;&lt;/a&gt; to work though the list, in this example
again from &lt;a href=&quot;https://egghead.io/lessons/node-js-retrieve-and-tweet-information-from-google-spreadsheets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;egghead.io&lt;/a&gt; we’ll go through a list of
links.&lt;/p&gt;&lt;p&gt;So, set up the bot and require &lt;code&gt;tabletop&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)
const Tabletop = require(&amp;#x27;tabletop&amp;#x27;)

const bot = new Twit(config)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On your &lt;a href=&quot;sheets.google.com&quot;&gt;&lt;code&gt;Google spreadsheet&lt;/code&gt;&lt;/a&gt; you’ll need to have a
header defined and then add your links, we’ll use the following for an
example:&lt;/p&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;links&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://www.freecodecamp.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.freecodecamp.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://github.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://www.reddit.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.reddit.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://twitter.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://twitter.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Now from Google sheets we can select ‘File’&amp;gt;‘Publish to the web’ and
copy the link that is generated we can use that in table top.&lt;/p&gt;&lt;p&gt;Now init Table top with three parameters, &lt;code&gt;key:&lt;/code&gt; which is the
spreadsheet URL, a &lt;code&gt;callback:&lt;/code&gt; function to get the data and
&lt;code&gt;simpleSheet:&lt;/code&gt; which is &lt;code&gt;true&lt;/code&gt; if you only have one sheet, like in our
example here:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const spreadsheetUrl =
  &amp;#x27;https://docs.google.com/spreadsheets/d/1842GC9JS9qDWHc-9leZoEn9Q_-jcPUcuDvIqd_MMPZQ/pubhtml&amp;#x27;

Tabletop.init({
  key: spreadsheetUrl,
  callback(data, tabletop) {
    console.log(data)
  },
  simpleSheet: true,
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Running the bot now should give output like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ node index.js
[ { &amp;#x27;links&amp;#x27;: &amp;#x27;https://www.freecodecamp.com&amp;#x27; },
  { &amp;#x27;links&amp;#x27;: &amp;#x27;https://github.com&amp;#x27; },
  { &amp;#x27;links&amp;#x27;: &amp;#x27;https://www.reddit.com&amp;#x27; },
  { &amp;#x27;links&amp;#x27;: &amp;#x27;https://twitter.com&amp;#x27; } ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now we can tweet them using &lt;code&gt;.post(&amp;#x27;statuses/update&amp;#x27;,...&lt;/code&gt; with a
&lt;code&gt;forEach&lt;/code&gt; on the &lt;code&gt;data&lt;/code&gt; that is returned in the callback:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;Tabletop.init({
  key: spreadsheetUrl,
  callback(data, tabletop) {
    data.forEach(d =&amp;gt; {
      const status = `${d.links} a link from a Google spreadsheet`
      bot.post(
        &amp;#x27;statuses/update&amp;#x27;,
        {
          status,
        },
        (err, response, data) =&amp;gt; {
          if (err) {
            console.log(err)
          } else {
            console.log(&amp;#x27;Post success!&amp;#x27;)
          }
        }
      )
    })
  },
  simpleSheet: true,
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that &lt;code&gt;${d.links}&lt;/code&gt; is the header name we use in the Google
spreadsheet, I tried using skeleton and camel case and both returned
errors so I went with a single name header on the spreadsheet.&lt;/p&gt;&lt;p&gt;The completed code here:&lt;/p&gt;&lt;details&gt;&lt;summary&gt;Click to expand&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)
const Tabletop = require(&amp;#x27;tabletop&amp;#x27;)

const bot = new Twit(config)

const spreadsheetUrl =
  &amp;#x27;https://docs.google.com/spreadsheets/d/1842GC9JS9qDWHc-9leZoEn9Q_-jcPUcuDvIqd_MMPZQ/pubhtml&amp;#x27;

Tabletop.init({
  key: spreadsheetUrl,
  callback(data, tabletop) {
    data.forEach(d =&amp;gt; {
      const status = `${d.links} a link from a Google spreadsheet`
      console.log(status)
      bot.post(
        &amp;#x27;statuses/update&amp;#x27;,
        {
          status,
        },
        (err, response, data) =&amp;gt; {
          if (err) {
            console.log(err)
          } else {
            console.log(&amp;#x27;Post success!&amp;#x27;)
          }
        }
      )
    })
  },
  simpleSheet: true,
})
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;h2 id=&quot;putting-it-all-together&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#putting-it-all-together&quot; aria-label=&quot;putting it all together permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Putting it all together&lt;/h2&gt;&lt;p&gt;Ok, so those examples were good n’ all but we haven’t really got a bot
out of this have we? I mean you run it from the terminal and that’s it
done, we want to be able to kick off the bot and leave it to do its
thing.&lt;/p&gt;&lt;p&gt;One way I have found to do this is to use &lt;code&gt;setInterval&lt;/code&gt; which will
kick off events from the main &lt;code&gt;bot.js&lt;/code&gt; module, so let’s try this:&lt;/p&gt;&lt;p&gt;Take the example we did to tweet a picture and add it to it’s own
module, so from the root directory of our project:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd src
touch picture-bot.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Take the example code from that and paste it into the new module, then
we’re going to make the following changes, to &lt;code&gt;getPhoto&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const getPhoto = () =&amp;gt; {
  const parameters = {
    url: &amp;#x27;https://api.nasa.gov/planetary/apod&amp;#x27;,
    qs: {
      api_key: process.env.NASA_KEY,
    },
    encoding: &amp;#x27;binary&amp;#x27;,
  }
  request.get(parameters, (err, respone, body) =&amp;gt; {
    body = JSON.parse(body)
    saveFile(body, &amp;#x27;nasa.jpg&amp;#x27;)
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then at the bottom of the module add:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = getPhoto
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now we can call the &lt;code&gt;getPhoto&lt;/code&gt; function from the &lt;code&gt;picture-bot.js&lt;/code&gt;
module in our &lt;code&gt;bot.js&lt;/code&gt; module, our &lt;code&gt;bot.js&lt;/code&gt; module should look
something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const picture = require(&amp;#x27;./picture-bot&amp;#x27;)

picture()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That’s it, two lines of code, try running that from the terminal now:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn start
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We should get some output like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn start v0.23.4
$ node index.js
Media saved!
file PATH C:\Users\path\to\project\tweebot-play\nasa.jpg
{ media_id: 863020197799764000,
  media_id_string: &amp;#x27;863020197799763968&amp;#x27;,
  size: 371664,
  expires_after_secs: 86400,
  image: { image_type: &amp;#x27;image/jpeg&amp;#x27;, w: 954, h: 944 } }
Status posted!
Done in 9.89s.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, so thats the picture of the day done, but it has run once and
completed we need to put it on an interval with &lt;code&gt;setInterval&lt;/code&gt; which we
need to pass two options to, the function it’s going to call and the
timeout value.&lt;/p&gt;&lt;p&gt;The picture updates every 24 hours so that will be how many
milliseconds in 24 hours [8.64e+7] I don’t even 🤷‍&lt;/p&gt;&lt;p&gt;I work it out like this, 1000 &lt;em&gt; 60 = 1 minute, so 1000 &lt;/em&gt; 60 &lt;em&gt; 60 &lt;/em&gt; 24
so for now let’s add that directly into the &lt;code&gt;setInterval&lt;/code&gt; function:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const picture = require(&amp;#x27;./picture-bot&amp;#x27;)

picture()
setInterval(picture, 1000 * 60 * 60 * 24)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cool, that’s a bot that will post the NASA image of the day every 24
hours!&lt;/p&gt;&lt;p&gt;Let’s keep going, now let’s add some randomness in with the Markov
bot, like we did in the picture of the day example, let’s create a new
module for the Markov bot and add all the code in there from the
previous example, so from the terminal:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd src
touch markov-bot.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then copy pasta the markov bot example into the new module, then we’re
going to make the following changes:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const tweetData = () =&amp;gt; {
  fs.createReadStream(filePath)
    .pipe(
      csvparse({
        delimiter: &amp;#x27;,&amp;#x27;,
      })
    )
    .on(&amp;#x27;data&amp;#x27;, row =&amp;gt; {
      inputText = `${inputText} ${cleanText(row[5])}`
    })
    .on(&amp;#x27;end&amp;#x27;, () =&amp;gt; {
      const markov = new rita.RiMarkov(10)
      markov.loadText(inputText).toString().substring(0, 140)
      const sentence = markov.generateSentences(1)
      bot.post(
        &amp;#x27;statuses/update&amp;#x27;,
        {
          status: sentence,
        },
        (err, data, response) =&amp;gt; {
          if (err) {
            console.log(err)
          } else {
            console.log(&amp;#x27;Markov status tweeted!&amp;#x27;, sentence)
          }
        }
      )
    })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then at the bottom of the module add:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = tweetData
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, same again as with the picture bot example we’re going to add the
&lt;code&gt;tweetData&lt;/code&gt; export from &lt;code&gt;markov-bot.js&lt;/code&gt; to our &lt;code&gt;bot.js&lt;/code&gt; module, which
should now look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const picture = require(&amp;#x27;./picture-bot&amp;#x27;)
const markov = require(&amp;#x27;./markov-bot&amp;#x27;)

picture()
setInterval(picture, 1000 * 60 * 60 * 24)

markov()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s make the Markov bot tweet at random intervals between 5 minutes
and 3 hours&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const picture = require(&amp;#x27;./picture-bot&amp;#x27;)
const markov = require(&amp;#x27;./markov-bot&amp;#x27;)

picture()
setInterval(picture, 1000 * 60 * 60 * 24)

const markovInterval = (Math.floor(Math.random() * 180) + 1) * 1000
markov()
setInterval(markov, markovInterval)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Allrighty! Picture bot, Markov bot, done 👍&lt;/p&gt;&lt;p&gt;Do the same with the link bot? Ok, same as before, you get the idea
now, right?&lt;/p&gt;&lt;p&gt;Create a new file in the &lt;code&gt;src&lt;/code&gt; folder for link bot:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;touch link-bot.js
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Copy pasta the code from the link bot example into the new module,
like this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const link = () =&amp;gt; {
  Tabletop.init({
    key: spreadsheetUrl,
    callback(data, tabletop) {
      data.forEach(d =&amp;gt; {
        const status = `${d.links} a link from a Google spreadsheet`
        console.log(status)
        bot.post(
          &amp;#x27;statuses/update&amp;#x27;,
          {
            status,
          },
          (err, response, data) =&amp;gt; {
            if (err) {
              console.log(err)
            } else {
              console.log(&amp;#x27;Post success!&amp;#x27;)
            }
          }
        )
      })
    },
    simpleSheet: true,
  })
}

module.exports = link
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we can call it from the bot, so it should look something like
this:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const picture = require(&amp;#x27;./picture-bot&amp;#x27;)
const markov = require(&amp;#x27;./markov-bot&amp;#x27;)
const link = require(&amp;#x27;./link-bot&amp;#x27;)

picture()
setInterval(picture, 1000 * 60 * 60 * 24)

const markovInterval = (Math.floor(Math.random() * 180) + 1) * 1000
markov()
setInterval(markov, markovInterval)

link()
setInterval(link, 1000 * 60 * 60 * 24)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok? Cool 👍😎&lt;/p&gt;&lt;p&gt;We can now leave the bot running to do its thing!!&lt;/p&gt;&lt;h2 id=&quot;deploy-to-now&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#deploy-to-now&quot; aria-label=&quot;deploy to now permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deploy to now&lt;/h2&gt;&lt;p&gt;Right, we have a bot that does a few things but it’s on our
development environment, so it can’t stay there forever, well it could
but it’d be pretty impcratcical. Let’s put our bot on a server
somewhere to do it’s thing.&lt;/p&gt;&lt;p&gt;To do this we’re going to be using &lt;a href=&quot;https://zeit.co/now&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;now&lt;/a&gt;, &lt;code&gt;now&lt;/code&gt; allows for simple
deployments from the CLI if you’re not fimailiar with now then take a
quick look at the &lt;a href=&quot;https://zeit.co/now&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt; in these examples we’re going
to be using the &lt;code&gt;now-cli&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;There’s a few things we need to do in order to get our bot ready to go
on &lt;a href=&quot;https://zeit.co/now&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;now&lt;/a&gt;, let’s list them quickly and then go into detail.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Signup and install now-cli&lt;/li&gt;&lt;li&gt;Add now settings + .npmignore file&lt;/li&gt;&lt;li&gt;Add .env variables as secrets&lt;/li&gt;&lt;li&gt;Add npm deploy script&lt;/li&gt;&lt;li&gt;Re jig picture-bot.js&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Ready? Let’s do this! 💪&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Signup and install now-cli&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Fist up let’s signup for &lt;a href=&quot;https://zeit.co/login&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;zeit&lt;/a&gt; ▲ create an account and
authenticate, then we can install the CLI.&lt;/p&gt;&lt;p&gt;Install &lt;code&gt;now&lt;/code&gt; globally on our machine so you can use it everywhere, to
install the &lt;code&gt;now-cli&lt;/code&gt; from the terminal enter:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install -g now
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once it’s completed login with:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now --login
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first time you run &lt;code&gt;now&lt;/code&gt;, it’ll ask for your email address in
order to identify you. Go to the email account to supplied when
sigining up an click on the email sent to you from &lt;code&gt;now&lt;/code&gt;, and you’ll
be logged in automatically.&lt;/p&gt;&lt;p&gt;If you need to switch the account or re-authenticate, run the same
command again.&lt;/p&gt;&lt;p&gt;You can always check out the &lt;a href=&quot;https://zeit.co/docs/getting-started/installing-now#cli-with-npm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;now-cli&lt;/a&gt;
documentation for more information along with the &lt;a href=&quot;https://zeit.co/docs/getting-started/your-first-deployments#deploying-node&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;your first
deployment&lt;/a&gt; guide.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Add now settings&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Ok, so that’s signup and install sorted, we can now configure the bot
for deploying to &lt;code&gt;now&lt;/code&gt;. First up let’s add the &lt;code&gt;now&lt;/code&gt; settings to our
&lt;code&gt;package.json&lt;/code&gt; file, I’ve put it in between my &lt;code&gt;npm&lt;/code&gt; scripts and the
author name in my &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node index.js&amp;quot;
  },
  &amp;quot;now&amp;quot;: {
    &amp;quot;alias&amp;quot;: &amp;quot;my-awesome-alias&amp;quot;,
    &amp;quot;files&amp;quot;: [
      &amp;quot;src&amp;quot;,
      &amp;quot;index.js&amp;quot;
    ]
  },
  &amp;quot;author&amp;quot;: &amp;quot;Scott Spence&amp;quot;,
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This was a source of major confusion for me so I’m hoping I can save
you the pain I went through trying to configure this, all the relevant
documentation is there you just need to put it all together 😎&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If you find anything in here that doesn’t make sense or is just
outright wrong then please &lt;a href=&quot;https://github.com/spences10/twitter-bot-playground/issues/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;log an issue&lt;/a&gt; or create a
pull request 👍&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The now settings &lt;code&gt;alias&lt;/code&gt; is to give your deployment a shothand name
over the auto generated URL that &lt;code&gt;now&lt;/code&gt; creates, the &lt;code&gt;files&lt;/code&gt; section
covers what we want to include in the depoloyment to &lt;code&gt;now&lt;/code&gt; we’ll go
over the file structure shortly. Basically what is included in the
&lt;code&gt;files&lt;/code&gt; array is all that get pused up to the now servers.&lt;/p&gt;&lt;p&gt;All good so for?&lt;/p&gt;&lt;p&gt;Ok, now we need to add a &lt;code&gt;.npmignore&lt;/code&gt; file in the root of the project
and add the following line to it:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;!tweets.csv
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;tweets.csv&lt;/code&gt; needs to go up to the &lt;code&gt;now&lt;/code&gt; server to be used by the
bot, but we previously included it in our &lt;code&gt;.gitignore&lt;/code&gt; which is what
&lt;code&gt;now&lt;/code&gt; uses to build your project when it’s being loaded to the server.
So this means that the file isn’t going to get loaded unless we add
the &lt;code&gt;.npmignore&lt;/code&gt; to not ignore the &lt;code&gt;tweets.csv&lt;/code&gt; 😅&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Add .env variables as secrets&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Ok, our super duper secret Twitter keys will need to be stored as
&lt;code&gt;secrets&lt;/code&gt; in &lt;code&gt;now&lt;/code&gt; this is a pretty neat feature where you can define
anything as a secret and reference it as an alias with &lt;code&gt;now&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Let’s start, so the syntax is &lt;code&gt;now secrets add my-secret &amp;quot;my value&amp;quot;&lt;/code&gt;
so for our &lt;code&gt;.env&lt;/code&gt; keys add them all in giving them a descriptive [but
short!] name.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;You will not need to wrap your “my value” in quotes but the
documentation does say “when in doubt, wrap your value in quotes”&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Ok, so from the terminal &lt;code&gt;now secrets ls&lt;/code&gt; should list out your
&lt;code&gt;secrets&lt;/code&gt; you just created:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ now secrets ls
&amp;gt; 5 secrets found under spences10 [1s]

                            id  name                   created
  sec_xxxxxxxxxxZpLDxxxxxxxxxx  ds-twit-key            23h ago
  sec_xxxxxxxxxxTE5Kxxxxxxxxxx  ds-twit-secret         23h ago
  sec_xxxxxxxxxxNorlxxxxxxxxxx  ds-twit-access         23h ago
  sec_xxxxxxxxxxMe1Cxxxxxxxxxx  ds-twit-access-secret  23h ago
  sec_xxxxxxxxxxMJ2jxxxxxxxxxx  nasa-key               23h ago
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Add npm deploy script&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Now we have our secrets defined we can create a deployment script to
deploy to &lt;code&gt;now&lt;/code&gt;, so in our &lt;code&gt;package.json&lt;/code&gt; let’s add an additional
script:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;node index.js&amp;quot;,
    &amp;quot;deploy&amp;quot;: &amp;quot;now -e CONSUMER_KEY=@ds-twit-key
        -e CONSUMER_SECRET=@ds-twit-secret -e ACCESS_TOKEN=@ds-twit-access
        -e ACCESS_TOKEN_SECRET=@ds-twit-access-secret -e NASA_KEY=@nasa-key&amp;quot;
  },
  &amp;quot;now&amp;quot;: {
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let’s go over what we have added there, &lt;code&gt;deploy&lt;/code&gt; will run the &lt;code&gt;now&lt;/code&gt;
command and pass it all our environment &lt;code&gt;-e&lt;/code&gt; variables and the
associated &lt;code&gt;secret&lt;/code&gt; value, if we break it down into separate lines it
will be a bit clearer:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;now
-e CONSUMER_KEY=@ds-twit-key
-e CONSUMER_SECRET=@ds-twit-secret
-e ACCESS_TOKEN=@ds-twit-access
-e ACCESS_TOKEN_SECRET=@ds-twit-access-secret
-e NASA_KEY=@nasa-key
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Re jig picture-bot.js&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Ok, because &lt;code&gt;now&lt;/code&gt; deployments are &lt;a href=&quot;https://blog.codeship.com/immutable-deployments/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;immutable&lt;/a&gt; it
means that there’s no write access to the disk where we want to save
our NASA photo of the day, so to get around that we need to use the
&lt;code&gt;/tmp&lt;/code&gt; file location.&lt;/p&gt;&lt;p&gt;Shout out to &lt;a href=&quot;https://github.com/timneutkens&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@Tim&lt;/a&gt; from &lt;code&gt;zeit&lt;/code&gt; for helping me out with this!&lt;/p&gt;&lt;p&gt;In the &lt;code&gt;picture-bot.js&lt;/code&gt; module add the following two lines to the top
of the module:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const os = require(&amp;#x27;os&amp;#x27;)
const tmpDir = os.tmpdir()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Those two lines give us the &lt;code&gt;temp&lt;/code&gt; directory of the operating system,
so if like me you’re on Windows it will work as well as if you are on
another stsyem like a linux based system, which is what &lt;code&gt;now&lt;/code&gt; is. In
our &lt;code&gt;saveFile&lt;/code&gt; function we’re going to use &lt;code&gt;tmpDir&lt;/code&gt; to save our file.&lt;/p&gt;&lt;p&gt;We’ve taken out the &lt;code&gt;nasa.jpg&lt;/code&gt; from the &lt;code&gt;getPhoto&lt;/code&gt; function as we can
define that information in the &lt;code&gt;saveFile&lt;/code&gt; function, the NASA potd is
not just a &lt;code&gt;&amp;#x27;jpeg&lt;/code&gt; some items posted there are videos as well. We we
can define the type with a &lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ternary function&lt;/a&gt; off of the
&lt;code&gt;body&lt;/code&gt; being passed in, this will send a tweet with a link to the
video:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function saveFile(body) {
  const fileName =
    body.media_type === &amp;#x27;image/jpeg&amp;#x27; ? &amp;#x27;nasa.jpg&amp;#x27; : &amp;#x27;nasa.mp4&amp;#x27;
  const filePath = path.join(tmpDir + `/${fileName}`)

  console.log(`saveFile: file PATH ${filePath}`)
  if (fileName === &amp;#x27;nasa.mp4&amp;#x27;) {
    // tweet the link
    const params = {
      status: &amp;#x27;NASA video link: &amp;#x27; + body.url,
    }
    postStatus(params)
    return
  }
  const file = fs.createWriteStream(filePath)

  request(body)
    .pipe(file)
    .on(&amp;#x27;close&amp;#x27;, err =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(&amp;#x27;Media saved!&amp;#x27;)
        const descriptionText = body.title
        uploadMedia(descriptionText, filePath)
      }
    })
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The completed code here:&lt;/p&gt;&lt;details&gt;&lt;summary&gt;Click to expand&lt;/summary&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twit = require(&amp;#x27;twit&amp;#x27;)
const request = require(&amp;#x27;request&amp;#x27;)
const fs = require(&amp;#x27;fs&amp;#x27;)
const config = require(&amp;#x27;./config&amp;#x27;)
const path = require(&amp;#x27;path&amp;#x27;)

const bot = new Twit(config)

const os = require(&amp;#x27;os&amp;#x27;)
const tmpDir = os.tmpdir()

const getPhoto = () =&amp;gt; {
  const parameters = {
    url: &amp;#x27;https://api.nasa.gov/planetary/apod&amp;#x27;,
    qs: {
      api_key: process.env.NASA_KEY,
    },
    encoding: &amp;#x27;binary&amp;#x27;,
  }
  request.get(parameters, (err, respone, body) =&amp;gt; {
    body = JSON.parse(body)
    saveFile(body)
  })
}

function saveFile(body) {
  const fileName =
    body.media_type === &amp;#x27;image/jpeg&amp;#x27; ? &amp;#x27;nasa.jpg&amp;#x27; : &amp;#x27;nasa.mp4&amp;#x27;
  const filePath = path.join(tmpDir + `/${fileName}`)

  console.log(`saveFile: file PATH ${filePath}`)
  if (fileName === &amp;#x27;nasa.mp4&amp;#x27;) {
    // tweet the link
    const params = {
      status: &amp;#x27;NASA video link: &amp;#x27; + body.url,
    }
    postStatus(params)
    return
  }
  const file = fs.createWriteStream(filePath)

  request(body)
    .pipe(file)
    .on(&amp;#x27;close&amp;#x27;, err =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(&amp;#x27;Media saved!&amp;#x27;)
        const descriptionText = body.title
        uploadMedia(descriptionText, filePath)
      }
    })
}

function uploadMedia(descriptionText, fileName) {
  console.log(`uploadMedia: file PATH ${fileName}`)
  bot.postMediaChunked(
    {
      file_path: fileName,
    },
    (err, data, respone) =&amp;gt; {
      if (err) {
        console.log(err)
      } else {
        console.log(data)
        const params = {
          status: descriptionText,
          media_ids: data.media_id_string,
        }
        postStatus(params)
      }
    }
  )
}

function postStatus(params) {
  bot.post(&amp;#x27;statuses/update&amp;#x27;, params, (err, data, respone) =&amp;gt; {
    if (err) {
      console.log(err)
    } else {
      console.log(&amp;#x27;Status posted!&amp;#x27;)
    }
  })
}

module.exports = getPhoto
&lt;/code&gt;&lt;/pre&gt;&lt;/details&gt;&lt;p&gt;Ok, thats it! We’re ready to deploy to &lt;code&gt;now&lt;/code&gt;!🚀&lt;/p&gt;&lt;p&gt;So from the terminal we call our deployment script we defined earlier:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;yarn deploy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You will get some output:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;λ yarn deploy
yarn deploy v0.24.4
$ now -e CONSUMER_KEY=@ds-twit-key -e CONSUMER_SECRET=@ds-twit-secret
    -e ACCESS_TOKEN=@ds-twit-access  -e ACCESS_TOKEN_SECRET=@ds-twit-access-secret
    -e NASA_KEY=@nasa-key
&amp;gt; Deploying ~\gitrepos\tweebot-play under spences10
&amp;gt; Using Node.js 7.10.0 (default)
&amp;gt; Ready! https://twee-bot-play-rapjuiuddx.now.sh (copied to clipboard) [5s]
&amp;gt; Upload [====================] 100% 0.0s
&amp;gt; Sync complete (1.54kB) [2s]
&amp;gt; Initializing…
&amp;gt; Building
&amp;gt; ▲ npm install
&amp;gt; ⧗ Installing:
&amp;gt;  ‣ csv-parse@^1.2.0
&amp;gt;  ‣ dotenv@^4.0.0
&amp;gt;  ‣ rita@^1.1.63
&amp;gt;  ‣ tabletop@^1.5.2
&amp;gt;  ‣ twit@^2.2.5
&amp;gt; ✓ Installed 106 modules [3s]
&amp;gt; ▲ npm start
&amp;gt; &amp;gt; tweet-bot-playground@1.0.0 start /home/nowuser/src
&amp;gt; &amp;gt; node index.js
&amp;gt; saveFile: file PATH /tmp/nasa.jpg
&amp;gt; Media saved!
&amp;gt; uploadMedia: file PATH /tmp/nasa.jpg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Woot! You have your bot deployed! 🙌&lt;/p&gt;&lt;p&gt;If you click on the link produced you will be able to inspect the bot
as it is on &lt;code&gt;now&lt;/code&gt; there’s also a handy logs section on the page where
you can check for output. 👍&lt;/p&gt;&lt;h2 id=&quot;contributing&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#contributing&quot; aria-label=&quot;contributing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Contributing&lt;/h2&gt;&lt;p&gt;Please fork this repository and contribute back using pull requests.&lt;/p&gt;&lt;p&gt;Any contributions, large or small, major features, bug fixes and
integration tests are welcomed and appreciated but will be thoroughly
reviewed and discussed.&lt;/p&gt;&lt;h2 id=&quot;license&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#license&quot; aria-label=&quot;license permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;License&lt;/h2&gt;&lt;p&gt;MIT License&lt;/p&gt;&lt;p&gt;Copyright (c) 2017, Scott Spence. All rights reserved.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Code life balance]]></title><description><![CDATA[Just some rationalisation of what I'm currently doing. Recently I have decided that I'm going to improve my current skill
set. To do this I…]]></description><link>https://scottspence.com/2017/03/15/code-life-balance/</link><guid isPermaLink="false">https://scottspence.com/2017/03/15/code-life-balance/</guid><pubDate>Wed, 15 Mar 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just some rationalisation of what I’m currently doing.&lt;/p&gt;&lt;p&gt;Recently I have decided that I’m going to improve my current skill
set. To do this I’m studying with freeCodeCamp for a full stack
developer certification, I’m also trying to learn as much as I can
about the languages that come with that HTML, CSS and JavaScript as
well as getting familiar with everything else in between like Git and
GitHub, development environments like Cloud9 and services like Digital
Ocean and AWS.&lt;/p&gt;&lt;p&gt;To do all of this I need time and being married with a young family
and having a full time job my time is at a premium.&lt;/p&gt;&lt;p&gt;The freeCodeCamp curriculum is 2,080 hours, so let’s break that down
quickly.&lt;/p&gt;&lt;p&gt;Like I said with a full time job and a family spare time is precious,
I have taken to getting up most mornings around an hour earlier than
usual @~05:30 that gave me around 1.5 hours before having to get ready
for the day taking kids to school and the daily commute. In the
evenings I usually have from 20:00–22:00 but this is full of
interruptions so you could probably condense it down to about 1.5
hours again.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:500px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/41380a3023ea4dbe9e3e83abd7631843/41099/gollum.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:86.25%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;344\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20344\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20172v172h200a15564%2015564%200%2000168-2v-2l1-3c0-2%200-2-1%200s-2%202-4%202c-3-1-4-4-2-6s2-3%200-3l-2%201v7c1%201%201%201-1%201s-2-1-2-3c0-1%200-2-1-1l-1%202c1%201-4%203-6%202s-1-4%202-4c2-1%202-1-1-1s-3%201-3%203l-1%202c-2%200-2-1-2-2v-4l-1%201v3l-3%202c-3%200-3%200-3-3%200-4-1-3-2%200v4l-1-2v-3l-1-1c-1%200-2%201-2%203l-1%202-1-4c1-3%200-3%2010-3%204%200%204-1-1-1l-2-1h-2c-2%200-2%200-1-1v-6c-1-1-2-3-3-10%200-5%203-8%208-8%202%200%203%200%202-1v-2c1-2%201-2-1-5l-3-4-1-3c-2-1-2-2-1-6l-1-7v-3l-2-3-3-3-2-4-4-8-1-8c-1-1-11-2-12-1s1%207%202%207l1%202c0%201%200%202%201%201%201-2%202-1%202%202l3%206%202%204%202%203c2%202%201%204-1%204-1-1-2%200-3%201-2%202-3%201-3-2l-1-3-2-1h-1c-3%202-2%200%200-4v-3l-1-1-3-3h-3l-4-1v-10c0-7%200-8-2-9-1%200-2-1-1-2%200-2%200-2-1-1-1%202-5-2-6-6l-1-5c-2-4-1-12%201-14l1-4%201-4c1-1%200-3-2-3s-2%200-2-14c0-8%200-10-2-12l-2-6c-1-3-4-4-6-2-1%201-1%201%201%201s2%200%201%201l-1%204c0%203%200%203-7%203-9%200-10-1-11-5%200-3%200-3%202-3l2-1%202-2%202%201c0%202%203%200%204-3s1-13-1-16c-1-2%200-7%202-7s4%202%204%204c0%205%202%209%204%208l3-1c0-1%203%201%203%203l2%201c6-3%207-2%208%206%200%209-3%2015-6%2014-1%200-2%200-2%202-2%205-1%207%202%207%201%200%202%200%201%201l2%204%202%203c-1%201%201%204%202%204l2-2%202-2%201-2h-1c-2%201-2%201-3-1-1-4-1-6%201-7l2-3c1-2%201-2%201%201v4c2%200%202%207%201%2010l-3%209-2%205%201%205%204%2016c1%204%204%206%204%202%200-1%201-2%203-2l2-1c0-2%202-1%203%203l2%203%204%207%205%208%204%207%204%207%2012%2021c5%2011%2024%2038%2029%2043l2%202-1-4v-7l-1-5v-1l4-3%203-4h2l-1-11-1-4-1-4c-1%201-2-1-2-5-1-6-3-11-5-10l-3-6-5-11-1-4-2-3c-1-2-1-2%201-4%203-3%205-7%203-9v-3c-2%200-2-1-2-2l1-2h1l1%202%202%202%201-2-1-2-2-2-1-1c-2%200-1-3%201-5s2-2%201-4c-1-3-1-4%201-2%201%202%201%202%201-1l-2-5c-2-1-3-3-3-5s-1-3-2-3l-2-2v-8c1%200%209%208%2012%2013l5%206%209%2016c5%209%2012%2046%209%2048v2c1%200%202%2022%200%2022l-2-6c0-3-2-3-3%201l-1%207c-1%204-1%205%201%209l3%205%201%202%201%201%201%2014%201-157V0H258l2%203%204%204c1%201%201%201-1%201l-4%201-2-1-2-3-2-3c0-2-1-2-4-2-4%200-4%200-4%203l-1%202h-1l1%202c2%200-1%202-4%202l-2%202c-1%203-1-3-1-8%200-3%200-3-6-3-4%200-5%200-6%202l-1%201-1-1-2-1h-3l-3-1-2%201%202%203%202%204-2%201-3%202c-1%202-2%200-2-3l-2-3-1-2c-1-2-2-3-5-3-5%200-5%200-4%202l2%202%201%202c1%202%200%202-4%202a53%2053%200%2000-8%201l-2%202v3l-2-2c-4-4-24-5-26-2h-2l-5-1c-6-1-6-2%200-2l7-1%205-2%204-1-2-1-2-1-46-1C75%200%2073%200%2072%202c-1%203-3%203-2%200%201-2%201-2-1-2s-2%201-3%204c0%203-1%204-3%205-4%201-4%201-3-2%203-7%204-7-29-7H0v172M220%2011c-7%202-8%204-8%2020%200%2017%200%2019%207%2021%209%203%2017-2%2017-11v-5h-10v5c-1%205-1%206-3%205V18c1-1%203%202%203%207v4h10v-5c0-10-6-15-16-13M62%2012v17l1%2019v4h9V30l2%209c2%2013%202%2013%205%2013h3l2-12%202-12v24h9V12h-6c-8-1-8-1-9%208%200%209-1%209-3%200v-7l-7-1h-8m37%200l3%2012c2%209%203%2013%203%2020v8h10v-7c0-6%201-11%204-20l3-13h-9l-1%207-2%207-1-6-1-7-3-1-4-1-2%201m90%201v20l1%2019h18v-8h-8v-4c0-5%200-5%204-5%203%200%203%200%203-4s0-4-3-4c-4%200-4%200-4-3%200-4%200-4%204-4%203%200%203%200%203-4v-4h-9l-9%201m70%200l-2%203-1%2015v15l3%203c5%206%2016%205%2020-2%202-4%201-27-1-31-3-6-14-7-19-3m27-1v35c3%206%2015%208%2020%203l3-3V12h-10l-1%2017-1%2017c-1-1-2-5-2-17V12h-9m30%201c-3%203-3%204-3%208%200%206%201%209%208%2013%205%204%206%206%206%2010-1%203-3%202-4-3%200-3-1-4-5-4h-5v4c0%208%206%2013%2014%2012%206-1%209-4%2010-9%201-7-1-11-8-16-6-4-6-4-6-7%201-4%202-4%203%200%200%203%200%203%205%203h5v-3l-1-5c-2-5-15-7-19-3M135%2032v20h10v-8c0-8%200-8%202-8%207%200%2010-2%2010-8%201-14%200-16-13-16h-9v20m26%200v20h11v-9l1-9c1%201%202%204%202%209v9h10v-9c0-8-1-9-2-11-2-1-2-1-1-2%204-2%203-15-1-17l-11-1h-9v20m80%200v20h10V12h-10v20m41%2016c-1%203%200%207%204%2011l3%204%202%204c2%203%203%2010%202%2012-2%202-2%209-1%209l1%202-1%201-1%203v3l-1%202%202%201c2%200%203%202%203%205l2%205%202%206c0%202%205%205%206%203%200-2%202-1%202%200l1%202-1-13-1-6c1-4%201-6-1-8v-7l-1-4c-2%200-2-1-1-1%202-1%202-6-1-10l-2-10c-1-6-1-6-6-6-6-1-10-4-11-8h-1m-72%205c0%202-1%202-10%202l-9%201%202%204c3%203%203%204%202%204-2%201-2%201-3-1l-2-3c-2%200-2%202%200%204%209%2010%2011%2013%208%2016-1%201-3%205-2%206%200%202%202%203%202%201h7l-5%2015c-1%201-1%202%201%202l-1%203-2%204-1%201v4c1%203%200%205-3%205-2%200-2%201-2%203%200%203%200%203-2%203-4%200-4%202-1%202l2%202-3%201c-1-1-2%200-2%201-1%202%200%203%201%203l1%205c-1%206%201%2015%203%2017v6l3%204v2l2-1%203-4a108%20108%200%20011-10l1-3v-1l-1-3c0-2%205-8%207-8l1-2%201-2c3%200%2011-5%2011-7v-1c2%200%206-4%206-5l1-2c1%200%202-1%201-2l1-1%201-1%202-5%202-6%201-4c3-3%203-18%200-25l-3-9-1-5-2-4c-2-3-2-3-5-3-4%200-11-2-12-4-1-1-1-1-2%201m47%201l3%204%203%205%201%201%203%204%202%205c2%201%203%206%204%2011v3l1%206c0%206%202%2011%206%2012%202%200%203%202%201%204l1%203c2%201%203%203%203%205%200%203%202%206%203%204l3-3c3-1%203-7%201-10l-3-5-3-6c-2-2-3-7-3-13%200-2-1-3-2-3l-1-2h2c0-2-1-4-3-3l-3-3a3106%203106%200%2000-1-4c3%201%202%200-1-3l-2-3c0-2-5-7-8-8a85%2085%200%2001-7-1m-12%207l3%207%204%205%203%206%202%204%201%206%202%206c2%201%202%202%201%204-1%201%200%202%201%204l1%205c-1%202%200%203%202%202l1-2c0-2%200-2%202%201l7%209c2%200%201-4%200-6-2-2-4-9-5-16%200-5-1-7-2-7h-3v-3c2%200%201-3-1-4-5%200-5-1-3-3l3-2-3-3-4-8c-5-12-4-11-10-11h-5l3%206m-76%203l-1%201v2c-1%202-1%202%202%202%207%200%2013%205%2011%207l-2%203c0%202%203%201%203-1%201-2%205%201%205%204s3%202%205%200c3-6-1-13-9-16-5-3-14-3-14-2m-49%2013v15l-1%203a257%20257%200%20014%2025l5%205c0%201%204%203%207%203%204%200%206-3%204-4-2%200-2-1-1-1v-2l3-2c3-1%206-4%206-5l-3-2-3-3-3-5-4-11c-2-6-3-8-5-9l-4-4c-2-4-4-6-5-3m-45%205c-1%201%200%203%203%203%204%200%2011%203%2011%204l-2%203c-2%201-3%204-2%204%202%200%209-5%209-6%200-4-6-8-12-8h-7m233%2052c0%202-1%203-3%201l-2-1h-2l-3-1c-2%201-3%201-2%202l1%202%202%201c2%200%202%201%202%202l1%204c1%201%206%201%207-1v-10c-1-1-1%200-1%201m-154%2014c-3%203-3%205%201%203%203-2%206%201%203%203h-6c0-2-3-2-4%200%200%202-9%206-11%206h-1l-1%203c0%202%200%202%2020%202%2012%200%2017%201%2018%202%202%201%203%201%203-1l1-3v-4l-2-3c1-1-4-6-6-6h-1l-6-1-6-2-2%201m158%204c-2%205-2%206-3%203%200-3-2-3-3%200l-2%202c-2%200-3%201-3%209l1%202h6c1%201%202%200%204-7%203-7%203-9%202-11-1-1-1-1-2%202m-154%2034c-7%205-9%208-5%208l3%202c1%203%202%203%207%204%202%200%203%201%203%203%201%207%207%208%209%201v-6l-1-2h-1c0%202-3%201-3%200l-1-2-3-7-5-3-3%202m-31%2053c-6%204-15%2015-15%2018l-2%204c-3%203-9%2019-9%2020%201%201%203-3%207-12%207-16%2022-31%2022-23%200%203%202%203%207-1%205-5%206-6%203-7l-3-1c-3-2-6-1-10%202m-1%2023v6h9v49h16v-49h9v-12h-34v6m39%2025v30h16v-61h-16v31m23%200v30h7c6%200%206%200%206-2a836%20836%200%20000-35l6%2036%205%201c6%200%205%202%208-19l2-15%201%2016v18h13v-61h-10c-11%200-10-2-12%2015l-2%2011-2-10-2-13v-3h-20v31m57-1v30l13%201h14v-12h-11l-1-7v-6h10v-12h-10v-6l1-5%205-1h5v-12h-26v30m77-5c-2%204-2%209%200%2010l1%203%202%203v2c-2%202-1%204%202%204l1%201h2c3%200%203-4%200-5-2%200-2%200%200-2s2-2%200-5c0-2-2-4-3-5l-1-4c1-5-2-7-4-2M73%20298l-1%204-1%204-1%209c0%208-2%2013-6%2013v1l2%201c3%200%203%204%200%207-2%202-2%202%200%203v1l4%201c8%201%2012%200%2011-1v-14c0-12-2-25-3-21l-1%206c0%204-1%205-2%203v-8c1-8%200-11-2-9\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/41380a3023ea4dbe9e3e83abd7631843/60a22/gollum.webp 160w,/static/41380a3023ea4dbe9e3e83abd7631843/4c812/gollum.webp 320w,/static/41380a3023ea4dbe9e3e83abd7631843/b0a15/gollum.webp 500w&quot; sizes=&quot;(max-width: 500px) 100vw, 500px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/41380a3023ea4dbe9e3e83abd7631843/0913d/gollum.jpg 160w,/static/41380a3023ea4dbe9e3e83abd7631843/cb69c/gollum.jpg 320w,/static/41380a3023ea4dbe9e3e83abd7631843/41099/gollum.jpg 500w&quot; sizes=&quot;(max-width: 500px) 100vw, 500px&quot; type=&quot;image/jpeg&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/41380a3023ea4dbe9e3e83abd7631843/41099/gollum.jpg&quot; alt=&quot;gollum&quot; title=&quot;gollum&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;So.&lt;/p&gt;&lt;p&gt;Let say I’m lazer focussed and relentlessly do 1 hour in the morning
and 3 hours in the evening 4 hours a day 2,080/4 so 520 days? That’s
1.4 years, wow! Ok now let’s be a bit more realistic, 1 hour in the
morning 1 hour in the evening, 1040 = 2.85 nearly 3 years, oh!&lt;/p&gt;&lt;p&gt;Ok, so what if I was a full time student? 8 hours a day 1,080/8=135
three months! How much do I want this then?&lt;/p&gt;&lt;p&gt;Currently I’m managing 45min-1hour in the AM then 1hr-2hrs in the PM
so at very best I could manage to finish the curriculum in a year,
that’s if I finish the curriculum at all, I read loads of posts about
how people have managed to get full time developer jobs after only
doing half of the freeCodeCamp curriculum this doesn’t help. It’s
great to see success stories and inspiring to read but a lot of the
time this adds unnecessary pressure on yourself.&lt;/p&gt;&lt;p&gt;My family are great and understand the situation but your
relationships are priority and they can get a bit strained when all
you’re doing is staring at a monitor whenever you get a spare 45
minutes.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/95e36e149f280ce66a0f04667dbbd265/e5166/fccbreakdown.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:56.25%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;225\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20225\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%20113v112h401V0H0v113m271-73c-5%206-5%207-1%207%203-1%203-1%203%202%201%203%202%203%203%200%200-3%203-5%203-2s3%205%206%205c4-2%205-12%201-15-3-3-6-1-7%204-2%205-3%204-3-2v-4l-5%205m-139%204v8l5-1c7%200%2010-3%209-10%200-3-4-5-9-5h-5v8m159-6c-3%205%200%2014%204%2014s6-8%204-13c-2-4-6-4-8-1m-95%2011l1%208%202-3%201-2c2%200%206-3%206-6s-3-5-7-5h-3v8M95%2069l1%208h5c4%200%205%200%207-3%205-6%201-12-8-12h-5v7m185-5c-2%202-2%2010%201%2012%205%206%2011-6%206-13-2-1-5-1-7%201m11%200c-3%205%200%2014%204%2014s6-8%204-13c-2-4-6-4-8-1m-169%202c-1%202%200%2010%202%2011h5l4%201c3-1%203-1%203-5l-1-5h-7l-1-1-2-1h-3m160%2022c-4%203-4%2012-1%2015%204%202%206%200%207-4%202-7-2-14-6-11m12%200c-4%201-6%2010-2%2014s8%200%208-6-2-9-6-8M43%2095v8h5c5-1%207-4%205-6l-2-5c0-3%200-4-4-4h-4v7m89%201v7h5c8%200%2012-5%208-11-1-3-3-4-9-4h-4v8m64%205c0%207%202%2010%203%205l1-2c2%201%206-3%206-5%200-4-3-6-7-6h-3v8M83%20121c0%209%202%2011%202%202l1-5%204%205c6%208%208%208%207-1%200-10-2-12-2-3v6l-3-4-8-8-1%208m187-7c-2%202-2%203-2%205v4c-2%203%201%206%205%206h4v-7c0-6%200-7-2-8h-5m10%201c-2%202-2%2010%200%2013l4%201c5%200%207-8%203-13-3-4-4-4-7-1m12%200c-4%204-2%2014%203%2014%204%200%205-3%205-9-1-6-4-9-8-5m-53%203c-1%201-2%202-5%201-2%200-4%200-5%202-3%204%201%209%205%208%204%200%204-2%200-2-2%200-2-1-2-3s0-3%203-3l4%201c-1%206%200%207%206%207%208%200%2010-2%205-6-2-2-2-2%200-2l2-1c0-2-6-1-6%200-1%201%200%203%202%204l2%203h-4c-5%200-5%200-5-3%200-2%201-3%202-3l1-1-1-1-2-1h-2m-116%209c1%207%202%2010%203%205%200-2%201-3%202-3%203%200%205-2%205-5s-2-5-7-5h-3v8m12-3l1%205c1%200%202-1%201-2v-3c1-4%206-4%206%200%200%203%202%205%206%205s7-5%203-8c-1-2-7-3-8-1h-1l-5-1c-3%200-3%200-3%205m89%2023c0%206%200%208%202%208l1-3c0-2%201-3%203-3%205-2%205-9%201-9h-5c-2-1-2%200-2%207m57-7c-1%201-2%203-2%208l1%207h3c4%200%207-3%205-6v-4c2-4-4-8-7-5m11%201c-5%205-1%2016%204%2014%206-1%205-16-1-16l-3%202m-38%2012l1%207%202-2c0-2%201-3%202-3%207%200%207-10-1-10h-4v8M41%20168l164%201%20164-1H41m39%2015c-3%202-3%2010%200%2012%203%204%207%202%208-5%200-7-4-11-8-7m11%200c-2%201-2%203-1%205v8h8v-14c-2-1-6-1-7%201m11%200c-3%204-2%2013%202%2014%204%200%206-3%206-8%200-7-5-11-8-6m128-1v3c1%201%200%201-1%201-3%200-6%203-6%206s3%205%207%205h3v-7c0-7-1-11-3-8m23%205c-2%201-2%202-2%205v5c-2%202%200%205%204%205%205%200%207-4%202-6l-2-2c2%200%204-2%204-5%201-3%201-3-2-3l-4%201m37%200c-2%201-1%2015%200%2015l1-3c0-2%201-2%202-2%204%200%207-5%205-8-2-2-7-4-8-2\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/95e36e149f280ce66a0f04667dbbd265/60a22/fccbreakdown.webp 160w,/static/95e36e149f280ce66a0f04667dbbd265/4c812/fccbreakdown.webp 320w,/static/95e36e149f280ce66a0f04667dbbd265/0ba47/fccbreakdown.webp 640w,/static/95e36e149f280ce66a0f04667dbbd265/e46b2/fccbreakdown.webp 960w,/static/95e36e149f280ce66a0f04667dbbd265/92f8c/fccbreakdown.webp 1200w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/95e36e149f280ce66a0f04667dbbd265/0913d/fccbreakdown.jpg 160w,/static/95e36e149f280ce66a0f04667dbbd265/cb69c/fccbreakdown.jpg 320w,/static/95e36e149f280ce66a0f04667dbbd265/c08c5/fccbreakdown.jpg 640w,/static/95e36e149f280ce66a0f04667dbbd265/6a068/fccbreakdown.jpg 960w,/static/95e36e149f280ce66a0f04667dbbd265/e5166/fccbreakdown.jpg 1200w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/jpeg&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/95e36e149f280ce66a0f04667dbbd265/c08c5/fccbreakdown.jpg&quot; alt=&quot;fccbreakdown&quot; title=&quot;fccbreakdown&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;[#100DaysOfCode] has been a great tool for me with regard to building
good habits and something that has both distracted me from purely
concentrating on my freeCodeCamp and also accelerated my GitHub open
source interactions. Since starting the challenge I have contributed
to several GitHub projects and made some of my own.&lt;/p&gt;&lt;p&gt;I have also created a personal goals repo like the one Una Kravets has
on her GitHub this will be what I’ll use going forward after I have
completed the 100 Days of Code challenge, I’m not going to take part
in the 301 days of code challenge as I’d like to go on holiday without
having to think about any coding for a week or so.&lt;/p&gt;&lt;p&gt;I often think if I am a proper developer and what am I doing all this
for, then I take this handy little quiz:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://amiarealdeveloper.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://amiarealdeveloper.com/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We shall see where I am in a years time 👍&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Easily set up your own Twitter bot]]></title><description><![CDATA[Want to get set up with your very own Twitter bot quickly and easily,
with this guide you can be set up in under 30 minutes. But first, why…]]></description><link>https://scottspence.com/2017/01/28/twitter-bot-bootstrap/</link><guid isPermaLink="false">https://scottspence.com/2017/01/28/twitter-bot-bootstrap/</guid><pubDate>Sat, 28 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Want to get set up with your very own Twitter bot quickly and easily,
with this guide you can be set up in under 30 minutes. But first, why
should you want to build a Twitter bot?&lt;/p&gt;&lt;p&gt;There are some really useful Twitter bots out there that do some
pretty cool stuff they don’t all spam current hashtags and follow
users relentlessly.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./rust-bird.jpg&quot;/&gt;&lt;/p&gt;&lt;p&gt;Take the &lt;a href=&quot;https://twitter.com/twisst&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twisst ISS alerts&lt;/a&gt; bot that
sends you a DM when the international space station (ISS) will be
visible at your location.&lt;/p&gt;&lt;p&gt;Or there’s public service bots like the
&lt;a href=&quot;https://twitter.com/earthquakeBot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Earthquake Robot&lt;/a&gt; that tweets
about any earthquake greater than 5.0 on the Richter Scale as they
happen.&lt;/p&gt;&lt;p&gt;There’s &lt;a href=&quot;https://twitter.com/GoogleFacts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GoogleFacts&lt;/a&gt; which tweets
facts from Google, just remember to fact check these facts on, err,
Google?&lt;/p&gt;&lt;p&gt;And of course a robot that tweets poetry,
&lt;a href=&quot;https://twitter.com/poem_exe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;poem.exe&lt;/a&gt; along with one that will
retweet your tweets that also happen to be an
&lt;a href=&quot;https://twitter.com/accidental575&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Accidental Haiku&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Bots can be used for many purposes in my case I have used it to
enhance my &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@spences10&lt;/a&gt; account by
liking and re-tweeting subjects I have an interest in, in the case of
the &lt;a href=&quot;https://medium.freecodecamp.com/start-2017-with-the-100daysofcode-improved-and-updated-18ce604b237b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#100DaysOfCode&lt;/a&gt; community challenge there is a
community bot which congratulates you on starting
&lt;a href=&quot;https://twitter.com/hashtag/100DaysOfCode?src=hash&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#100DaysOfCode&lt;/a&gt; and again on completing it, these are
specific responses to tweets with keywords for a community, there is
also sentiment detection used under the &lt;a href=&quot;https://twitter.com/hashtag/100DaysOfCode?src=hash&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#100DaysOfCode&lt;/a&gt;
community hashtag where the bot will tweet you with encouraging words
if you post a tweet with negative sentiment.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./100daysofcodetweet.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;One question I’m asked in job interviews quite often is “what do you
get out of working with technology?“. My answer, “I like to automate
stuff, repetitive tasks to save me time so I can concentrate on other
stuff, I like the fact I have saved myself some time”&lt;/p&gt;&lt;p&gt;In the case of my @spences10 bot it’s usually an opener for a
conversation with another user that follows me, so the bot can
initiate the conversation and I can carry on from where the bot left
off.&lt;/p&gt;&lt;p&gt;Bearing this in mind the bot is only as good as the person that has
programmed it, whilst researching this post I found a really good
resource for bots in general,
&lt;a href=&quot;https://botwiki.org/bot-ethics&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;botwiki.org&lt;/a&gt; has a bot ethics
section:&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;Please don’t make annoying bots&lt;ul&gt;&lt;li&gt;An annoying bot mentions or follows people who didn’t ask for it&lt;/li&gt;&lt;li&gt;Posts common or trending hashtags&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Please don’t make abusive or harassing robots&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;So, ready to get started?&lt;/p&gt;&lt;p&gt;Ok, let’s do this!!&lt;/p&gt;&lt;hr/&gt;&lt;h1 id=&quot;twitter-bot-bootstrap&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#twitter-bot-bootstrap&quot; aria-label=&quot;twitter bot bootstrap permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Twitter bot bootstrap&lt;/h1&gt;&lt;p&gt;This is a bootstrap for setting up a Twitter bot with Node.js using
the &lt;code&gt;twit&lt;/code&gt; library, the bot will like and re-tweet what you specify
when configuring it, it will also reply to followers with a selection
of canned responses.&lt;/p&gt;&lt;p&gt;As a primer for this there are the great posts by
&lt;a href=&quot;https://twitter.com/amanhimself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amanhimself&lt;/a&gt; on making your own
twitter bot and this is an expansion on that with further detail on
configuration on Heroku&lt;/p&gt;&lt;h2 id=&quot;what-youll-need&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-youll-need&quot; aria-label=&quot;what youll need permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What you’ll need&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Twitter account [Duh!]&lt;/li&gt;&lt;li&gt;Development environment with Node.js and NPM&lt;ul&gt;&lt;li&gt;c9 account&lt;/li&gt;&lt;li&gt;Node.js&lt;/li&gt;&lt;li&gt;NPM&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Heroku account&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;setup-twitter&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#setup-twitter&quot; aria-label=&quot;setup twitter permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup twitter&lt;/h2&gt;&lt;p&gt;Set up an application on the Twitter account you want to favorite and
retweet from via:
&lt;a href=&quot;https://apps.twitter.com/app/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://apps.twitter.com/app/new&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As an example I’ll configure the old
&lt;a href=&quot;https://twitter.com/droidscott&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@DroidScott&lt;/a&gt; twitter account I have
so you can follow along.&lt;/p&gt;&lt;p&gt;Straight forward enough for the twitter application, just make sure
you add your phone number to your Twitter account before clicking the
&lt;strong&gt;Create your Twitter application&lt;/strong&gt; button.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./twitter-application-setup.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;You should now be in the ‘Application Management’ section where you
will need to take a note of your keys, you should have your ‘Consumer
Key (API Key)’ and ‘Consumer Secret (API Secret)’ already available.&lt;/p&gt;&lt;p&gt;You’ll need to scroll to the bottom of the page and click the &lt;strong&gt;Create
my access token&lt;/strong&gt; to get the ‘Access Token’ and ‘Access Token Secret’
take note of all four of them you’ll need them when setting up the
bot.&lt;/p&gt;&lt;h2 id=&quot;setup-development-environment&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#setup-development-environment&quot; aria-label=&quot;setup development environment permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup development environment&lt;/h2&gt;&lt;p&gt;For this I’m just going to say use &lt;a href=&quot;https://c9.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cloud9&lt;/a&gt; as you can
be up and running in minutes with one of the pre made Node.js
environments.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./c9-node-env.png&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;set-up-the-bot&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#set-up-the-bot&quot; aria-label=&quot;set up the bot permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Set up the bot&lt;/h2&gt;&lt;p&gt;In the project tree delete the example project files of &lt;code&gt;client&lt;/code&gt;,
&lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;README.md&lt;/code&gt; and &lt;code&gt;server.js&lt;/code&gt; you’ll not need them, you
can leve them there if you desire.&lt;/p&gt;&lt;p&gt;In your new Node.js c9 environment go to the terminal and enter:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git clone https://github.com/spences10/twitter-bot-bootstrap
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;project-structure&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#project-structure&quot; aria-label=&quot;project structure permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Project structure&lt;/h2&gt;&lt;p&gt;The environment project tree should look something like this.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./project-structure.png&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;node-dependencies&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#node-dependencies&quot; aria-label=&quot;node dependencies permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Node dependencies&lt;/h2&gt;&lt;p&gt;Before configuring the bot we’ll need to install some dependencies,
from the terminal enter:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ npm install --save twit
$ npm install --save unique-random-array
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then cd into your new folder &lt;code&gt;cd tw*&lt;/code&gt; will move you to
&lt;code&gt;:~/workspace/twitter-bot-bootstrap (master) $&lt;/code&gt; form here you can
configure the bot, from the terminal enter.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ npm init
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will configure the &lt;code&gt;package.json&lt;/code&gt; file with your details as
desired, just keep hitting return if you’re happy with the defaults.&lt;/p&gt;&lt;p&gt;Onto the Twitter keys, now you’ll need to add these to the &lt;code&gt;config.js&lt;/code&gt;
file and you can then add some keywords into the &lt;code&gt;strings.js&lt;/code&gt; file for
what you want to search on.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./c9-strings-config.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Then add the username of the Twitter account you are using to the
&lt;code&gt;tweetNow&lt;/code&gt; function in the &lt;code&gt;bot.js&lt;/code&gt; file, this will ensure your bot
doesn’t reply to itself when it has been followed by a user.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./c9-strings-config1.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;This step isn’t strictly necessary if this account isn’t going to be
following any users.&lt;/p&gt;&lt;p&gt;That should be it, go to the terminal and enter &lt;code&gt;npm start&lt;/code&gt; you should
get some output:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./bot-output.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Check the Twitter account:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./twitter-account.png&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;heroku&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heroku&quot; aria-label=&quot;heroku permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heroku&lt;/h2&gt;&lt;p&gt;Cool, now we have a bot that we can test on our dev environment but we
can’t leave it there, we’ll need to deploy it to Heroku.&lt;/p&gt;&lt;p&gt;If you haven’t done so already set up a
&lt;a href=&quot;https://signup.heroku.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Heroku account&lt;/a&gt; then select &lt;strong&gt;Create a new
app&lt;/strong&gt; from the dropdown box top right of your dashboard, in the next
screen name the app it if you want, then click &lt;strong&gt;Create App&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./heroku-create-new-app.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;You’ll be presented with your app dashboard and instructions for the
deployment method.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./heroku-deploy.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Your app name should be displayed on the top of your dashboard, you’ll
need this when logging in with the Heroku CLI.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./heroku-app-name.png&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;heroku-cli&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heroku-cli&quot; aria-label=&quot;heroku cli permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heroku CLI&lt;/h2&gt;&lt;p&gt;We’re going to deploy initially via the Heroku Command Line Interface
&lt;em&gt;CLI&lt;/em&gt;&lt;/p&gt;&lt;p&gt;From your c9 environment terminal, log into Heroku [it should be
installed by default]&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ heroku login
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Enter your credentials.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ cd twitter-bot-bootstrap
$ git init
$ heroku git:remote -a your-heroku-app-name
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Deploy your application.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git add .
$ git commit -am &amp;#x27;make it better&amp;#x27;
$ git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You should get build output on the terminal.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./heroku-build.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Then check the output with.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ heroku logs -t
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All good? Cool! :sunglasses:&lt;/p&gt;&lt;h2 id=&quot;heroku-variables&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heroku-variables&quot; aria-label=&quot;heroku variables permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heroku variables&lt;/h2&gt;&lt;p&gt;Now that we have our bot on Heroku we can use environment variables to
store our Twitter keys so that if in the future we want to add our
code to GitHub we don’t have to exclude the &lt;code&gt;config.js&lt;/code&gt; file or add
our keys publicly.&lt;/p&gt;&lt;p&gt;If you take a look at the &lt;code&gt;config.js&lt;/code&gt; file of this project you’ll see
there’s several lines commented output:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;module.exports = {
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  access_token: process.env.ACCESS_TOKEN,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET,
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All you need to do is go to the console of your Heroku app and select
the ‘Settings’ sections and add in your Twitter keys, click the
‘Reveal Config Vars’ button and add in the variables with their
corresponding values.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;CONSUMER_KEY
CONSUMER_SECRET
ACCESS_TOKEN
ACCESS_TOKEN_SECRET
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once you have the Heroku vars set up then you can un-comment the
&lt;code&gt;module.exports&lt;/code&gt; section in the &lt;code&gt;config.js&lt;/code&gt; file on your development
environment and you’re ready to deploy to Heroku again without your
Twitter keys.&lt;/p&gt;&lt;p&gt;Your console commands should look something like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git add .
$ git commit -m &amp;#x27;add environment variables&amp;#x27;
$ git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then you can check the Heroku logs again with.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ heroku logs -t
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You should now have a bot you can leave to do its thing forever more,
or until you decide you want to change the search criteria :smile:&lt;/p&gt;&lt;h2 id=&quot;heroku-deployment-via-github&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heroku-deployment-via-github&quot; aria-label=&quot;heroku deployment via github permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heroku deployment via GitHub&lt;/h2&gt;&lt;p&gt;You can also deploy your app by connecting to GitHub and deploy
automatically to Heroku each time your master branch is updated on
GitHub, this is straight forward enough.&lt;/p&gt;&lt;p&gt;Go to the ‘Deploy’ dashboard on Heroku, select GitHub as the
deployment method if you have connected your GitHub account to your
Heroku account then you can search for the repository so if you forked
this repo then you can just enter &lt;code&gt;twitter-bot-bootstrap&lt;/code&gt; and
&lt;strong&gt;Search&lt;/strong&gt; you can then click the &lt;strong&gt;Connect&lt;/strong&gt; button, you can then
auto deploy from GitHub.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./heroku-connect-github.png&quot;/&gt;&lt;/p&gt;&lt;h2 id=&quot;heroku-troubleshooting&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heroku-troubleshooting&quot; aria-label=&quot;heroku troubleshooting permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heroku troubleshooting&lt;/h2&gt;&lt;p&gt;What do you mean it crashed!?&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;./heroku-crash.png&quot;/&gt;&lt;/p&gt;&lt;p&gt;Ok, I found that sometimes the &lt;code&gt;worker&lt;/code&gt; is set as &lt;code&gt;web&lt;/code&gt; and it crashes
out, try setting the &lt;code&gt;worker&lt;/code&gt; again with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ heroku ps:scale worker=0
$ heroku ps:scale worker=1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Other useful Heroku commands I use:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ heroku restart
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;By default you can only push your master branch if you are working on
a development branch i.e. &lt;code&gt;dev&lt;/code&gt; branch and you want to test on Heroku
then you can use:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git push heroku dev:master
&lt;/code&gt;&lt;/pre&gt;&lt;hr/&gt;&lt;h2 id=&quot;contributing&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#contributing&quot; aria-label=&quot;contributing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Contributing&lt;/h2&gt;&lt;p&gt;Please fork this repository and contribute back using pull requests.&lt;/p&gt;&lt;p&gt;Any contributions, large or small, major features, bugfixes and
integration tests are welcomed and appreciated but will be thoroughly
reviewed and discussed.&lt;/p&gt;&lt;hr/&gt;&lt;h3 id=&quot;links&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#links&quot; aria-label=&quot;links permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Links&lt;/h3&gt;&lt;p&gt;Credit for the inspiration for this should go to
&lt;a href=&quot;https://twitter.com/amanhimself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amanhimself&lt;/a&gt; and his posts on
creating your own twitter bot.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://hackernoon.com/create-a-simple-twitter-bot-with-node-js-5b14eb006c08#.flysreo60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;create-a-simple-twitter-bot-with-node-js&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://chatbotslife.com/how-to-make-a-twitter-bot-with-nodejs-d5cb04fdbf97#.h5ah8dq5n&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;how-to-make-a-twitter-bot-with-nodejs&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://medium.com/@spences10/twitter-mctwitbot-4d15cd005dc0#.dp9q5f427&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twitter-mctwitbot&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/amandeepmittal/awesome-twitter-bots&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;awesome-twitter-bots&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Other posts detailing useful Twitter bots.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.brit.co/twitter-bots-to-follow/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.brit.co/twitter-bots-to-follow&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.hongkiat.com/blog/using-twitter-bots/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.hongkiat.com/using-twitter-bots&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Git and GitHub]]></title><description><![CDATA[I know why Linus called it that now! If you're reading this there's a good chance you know at least the
basics of Git but if like me and you…]]></description><link>https://scottspence.com/2017/01/05/git-and-github/</link><guid isPermaLink="false">https://scottspence.com/2017/01/05/git-and-github/</guid><pubDate>Thu, 05 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I know why Linus called it that now!&lt;/p&gt;&lt;p&gt;If you’re reading this there’s a good chance you know at least the
basics of Git but if like me and you are the only person making
changes to your repos then there’s a good chance that you just use
&lt;code&gt;git push origin master&lt;/code&gt; to move your changes from your local machine
to GitHub, this is not best practice.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/536686b63ad7e966fc425ed4c67c2ddc/ac4a7/git-logo.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:100%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;400\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20400\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M99%2037c-2%205-4%2014-4%2019v4h5c9%200%2018-5%2022-13%203-7%203-8-5-10-10-3-17-3-18%200m175%200l-6%202%202%204c3%2010%2012%2017%2022%2017h5v-6l-3-12-2-7h-6l-12%202m40%2091c-5%203-15%205-36%208h-4l3%204c7%208%2010%2016%2010%2026%200%2017-4%2029-12%2038l-19%2011-29%204c-17%201-52%201-63-1-38-6-54-21-54-51%200-11%202-17%208-25l4-5-8-1c-11-1-25-4-30-6s-5-2-6%200c-1%204%203%2037%205%2044%201%202-1%202-22%202-26%201-59%204-61%207a378%20378%200%200169-5h16l1%203%202%204h-9a345%20345%200%2000-66%2012c19-5%2043-8%2065-9l11-1%203%205%206%208%203%204-5%201c-6%201-7%201-7-1l-2-7-1-5-2%202c-7%206-5%2019%204%2024%204%202%206%209%204%2013-3%205%201%2023%206%2031l3%204-2%204c-2%203-2%206-2%209%202%2015%2025%2019%2031%205l2-5h10c12-1%2011-1%2011%203%200%206%200%206-3%206l-7%202-9%202-11%201-12%203c-4%200-6%201-8%203l-10%206-11%205-14%206-15%206-11%205c-10%203-14%209-8%2012l24%207c5%200%2014%203%2021%205l13%204c2%200%204%202%203%203l-8%202-7%202h6l12%201%2024%204c16%201%2018%202%2023%204%204%202%206%203%2015%204l10%201%209%201a549%20549%200%2000140-19c6%200%2016-4%2022-8%205-4%209-5%2017-6a54%2054%200%200023-8c2%200%202-3-2-7-3-3-4-4-9-4l-14-5-11-4-6-2c-2-2-9-4-15-6l-10-4c3-2-5-6-17-7-6-1-10-2-18-6-10-5-11-5-17-5l-10%202h-2v-15c0-22-3-31-11-40l-3-4%2010-2c29-4%2051-16%2062-33l4-7h10a410%20410%200%200178%2011%20345%20345%200%2000-88-13l1-4%201-3h16a395%20395%200%200172%205c2-1%201-1-2-2l-15-1a409%20409%200%2000-70-6c3-8%205-46%203-47l-2%201m-168%2024c-4%201-8%2010-8%2016%200%2016%2015%2024%2022%2011%207-14-2-32-14-27m97%202c-9%209-5%2029%205%2032%2014%202%2020-24%208-33-4-3-9-3-13%201m-134%2059c-3%203-1%2010%203%2014%202%202%203%207%201%2010l1%208c1%206%201%206%206%208%207%203%2017%203%2026%201l6-2%203-7c1-4%204-9%207-12l4-5h-6c-14-2-36-9-45-14l-4-3-2%202m88%2057c0%209%200%2016%201%2015%200-3%203-2%203%201%201%201%201-5%201-15%200-17-1-18-3-18h-2v17m-24-10c-2%204-2%207-2%2013%200%209%200%209%203%209l2%201v-27l-3%204m50%2010v15h5v-10c0-8%200-11-2-15l-3-4v14m-117%206c-1%203%200%204%202%207%205%205%2012%202%2012-5l-1-1-7-2-5-3-1%204\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/536686b63ad7e966fc425ed4c67c2ddc/60a22/git-logo.webp 160w,/static/536686b63ad7e966fc425ed4c67c2ddc/4c812/git-logo.webp 320w,/static/536686b63ad7e966fc425ed4c67c2ddc/0ba47/git-logo.webp 640w,/static/536686b63ad7e966fc425ed4c67c2ddc/c1a89/git-logo.webp 896w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/536686b63ad7e966fc425ed4c67c2ddc/0913d/git-logo.jpg 160w,/static/536686b63ad7e966fc425ed4c67c2ddc/cb69c/git-logo.jpg 320w,/static/536686b63ad7e966fc425ed4c67c2ddc/c08c5/git-logo.jpg 640w,/static/536686b63ad7e966fc425ed4c67c2ddc/ac4a7/git-logo.jpg 896w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/jpeg&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/536686b63ad7e966fc425ed4c67c2ddc/c08c5/git-logo.jpg&quot; alt=&quot;image of octocat&quot; title=&quot;image of octocat&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;What if it’s not your repository you want to make changes to? You’ll
need to create a pull request, where you make a copy (fork) of the
repo, make the changes to your copy (fork) then request that the owner
of the original repo pulls your changes into their repo. All super
straight forward, right?&lt;/p&gt;&lt;p&gt;As an example I’m going to document my change to the
&lt;a href=&quot;https://github.com/spences10/awesome-twitter-bots&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;awesome-twitter-bots&lt;/a&gt;
repo that &lt;a href=&quot;https://twitter.com/amanhimself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amanhimself&lt;/a&gt; asked me to
contribute to after I made a Twitter bot with his guides.&lt;/p&gt;&lt;h2 id=&quot;step-1&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#step-1&quot; aria-label=&quot;step 1 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 1&lt;/h2&gt;&lt;p&gt;I will need to fork the repository on GitHub so I can make my changes.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/7898cedb809d19d597af446ca0683bd8/ebf47/fork-a-repo.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:13.750000000000002%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;55\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2055\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M172%2021c-1%202-2%203-4%203s-2%200%200%202l1%205c0%202%200%202%202%201h6c1%201%202%201%201-1l1-4c3-2%202-3%200-3l-4-3-2-2-1%202M26%2023c-2%202-3%203-2%205%204%207%2013%207%2017%200%202-3-4-8-8-8-3%200-5%201-7%203\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/7898cedb809d19d597af446ca0683bd8/60a22/fork-a-repo.webp 160w,/static/7898cedb809d19d597af446ca0683bd8/4c812/fork-a-repo.webp 320w,/static/7898cedb809d19d597af446ca0683bd8/0ba47/fork-a-repo.webp 640w,/static/7898cedb809d19d597af446ca0683bd8/01c7f/fork-a-repo.webp 688w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/7898cedb809d19d597af446ca0683bd8/69538/fork-a-repo.png 160w,/static/7898cedb809d19d597af446ca0683bd8/72799/fork-a-repo.png 320w,/static/7898cedb809d19d597af446ca0683bd8/6af66/fork-a-repo.png 640w,/static/7898cedb809d19d597af446ca0683bd8/ebf47/fork-a-repo.png 688w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/7898cedb809d19d597af446ca0683bd8/6af66/fork-a-repo.png&quot; alt=&quot;fork-a-repo&quot; title=&quot;fork-a-repo&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Then clone my forked repository to where I’m all going to make the
changes on my computer:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git clone https://github.com/spences10/awesome-twitter-bots
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Connect the fork to the Original Repository:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git remote add upstream https://github.com/amandeepmittal/awesome-twitter-bots
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;step-2&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#step-2&quot; aria-label=&quot;step 2 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 2:&lt;/h2&gt;&lt;p&gt;Use &lt;code&gt;git status&lt;/code&gt; to check what branch you are currently on.&lt;/p&gt;&lt;p&gt;Make a (my) branch:&lt;/p&gt;&lt;p&gt;I’m adding the
&lt;a href=&quot;https://spences10.github.io/2017/01/04/twitter-mctwitbot.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter bot&lt;/a&gt;
I made so I’m going to give my branch the same name as my repo&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git branch spences10-twitter-bot
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now change to that branch with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git checkout spences10-twitter-bot
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It should say you have switched to the branch but you can check with
&lt;code&gt;git status&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Add your files &lt;strong&gt;&lt;em&gt;note&lt;/em&gt;&lt;/strong&gt; if you are adding a folder (like I am) just
using &lt;code&gt;git add .&lt;/code&gt; will add the folder as a file (which I learned from
bitter experience), what you will need to do is:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git add spences10-twitter-bot/\\*
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will add the folder and all its contents, I would post my
terminal ‘output of shame’ here as it would take up the whole screen.
So now I have added the folder I need to commit to my local repo with:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git commit -m &amp;#x27;initial commit&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I get the terminal output confirming my files are added, then I
&lt;code&gt;git push&lt;/code&gt; to my branch I checked out earlier:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git push origin spences10-twitter-bot
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A quick check of the repo on GitHub confirms that the files are there
I’m now ready to add a contributor
&lt;a href=&quot;https://github.com/amandeepmittal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amandeepmittal&lt;/a&gt; via the
&lt;a href=&quot;https://github.com/spences10/awesome-twitter-bots/settings/collaboration&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;/settings/collaboration&lt;/a&gt;
section of my repo. I can then copy the invite link and send to Aman,
I’m sure he’ll be thrilled to see it!&lt;/p&gt;&lt;h2 id=&quot;step-3&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#step-3&quot; aria-label=&quot;step 3 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 3&lt;/h2&gt;&lt;p&gt;Visit Aman’s repo and GitHub will have detected that I have pushed a
branch to a fork, from here I can click on the ‘Compare &amp;amp; pull
request’ button.&lt;/p&gt;&lt;p&gt;In the ‘Open a pull request’ page I’ll need to select the my fork and
then my branch, so &lt;code&gt;spences10\awesome-twitter-bots&lt;/code&gt; and my branch
which is &lt;code&gt;spences10-twitter-bot&lt;/code&gt; click the ‘Create pull request’
button.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/3344c43215debf994772b5f1893bc581/54bf4/open-a-pull-request.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:32.49999999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;131\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20131\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M62%2039h-7l-6%201c0%203%2035%203%2036%201h1l16%201c9%200%2016%200%2015-1l-2-2h-1a110%20110%200%2001-29%200h-3l-2%201-14-1h-4m166%201h-1c-1-1-17-1-17%201l4%201a1042%201042%200%200156-2c1-1%201-1-9-1a199%20199%200%2001-30-1c-3%200-4%201-3%202m106%200h-1c-1-1-16-1-16%201l3%201a731%20731%200%200145-2l-3-1h-23l-2-1c-2%200-3%201-3%202M5%2074c-1%203%200%205%201%207%202%201%202%202%201%202l-2%203%201-1h2l3%202c3-1%207-4%205-4-1-1-1-1%201-2s3-4%201-9c0-2-1-2-7-2H5v4\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/3344c43215debf994772b5f1893bc581/60a22/open-a-pull-request.webp 160w,/static/3344c43215debf994772b5f1893bc581/4c812/open-a-pull-request.webp 320w,/static/3344c43215debf994772b5f1893bc581/0ba47/open-a-pull-request.webp 640w,/static/3344c43215debf994772b5f1893bc581/e46b2/open-a-pull-request.webp 960w,/static/3344c43215debf994772b5f1893bc581/aa5f8/open-a-pull-request.webp 1007w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/3344c43215debf994772b5f1893bc581/69538/open-a-pull-request.png 160w,/static/3344c43215debf994772b5f1893bc581/72799/open-a-pull-request.png 320w,/static/3344c43215debf994772b5f1893bc581/6af66/open-a-pull-request.png 640w,/static/3344c43215debf994772b5f1893bc581/d9199/open-a-pull-request.png 960w,/static/3344c43215debf994772b5f1893bc581/54bf4/open-a-pull-request.png 1007w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/3344c43215debf994772b5f1893bc581/6af66/open-a-pull-request.png&quot; alt=&quot;open-a-pull-request&quot; title=&quot;open-a-pull-request&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;The rest is up to the repository owner (Aman) now where he can chose
to merge my changes into his repo.&lt;/p&gt;&lt;hr/&gt;&lt;h3 id=&quot;thats-not-the-end-though&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#thats-not-the-end-though&quot; aria-label=&quot;thats not the end though permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;That’s not the end though&lt;/h3&gt;&lt;p&gt;It turned out that Aman just wanted me to update the
&lt;a href=&quot;https://github.com/amandeepmittal/awesome-twitter-bots/blob/master/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;README.md&lt;/a&gt;
on the repo so my pull request was cancelled :flushed:&lt;/p&gt;&lt;p&gt;This was good though because I had the opportunity to go through the
whole thing again, thus getting more familiar with the process, after
making my changes to my fork it was another pull request [PR] which
was then successfully merged as PR
&lt;a href=&quot;https://github.com/amandeepmittal/awesome-twitter-bots/pull/2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#2&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;resources&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#resources&quot; aria-label=&quot;resources permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources&lt;/h3&gt;&lt;p&gt;A great resource for me was
&lt;a href=&quot;http://jlord.us/git-it/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git-It&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And obviously the &lt;a href=&quot;https://help.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub Help&lt;/a&gt;
documentation.&lt;/p&gt;&lt;h3 id=&quot;2fa&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#2fa&quot; aria-label=&quot;2fa permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2fa&lt;/h3&gt;&lt;p&gt;Another thing to note is if you’re using two factor authentication
you’ll need to add your auth token in as a &lt;code&gt;remote set-url&lt;/code&gt; so you can
push/pull without having to authenticate each time.&lt;/p&gt;&lt;p&gt;&lt;code&gt;git remote set-url origin https://yourgithubuser:your-token@github.com/yourgithubuser/yourrepo.git&lt;/code&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Twitter McTwitBot]]></title><description><![CDATA[I must say this was great to do and a nice little introduction to node
and npm. I got to doing this from finding it on  GitHub  I think I…]]></description><link>https://scottspence.com/2017/01/04/twitter-mctwitbot/</link><guid isPermaLink="false">https://scottspence.com/2017/01/04/twitter-mctwitbot/</guid><pubDate>Wed, 04 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I must say this was great to do and a nice little introduction to node
and npm.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2017/twitter-mctwitbot/twitter-bird.png&quot; alt=&quot;twitter logo&quot;/&gt;&lt;/p&gt;&lt;p&gt;I got to doing this from finding it on &lt;a href=&quot;https://github.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt; I think I was looking
for the Twitter icon in bootstrap whilst working on my &lt;a href=&quot;http://codepen.io/spences10/full/dOaYbP/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Random Quote
Generator&lt;/a&gt; I stumbled across the &lt;a href=&quot;https://github.com/mobeets/twitter-bot-bootstrap&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;twitter-bot-bootstrap&lt;/a&gt; (as you do)
so after stalling with my progress on the freeCodeCamp(🔥) zipline for
a Wikipedia viewer I decided to give the Twitter bot a try and managed
to create it and add it to &lt;a href=&quot;https://heroku.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Heroku&lt;/a&gt; 🎉”&lt;/p&gt;&lt;p&gt;This app didn’t work as well as expected though 😦, so I then decided
to take a look at &lt;a href=&quot;https://twitter.com/amanhimself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amanhimself&lt;/a&gt;’s Twitter bot he had created for the
&lt;a href=&quot;https://medium.freecodecamp.com/start-2017-with-the-100daysofcode-improved-and-updated-18ce604b237b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;#100DaysOfCode&lt;/a&gt; challenge, which I just happen to be taking part in.&lt;/p&gt;&lt;p&gt;So with his great documentation &lt;a href=&quot;https://hackernoon.com/create-a-simple-twitter-bot-with-node-js-5b14eb006c08&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://community.risingstack.com/how-to-make-a-twitter-bot-with-node-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;and here&lt;/a&gt; I managed to cobble
together my own Twitter-bot which I use on my &lt;a href=&quot;https://twitter.com/spences10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@spences10&lt;/a&gt; Twitter
account.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;If you’r wondering about the post name &lt;a href=&quot;https://en.wikipedia.org/wiki/RRS_Sir_David_Attenborough#Boaty_McBoatface_Naming_Controversy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;check here&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;technologies-used&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#technologies-used&quot; aria-label=&quot;technologies used permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Technologies used&lt;/h2&gt;&lt;p&gt;Preamble out of the way, now I can walk through what was used.&lt;/p&gt;&lt;h3 id=&quot;cloud-9&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#cloud-9&quot; aria-label=&quot;cloud 9 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cloud 9&lt;/h3&gt;&lt;p&gt;I love this development environment, I soon became a fan of &lt;a href=&quot;https://c9.io/?redirect=0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;c9&lt;/a&gt; when
trying to install Ruby on my windows machine and then again after
installing Node.js on my computer for the first time.&lt;/p&gt;&lt;h3 id=&quot;nodejs&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#nodejs&quot; aria-label=&quot;nodejs permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Node.js&lt;/h3&gt;&lt;p&gt;I already had this installed on my c9 environment so I just had to
&lt;code&gt;npm install --save twit&lt;/code&gt; then I was up and running&lt;/p&gt;&lt;h3 id=&quot;heroku&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#heroku&quot; aria-label=&quot;heroku permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heroku&lt;/h3&gt;&lt;p&gt;I didn’t really get what Heroku was until I started this project but
once I’d read the guides it was quite straightforward and the &lt;a href=&quot;https://devcenter.heroku.com/articles/heroku-cli&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Heroku
CLI&lt;/a&gt; was already installed on c9 i checked with &lt;code&gt;heroku --version&lt;/code&gt;
before attempting to install it.&lt;/p&gt;&lt;h3 id=&quot;github&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#github&quot; aria-label=&quot;github permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GitHub&lt;/h3&gt;&lt;p&gt;You can deploy straight from your c9 environment to Heroku and there
are loads of other integration tools you can use which I haven’t had
time to look into yet. It’s good practice to have your code on a
repository somewhere and GitHub is widely used.&lt;/p&gt;&lt;h3 id=&quot;twitter&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#twitter&quot; aria-label=&quot;twitter permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Twitter&lt;/h3&gt;&lt;p&gt;You will need to set up a Twitter application from the &lt;a href=&quot;https://apps.twitter.com/app/new&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Twitter dev
portal&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;All of the information above is in addition to the guides given by
&lt;a href=&quot;https://github.com/amandeepmittal&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aman&lt;/a&gt; the stuff I’m going to go through now my experience with
deploying to Heroku, you may want to host the app somewhere different.&lt;/p&gt;&lt;h2 id=&quot;my-approach&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#my-approach&quot; aria-label=&quot;my approach permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Approach&lt;/h2&gt;&lt;p&gt;Use &lt;code&gt;node bot.js&lt;/code&gt; to test locally, in &lt;a href=&quot;https://twitter.com/amanhimself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amanhimself&lt;/a&gt;’s example it will
tweet and favourite straight away then go on a timer.&lt;/p&gt;&lt;p&gt;Deploy to Heroku &lt;code&gt;git push heroku master&lt;/code&gt;&lt;/p&gt;&lt;p&gt;This is after I have added the changes to Git with a commit message
and pushed the changes to my repo, here’s the terminal commands:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ git add .
$ git commit -m &amp;#x27;my detailed commit message&amp;#x27;
$ git push origin master
$ git push heroku master
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The final command will build the app on Heroku for you with output
like this:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2017/twitter-mctwitbot/heroku-build.png&quot; alt=&quot;heroku-build&quot;/&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;I know this isn’t standard practice for GitHub and I am in the
process of understanding how to branch and use Pull Requests so bear
with me 😄&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;The first gotcha for me was the Heroku &lt;code&gt;Procfile&lt;/code&gt; I couldn’t
understand why it kept timing out, this was because it was trying to
run the default &lt;code&gt;web&lt;/code&gt; process instead of the &lt;code&gt;worker&lt;/code&gt; process which is
whats needed for the bot.&lt;/p&gt;&lt;p&gt;After getting the bare bones set up on part 1 I then got to playing
around with the timings and the query strings used by the bot, this is
where things started to go a bit &lt;a href=&quot;https://en.oxforddictionaries.com/definition/us/off-piste&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;off-piste&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2017/twitter-mctwitbot/heroku-error-output.png&quot; alt=&quot;heroku-error-output&quot;/&gt;&lt;/p&gt;&lt;p&gt;For quite a while I couldn’t understand why I was getting so many
errors, with a whole lot of &lt;code&gt;console.log(var)&lt;/code&gt; throughout the code I
came to the conclusion that that the query string I was using:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;var queryString = &amp;#x27;#100DaysOfCode, #GitHub, #VSCode&amp;#x27;;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can get the logs from Heroku when you app is running by typing:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ herouku logs -t
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will give you your logs back from Heroku so you can add all the
debug lines you want in there to determine whats going on.&lt;/p&gt;&lt;p&gt;I was getting the errors pictured so I started to play with the query
string and just using one value at a time which didn’t cause any
errors so I decided to pass one value at a time by adding the Gist
below.&lt;/p&gt;&lt;script src=&quot;https://gist.github.com/spences10/46d9981a805786e7c965cf292b9cb3ae.js&quot;&gt;&lt;/script&gt;&lt;p&gt;This worked, for a while then the same errors started creeping in, I
then noticed that the &lt;code&gt;retweet&lt;/code&gt; and &lt;code&gt;favoriteTweet&lt;/code&gt; were on a timer
but using the same random text from the &lt;code&gt;queryString&lt;/code&gt; which was about
as much use as the previous piece of code as it was a one time
initialisation [or initialization] so the same string was being used
multiple times causing the errors.&lt;/p&gt;&lt;p&gt;So after some head scratching and playing around with the code, [and
tweeting &lt;a href=&quot;https://twitter.com/amanhimself&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@amanhimself&lt;/a&gt; numerous times] Aman suggested that I use the
npm package &lt;a href=&quot;https://www.npmjs.com/package/unique-random-array&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;unique-random-array&lt;/a&gt; to return a random string value from
the string list.&lt;/p&gt;&lt;p&gt;So I added the &lt;code&gt;var&lt;/code&gt; in:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;var uniqueRandomArray = require(&amp;#x27;unique-random-array&amp;#x27;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Built the query string:&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;var queryString = uniqueRandomArray([
  &amp;#x27;100daysofcode&amp;#x27;,
  &amp;#x27;freecodecamp&amp;#x27;,
  &amp;#x27;github&amp;#x27;,
  &amp;#x27;vscode&amp;#x27;,
  &amp;#x27;visual studio code&amp;#x27;,
  &amp;#x27;nodejs&amp;#x27;,
  &amp;#x27;node.js&amp;#x27;,
  &amp;#x27;vuejs&amp;#x27;,
  &amp;#x27;vue.js&amp;#x27;,
  &amp;#x27;inferno_js&amp;#x27;,
  &amp;#x27;inferno.js&amp;#x27;,
  &amp;#x27;jekyll&amp;#x27;,
])
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then just replaced the &lt;code&gt;queryString&lt;/code&gt; string with the &lt;code&gt;queryString()&lt;/code&gt;
method.&lt;/p&gt;&lt;p&gt;Some other things to note that I discovered when playing around with
the bot is the &lt;code&gt;retweet&lt;/code&gt; and &lt;code&gt;favoriteTweet&lt;/code&gt; function &lt;code&gt;params&lt;/code&gt; was the
&lt;code&gt;result_type:&lt;/code&gt; options, here’s my comments copy pasted from the
Twitter dev portal:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;// result_type: options, mixed, recent, popular
// * mixed : Include both popular and real time results in the response.
// * recent : return only the most recent results in the response
// * popular : return only the most popular results in the response.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The next stage for this could be to use the &lt;code&gt;unique-random-array&lt;/code&gt;
package to change that value too.&lt;/p&gt;&lt;p&gt;That’s it for now, I still have a weird bug where if I follow someone
and then someone else follows me the bot decides to tweet back to
itself!&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://now-images-wine.now.sh/2017/twitter-mctwitbot/yes-tweet-yourself.png&quot; alt=&quot;yes-tweet-yourself&quot;/&gt;&lt;/p&gt;&lt;h3 id=&quot;coming-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#coming-up&quot; aria-label=&quot;coming up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Coming up&lt;/h3&gt;&lt;p&gt;More stuff with the &lt;code&gt;.stream()&lt;/code&gt; function, like auto follow back and
better replies.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Starting again with Jekyll]]></title><description><![CDATA[Since setting up this blog I haven't really bothered with Jekyll any
more than just forking Barry Clarke's repo of Jekyll Now and adding…]]></description><link>https://scottspence.com/2016/12/17/starting-again-with-jekyll/</link><guid isPermaLink="false">https://scottspence.com/2016/12/17/starting-again-with-jekyll/</guid><pubDate>Sat, 17 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Since setting up this blog I haven’t really bothered with Jekyll any
more than just forking Barry Clarke’s repo of Jekyll Now and adding
these posts as and when the feeling takes me.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:498px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/9a6784d0e7ab903d7aa9970e804ccaa3/79e1b/jekyll-logo.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:46.25%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;185\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20185\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M354%2019c-2%201%200%204%206%207%2011%205%2019%205%2015%200-4-4-18-9-21-7m26%2016c-2%202-9%2020-25%2062l-24%2062c-3%205-8%208-15%208-4%200-5%200-4%201%204%203%2014%200%2018-4l24-61c26-67%2024-64%2028-68l3-3c0-2-2-1-5%203m-23%2039c-4%203-10%206-17%208-9%203-13%207-18%2020-4%2011-4%2011%200%207l4-2-9%209c-9%209-11%2012-6%208%204-3%204-3-2%2012s-6%2018-1%2024c3%202%205%203%208%203%209%200%209%200%2027-48a1572%201572%200%200014-41\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/9a6784d0e7ab903d7aa9970e804ccaa3/60a22/jekyll-logo.webp 160w,/static/9a6784d0e7ab903d7aa9970e804ccaa3/4c812/jekyll-logo.webp 320w,/static/9a6784d0e7ab903d7aa9970e804ccaa3/71ce1/jekyll-logo.webp 498w&quot; sizes=&quot;(max-width: 498px) 100vw, 498px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/9a6784d0e7ab903d7aa9970e804ccaa3/69538/jekyll-logo.png 160w,/static/9a6784d0e7ab903d7aa9970e804ccaa3/72799/jekyll-logo.png 320w,/static/9a6784d0e7ab903d7aa9970e804ccaa3/79e1b/jekyll-logo.png 498w&quot; sizes=&quot;(max-width: 498px) 100vw, 498px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/9a6784d0e7ab903d7aa9970e804ccaa3/79e1b/jekyll-logo.png&quot; alt=&quot;jekyll logo&quot; title=&quot;jekyll logo&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;So I got to checking out Barry’s blog and his Jekyll Now templates and
tried to make sense of the two so I could make my own, based off of
the ideas I got from Barry’s blog.&lt;/p&gt;&lt;h2 id=&quot;development-environment-enter-cloud-9&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#development-environment-enter-cloud-9&quot; aria-label=&quot;development environment enter cloud 9 permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Development environment, enter Cloud 9&lt;/h2&gt;&lt;p&gt;I tried to set up Ruby on my Windows machine and it didn’t go well,
then I tried to set it up on my Raspberry Pi, that didn’t go well
either. Then I recalled that I could have any number of different
environments with &lt;a href=&quot;https://c9.io/?redirect=0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Cloud9&lt;/a&gt; so I set up a
Ruby machine on there and installed Jekyll, no problem&lt;/p&gt;&lt;h3 id=&quot;setup&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#setup&quot; aria-label=&quot;setup permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup&lt;/h3&gt;&lt;p&gt;It wasn’t as simple as just going to the local host page as it’s a
cloud based system so after som digging I found this from
Jean-François L’Heureux &lt;a href=&quot;https://github.com/jflheureux&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jflheureux&lt;/a&gt; on
GitHub.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.jflh.ca/2016-01-18-running-jekyll-on-cloud9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.jflh.ca/2016-01-18-running-jekyll-on-cloud9&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Basically you need to set up a Run Configuration on your c9 box,
thanks for that Jean-François.&lt;/p&gt;&lt;h2 id=&quot;css&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#css&quot; aria-label=&quot;css permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CSS&lt;/h2&gt;&lt;p&gt;For some reason I thought that a Jekyll page didn’t use CSS, well the
reason may have been that there was nothing like that in the ‘vanilla’
Jekyll site when you run the &lt;code&gt;jekyll new myblog&lt;/code&gt; you get very little
in the was of bells and whistles.&lt;/p&gt;&lt;h4 id=&quot;here-is-the-base-project&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#here-is-the-base-project&quot; aria-label=&quot;here is the base project permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;here is the base project&lt;/h4&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:430px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/f23bbe735fd8a42717474db5013e7542/05ed2/base-jekyll-project.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:137.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;550\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20550\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M13%2029c-3%204-3%2011%200%2014%204%204%2013%202%2013-3%200-2-3-2-4%200-2%202-6%201-7-3%200-5%203-8%206-4%202%201%205%201%205-1s-5-5-8-5l-5%202m61-1l-1%203c0%201%200%202-2%201-5-1-9%206-6%2011%202%202%203%202%207%202h5v-9c0-9-1-11-3-8m7%201c-4%204-1%2011%204%2010%201-1%202%200%202%201%200%202-2%202-4%201l-3-1c-1%202%202%204%205%205%204%200%206-3%206-8%200-9-5-13-10-8m119-1l-1%209v8h7l7-1-5-1c-6%200-6%200-6-3s0-3%205-3l5-1-5-1c-5%200-5%200-5-2%200-3%200-3%205-3l6-1c0-2-12-2-13-1m24%200l-1%203c0%201%200%202-2%201-4%200-6%202-6%206%200%205%201%207%207%207h4v-9c0-8-1-10-2-8m92%202c0%202%200%203-3%202-2%200-3%200-4%202-4%205-1%2011%205%2011h4v-8a297%20297%200%2001-1-10l-1%203M37%2034c-3%202-3%207%200%209%206%206%2015-3%209-9-2-2-6-3-9%200m14%204l1%207h10v-6c0-6%200-7-2-7s-2%201-2%205c-1%206-3%207-3%200%200-3-1-5-2-5-2%200-2%201-2%206m103-5c-2%201-3%206-2%209%202%203%208%204%2010%202s0-4-1-2h-6c-1-2-1-2%203-2%205%200%205%200%205-2%200-4-5-7-9-5m223%201c-4%204-1%2011%204%2011l5-2c2-2%201-2-2-1s-6%201-6-1l5-1c4%200%204%200%204-2%200-5-6-8-10-4M53%2099c-4%202-6%2021-3%2024h31v-20l-8-1c-6%200-7%200-9-2s-8-3-11-1m289%203c0%202%200%202-3%202-3-1-6%201-4%203%201%201%200%204-2%204-1-1-1%200-1%202l1%203c2%200%203%202%202%203s-1%202%201%203c1%202%202%202%202%201%202-2%204-1%204%201%200%201%201%202%203%202l2-2c0-2%203-3%204-1%203%202%205-2%203-4-1-2-1-2%201-3%204-1%204-5%201-5-2-1-2-1-2-4%201-3-1-6-3-4-1%202-4%201-4-1l-2-2c-2%200-3%201-3%202M51%20113v9h30v-7c0-12%201-11-16-11H51v9m63%200c0%207%200%208%203%208s6-3%206-7c0-3-2-5-5-5-2%201-2%200-2-2l-1-2-1%208m82-3a267%20267%200%20001%2014l1-2c0-1%200-2%202-1s5-3%205-7-2-5-6-5l-3%201M79%20140c-4%202-6%2021-3%2024h31v-20l-8-1c-6%200-8%200-9-2s-8-3-11-1m-2%2014v9h30v-17l-15-1H77v9m61-6l-2%202-2%201c-5-2-9%202-7%207%200%203%203%204%206%203%203%200%202-2-1-2s-3%200-3-3%201-4%204-4l4%202%204%202c3%200%202%202-1%203-2%201-3%202-1%203%206%201%209-11%205-15-3-1-4-1-6%201m-60%2033l-2%204v20h31v-20l-8-1c-6%200-8%200-9-2s-10-3-12-1m-1%2014v9h30v-17l-15-1H77v9m90%204l1%207%201-2%201-2c3%201%206-2%206-5%200-4-2-6-6-6h-3v8M16%20216c-4%201-4%203-4%2020%200%2014%200%2017%202%2018%201%202%2019%202%20183%202h182l1-2c2-2%202-6%202-19v-16l-3-2-2-2H197l-181%201m61%2020v9h14c17%200%2016%201%2016-11v-6l-15-1H77v9m71-1v8h4c4%200%206-1%206-5s-2-6-5-6l-2-2-2-3-1%208m-27%203l1%205%201-4%201-4c2-1%203%200%203%204%200%206%203%205%203%200%201-6%203-6%203-1%200%204%200%205%202%205%201%200%202-8%200-10l-8-1h-6v6m44-4c-2%201-2%206-1%208%202%202%208%201%209-1h2l4%202c2%200%203%200%202%201l-3%201c-2-1-3-1-3%201%200%201%206%202%208%200l1-8v-6h-3c-3%200-4%201-5%202l-2%202-2-2c-1-2-5-3-7%200m-66%2033c-3%205-3%2018%200%2020h30l1-11v-9l-8-1c-6%200-8%200-9-2s-2-2-7-2h-5l-2%205m1%201l-1%209%201%209h29v-9l-1-9-14-1-14%201m86%204v7l1%205h6c6%200%207-1%207-3s-1-2-3-3c-3-1-3-3%201-3h2c-1-2-5-2-7-1h-1l-2-1-2-1c0-3-2-2-2%200m-32%209l1%207%201-2c0-2%201-2%203-2%204%200%206-4%204-8%200-2-1-3-5-3h-4v8m-4%2034l-1%205c0%203%202%205%205%205%201%200%202%200%201%201l-3%201c-1-1-2%200-2%201h7l1-8v-6h-3l-5%201m28%201c-4%204-2%209%203%209%202%200%203%200%202%201l-3%201h-3c1%202%206%202%207%200%202-1%202-3%202-7v-6h-3l-5%202m-56%200l1%204v4c-1%201-1%201-1-1%200-4-1-5-5-4-3%200-3%200-3%204l-1%204c-2-1-2%200-2%202s0%203%202%203h7l4-1%201-2%201-3%201-3-1-2-1-2-1-3h-2m76%2040l-1%205c0%203%202%205%205%205%201%200%202%200%201%201l-3%201c-1-1-2%200-2%201h7l1-8v-6h-3l-5%201m-44%2043v8h3c5%200%206-2%206-7%200-3-1-3-4-3s-3-1-3-3l-1-3-1%208m71-5l-2%202c-3%200-6%203-6%205%200%204%202%206%206%206h4v-8l-1-8-1%203m-59%20123c0%202%200%202-2%202-1-1-6%203-6%205%200%203%203%206%207%206h3v-8l-1-8-1%203m55%200c0%201%200%202-1%201-2-1-6%203-6%206%200%204%202%206%206%206h4v-8l-1-8c-1%200-2%201-2%203\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/f23bbe735fd8a42717474db5013e7542/60a22/base-jekyll-project.webp 160w,/static/f23bbe735fd8a42717474db5013e7542/4c812/base-jekyll-project.webp 320w,/static/f23bbe735fd8a42717474db5013e7542/866c5/base-jekyll-project.webp 430w&quot; sizes=&quot;(max-width: 430px) 100vw, 430px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/f23bbe735fd8a42717474db5013e7542/69538/base-jekyll-project.png 160w,/static/f23bbe735fd8a42717474db5013e7542/72799/base-jekyll-project.png 320w,/static/f23bbe735fd8a42717474db5013e7542/05ed2/base-jekyll-project.png 430w&quot; sizes=&quot;(max-width: 430px) 100vw, 430px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/f23bbe735fd8a42717474db5013e7542/05ed2/base-jekyll-project.png&quot; alt=&quot;bas-project-layout&quot; title=&quot;bas-project-layout&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Running the following from the terminal on my Ruby development box&lt;/p&gt;&lt;pre&gt;&lt;code&gt;~ $ gem install jekyll bundler
~ $ jekyll new myblog
~ $ cd myblog
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Omitting the &lt;code&gt;~/myblog $ bundle exec jekyll serve&lt;/code&gt; and
&lt;code&gt;# =&amp;gt; Now browse to http://localhost:4000&lt;/code&gt; for reasons just mentioned.&lt;/p&gt;&lt;p&gt;Use the run configuration
&lt;code&gt;jekyll serve --host $IP --port $PORT --config _config.yml,_local_config.yml&lt;/code&gt;&lt;/p&gt;&lt;p&gt;You get this:&lt;/p&gt;&lt;h4 id=&quot;new-blog-yay&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#new-blog-yay&quot; aria-label=&quot;new blog yay permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;new blog yay!&lt;/h4&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/bec10c4a17adb57f6381b8bc833f463f/db7be/base-jekyll-site.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:61.24999999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;245\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20245\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%203c0%202%20400%201%20401-1L201%201C23%201%200%201%200%203m36%2013l-1%203c0%203%200%203%203%203s3%200%203-3c0-2%200-2%201%200%201%203%203%204%203%201h1c1%202%203%203%203%201s0-2%202%200l3%201c3%200%202-2%200-1l-2-1c0-1%206-2%208%200h-1l-2%201h13l1%201%201-2%201-3%201%203%201%202%201-2%201-3%201%202c0%202%201%203%204%203l4-1h-2l-2-1%203-1c2%200%202%200%201-2s-3-3-5%200h-2c-1-2-9-2-9%200h-1c-1-3-4-2-5%200-2%202-2%202-4%201v-1c2%200%202%200%201-1H50l-1%201-2%202v-2l-1-2-1%202-2%202v-2c-1-2-1-2-2-1h-5\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/bec10c4a17adb57f6381b8bc833f463f/60a22/base-jekyll-site.webp 160w,/static/bec10c4a17adb57f6381b8bc833f463f/4c812/base-jekyll-site.webp 320w,/static/bec10c4a17adb57f6381b8bc833f463f/0ba47/base-jekyll-site.webp 640w,/static/bec10c4a17adb57f6381b8bc833f463f/e46b2/base-jekyll-site.webp 960w,/static/bec10c4a17adb57f6381b8bc833f463f/af3f0/base-jekyll-site.webp 1280w,/static/bec10c4a17adb57f6381b8bc833f463f/6926e/base-jekyll-site.webp 1603w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/bec10c4a17adb57f6381b8bc833f463f/69538/base-jekyll-site.png 160w,/static/bec10c4a17adb57f6381b8bc833f463f/72799/base-jekyll-site.png 320w,/static/bec10c4a17adb57f6381b8bc833f463f/6af66/base-jekyll-site.png 640w,/static/bec10c4a17adb57f6381b8bc833f463f/d9199/base-jekyll-site.png 960w,/static/bec10c4a17adb57f6381b8bc833f463f/21b4d/base-jekyll-site.png 1280w,/static/bec10c4a17adb57f6381b8bc833f463f/db7be/base-jekyll-site.png 1603w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/bec10c4a17adb57f6381b8bc833f463f/6af66/base-jekyll-site.png&quot; alt=&quot;base-jekyll-site&quot; title=&quot;base-jekyll-site&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;h2 id=&quot;confusing&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#confusing&quot; aria-label=&quot;confusing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Confusing&lt;/h2&gt;&lt;p&gt;Jekyll uses Liquid templating language which, for someone like me was
a bit confusing. With me just getting used to the layout of a
‘standard’ web page I was then presented with liquid ‘tags’ something
I’m still not completely clear on what some of them do.&lt;/p&gt;&lt;p&gt;&lt;code&gt;_layouts, _includes, meta.html&lt;/code&gt;&lt;/p&gt;&lt;p&gt;WTF? I had no idea, I’m still not totally clear on the why, I add a
default.html then Jekyll complains that there’s a missing meta.html
file, I create a _includes folder and add an empty meta.html and it
builds fine, no idea.&lt;/p&gt;&lt;p&gt;So after creating a &lt;code&gt;default.html&lt;/code&gt; and then comparing with Jekyll Now
and Barry’s sites I was able to piece together a &lt;code&gt;default.html&lt;/code&gt;,
&lt;code&gt;page.html&lt;/code&gt; and &lt;code&gt;post.html&lt;/code&gt; which looked hideous so I then had to
start with CSS on the page,I took the majority of it from Barry’s blog
page with the intention of modifying it to my own liking.&lt;/p&gt;&lt;p&gt;In the end I took quite a bit of CSS, the
&lt;a href=&quot;http://meyerweb.com/eric/tools/css/reset/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Meyer Reset&lt;/a&gt; was something
I knew nothing of before starting this, now I think it’s quite a handy
thing to have/know.&lt;/p&gt;&lt;p&gt;Variables, again I knew nothing about this before playing around with
Jekyll but really helped me understand CSS a little bit more than I
did before.&lt;/p&gt;&lt;p&gt;Then stuff for analytics and Disqus, then there was stuff I added in
that I liked, like font-awesome and some Google fonts I like so I
could have a nice footer like the one in my CodePen portfolio I like.&lt;/p&gt;&lt;h2 id=&quot;markdown&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#markdown&quot; aria-label=&quot;markdown permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Markdown&lt;/h2&gt;&lt;p&gt;Oh, it’s not the right Markdown, why isn’t is showing the GitHub
Markdown Scott?? Because you’ve used the &lt;code&gt;@import &amp;quot;highlights&amp;quot;;&lt;/code&gt; on
your &lt;code&gt;style.css&lt;/code&gt; oh ok, so I’d prefer GitHub Markdown, ok no problem,
go remove the &lt;code&gt;@import &amp;quot;highlights&amp;quot;;&lt;/code&gt; from your &lt;code&gt;style.css&lt;/code&gt; you’ll be
golden, no worries. Queue a raft of commits with me dicking around
with various combinations of having corrected &lt;code&gt;_config.yml&lt;/code&gt; entries it
got pretty messy.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/8e23cb21d43675e06988080fad218959/10b63/dem-commits.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:50%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;200\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20200\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M8%206c-2%201-1%208%201%209v2c-2%201-2%202-2%203l2-1h2c2%201%205%200%205-1h2l1%201-1-2v-3c1-1%202-3%201-5V5h-5L8%206m0%2024c-2%200-1%209%201%209l1%202c-1%201%202%204%203%204l3-2%201-2c-1%200-1-1%201-2%205-5-2-13-10-9m0%2025c-2%201-1%208%200%209%202%201%202%201%200%203v2l1-1h8v-2l1-2c1-2%202-3%201-6s-1-4-6-4l-5%201m0%2025c-2%201-1%208%201%209v2c-2%201-2%202-2%203l2-1h10l-1-2v-3c1-1%202-3%201-5v-4h-5l-6%201m-1%2028c0%203%200%205%202%205l1%202%201%202c2%202%205%202%205%200h2l1%201-2-3%201-2c1-1%202-3%201-5v-4H7v4m1%2021c-2%201-1%208%200%209%202%201%202%201%200%203v2l1-1h8v-2l1-2c2-2%202-4%200-9%200-1-9-2-10%200m0%2025c-2%201-1%208%201%209v2c-2%201-2%202-2%203l2-1h2c2%201%205%200%205-1h2l1%201-1-2v-3c1-1%202-3%201-5v-4h-5l-6%201m2%2024c-3%200-3%201-3%204%200%204%200%205%202%205l1%202%203%204%203-2%201-2c-1%200-1-1%201-2%202-2%202-9-1-9h-7\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/8e23cb21d43675e06988080fad218959/60a22/dem-commits.webp 160w,/static/8e23cb21d43675e06988080fad218959/4c812/dem-commits.webp 320w,/static/8e23cb21d43675e06988080fad218959/0ba47/dem-commits.webp 640w,/static/8e23cb21d43675e06988080fad218959/e46b2/dem-commits.webp 960w,/static/8e23cb21d43675e06988080fad218959/af3f0/dem-commits.webp 1280w,/static/8e23cb21d43675e06988080fad218959/eccbe/dem-commits.webp 1897w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/8e23cb21d43675e06988080fad218959/69538/dem-commits.png 160w,/static/8e23cb21d43675e06988080fad218959/72799/dem-commits.png 320w,/static/8e23cb21d43675e06988080fad218959/6af66/dem-commits.png 640w,/static/8e23cb21d43675e06988080fad218959/d9199/dem-commits.png 960w,/static/8e23cb21d43675e06988080fad218959/21b4d/dem-commits.png 1280w,/static/8e23cb21d43675e06988080fad218959/10b63/dem-commits.png 1897w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/8e23cb21d43675e06988080fad218959/6af66/dem-commits.png&quot; alt=&quot;dem-commits&quot; title=&quot;dem-commits&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Currently I am still with the &lt;code&gt;_hilights.scss&lt;/code&gt; in the &lt;code&gt;sass&lt;/code&gt; folder
which I’m going to have to play around with to get it how I like it,
hopefully I’ll get to learn a bit more about it all and understand how
much of a tool I was.&lt;/p&gt;&lt;h2 id=&quot;preview&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#preview&quot; aria-label=&quot;preview permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Preview&lt;/h2&gt;&lt;p&gt;One last thing that bugged me that I couldn’t do was the content
preview thing on the posts, it’s partly why I went from Jekyll Now to
my own vanilla build, I was getting that first paragraph to show on
the main blog page I found it eventually, not on the &lt;code&gt;post.html&lt;/code&gt; or
the &lt;code&gt;default.html&lt;/code&gt; no it was on the &lt;code&gt;index.html&lt;/code&gt; here:&lt;/p&gt;&lt;p&gt;&lt;code&gt;{``{ post.content | split:&amp;quot;&amp;lt;!--more--&amp;gt;&amp;quot; | first }``}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Then add the &lt;code&gt;&amp;lt;!--more--&amp;gt;&lt;/code&gt; tag after the first paragraph on your post,
then I added a class to float the image on the top of the post and
flow around the image, the CSS is this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;// see image in content preview
// only adjust width OR height so aspect ration is maintained
.floated{
  float: right;
  display: block;
  width: 33vw;
  max-width: 250px;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So I have the basics I think, still a fair bit to play around with but
for now I have what I need.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Job hunting, one class 'A' ballache]]></title><description><![CDATA[This is basically a rant about the job market, I was laid off back in
August, this is a terrible time of year to be looking for work…]]></description><link>https://scottspence.com/2016/12/05/job-hunting/</link><guid isPermaLink="false">https://scottspence.com/2016/12/05/job-hunting/</guid><pubDate>Mon, 05 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is basically a rant about the job market, I was laid off back in
August, this is a terrible time of year to be looking for work,
everyone is on holiday so things are generally pretty slow so when
this happened to me I did the same and went on holiday for the end of
August and first week of September. Coming back from holiday I found
that things were still pretty slow with the occasional phone call
about roles that were not really suited to my skill set. It was at
this point that I began to struggle and stress about ever being
employed again.&lt;/p&gt;&lt;h2 id=&quot;no-one-wants-to-hire-you&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#no-one-wants-to-hire-you&quot; aria-label=&quot;no one wants to hire you permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;No one wants to hire you&lt;/h2&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/76b7f4c70276388a047bbf68a48a19a5/3ac88/stress-office.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.875%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;267\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20267\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M85%2024c-21%205-34%2020-36%2043%200%206-1%208-3%2011-5%206-3%2018%205%2026%206%206%207%208%207%2017%200%206%200%208-2%2010-3%203-1%2012%204%2017%204%203%205%205%2022%2016%2010%207%2016%2012%2016%2014%200%207-9%2030-11%2030l-5-3c-2-2-3-3-4-2l-2%201v2c1%202%200%203-9%2010-4%203-5%204-5%208-1%205-3%205-9%202l-24-19c-3-4-5-5-5-3s29%2028%2032%2028c1%200%203%203%203%206%200%202%201%203%203%204%206%202%2025%2015%2031%2022l3%203h40l-1-8c0-7%200-8%202-12%202-3%203-6%205-18%202-7%202-8%200-13l-1-7v-3c-1-3-1-2-3%207-2%2010-2%2012-4%2011v-9c3-12%203-29%201-31l-2-2%202%201h1c0-3%202%200%202%203l1%202v-6l-1-3-2-1v-3l2-1c1-2%205-3%206-1l8%201c2%200%203%201%204%203%201%203%201%203%202%202h3c1%200%204%202%204%204l2%202c2%201%203%200%201-5l-1-4c1%200%207%206%206%208l2%207a312%20312%200%20019%2027c2%200-4-29-6-32l-2-2h6l12-4c10-4%2012-4%2011%200l1%206c1%201%201-1%201-7-1-9-3-15-5-17-2-1-9-13-11-19l-7-11-9-14c-4-6-4-6-9-6a701%20701%200%2001-12-3l-7-5c-2%200-1-16%201-20%203-4%202-7%200-13l-4-12c-4-15-14-27-25-33-7-3-24-4-34-2m38%2053l1%205v3l-2%202-2%202c-3%200-4%204-1%205%202%201%206-2%207-4l2-2c1%201%202-2%201-5v-3c1-1-2-6-4-6s-2%201-2%203M89%2090l-1%201c-1-1-2%203-2%204v1l-2%202c0%202%201%203%203%201h2l3%201c2-1%203%200%201%203v8l2%205%202%202%201%201c1%201%201%201%201-1v-2c1%201%201%201%201-1v-3c1%200%202-1%202-3s0-4%202-5c2-2%203-3%202-5h-1l-2%202c-2%200-2%200-1-2%201-1%202-2%201-3v-2c0-3-12-6-14-4m66%2035c-4%202-8%206-7%207l4-2c2-2%203-2%2010-2%208%200%209%200%2011%203s3%203%203%201c1-1%200-2-3-5-4-4-13-5-18-2m19%2019v2c-1%201-1%201%202%201s3%200%203%202v3c-1%201-1%201%201%202%203%201%204%204%202%204l1%2010c1%203%204%206%208%206l1-1h1c2%202%202%200%202-4-1-3-2-7-4-9l-3-6-2-1v-1c3-2%202-5-2-6-4-2-11-3-10-2m-63%2023l-7%205c-4%204-4%204-2%205l2%201%207%204h2c1%203%202-1%202-7%201-7%200-9-4-8M0%20197a885%20885%200%200127%2039c9%2011%2021%2022%2023%2020l2-3c1-2%201-2-2-3l-20-20a175%20175%200%2000-10-13l-3-4-15-18c-2-2-2-2-2%202m0%2029c0%206%201%2010%206%2024l5%2017h6l6-1a345%20345%200%2000-20-45c-3-4-3-4-3%205m188%2014l1%2026%203%201c2%200%202%200%201-1l-1-3c0-2%200-2-1-1s-1%201-1-2c0-2%201-5%204-9%203-5%204-7%201-5-1%201-1%201-1-1%201-2%201-2-1-1-2%203-3%202-2-1%200-4-1-5-3-3\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/76b7f4c70276388a047bbf68a48a19a5/60a22/stress-office.webp 160w,/static/76b7f4c70276388a047bbf68a48a19a5/4c812/stress-office.webp 320w,/static/76b7f4c70276388a047bbf68a48a19a5/0ba47/stress-office.webp 640w,/static/76b7f4c70276388a047bbf68a48a19a5/e46b2/stress-office.webp 960w,/static/76b7f4c70276388a047bbf68a48a19a5/4ef06/stress-office.webp 1260w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/76b7f4c70276388a047bbf68a48a19a5/0913d/stress-office.jpg 160w,/static/76b7f4c70276388a047bbf68a48a19a5/cb69c/stress-office.jpg 320w,/static/76b7f4c70276388a047bbf68a48a19a5/c08c5/stress-office.jpg 640w,/static/76b7f4c70276388a047bbf68a48a19a5/6a068/stress-office.jpg 960w,/static/76b7f4c70276388a047bbf68a48a19a5/3ac88/stress-office.jpg 1260w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/jpeg&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/76b7f4c70276388a047bbf68a48a19a5/c08c5/stress-office.jpg&quot; alt=&quot;stress-office&quot; title=&quot;stress-office&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;For the longest time I thought there was something wrong with my CV so
I read up on &lt;a href=&quot;https://lmgtfy.com/?q=what+is+an+ats&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ATS’&lt;/a&gt; and added
what I thought was needed to at least meet the minimum requirements
for passing the ATS if there was one for the roles I was applying for.&lt;/p&gt;&lt;p&gt;What I have also found is that my skill set is now in a minority,
that’s not to say that banks are going to stop using Excel overnight
but it does mean that there are other technologies being used here,
Visual Studio Tools for Office and Excel DNA mean that there are .NET
controls that can be used in lil old Excel which a lot of
organisations want now.&lt;/p&gt;&lt;p&gt;This has basically brought me to the conclusion that I should be
expanding my skill set, so I have been busy getting the skills I need
to become a full stack web developer using the awesome free course
material at &lt;a href=&quot;https://www.freecodecamp.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;freeCodeCamp&lt;/a&gt; (fCC) I’m
still in the very early stages of this and am not about to start
looking for full stack web developer jobs but it is something that I’m
going to commit a lot of my spare time to so I can build a portfolio
to showcase my skills for prospective employers. This will be an
additional tool to my toolkit I’m also hoping to gain a lot of insight
into general purpose programming languages, something currently
lacking from my ‘skill stack’.&lt;/p&gt;&lt;p&gt;What I found whilst searching for roles is that someone with VBA, SQL
and C# there is also the need now for Tableau, ClikView or some other
data visualisation software which stands to reason that now we have
all this data that we should actually be able to gain some insight
from it, this is something I’ll be looking into with the scripting
language Python (general purpose programming language) once I have
progressed with my FCC certification.&lt;/p&gt;&lt;blockquote&gt;&lt;h2 id=&quot;its-an-employers-market&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#its-an-employers-market&quot; aria-label=&quot;its an employers market permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It’s an employers market&lt;/h2&gt;&lt;p&gt;Another thing which is bad, because it’s an employer’s market
(apparently) employers are being very specific about the skills they
want potential candidates to have and currently they are driving
down the cost of resources with these job specifications, like: C#
developer with 5 years commercial experience + x,y,z unrelated
skills for £37k, that is at very least a mid-senior level role £50k+
but once one of these is on the market then other employers see this
and decide to put their role at the same level.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;lessons-learned&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#lessons-learned&quot; aria-label=&quot;lessons learned permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lessons learned&lt;/h2&gt;&lt;p&gt;Things I have learned, most of the time the job doesn’t exist (lead
generation) If it does exist and you match one of the skills on the
spec you will have every resourcer in the country [and abroad] calling
you for the role. Wild salary ranges £40k-£80k that’s a pretty big
range, these ads usually come with every skill imaginable so it’s safe
to say that they don’t really know what they want or the role doesn’t
really exist.&lt;/p&gt;&lt;h2 id=&quot;recruiters&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#recruiters&quot; aria-label=&quot;recruiters permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Recruiters&lt;/h2&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/39c169147b3806bbb9898f3b553bf0a6/3ac88/shady-recruiter-middle-man.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:75%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;300\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20300\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M167%201l2%208c2%206%203%207%202%209-3%206-5%208-9%208l-15%205-24%207c-24%205-26%207-26%2014l-2%207-5%2011-7%2017-5%2011-2%204c-2%201-3%204-4%206%200%202-1%206-3%208l-2%206-5%206c-4%206-8%2015-8%2021l-4%209c-4%206-5%2013-5%2024%200%2012%206%2020%2036%2049a251%20251%200%200033%2026c2%201%202%206-1%2017l-3%2025%2096%201h95v-5l-4-16-1-11c0-2%203-4%208-10a240%20240%200%200015-19l11-15c5-5%2018-23%2020-28%202-4%203-13%202-25l-2-4c-2-1-4-6-5-11l-5-11v-6c1-3-3-11-7-15-3-2-6-11-5-15%200-3%200-4-2-6-3-2-4-5-10-22l-3-7-1-3-2-7-2-7c0-7-3-10-9-12l-10-3-14-4c-40-12-39-12-43-18v-8c4-12%204-12-1-12-4%200-5%201-7%206l-1%202-1%202-1%202-2-5-2-4c-2-3-12-4-12-2l1%201c3%200-3%202-7%202l-6%201c-3%202-4%201-3-1%200-3-2-2-4%200s-3%207-1%207l3-2c5-3%2028-1%2027%203%200%202-4%203-4%201s-4-3-10-3c-4%200-4%200-3%202%200%201%200%202-2%202l-1%201c1%202%2010%202%209%200l1-2h2l1%204%203%201c9%200%204%205-5%206l-7%202c-6%206-19-6-20-17h-1c-1%202-2%201-4-3l-3-4-1-1-1-1-2%201m5%2022l5%2025a363%20363%200%200111%2058c2%206%202%206%202-16%201-21%202-25%205-34%202-4%201-5-3-2l-4%202-3%201c-1%202-2%202-3%202%200-1%205-8%2012-15%204-5%204-5-2-7-5-1-13-8-17-15l-3-5v6m55%200c-4%206-8%2010-14%2012l-8%204-3%201%203%203%207%209-7%203c-2%201-2%203-1%209%200%204%200%204%201%202l1%207a489%20489%200%20004%2042%20707%20707%200%20005%2045c1%2010%201%206%206-37l5-65c0-8%200-8-2-10-4-1-4-3%200-8%204-7%206-13%206-18v-3l-3%204M110%20150l-8%2012-3%209c0%208%201%2010%209%2014s16%2012%2016%2015%200%203%202%203l2-1c1%200%200-11-2-20l-2-12-4-9-4-11c0-9-1-9-6%200m176%208l-4%2015c-4%2013-6%2030-5%2035%201%202%201%202%204%200l5-3%202-4%206-9c6-7%207-13%203-22l-4-8c0-3-4-8-4-6h-1c-1-1-1-1-2%202m-102%2049l-8%201-7%201c-2%202-14%206-16%206-6-2-17%2013-18%2026%200%206%204%2027%205%2027l1-3a177%20177%200%2001-1-21c0%207%201%207%205%2011%205%205%2011%206%2016%203%202-2%204-2%206-2%204%201%2011-1%2011-2l-8-1c-7%200-9%200-10-2-2-2-1-2%2011-3%2012%200%2015-1%2015-2v-1l1-2c0-2%200-2-13-2s-16-1-15-3h14c13%200%2014-1%2017-3l4-4-12-1c-13-1-16-1-16-3h28c4-1%206-7%203-8v-3l-4-5c-2-5-3-6-9-4m50%2010c-9%203-16%204-19%202l-3-1%205%207c4%203%205%203%2012%203h8l-2%203c-1%201-2%202-3%201l-7-1c-5-1-10-3-13-7-3-3-6-2-5%202v11l5%2016%204-1c2-1%203-1%204%201l2%201a233%20233%200%200021%204c2%200%203%201%203%202%200%202%200%202%203%201l3%201c3%202%2011-2%209-5-1-1%202-2%204-1%201%202%207-2%209-5l1-8v-5l2%205c1%203%203%2011%203%2017%202%2013%202%2014%205%2012v-8l-1-14c1-18-10-32-20-27l-3%201-9-4c-11-6-11-6-18-3m-20%2038l-1%204v4h9a235%20235%200%200119%200l-1-1a95%2095%200%2001-26-7\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/39c169147b3806bbb9898f3b553bf0a6/60a22/shady-recruiter-middle-man.webp 160w,/static/39c169147b3806bbb9898f3b553bf0a6/4c812/shady-recruiter-middle-man.webp 320w,/static/39c169147b3806bbb9898f3b553bf0a6/0ba47/shady-recruiter-middle-man.webp 640w,/static/39c169147b3806bbb9898f3b553bf0a6/e46b2/shady-recruiter-middle-man.webp 960w,/static/39c169147b3806bbb9898f3b553bf0a6/4ef06/shady-recruiter-middle-man.webp 1260w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/39c169147b3806bbb9898f3b553bf0a6/0913d/shady-recruiter-middle-man.jpg 160w,/static/39c169147b3806bbb9898f3b553bf0a6/cb69c/shady-recruiter-middle-man.jpg 320w,/static/39c169147b3806bbb9898f3b553bf0a6/c08c5/shady-recruiter-middle-man.jpg 640w,/static/39c169147b3806bbb9898f3b553bf0a6/6a068/shady-recruiter-middle-man.jpg 960w,/static/39c169147b3806bbb9898f3b553bf0a6/3ac88/shady-recruiter-middle-man.jpg 1260w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/jpeg&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/39c169147b3806bbb9898f3b553bf0a6/c08c5/shady-recruiter-middle-man.jpg&quot; alt=&quot;shady-recruiter-middle-man&quot; title=&quot;shady-recruiter-middle-man&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;So this is where we get all warm and fuzzy talking about recruiters
and what great jobs they do. How they are always busy talking to
hiring managers for many different roles and juggling multiple
candidates.&lt;/p&gt;&lt;p&gt;I have worked in the past in the same office as recruiters and
understand what they do for a job, and the time and effort needed to
find good candidates.&lt;/p&gt;&lt;h4 id=&quot;what-the-recruiter-says&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-the-recruiter-says&quot; aria-label=&quot;what the recruiter says permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What the recruiter says:&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;“hi Scott, just seen your profile and think you will be a really good match for a role I’m recruiting for”&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;what-it-actually-means&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-it-actually-means&quot; aria-label=&quot;what it actually means permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What it actually means:&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;“you have come up in my keyword search and I&amp;#x27;m blindly calling you, I haven’t really read your profile”&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;This was incredibly frustrating experience for me, yes I could have
done things better and like I said this was basically a rant, this is
so people can relate, &lt;strong&gt;BUT!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Gone are the days of carefully crafted covering letters and tailoring
your CV for that specific job, most of the time your CV doesn’t even
get seen by a human and is instead rejected by an ATS.&lt;/p&gt;&lt;p&gt;If we all went back to the days of trust and real relationships with
recruiters that we trusted and had met and that understood our needs
would they have the role we needed?&lt;/p&gt;&lt;p&gt;Just because we have an understanding with a few recruiters doesn’t
mean that they have the perfect role waiting for us when we start
looking for work, although you will be at the top of their list if
they do get that role.&lt;/p&gt;&lt;p&gt;What I like and respect in a recruiter is if I can get five minutes
into a phone conversation with a recruiter that has actually read my
profile or my CV.&lt;/p&gt;&lt;p&gt;What I found with recruiters is first a ten minute conversation asking
me how I’m finding the market and then asking me what my ideal next
role would be.&lt;/p&gt;&lt;p&gt;This is basically their due diligence, what they should have
determined by looking at your profile before calling you.&lt;/p&gt;&lt;p&gt;After this it goes one of two ways, the recruiter then being honest
with you [in some cases] and telling you they actually don’t think you
are suitable for the role (which they could have done if they took the
time to read your profile) let’s just bear in mind ten minutes before
it was,&lt;/p&gt;&lt;blockquote&gt;&lt;h2 id=&quot;hi-scott-just-seen-your-profile-on-linkedin-and-im-really-keen-to-talk-to-you-about-a-role-with-one-of-our-very-high-profile-clients-im-recruiting-for&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#hi-scott-just-seen-your-profile-on-linkedin-and-im-really-keen-to-talk-to-you-about-a-role-with-one-of-our-very-high-profile-clients-im-recruiting-for&quot; aria-label=&quot;hi scott just seen your profile on linkedin and im really keen to talk to you about a role with one of our very high profile clients im recruiting for permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;“Hi Scott, just seen your profile on LinkedIn and I’m really keen to talk to you about a role with one of our very high profile clients I’m recruiting for.”&lt;/h2&gt;&lt;/blockquote&gt;&lt;p&gt;The call usually ends with a
&lt;code&gt;&amp;quot;I&amp;#x27;ll send the spec through for you to look at let me know what you think&amp;quot;&lt;/code&gt;
and the mail never turns up or the old chestnut
&lt;code&gt;I&amp;#x27;ll pass you details on to my colleague\I&amp;#x27;ll update your details on our database&lt;/code&gt;&lt;/p&gt;&lt;p&gt;So now we’re near the end of Ranty McRantRant’s post, if you made it
this far thank you for persevering, if you can relate I’d be keen to
hear your story.&lt;/p&gt;&lt;p&gt;Take a look at these posts too which have partly motivated me to make
this post:&lt;/p&gt;&lt;p&gt;LinkedIn:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/recruitment-industry-die-2018-oleg-vishnepolsky&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;“Recruitment industry will die in 2018.”&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/recruiter-shts-woods-nobody-around-hear-tim-chattaway&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;“If a Recruiter Sh*ts in the woods and nobody is around to hear it?”&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Medium:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://medium.freecodecamp.com/lessons-from-my-post-bootcamp-job-search-in-london-cb37ea12ec2f#.ckpg5lkpa&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lessons From My Post-bootcamp Job Search in London&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[My first Microsoft Visual Studio Code [VSCode] extension]]></title><description><![CDATA[I'm a published developer!  sort of  Well that was a bit painful, well
not actually I mean from the documentation I feel I was a bit mislead…]]></description><link>https://scottspence.com/2016/12/03/first-vscode-extension/</link><guid isPermaLink="false">https://scottspence.com/2016/12/03/first-vscode-extension/</guid><pubDate>Sat, 03 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m a published developer! [sort of] Well that was a bit painful, well
not actually I mean from the documentation I feel I was a bit mislead.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:375px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/50f58b39bdbe05c6e32a31e989f12802/5ff7e/visual-studio-marketplace.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:63.74999999999999%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;254\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20254\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2042v42h401V0H0v42m58-29c-3%203-4%203-5%201-3-2-4-1-4%204s0%206%204%204c1-2%202-2%205%201%202%203%203%203%205%203%203-1%203-1%203-8-1-9-3-11-8-5m290%2044l4%209%203-5%202-4v4c0%205%202%206%205%204h4c1-2%203-2%205%200s2%200%200-4c-2-6-3-6-5-1l-2%205v-3l-2-5-4-1c-3%200-3%200-4%203s-3%204-3%202-3-6-3-4m-34%2072l-1%203c0%203%200%204-3%203-6-1-9%208-5%2012%202%202%205%203%207%201h2c2%202%203%200%203-10%200-9-1-11-3-9m-77%201c-2%202%205%2019%207%2019s8-15%208-19c0-3-3%200-5%207-3%208-3%208-5%200-2-6-4-9-5-7m21%200l-3%204c0%203%203%206%205%206l2%202c3%203%201%205-4%205-3-1-4%200-1%201%208%204%2014-5%206-10-6-3-6-5-1-5%204%200%205-2%202-3h-6m17%201c-11%205-5%2021%207%2018%203-1%203-3%200-2-5%201-9-3-9-8%200-4%203-7%208-7%203%201%204-1%201-2s-3-1-7%201m67-1c0%204%206%2019%208%2019s9-16%208-19c-1-2-3%200-5%207l-3%207-3-7c-2-6-5-10-5-7m20%200l-1%2010v9h4c7%200%2012-5%207-9v-9c-2-1-9-2-10-1m21%200l-7%2019%204-3%202-2h4c2%200%203%201%204%203%200%202%203%203%203%201%200-3-6-18-8-19l-2%201m-94%207c-5%204-2%2012%205%2012%203%200%206-3%206-7%200-6-6-9-11-5m33%200c-4%204-1%2012%205%2012l4-2h-2c-2%200-3%200-4-2-3-2-2-3%204-3%204%200%204%200%203-2-1-5-6-7-10-3m-154%2018l-1%205-2%207-3%2012a109%20109%200%2000-7%2028c-1%201%200%202%201%202%202%201%202%200%202-2l1-4%203-8c3-9%202-9%209-10%206%200%206%200%208%203l2%205%202%204%201%205c0%203%202%207%204%207%202-1%202%200%200%201v2h3v-4l-2-3-1-3c-3-6-5-16-4-17%202-1%200-3-2-3s-2%200-2-2c1-1-1-6-3-8v-1l1-1-6-14-1-3-1-2c-2%200-2%201-2%204m-54%203v11c3%2028%203%2032%201%2039%200%203%200%203%203%203%209%201%2013%200%2014-1h3c3%200%207-3%208-5l1-1%202-2%201-5c0-5-5-13-10-14-5%200-6-2-3-5%206-8%204-18-3-20h-17m4%203v21l5-1%204-2%201-1c2%200%207-8%207-10%200-5-4-8-11-8l-6%201m50%203l-2%209-1%207-1%203c-1%201-1%201%203%201l6-1c4%200%204-1%200-13l-2-9c0-3-2%200-3%203m-103%205l3%207%203%208%202%204%202%205%202%203%202%204c2%207%209%2012%209%207s0-5%202-6l5-9%206-10c5-10%207-16%204-16l-5%207a134%20134%200%2001-12%2022c-3%204-5%206-5%204l-7-15-2-4-1-2-1-2-1-2-1-3c0-4-1-6-3-6s-2%200-2%204m319%201l-2%203v2c1%201%201%201-1%201-3%200-3%200-3%203%200%202%200%202%208%202%207%200%207%200%207-2s-1-3-2-3c-2%200-3%200-2-1l-1-2-1-2-1-3-2%202m-266%2016l1%2012c0%208%201%208%203%208l1%202c0%202%201%202%203%200l3-1h1l3-1c7%200%2014-11%209-14l-5-4c-2-2-9-4-13-3l-3-1c-2-2-3-1-3%202\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/50f58b39bdbe05c6e32a31e989f12802/60a22/visual-studio-marketplace.webp 160w,/static/50f58b39bdbe05c6e32a31e989f12802/4c812/visual-studio-marketplace.webp 320w,/static/50f58b39bdbe05c6e32a31e989f12802/f3a60/visual-studio-marketplace.webp 375w&quot; sizes=&quot;(max-width: 375px) 100vw, 375px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/50f58b39bdbe05c6e32a31e989f12802/69538/visual-studio-marketplace.png 160w,/static/50f58b39bdbe05c6e32a31e989f12802/72799/visual-studio-marketplace.png 320w,/static/50f58b39bdbe05c6e32a31e989f12802/5ff7e/visual-studio-marketplace.png 375w&quot; sizes=&quot;(max-width: 375px) 100vw, 375px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/50f58b39bdbe05c6e32a31e989f12802/5ff7e/visual-studio-marketplace.png&quot; alt=&quot;market-place-image&quot; title=&quot;market-place-image&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;So for those of you that know what I do for a living I’m primarily an
Analyst Developer with a skill set of VBA and SQL which has put me in
good stead for the last 10+ years. I’m currently ‘up-skilling’ myself
on more general programming languages, but enough of that! I basically
wanted to use &lt;a href=&quot;https://code.visualstudio.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VSCode&lt;/a&gt; with VBA which is fine as it’s just
text files but I wanted some of the shexy stuff that VSCode comes
with.&lt;/p&gt;&lt;p&gt;I’m not going to go into how awesome (I think) VSCode is here but I
will mention that for the purpose of me wanting to use (or at least
see syntax highlighting) I found this extension for
&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=luggage66.VBScript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VBScript&lt;/a&gt; which was neat but didn’t give me any
intellisense for even the most straight forward stuff like to create a
&lt;code&gt;Sub&lt;/code&gt; or &lt;code&gt;Function&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;So that got me playing around with making my own &lt;a href=&quot;https://code.visualstudio.com/Docs/customization/userdefinedsnippets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;snippets&lt;/a&gt;
and I found that after a while I had quite a lot of them so I decided
to put them on the VSCode market place.&lt;/p&gt;&lt;p&gt;So, what I found is that Microsoft really want you to make VSCode
extensions and give you all the tools you need to do so.&lt;/p&gt;&lt;p&gt;I found guides &lt;a href=&quot;https://code.visualstudio.com/docs/extensions/overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;https://code.visualstudio.com/docs/extensions/example-hello-world&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://code.visualstudio.com/docs/extensions/testing-extensions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt; all
of which have you using &lt;a href=&quot;http://yeoman.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Yeoman&lt;/a&gt; by installing via
npm, now I’ve never heard of Yeoman before trying to do this so I
don’t have an opinion on that apart from to say it was a bit of a
ballache to get any of it up and running. I tried installing it on
both my home machine and a Cloud9 machine several times over with no
success.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/0d720ffedb48cce898538fc5510ccb14/5819f/yeoman-err.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:35%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;140\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%20140\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2070v70h401V0H0v70m0%201v70l1-65V12h2c2%200%202%200%201-1l-2-1%202-1V8L3%207c3%200%202-2%200-2L1%203C0%202%200%2032%200%2071\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/0d720ffedb48cce898538fc5510ccb14/60a22/yeoman-err.webp 160w,/static/0d720ffedb48cce898538fc5510ccb14/4c812/yeoman-err.webp 320w,/static/0d720ffedb48cce898538fc5510ccb14/0ba47/yeoman-err.webp 640w,/static/0d720ffedb48cce898538fc5510ccb14/e46b2/yeoman-err.webp 960w,/static/0d720ffedb48cce898538fc5510ccb14/20e4c/yeoman-err.webp 1042w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/0d720ffedb48cce898538fc5510ccb14/69538/yeoman-err.png 160w,/static/0d720ffedb48cce898538fc5510ccb14/72799/yeoman-err.png 320w,/static/0d720ffedb48cce898538fc5510ccb14/6af66/yeoman-err.png 640w,/static/0d720ffedb48cce898538fc5510ccb14/d9199/yeoman-err.png 960w,/static/0d720ffedb48cce898538fc5510ccb14/5819f/yeoman-err.png 1042w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/0d720ffedb48cce898538fc5510ccb14/6af66/yeoman-err.png&quot; alt=&quot;YeomanErr&quot; title=&quot;YeomanErr&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Got tired after uninstalling and reinstalling several times at home
and on the cloud so moved on. I read
&lt;a href=&quot;https://code.visualstudio.com/docs/tools/vscecli&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this&lt;/a&gt; guide about
setting yourself up as a publisher on the Microsoft VSCode
&lt;a href=&quot;https://marketplace.visualstudio.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Marketplace&lt;/a&gt; using with &lt;code&gt;vsce&lt;/code&gt;
(agin installed with npm) so after creating a Personal Access Token
and creating my publisher account I could then publish my extension.
But this was the thing my extension is just the &lt;code&gt;vbscrip.json&lt;/code&gt; file on
my hard drive.&lt;/p&gt;&lt;h2 id=&quot;how-do-i-make-it-into-a-extension&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#how-do-i-make-it-into-a-extension&quot; aria-label=&quot;how do i make it into a extension permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How do I make it into a extension?&lt;/h2&gt;&lt;p&gt;After reading up on extension I thought that you needed to have your
package ‘packaged’ with a &lt;code&gt;.vsix&lt;/code&gt; extension so looking at the links
earlier you need to install Yeoman (bugger!)&lt;/p&gt;&lt;p&gt;I looked around at other snippets packages on GitHub and couldn’t
understand why I needed to have my snippets packaged up in this
&lt;code&gt;.vsix&lt;/code&gt; file, all it was, was the &lt;code&gt;.json&lt;/code&gt; file from my computer.&lt;/p&gt;&lt;p&gt;So this is what I did, I copied the file structure from one of another
GitHub repositories that were just snippets, it basically consisted of
two folders and a &lt;code&gt;package.json&lt;/code&gt; file. I replaced all the relevant
properties in the &lt;code&gt;.json&lt;/code&gt; file and created a
&lt;a href=&quot;https://github.com/spences10/vba-snippets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt; repository just
for the sake of having all my lovingly crafted snippets kept safe.&lt;/p&gt;&lt;p&gt;So it looked like I had no way to get this onto the Marketplace, I was
pretty bummed but thought I’d just go though the process of publishing
an extension with &lt;code&gt;vsce&lt;/code&gt; by cd’ing to the folder the package was in
and going through the commands so I tried &lt;code&gt;vsce publish 1.0.0&lt;/code&gt;&lt;/p&gt;&lt;p&gt;I was pretty surprised (and relieved) to see the output pictured.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/4e408c5714752608e16b26532fdddb43/e548f/vsce-publish.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:17.5%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;71\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2071\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%2036v35h401V0H0v36m0%200l1%2031c0-3%201-5%203-6%202-2%202-2%201-3l-3-2c-1%201-1%200-1-2s1-3%203-3c3-1%203-2%200-4l-1-2%202-1-2-1c-2%201-2%200-2-1%200-4%201-7%203-7%203-1%202-4-1-5-4%200-3-7%201-8%203-1%202-4-1-5-4%200-3-7%201-8%203-1%202-4-1-5L1%202C0%201%200%2016%200%2036\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/4e408c5714752608e16b26532fdddb43/60a22/vsce-publish.webp 160w,/static/4e408c5714752608e16b26532fdddb43/4c812/vsce-publish.webp 320w,/static/4e408c5714752608e16b26532fdddb43/0ba47/vsce-publish.webp 640w,/static/4e408c5714752608e16b26532fdddb43/e46b2/vsce-publish.webp 960w,/static/4e408c5714752608e16b26532fdddb43/1e975/vsce-publish.webp 975w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/4e408c5714752608e16b26532fdddb43/69538/vsce-publish.png 160w,/static/4e408c5714752608e16b26532fdddb43/72799/vsce-publish.png 320w,/static/4e408c5714752608e16b26532fdddb43/6af66/vsce-publish.png 640w,/static/4e408c5714752608e16b26532fdddb43/d9199/vsce-publish.png 960w,/static/4e408c5714752608e16b26532fdddb43/e548f/vsce-publish.png 975w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/4e408c5714752608e16b26532fdddb43/6af66/vsce-publish.png&quot; alt=&quot;vscePublish&quot; title=&quot;vscePublish&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;I had a quick check of my publisher profile and lo and behold, there’s
my extension!&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:640px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/ed95fb9a535f6a2cfc14a3745830a20a/e513b/marketplace-extensions-management.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:18.125%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/svg+xml,%3csvg%20xmlns=\&amp;#x27;http://www.w3.org/2000/svg\&amp;#x27;%20width=\&amp;#x27;400\&amp;#x27;%20height=\&amp;#x27;73\&amp;#x27;%20viewBox=\&amp;#x27;0%200%20400%2073\&amp;#x27;%20preserveAspectRatio=\&amp;#x27;none\&amp;#x27;%3e%3cpath%20d=\&amp;#x27;M0%207v6h401V1H0v6m333%2017v5h61V19h-61v5\&amp;#x27;%20fill=\&amp;#x27;%23d3d3d3\&amp;#x27;%20fill-rule=\&amp;#x27;evenodd\&amp;#x27;/%3e%3c/svg%3e&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;picture&gt;
        &lt;source srcSet=&quot;/static/ed95fb9a535f6a2cfc14a3745830a20a/60a22/marketplace-extensions-management.webp 160w,/static/ed95fb9a535f6a2cfc14a3745830a20a/4c812/marketplace-extensions-management.webp 320w,/static/ed95fb9a535f6a2cfc14a3745830a20a/0ba47/marketplace-extensions-management.webp 640w,/static/ed95fb9a535f6a2cfc14a3745830a20a/e46b2/marketplace-extensions-management.webp 960w,/static/ed95fb9a535f6a2cfc14a3745830a20a/af3f0/marketplace-extensions-management.webp 1280w,/static/ed95fb9a535f6a2cfc14a3745830a20a/dcad1/marketplace-extensions-management.webp 2353w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/webp&quot;/&gt;
        &lt;source srcSet=&quot;/static/ed95fb9a535f6a2cfc14a3745830a20a/69538/marketplace-extensions-management.png 160w,/static/ed95fb9a535f6a2cfc14a3745830a20a/72799/marketplace-extensions-management.png 320w,/static/ed95fb9a535f6a2cfc14a3745830a20a/6af66/marketplace-extensions-management.png 640w,/static/ed95fb9a535f6a2cfc14a3745830a20a/d9199/marketplace-extensions-management.png 960w,/static/ed95fb9a535f6a2cfc14a3745830a20a/21b4d/marketplace-extensions-management.png 1280w,/static/ed95fb9a535f6a2cfc14a3745830a20a/e513b/marketplace-extensions-management.png 2353w&quot; sizes=&quot;(max-width: 640px) 100vw, 640px&quot; type=&quot;image/png&quot;/&gt;
        &lt;img class=&quot;gatsby-resp-image-image&quot; src=&quot;/static/ed95fb9a535f6a2cfc14a3745830a20a/6af66/marketplace-extensions-management.png&quot; alt=&quot;YeomanErr&quot; title=&quot;YeomanErr&quot; loading=&quot;lazy&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot;/&gt;
      &lt;/picture&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Here’s my extension:
&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=spences10.vba-snippets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VBA Snippets&lt;/a&gt;
from there you can fin the
&lt;a href=&quot;https://github.com/spences10/vba-snippets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt; repository too, I
hope it comes in handy for you one day!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[VBA Code Export for Version Control Systems]]></title><description><![CDATA[I have seen the same situation many times now in my career as a VBA
Developer about how source code control is managed with VBA projects…]]></description><link>https://scottspence.com/2016/11/14/vba-ide-export/</link><guid isPermaLink="false">https://scottspence.com/2016/11/14/vba-ide-export/</guid><pubDate>Mon, 14 Nov 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have seen the same situation many times now in my career as a VBA
Developer about how source code control is managed with VBA projects.&lt;/p&gt;&lt;p&gt;Source control on VBA has long been a bit of a nonsense, there isn’t
any really. When I started my first developer role it was talked about
in my team why we don’t use it and the best efforts the team did at
the time was save the new version to a different folder location and
to compare changes in the code from a previous version meant getting a
text compare app copy pasting the code into it from the two different
versions so you could track what was changed.&lt;/p&gt;&lt;p&gt;My colleague at the time and now very good friend
&lt;a href=&quot;https://uk.linkedin.com/in/paul-crook-4065a461&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Paul Crook&lt;/a&gt; came up
with the base of what I have done with the
&lt;a href=&quot;https://github.com/spences10/VBA-IDE-Code-Export&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VBA IDE Code Export tool&lt;/a&gt;
I have just extended some parts of his base that I feel were needed.&lt;/p&gt;&lt;p&gt;What was lacking from Crookie’s code, which I brought up at the time
with him was that it only exported &lt;code&gt;*.bas&lt;/code&gt;, &lt;code&gt;*.cls&lt;/code&gt; and &lt;code&gt;*.frm&lt;/code&gt; files
I did ask about code contained within the &lt;code&gt;ThisWorkbook&lt;/code&gt; and the
&lt;code&gt;Sheet*&lt;/code&gt; modules. What we decided to do was if there was code in those
modules was to abstract it out into its own module, so &lt;code&gt;ThisWorkbook&lt;/code&gt;
would call out to &lt;code&gt;ThisWorkbook.bas&lt;/code&gt; this was a bit of extra work to
begin with but ultimately benefited us in the long run with good
version control.&lt;/p&gt;&lt;p&gt;I wasn’t keen on how you had to work with this so decided to have a
play around with it when I put it on
&lt;a href=&quot;https://github.com/spences10/VBA-IDE-Code-Export&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitHub&lt;/a&gt; I decided
to try right some of that, I think I may have made some things worse
but I’m keen to make another revision of the tool in the future to
correct that.&lt;/p&gt;&lt;h3 id=&quot;what-did-you-make-better&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-did-you-make-better&quot; aria-label=&quot;what did you make better permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;what did you make better&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;added functionality to save code from &lt;code&gt;ThisWorkbook&lt;/code&gt; and &lt;code&gt;Sheet*&lt;/code&gt;&lt;/li&gt;&lt;li&gt;made a &lt;code&gt;.conf&lt;/code&gt; file to save the project contents to meaning there
were no modules left in the project after export&lt;/li&gt;&lt;li&gt;added the ability to specify an import and export location, it was
defaulted to the root of where the source workbook was located&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;what-did-you-mess-up&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#what-did-you-mess-up&quot; aria-label=&quot;what did you mess up permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;what did you mess up&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;added a form, means more validation&lt;/li&gt;&lt;li&gt;added ranges to the configuration worksheet for storing locations
other than the &lt;code&gt;ThisWorkbook&lt;/code&gt; file location&lt;/li&gt;&lt;li&gt;didn’t add the new functionality to the existing code&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;up-next&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#up-next&quot; aria-label=&quot;up next permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;up next&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;possibly remove the old method that copied out the project contents
to a module and go full retard with the &lt;code&gt;.conf&lt;/code&gt; file&lt;/li&gt;&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[freeCodeCamp]]></title><description><![CDATA[Ok, I have recently discovered and started doing freeCodeCamp(🔥)
which so far I'm really enjoying. Since being out of work I have had some…]]></description><link>https://scottspence.com/2016/11/13/freecodecamp/</link><guid isPermaLink="false">https://scottspence.com/2016/11/13/freecodecamp/</guid><pubDate>Sun, 13 Nov 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ok, I have recently discovered and started doing freeCodeCamp(🔥)
which so far I’m really enjoying.&lt;/p&gt;&lt;p&gt;Since being out of work I have had some time to start exploring
different programming languages and technologies but I haven’t found
any courses that I have started and thought “you know what I’m going
to stick this out” that’s before I discovered FCC, FCC is very much a
real world situation course where you go over some basics first then
apply them, once you have learnt enough you then have to complete
projects using the skills you have just learned.&lt;/p&gt;&lt;p&gt;So far I have made a tribute page
&lt;a href=&quot;http://codepen.io/spences10/full/NbqZob/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DJ Hype&lt;/a&gt; and created a
personal &lt;a href=&quot;http://codepen.io/spences10/full/NbGXoy/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Portfolio&lt;/a&gt; page on
&lt;a href=&quot;http://codepen.io/spences10/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CODEPEN.io&lt;/a&gt; there’s some great examples
on &lt;a href=&quot;http://codepen.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CODEPEN.io&lt;/a&gt; to help you get started and so far
I have really enjoyed them.&lt;/p&gt;&lt;p&gt;So now onto JavaScript!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hello World!]]></title><description><![CDATA[My first post using Gatsby, awesome static site generator
 Gatsby  from  Kyle Mathews So not a lot to see, I'll just be configuring this and…]]></description><link>https://scottspence.com/2016/10/hello-world/24/</link><guid isPermaLink="false">https://scottspence.com/2016/10/hello-world/24/</guid><pubDate>Mon, 24 Oct 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My first post using Gatsby, awesome static site generator
&lt;a href=&quot;https://github.com/gatsbyjs/gatsby&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Gatsby&lt;/a&gt; from &lt;a href=&quot;https://github.com/KyleAMathews&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Kyle Mathews&lt;/a&gt;&lt;/p&gt;&lt;p&gt;So not a lot to see, I’ll just be configuring this and adding all my
old blog posts.&lt;/p&gt;</content:encoded></item></channel></rss>