<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Monica Powell</title>
    <description>The latest articles on Forem by Monica Powell (@m0nica).</description>
    <link>https://forem.com/m0nica</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F18864%2F664e8e81-eeff-498e-a4dd-463d98e7f79f.png</url>
      <title>Forem: Monica Powell</title>
      <link>https://forem.com/m0nica</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/m0nica"/>
    <language>en</language>
    <item>
      <title>Tips for Debugging Software like a Detective</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sat, 15 May 2021 12:51:13 +0000</pubDate>
      <link>https://forem.com/m0nica/tips-for-debugging-software-like-a-detective-2oab</link>
      <guid>https://forem.com/m0nica/tips-for-debugging-software-like-a-detective-2oab</guid>
      <description>&lt;p&gt;Being an effective web developer when investigating a software issue, locally or in production, requires some detective-like debugging skills. As I've grown as a developer I've not only improved the breadth of my knowledge about various ways software can break in unexpected ways but I've also enhanced my debugging skills over time.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1392464056011866114-803" src="https://platform.twitter.com/embed/Tweet.html?id=1392464056011866114"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1392464056011866114-803');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1392464056011866114&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;In this article, I share a longer-form version of the above Twitter thread which highlights some of my thoughts on various ways to approach understanding why the computer doesn't appear to be doing what you tell it to do. Computers interpret instructions literally and to resolve a discrepancy between actual and expected functionality you may need to revisit your assumptions!&lt;/p&gt;

&lt;p&gt;Software engineers can hold a lot of ill-informed assumptions or falsehoods which can lead to subpar handling of "edge cases" like assuming a user's name is permanent or that a name must by X characters or that a name is only structured as first name, middle name, last name when in reality that is not a universal fact. Check out &lt;a href="https://github.com/kdeldycke/awesome-falsehood" rel="noopener noreferrer"&gt; awesome-falsehood &lt;/a&gt; if you'd like to learn more about common falsehoods that engineers believe about things like time, names, addresses, and more.&lt;/p&gt;

&lt;p&gt;If an issue seems to be isolated to my local environment and has gone from working to not working without any notable software changes I may try "turning it on and off again" by trying some of the following: rebuilding database, doing a fresh install of node_modules, restarting docker or your computer, etc. But what do you do when just turning it on and off again doesn’t resolve the issue?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run linting and read any errors&lt;/strong&gt; Is there a blaring syntax error? Is your code referencing an undefined variable? More times than I care to admit my code wasn't compiling locally because there was a rouge letter 'f' that I somehow added to a random line. This misplaced char is often picked up by my linting but if I do want to manually skim my changes since the app successfully compiled then I will use the &lt;a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens" rel="noopener noreferrer"&gt;VSCode Git Lens Integration&lt;/a&gt; to see if anything stands out as &lt;em&gt;off&lt;/em&gt; with my changes. Similar to linting errors, if there are other errors in your terminal, browser console, or webpage that are appearing when your app fails to compile or under the unexpected condition they can help guide your search to figure out what is going wrong. When I first was learning how to program, I more so stared 😳 at error messages instead of reading them. If you're still getting comfortable with error messages check out &lt;a href="https://nickymeuleman.netlify.app/blog/love-errors" rel="noopener noreferrer"&gt;Nicky Meuleman tips on learning to appreciate errors&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Only change one thing at a time&lt;/strong&gt;. It can be tempting to change everything at once. But try just changing one thing and before you change it think through how that one change will help you confirm or reject your current assumptions of the problem and ultimately help you further your understanding and bring you closer to a potential solution. Automated tests can be helpful to confirm how changes work under different test cases and to ensure as you progress through the problem you don't unknowingly break preexisting test cases that were previously passing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Confirm all of your assumptions.&lt;/strong&gt; Consistently reproduce the issue manually or with tests. Under what conditions does the system fail? To better understand an underlying issue you should determine what conditions it behaves unexpectedly in. Using logs, breakpoints, tests, check network calls, etc to sort out when it fails will get you closer to understanding why it's not working as expected. Is your API actually returning the data you expect? Is it an environment-specific issue? Are there missing environment variables?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lean on tests to automate confirming your assumptions and testing potential solutions&lt;/strong&gt; Approaching development with a red-green refactor development approach of defining desired functionality in test, implementing code to make the test go from red to green, and then refactoring without having to worry about unknowingly breaking the desired functionality. This approach prevents building out too much of a feature without testing its functionality and if bugs are resolved in a test-driven way then that means that if a similar regression is made in the future in the codebase that there will be a clear failing test warning future developers that something is amiss. Git also has command, bisect which can be used to quickly find a problematic commit, by strategically checking out specific commits from the git history and then based on whether or not that commit is identified as being before or after the software regression was introduced then the next commit is either earlier or later in the git history until the culprit can be identified. Git bisect can be combined with automated testing to make the process of identifying the problematic commit even more efficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Walkthrough your code line by line&lt;/strong&gt;. Try to read it with fresh eyes even if that means taking a 5 min break and revisiting. I'm always amazed how sleeping on a problem that stumped me usually makes a lot more sense in the morning. It's definitely possible for your mind to continue working through a problem even when you are not directly in front of a screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Look at the source code of the third-party package.&lt;/strong&gt; check for open issues. If the error may be related to third-party software look at its source code. I’ve looked at React, misc. packages with types, Webmention, etc on GitHub to better understand their functionality and find relevant open issues. Oftentimes others may have encountered a similar issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Google is your best friend&lt;/strong&gt; A quick search can be a developer’s best friend. &lt;strong&gt;Are you using a new function or package? Can you find an example where it's working?&lt;/strong&gt; If you want to see code that uses the same APIs in context then recommend searching your local repo or &lt;a href="https://grep.app" rel="noopener noreferrer"&gt;https://grep.app&lt;/a&gt; to search open source repos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Phone a friend.&lt;/strong&gt; I recommend integrating git blame into your development environment I use the &lt;a href="https://gitlens.amod.io/" rel="noopener noreferrer"&gt;Git lens&lt;/a&gt; plugin which shows you, directly within files in a code editor, who authored certain file changes and the PR which can be helpful for quickly getting more context regarding decisions by looking at the associated Pull Request or having the opportunity to connect directly with the committer. Pair programming can be an effective way to debug and share knowledge. Similar, to the magic of figuring out the solution to a bug in the shower or overnight there is a phenomenon called rubber ducky debugging in which just explaining the issue to someone else (even an inanimate rubber duck) can help make the solution more obvious.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you’ve sorted out a gnarly or even an "obvious" in hindsight bug remember to document your learnings. Even if it’s just a quick note for your future self.&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>tdd</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Add Instagram Timeline To a NextJS Site</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Thu, 08 Apr 2021 00:00:36 +0000</pubDate>
      <link>https://forem.com/m0nica/how-to-add-instagram-timeline-to-a-nextjs-site-4nd5</link>
      <guid>https://forem.com/m0nica/how-to-add-instagram-timeline-to-a-nextjs-site-4nd5</guid>
      <description>&lt;p&gt;I recently added an Instagram timeline to my site &lt;a href="https://www.indigitalcolor.com/"&gt;In Digital Color&lt;/a&gt; and wanted to share how I added the Instagram integration to my NextJS site and document some of the hiccups I encountered along the way with authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="/media/in-digital-color-ig-integration-screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="/media/in-digital-color-ig-integration-screenshot.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Screenshot of Instagram Timeline integration on indigitalcolor.com&lt;/em&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  Install and import &lt;code&gt;instagram-web-api&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;We'll use the &lt;a href="https://github.com/jlobos/instagram-web-api"&gt;&lt;code&gt;instagram-web-api&lt;/code&gt;&lt;/a&gt; npm package to do the heavy lifting for the integration. which should be installed within a NextJS site with &lt;code&gt;npm install instagram-web-api&lt;/code&gt; or &lt;code&gt;yarn add instagram-web-api&lt;/code&gt;. Once the package is successfully installed it should be imported into &lt;code&gt;index.js&lt;/code&gt; file (or whichever page you would like the Instagram feed to appear on) with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instagram-web-api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point the &lt;code&gt;index.js&lt;/code&gt; file where I imported &lt;code&gt;instagram-web-api&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instagram-web-api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*Other Page Content*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup getStaticProps to Fetch Data at Build Time
&lt;/h2&gt;

&lt;p&gt;Next, we need to set up a way to get fetched data into our component. In this case, I chose to use the async &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation"&gt;&lt;code&gt;getStaticProps&lt;/code&gt;&lt;/a&gt; function to pass data into our component.&lt;code&gt;getStaticProps&lt;/code&gt; is a function available to pages within NextJS that allows data to be fetched at build time and passed into page-level components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instagram-web-api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// empty array of instagram posts is being&lt;/span&gt;
&lt;span class="c1"&gt;// passed as a prop into the Index component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;instagramPosts&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*Other Page Content*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// set posts to an empty array as a placeholder&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// return the posts as the prop instagramPosts&lt;/span&gt;
      &lt;span class="c1"&gt;// for the Index function to use&lt;/span&gt;
      &lt;span class="na"&gt;instagramPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup Instagram Client Authentication
&lt;/h2&gt;

&lt;p&gt;Before we can retrieve data from Instagram we should set up authentication &lt;code&gt;instagram-web-api&lt;/code&gt; in &lt;code&gt;getStaticProps()&lt;/code&gt; to be able to fetch data from Instagram. We can accomplish this by setting up a new Instagram client with &lt;code&gt;new Instagram({username: IG_USERNAME, password: IG_PASSWORD})&lt;/code&gt; and attempting to log in with &lt;code&gt;await client.login()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// create a new client to communicate with  Instagram&lt;/span&gt;
  &lt;span class="c1"&gt;// this service requires authentication&lt;/span&gt;
  &lt;span class="c1"&gt;//with username and password parameters&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IG_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IG_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// attempt to log in to Instagram&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// throw an error if login to Instagram fails&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something went wrong while logging into Instagram&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;instagramPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Credentials such as the password should be accessed via environment variables that are only available locally and at build time to avoid exposing this information. In NextJS, local environment variables can be accessed by creating a file entitled &lt;code&gt;.env.development.local&lt;/code&gt;. Although the username is not a secret you can add it to the environment file if you'd like. &lt;code&gt;env.development.local&lt;/code&gt; should be added to your &lt;code&gt;.gitignore&lt;/code&gt; file to avoid committing it to version control. Separately, I set up my hosting to have access to the appropriate secrets at build time which supersedes the values in the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;env.development.local&lt;/code&gt; file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IG_USERNAME="super_cool_username"
IG_PASSWORD="super_secret_secure_password"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the &lt;code&gt;env.development.local&lt;/code&gt; at a minimum you should have a &lt;code&gt;.env&lt;/code&gt; file that sets the defaults for env variables. My &lt;code&gt;.env&lt;/code&gt; file looks like and is checked into version control:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Confirm Instagram Client is Functional
&lt;/h2&gt;

&lt;p&gt;If you're not already you should run the development server of your NextJS site with &lt;code&gt;npm run next&lt;/code&gt; and check in the terminal that is running the server to see if there are any console errors. You might encounter the error log we added of "Something went wrong while logging into Instagram" during this stage of the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolving 4xx Authentication Errors
&lt;/h2&gt;

&lt;p&gt;While I was setting up the Instagram client with the correct credentials I encountered various 4xx authentication relates errors (if you're not familiar with HTTP status codes check out my site &lt;a href="https://www.httriri.com/"&gt;https://www.httriri.com/&lt;/a&gt;) being returned to Instagram saying "Please wait a few minutes before trying again". I was able to temporarily circumnavigate the 4xx errors and "Please wait a few minutes before trying again" message by switching my IP address with a VPN (Virtual private network) and attempting to authenticate again. A VPN allows you to access the internet with a remote VPN server's IP address as opposed to your local IP address. &lt;a href="https://www.comparitech.com/blog/vpn-privacy/change-ip-address/"&gt;This article&lt;/a&gt; shares other ways you can change your IP address. I already had a VPN configured on my computer so I found that to be the most straightforward solution in my case. Using a VPN to access the internet resolved the issues I was encountering as they were IP address level issues. You can check if your issues are IP level by trying to log into Instagram manually on the same IP address and on another device that is connected to a separate cellular network (and has its own IP). I am wondering if there's a more official way to get Instagram to recognize API usage as not being unusual activity. If you are running into a 4xx error for a different reason this is a good time to manually confirm that the credentials you are providing are correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Request Timeline Data from Instagram
&lt;/h2&gt;

&lt;p&gt;Once authentication is successful we can request specific data from Instagram calling &lt;code&gt;client.getPhotosByUsername({username: process.env.IG_USERNAME})&lt;/code&gt; to fetch timeline data for the username that is passed in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IG_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IG_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// request photos for a specific instagram user&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instagram&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getPhotosByUsername&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IG_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge_owner_to_timeline_media&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// if we receive timeline data back&lt;/span&gt;
      &lt;span class="c1"&gt;//  update the posts to be equal&lt;/span&gt;
      &lt;span class="c1"&gt;// to the edges that were returned from the instagram API response&lt;/span&gt;
      &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instagram&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edge_owner_to_timeline_media&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;edges&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Something went wrong while fetching content from Instagram&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;instagramPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// returns either [] or the edges returned from the Instagram API based on the response from the `getPhotosByUsername` API call&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Render Instagram Data with InstagramFeed component
&lt;/h2&gt;

&lt;p&gt;Once we've successfully received timeline data back from the &lt;code&gt;getPhotosByUsername()&lt;/code&gt; call we can render this data. Below is the skeleton I used to transform the data returned from the Instagram API into a digestible and visually engaging component that displays recent photos and links to them on Instagram so that visitors can click through to the actual posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;InstagramFeed&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;instagramPosts&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.instagram.com/yourinstagramhandle/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Follow&lt;/span&gt; &lt;span class="nx"&gt;Us&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* let's iterate through each of the
         instagram posts that were returned
         from the Instagram API*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;instagramPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;// let's wrap each post in an anchor tag&lt;/span&gt;
            &lt;span class="c1"&gt;// and construct the url for the post using&lt;/span&gt;
            &lt;span class="c1"&gt;// the shortcode that was returned from the API&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
                &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://www.instagram.com/p/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shortcode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view image on Instagram&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* set the image src equal to the image
                url from the Instagram API*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
                  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thumbnail_src&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                  &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// the caption with hashtags removed&lt;/span&gt;
                    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edge_media_to_caption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;#&lt;/span&gt;&lt;span class="se"&gt;\w&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                  &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to actually render this component and the associated post data from Instagram we need to import &lt;code&gt;InstagramFeed&lt;/code&gt; into &lt;code&gt;index.js&lt;/code&gt; and render it withing the &lt;code&gt;Index&lt;/code&gt; component wiith the &lt;code&gt;instagramPosts&lt;/code&gt; prop we received from &lt;code&gt;getStaticProps&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Instagram&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;instagram-web-api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;InstagramFeed&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/instagramFeed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;// empty array of instagram posts is being&lt;/span&gt;
&lt;span class="c1"&gt;// passed as a prop into the Index component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;instagramPosts&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*Other Page Content*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InstagramFeed&lt;/span&gt; &lt;span class="nx"&gt;instagramPosts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;instagramPosts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything worked properly you should now see all of your latest Instagram posts rendered on the page and be able to click any given posts to be taken to it on Instagram. If you are not seeing any posts rendering there may have been an issue with authentication (invalid credentials or rate limited by Instagram). If so, I recommend following my above troubleshooting steps of manually verifying credentials (in case of invalid credentials) or exploring using a VPN (if your IP address has been rate limited).&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>api</category>
      <category>instagram</category>
    </item>
    <item>
      <title>Creating Protected Routes In NextJS With Supabase</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Wed, 07 Apr 2021 23:54:11 +0000</pubDate>
      <link>https://forem.com/m0nica/creating-protected-routes-in-nextjs-with-supabase-46gl</link>
      <guid>https://forem.com/m0nica/creating-protected-routes-in-nextjs-with-supabase-46gl</guid>
      <description>&lt;p&gt;&lt;br&gt;
This articles walks through how to create protected routes on NextJS with Supabase's user management. It assumes you already have a NextJS site up and running with the ability to create new Supabase users but if not check out the first part of this series on &lt;a href="https://aboutmonica.com/blog/creating-new-supabase-users-in-next-js" rel="noopener noreferrer"&gt;creating new Supabase users in NextJS&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;



&lt;h2&gt;
  
  
  Supabase Auth Overview
&lt;/h2&gt;

&lt;p&gt;Supabase has various methods in their JavaScript client library to handle user authentication and uses JSON Web Tokens (JWT) under the hood to manage authentication. If you want to learn more about how Auth works in Supabase check out the &lt;a href="https://supabase.io/docs/learn/auth-deep-dive/auth-deep-dive-jwts" rel="noopener noreferrer"&gt;Supabase auth deep-dive video series&lt;/a&gt;. In order to have protected routes on our NextJS site, we'll need a way to register and authenticate users. We can perform these user actions and checks with the following methods from the &lt;a href="https://supabase.io/docs/client/supabase-client" rel="noopener noreferrer"&gt;Supabase Auth client&lt;/a&gt;. :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://supabase.io/docs/client/auth-signup" rel="noopener noreferrer"&gt;supabase.auth.signUp&lt;/a&gt; - We should give users the ability to create an account (covered in the first article on &lt;a href="https://aboutmonica.com/blog/creating-new-supabase-users-in-next-js" rel="noopener noreferrer"&gt;creating new Supabase users in NextJS&lt;/a&gt;) &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://supabase.io/docs/client/auth-signin" rel="noopener noreferrer"&gt;supabase.auth.signIn&lt;/a&gt; - We need to give users the ability to sign-in. In this particular article, we'll cover the traditional method of using a username and password for sign-in but Supabase also supports other ways to log in, including OAuth providers (GitHub, Google, etc.) and magic links.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://supabase.io/docs/client/auth-user" rel="noopener noreferrer"&gt;supabase.auth.user&lt;/a&gt; - We need a way to determine if a user is currently logged-in in order to ensure that logged-out users are not able to view pages that should only be accessible to logged-in users and that the proper information is displayed in various places like the site navigation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://supabase.io/docs/client/auth-signout" rel="noopener noreferrer"&gt;supabase.auth.signOut&lt;/a&gt; - We should give users the ability to sign out and unauthenticate their session.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create Protected Route
&lt;/h2&gt;

&lt;p&gt;In order to create a protected route we need to have a particular page component we'd like to protect. For this example let's created a protected page at &lt;code&gt;pages/protected.js&lt;/code&gt; that we can view at &lt;code&gt;localhost:3000/protected&lt;/code&gt; when our site is running locally. This protected page will make a fetch request to a &lt;code&gt;getUser&lt;/code&gt; API route  to determine if there is currently an authenticated user loading the page.  The API call should return the current user when there is one. We can then use this API response to redirect the page to the login page when there is no current user and only display user-specific information on the protected route when there is a user.&lt;/p&gt;

&lt;p&gt;The API request can be made with &lt;code&gt;getServerSideProps()&lt;/code&gt; which is a NextJS function that is called before a page renders. This allows us to redirect before the page renders based on the response from the &lt;code&gt;getUser&lt;/code&gt; API call.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;basePath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../utils/siteConfig&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We need to implement `/api/getUser` by creating &lt;/span&gt;
    &lt;span class="c1"&gt;// an endpoint in `pages/api` but for now let's just call it&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;basePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/getUser`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

 &lt;span class="c1"&gt;// If the `getUser` endpoint doesn't have a user in its response&lt;/span&gt;
 &lt;span class="c1"&gt;// then we will redirect to the login page&lt;/span&gt;
 &lt;span class="c1"&gt;// which means this page will only be viewable when `getUser` returns a user.&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;permanent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// We'll pass the returned `user` to the page's React Component as a prop&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Protected&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="c1"&gt;// Let's greet the user by their e-mail address&lt;/span&gt;
            &lt;span class="nx"&gt;Welcome&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;waving hand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="err"&gt;👋🏾&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;{" "&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;{" "&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;          &lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;currently&lt;/span&gt; &lt;span class="nx"&gt;viewing&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
In this instance, NextJS requires absolute paths for the API routes and if you do not have an absolute route then you'll receive the following error: &lt;br&gt;
&lt;b&gt;"Error: only absolute urls are supported"&lt;/b&gt;. In order to resolve this I created a helper function in &lt;b&gt;utils/siteConfig&lt;/b&gt; to set the basePath based on the environment. In order for this to work there needs to be a &lt;b&gt;PRODUCTION_URL&lt;/b&gt; set in your deployed site's environment variables.&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;basePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRODUCTION_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Now, we need to actually implement the &lt;code&gt;getUser&lt;/code&gt; API route that the protected route is calling by creating a file &lt;code&gt;pages/api/getUser.js&lt;/code&gt;. Within this file we will make a request to &lt;code&gt;supabase.auth.user()&lt;/code&gt; which returns the current user when there is a user currently logged-in.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../utils/supabaseClient&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The above code assumes that you've already set up a Supabase Client which we covered in the &lt;a href="https://aboutmonica.com/blog/creating-new-supabase-users-in-next-js" rel="noopener noreferrer"&gt;first post of this series&lt;/a&gt;. The Supabase client we are using in this instance looks like the below and uses environment variables to determine the Supabase DB URL and associated key:&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can retrieve the API key and database URL associated with your Supabase project from &lt;code&gt;https://app.supabase.io/project/yourprojecturl]/settings/api&lt;/code&gt; which can be navigated to by going to your project &amp;gt; settings &amp;gt; API.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Sign-in and Redirect to Protected Page
&lt;/h2&gt;

&lt;p&gt;We'll allow folks to log in and log out of the site using the sitewide navigation. In order to show the appropriate links based on authentication status, we can use the state to track if a user is currently authenticated. As a default, we'll set authentication status to &lt;code&gt;false&lt;/code&gt; so that the navigation defaults to thelogged-out view. &lt;/p&gt;

&lt;p&gt;When a user is authenticated then we will show the Sign Out text in the nav: &lt;a href="/media/logged-in-nav.png" class="article-body-image-wrapper"&gt;&lt;img src="/media/logged-in-nav.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there is no authenticated user then we will link to the Sign-in and Sign Up pages: &lt;a href="/media/logged-out-nav.png" class="article-body-image-wrapper"&gt;&lt;img src="/media/logged-out-nav.png"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Let's use state to track if a user is currently authenticated&lt;/span&gt;
  &lt;span class="c1"&gt;// As a default we'll set this value to false so that the navigation defaults to thelogged-out view&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isAuthed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAuthStatus&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="c1"&gt;// We'll set up the nav, on mount to call the getUser endpoint we just &lt;/span&gt;
 &lt;span class="c1"&gt;// created to determine if a user is currently logged-in or not&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./api/getUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setAuthStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authenticated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;// If user is authenticated then we will show the Sign Out text&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isAuthed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="nx"&gt;Out&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="c1"&gt;// If there is no authenticated user then we will link to the Sign-in and Sign Up pages&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/signup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="nx"&gt;Up&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/nav&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;When a user clicks "Sign In" from the nav we will navigate the user to the &lt;code&gt;login&lt;/code&gt; page which contains a form to allow users to sign-in. The form will collect a user's email and password and on submit will fire a function &lt;code&gt;signInUser&lt;/code&gt; which makes an API request to an API route for &lt;code&gt;login&lt;/code&gt; and passes the &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; values from the form submit event to the API. If all goes well then we will receive a user object and can redirect (using NextJS's client-side router) to the &lt;code&gt;/protected&lt;/code&gt; route that serves as a landing page for logged-in users.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signInUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/login`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/protected`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;signInUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;autoComplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;required&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;required&lt;/span&gt;
      &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;login&lt;/code&gt; API route will use &lt;code&gt;supabase.auth.signIn&lt;/code&gt; to sign-in a user. If a user is successfully signed in then the API will return a 200 response, or else the API will return a 401 response. The form is not yet set up to handle this 401 response but ideally, we'd want to return some type of message to the user informing them that their credentials were invalid and prompt them to attempt to sign-in again or reset their password. However, as this app is currently being built the functionality to reset password does not yet exist so this error path cannot be fully handled yet.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../utils/supabaseClient&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;registerUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Sign Out and Redirect to Homepage
&lt;/h2&gt;

&lt;p&gt;Let's update the Sign Out link in the header to be functional by creating a &lt;code&gt;signOut&lt;/code&gt; function that fires on click of the Sign Out text.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;signOutUser&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Sign&lt;/span&gt; &lt;span class="nx"&gt;Out&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;       &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;We'll also want to import a router from &lt;code&gt;next/router&lt;/code&gt; to handle our client-side redirect.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;For &lt;code&gt;signOutUser&lt;/code&gt; let's make a call to a &lt;code&gt;logout&lt;/code&gt; API route that sets the &lt;code&gt;authStatus&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; when a user is successfully signed out. We also want to ensure that when a user is not logged-in they are not viewing an authenticated page by redirecting to the homepage if a user logs out on a page other than the homepage. Without explicitly redirecting to the homepage when a user signs out, the state of &lt;code&gt;authStatus&lt;/code&gt; would change in the nav as well as the logged-in vs.logged-out specific text however, the actual page regardless of authentication would continue showing protected information for unauthenticated users which we don't want.&lt;/p&gt;

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

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signOutUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/logout`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;setAuthStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// redirect to homepage when logging out users&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we need to create the &lt;code&gt;/api/logout&lt;/code&gt; route so that we can actually use it when the &lt;code&gt;signOutUser&lt;/code&gt; function fires.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../utils/supabaseClient&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;logoutUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User has been logged out&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;So in conclusion, we created a protected route by creating a page component in NextJS that calls a &lt;code&gt;getUser&lt;/code&gt; endpoint in &lt;code&gt;getServerSideProps()&lt;/code&gt; and redirects to the log in page, instead of loading the protected route, when there is not a user returned. We also set up client-side routing to redirect users to &lt;code&gt;/protected&lt;/code&gt; when they successfully logged-in and to the homepage &lt;code&gt;/&lt;/code&gt; when they logged out. The core functionality to update and check authentication was handle in API routes using Supabase's various auth methods (signIn, signOut, user).&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Code on GitHub
&lt;/h2&gt;

&lt;p&gt;You can view the full source code for the example code at: &lt;a href="https://github.com/M0nica/protected-routes-with-supabase-nextjs-example" rel="noopener noreferrer"&gt;https://github.com/M0nica/protected-routes-with-supabase-nextjs-example&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;I am looking forward to sharing more about the app development as I progress through my journey of developing &lt;a href="https://shinedocs.com" rel="noopener noreferrer"&gt;Shine Docs&lt;/a&gt; . As I wrap up the authentication for this site I am considering adding additional functionality like magic links or other auth providers, which are natively supported by Supabase. Before I extend the auth functionality to support additional ways of authenticating I will need to update the site to give users the ability to reset their own password and better handle authentication errors to ensure that the sign-in (are the user credentials invalid? did something go wrong during sign-in?) and sign up (has an e-mail already been claimed? is a password not secure enough?) flow are as seamless as possible.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>supabase</category>
      <category>database</category>
      <category>react</category>
    </item>
    <item>
      <title>Creating New Supabase Users In NextJS</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Wed, 07 Apr 2021 23:50:54 +0000</pubDate>
      <link>https://forem.com/m0nica/creating-new-supabase-users-in-nextjs-g3g</link>
      <guid>https://forem.com/m0nica/creating-new-supabase-users-in-nextjs-g3g</guid>
      <description>&lt;p&gt;&lt;br&gt;
  This article is the beginning of a series about setting up a NextJS with Supabase for user management and database storage. View the next part of this series: &lt;a href="https://aboutmonica.com/blog/creating-protected-routes-in-next-js-with-supabase" rel="noopener noreferrer"&gt;creating protected routes with NextJS and Supabase&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This article walks through how to create new users for a &lt;a href="https://supabase.io/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; database with an API written in NextJS. Note: at the time of this writing that Supabase is free for &lt;a href="https://supabase.io/beta" rel="noopener noreferrer"&gt;beta&lt;/a&gt; users which is pretty nifty as they include a hosted Postgres database which makes it faster to get an application up and running with a functional database. After the Beta period wraps up Supabase is &lt;a href="https://supabase.io/docs/pricing" rel="noopener noreferrer"&gt;planning on charging for hosting&lt;/a&gt; and will offer current Beta users 1 year of base tier usage for free.&lt;/p&gt;

&lt;p&gt;I am currently building a SaaS (Software as a Service) website along with some other &lt;a href="https://egghead.io/" rel="noopener noreferrer"&gt;Egghead&lt;/a&gt; folks who are creating different types of SaaS applications. I am building this app from "scratch" and am currently in the phase of setting up authentication. For this project I am focused on learning new technology and documenting my learnings therefore I decided to try out Supabase, which is an Open Source alternative to Google's &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;. The specific application I am working towards building is, &lt;a href="https://shinedocs.com" rel="noopener noreferrer"&gt;Shine Docs&lt;/a&gt; which will allow folks to document professional achievements in a granular way.&lt;/p&gt;

&lt;p&gt;Here's a blurb from the project's README:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...]your place to shine, showcase and document more granular professional (or otherwise) achievements. Did you fix a gnarly production bug in record time? Did you give your 1st (or 20th) conference talk? Did you write out some solid documentation? Make sure you capture all of this awesomeness in more in a dedicated space. These types of receipts translate well into future resumes, negotiations, annual reviews and reminders to yourself. Inspired by Julia Evan’s article on &lt;a href="https://jvns.ca/blog/brag-documents/" rel="noopener noreferrer"&gt;getting your work recognized with a brag document&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This application is intended for folks looking for more structure with how they document granular professional achievements as well as those looking to have their achievements be more visible.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;h2&gt;
  
  
  Set Up NextJS
&lt;/h2&gt;

&lt;p&gt;If you do not yet have a NextJS site you should set up a boilerplate NextJS site as a starting point. This can be done by running the command &lt;code&gt;npx create-next-app&lt;/code&gt; to spinup up a default NextJS site. After going through the prompts you should open your newly created directory containing the site.&lt;/p&gt;

&lt;p&gt;The next step in setting up NextJS to interact with Supabase is to install Supabase dependencies with &lt;code&gt;@supabase/supabase-js&lt;/code&gt; and then run &lt;code&gt;yarn dev&lt;/code&gt; to run the site locally. If everything worked out you should be able to visit &lt;code&gt;localhost:3000&lt;/code&gt; and see your Next site running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up Supabase Project
&lt;/h2&gt;

&lt;p&gt;On &lt;a href="https://app.supabase.io/" rel="noopener noreferrer"&gt;Supabase we will create a new project&lt;/a&gt; and then retrieve the API key and URL from &lt;code&gt;https://app.supabase.io/project/yourprojecturl]/settings/api&lt;/code&gt; which can be navigated to by going to your project &amp;gt; settings &amp;gt; API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0via2p30ysfp0yyprb3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0via2p30ysfp0yyprb3g.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;a screenshot of the Supabase settings page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In order for our application to be able to interact with our project's DB we will use environment variables to store the necessary values. As a Mac user, I tend to store environment variables in &lt;code&gt;~/.bash_profile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can add the following your &lt;code&gt;~/.bash_profile&lt;/code&gt; or wherever you store local environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SUPABASE_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"SUPABASEKEYFROMSETTINGSSCREEN"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SUPABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"SUPABASEURLFROMSETTINGSSCREEN"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have a terminal session running then after you save your environment variables you should run &lt;code&gt;source ~/.bash_profile&lt;/code&gt; to ensure that the newly exported environment variables are available to your NextJS app to access.&lt;/p&gt;

&lt;p&gt;We will then create a &lt;code&gt;supabaseClient.js&lt;/code&gt; file (in &lt;code&gt;utils/&lt;/code&gt;) to set up the Supabase client that is used to interact with Supabase DB to use the URL and API key that were set in the previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// retrieving environment variables&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SUPABASE_KEY&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;supabaseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having the Supabase client live in a standalone file will be helpful when we have multiple API endpoints that interact with Supabase that require the same credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering Supabase User
&lt;/h2&gt;

&lt;p&gt;Now we will call Supabase to register users by creating a new API function inside of &lt;code&gt;pages/api&lt;/code&gt; that uses our Supabase client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../utils/supabaseClient&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;registerUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// destructure the e-mail and password received in the request body.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;

  &lt;span class="c1"&gt;//make a SignUp attempt to Supabase and&lt;/span&gt;
  &lt;span class="c1"&gt;// capture the user (on success) and/or error.&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="c1"&gt;// Send a 400 response if something went wrong&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="c1"&gt;// Send 200 success if there were no errors!&lt;/span&gt;
  &lt;span class="c1"&gt;// and also return a copy of the object we received from Supabase&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can learn more about HTTP status codes on what different status codes mean on my site &lt;a href="https://www.httriri.com/" rel="noopener noreferrer"&gt;https://www.httriri.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's actually use the Supabase endpoint to create users. Our site's visitors will fill out a form to register therefore let's create a form that requires an e-mail and password and calls the previously created Register endpoint upon form submission. This form will then be imported and used in our index file, &lt;code&gt;index.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;registerUser&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;autoComplete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Password&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Register&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's define what happens &lt;code&gt;onSubmit&lt;/code&gt; when &lt;code&gt;registerUser&lt;/code&gt; is called by defining &lt;code&gt;registerUser&lt;/code&gt;. This function will receive the email and password typed into the form from the form submission event and will make a post request to the register endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registerUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// prevents page from redirecting on form submissiomn&lt;/span&gt;

    &lt;span class="c1"&gt;// call default function in pages/api/register&lt;/span&gt;
    &lt;span class="c1"&gt;// send the email and password from form submission event to that endpoint&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;registerUser&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      // above form omitted for brevity
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's look at the response that we are getting back from the API request to the register endpoint.If we destructure &lt;code&gt;res.json()&lt;/code&gt; like &lt;code&gt;const { user } = await res.json()&lt;/code&gt; then we can see the &lt;code&gt;user&lt;/code&gt; object for a successful request looks something like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2de33395-b88b-4004&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;aud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authenticated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authenticated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;confirmation_sent_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2021-03-09T12:35:02.895833829Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;app_metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;user_metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="nx"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2021-03-09T12:08:46.611304Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2021-03-09T12:35:03.466491Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we've received a 200 response (no errors!) and a user object back from our SignUp call to Supabase then we can redirect users to a message prompting them to confirm their e-mail address. We can use the NextJS router to handle this redirect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registerUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/welcome?email&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;registerUser&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*ommitted for brevity*/&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are currently redirecting folks to a Welcome page that doesn't exist so let's create a new page &lt;code&gt;page/welcome.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/footer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Welcome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Thank you for signing up. Please check your &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; inbox to verify
          your e-mail address!
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all went well then if you fill out the form with an email address and password then you should be redirected to the welcome screen, receive a confirmation e-mail from Supabase to the e-mail you submitted and see under the Authentication section of your project at &lt;code&gt;https://app.supabase.io/project/[yourprojecturl]/auth/users&lt;/code&gt; that there is a new user in your users table with the email address that you just submitted. By default Supabase is set up to not allow users to log in until they verify their e-mail address, so unless you've changed that setting you should see the column &lt;code&gt;Last Sign In&lt;/code&gt; showing the value "Waiting for verification...".&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Code on GitHub
&lt;/h2&gt;

&lt;p&gt;Checkout out the example code for this article at: &lt;a href="https://github.com/M0nica/register-supabase-users-nextjs-example" rel="noopener noreferrer"&gt;https://github.com/M0nica/register-supabase-users-nextjs-example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all I have for now! But I am looking forward to sharing more about how I implement Supabase as I continue my app development.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>supabase</category>
      <category>database</category>
      <category>react</category>
    </item>
    <item>
      <title>Set Yourself Up For Success During Hacktoberfest</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sat, 03 Oct 2020 13:31:24 +0000</pubDate>
      <link>https://forem.com/m0nica/set-yourself-up-for-success-during-hacktoberfest-55kb</link>
      <guid>https://forem.com/m0nica/set-yourself-up-for-success-during-hacktoberfest-55kb</guid>
      <description>&lt;p&gt;Throughout &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt; (October) people are encouraged to contribute to open-source to secure a t-shirt along with other swag. I have long been a fan of Hacktoberfest as some of my initial contributions to open-source software occurred during Hacktoberfest. Although, a downside to Hacktoberfest for some project maintainers is that people are encouraged to submit low-quality, spammy pull requests which directly increases the time required for them to maintain their projects without the benefit of being able to incorporate the code that was submitted [&lt;a href="https://hacktoberfest.digitalocean.com/hacktoberfest-update"&gt;As of 10/03/2020 project maintainers must opt-in to participating in Hacktoberfest&lt;/a&gt;]. A lot of project maintainers for projects without large corporate funding are unpaid (or underpaid) volunteers.&lt;/p&gt;

&lt;p&gt;As I've contributed to larger open-source projects and maintained smaller projects over the years I've learned more about what types of open-source contributions are generally accepted. I recently read through &lt;a href="https://press.stripe.com/#working-in-public"&gt;Working in Public&lt;/a&gt; by Nadia Eghbal (and &lt;a href="https://www.aboutmonica.com/blog/working-in-public-notes"&gt;shared my notes&lt;/a&gt;) which is a great primer if you are interested in learning more about the labor that goes into maintaining open-source software and norms for participating in various types of open-source communities.   Below are some of my thoughts on how to make quality contributions to open-source during Hacktoberfest and beyond! I plan on updating this post over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Finding Issues
&lt;/h2&gt;

&lt;p&gt;If you're newer to contributing and are looking for issues that are designed to be smaller in scope, instead of opening pull requests with unsolicited, 1 character changes, I'd recommend using GitHub's issues filter to &lt;a href="https://github.com/issues?q=label%3A%22good+first+issue%22+label%3Ahacktoberfest+"&gt;search for "Hacktoberfest" or "Good First Issue"&lt;/a&gt; or checking out these sites that help people find beginner-level issues that you're interested in contributing to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://goodfirstissue.dev/"&gt;https://goodfirstissue.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.firsttimersonly.com/"&gt;https://www.firsttimersonly.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MunGell/awesome-for-beginners"&gt;https://github.com/MunGell/awesome-for-beginners&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benefit of spending the time to find issues that are well-scoped to your interest and experience level is that if you make an attempt at resolving an issue based on the requirements usually maintainers are more willing to work with you to help get your changes accepted into a project.&lt;/p&gt;

&lt;p&gt;In addition to using the above resources to find good first issues, I'd also recommend contributing to projects you already use or check out the following projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/wesbos/awesome-uses/"&gt;awesome-uses&lt;/a&gt; • share your developer setup, gear, software and configs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/M0nica/httriri"&gt;httriri: HTTRiRi - HTTP Status Codes as Portrayed by Rihanna GIFs ✨💄&lt;/a&gt; • submit your favorite Rihanna GIF that accurately potrays a status code and improve an educational resource for those looking for an HTTP status code reference.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/twilio-labs/open-pixel-art"&gt;twilio-labs/open-pixel-art&lt;/a&gt; • Contribute to a fun, collaborative pixel art project to teach people how to contribute to open-source.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/selfdefined/web-app/issues"&gt;selfdefined/web-app: Dictionary database with future API and bot integrations&lt;/a&gt; • submit definitions and enhancements to the selfdefined dictionary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;
Note: Hacktoberfest has been updated to require maintainers to opt-in to having contributions to their projects count towards Hacktoberfest. If you would like your contributions to count towards the Hacktoberfest requirements, explore the &lt;a href="https://github.com/topics/hacktoberfest"&gt;Hacktoberfest topic on GitHub&lt;/a&gt; to find projects that have explicitly opted-in to participating.&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Claiming Issues
&lt;/h2&gt;

&lt;p&gt;Different projects have different norms for indicating that someone is planning on working on an issue. As a starter, I would recommend commenting on any issues that you are interested in working on to reduce the chances of multiple people submitting duplicate changes to resolve the same issues. Generally, unless a maintainer already had someone in mind to work on an issue whoever "claims" an issue first and submits a pull request first will be prioritized and later submissions may be viewed as spammy. Also, note that not all issues are opened by project maintainers and core contributors so it's helpful to read the conversation and tags on an issue to determine if a maintainer is interested in resolving the issues that were raised in the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Read the Documentation
&lt;/h2&gt;

&lt;p&gt;I would recommend focusing on contributing to projects that have at least a basic README that outlines how to get started with contributing and what the expectations are for contributors. Another file that some repositories have to help provide more context for contributors is a&lt;br&gt;
CONTRIBUTING.md which indicates what the expectations are for how people should contribute to a project. For example, for my project &lt;a href="https://www.httriri.com/"&gt;https://www.httriri.com/&lt;/a&gt;&lt;br&gt;
I've shared guidelines for how files should be named and how to make changes that are more likely to be accepted (i.e, not submitting duplicate content, checking open issues before submitting unsolicited changes) in the README file to help make it easier for new contributors to get new status code submissions accepted:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The GIF should include Rihanna and not already be included on &lt;a href="https://www.httriri.com/"&gt;https://www.httriri.com/&lt;/a&gt;. In rare cases, a GIF that already exists in the HTTRIRI collection can be used for another status code but within the same set of proposed changes, a new GIF should be chosen for the other status code to ensure there are no duplicate images and the overall size of the collection is growing. Excerpt from &lt;a href="https://github.com/M0nica/httriri"&gt;HTTRIRI Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If there are things specified within a repository regarding naming conventions, testing practices, where files should live, etc. these are usually requirements and not suggestions unless otherwise indicated. Therefore, it's in your best interest to follow those guidelines to hopefully have your changes accepted and to reduce the back and forth required to finalize your pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Opening a Pull request
&lt;/h2&gt;

&lt;p&gt;Once you feel like your changes adequately address an issue you should open a pull request in the repository. It's generally a best practice to reference the issue that you are resolving in your pull request and to add a link to your PR on the issue. Some projects will include a checklist or template when opening a new pull request, this generally should be filled out completely unless something is not applicable and gives you another chance to check that your contribution meets the requirements. For example, if a checklist indicates that unit tests should be updated or added for all changes then you should make sure that is done in your pull request and if not indicate why you have decided to forgo a particular requirement.&lt;/p&gt;

&lt;p&gt;If you're not quite ready to submit a PR for feedback but need assistance I'd recommend &lt;a href="https://github.blog/2019-02-14-introducing-draft-pull-requests/"&gt;opening a draft PR&lt;/a&gt; or sharing a link to your branch on the issue and requesting guidance from other contributors. Depending on the project they may indicate that other forums like Discord should be used to solicit help with contributing. Not all projects have the same capacity to help newer contributors, so you may have to ask for help from others that aren't necessarily directly involved in the project. For example, if you're contributing to a popular, React repository a project maintainer may not be able to answer a lot of follow-up questions but someone in a popular React Discord might be able to help you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Overall, to increase the chance of your pull request being accepted I would recommend first identifying an open issue that a maintainer has already given the green light to be worked on, indicating that you are interested in that issue if it's still up for grabs and hasn't been claimed, reading through the project documentation and guidelines to make sure your contribution is aligned with their expectations for contributions and opening a pull request once you've completed the previous steps. I hope these tips help you get closer to successfully contributing to open-source software! &lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>Best Practices For Keeping Server-Side Rendering Cool</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sat, 12 Sep 2020 13:31:42 +0000</pubDate>
      <link>https://forem.com/m0nica/keeping-server-side-rendering-cool-with-react-hydration-5fcp</link>
      <guid>https://forem.com/m0nica/keeping-server-side-rendering-cool-with-react-hydration-5fcp</guid>
      <description>&lt;p&gt;Server-side rendering can be powerful but it does require thinking in multiple contexts so it's important to be familiar with some of the common gotchas when developing Server-Side Rendered websites. This article is a written version of a talk I gave at &lt;a href="https://www.reactrally.com/"&gt;React Rally&lt;/a&gt; 2020 on keeping Server-Side Rendering Cool with React Hydration, where I shared some helpful things to keep in mind to render a seamless experience as a Server-Side Rendered (SSR) site transitions from a window-less (server) environment to a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Server-Side Rendering (SSR)?
&lt;/h2&gt;

&lt;p&gt;Let's take a step back. First, what is server-side rendering? When a server generates the initial HTML that loads in a browser. Frameworks like &lt;a href="https://nextjs.org/"&gt;NextJS&lt;/a&gt; and &lt;a href="https://www.gatsbyjs.com/"&gt;GatsbyJS&lt;/a&gt; support SSR out of the box. Server Side Rendered applications tend to initially load content faster and lead to higher SEO ranking than their Client-Side Rendered counterparts.&lt;/p&gt;

&lt;p&gt;There are different types of server-side rendering for example server-side rendering can be used to render every single page request or only the initial page request. &lt;a href="https://nextjs.org/docs/basic-features/pages#two-forms-of-pre-rendering"&gt;NextJS offers two forms of server-side rendering&lt;/a&gt;. You may be familiar with &lt;a href="https://github.com/facebook/create-react-app"&gt;Create React App&lt;/a&gt;, a default React app boilerplate which does not come with SSR functionality configured out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Client-Side Rendering (CSR)?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qfJ4Ekp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zlbda28h0umc8l0z9yfk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qfJ4Ekp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zlbda28h0umc8l0z9yfk.png" alt='Blank page in browser saying "You need to enable JavaScript to run this app"'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In contrast to Server-Side Rendering, a website that only supports Client-Side Rendering requires visitors to have HTML enabled to view content on the site. Often visitors will see a largely blank page when visiting a Client-Side rendered application if they do not have JavaScript enabled.&lt;/p&gt;

&lt;p&gt;If you look at the DOM in the developer tools of a Create React App (or client-side only rendered application) you'll notice very little HTML markup in the DOM. The markup might resemble something like the below code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- SEO/Metadata here --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;You need to enable JavaScript to run this app.&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;JavaScript&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/static/js/2.6158a3d8.chunk.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/static/js/main.ba831a9f.chunk.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Generally this markup will include the root where React is injected, a message saying you need to enable JavaScript to run the app as well as script tags that link to the JavaScript that needs to be loaded to hydrate the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of SSR (in static context)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dUVHZxoq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/20jzjv64p073cjjt1z6y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dUVHZxoq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/20jzjv64p073cjjt1z6y.png" alt="step by step illustration walking through react hydration steps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's walk through what happens in Server-Side Rendered applications like NextJS or Gatsby when all the pages for the site are statically generated at once in the server.&lt;/p&gt;

&lt;p&gt;First, you write the site in React ⚛️ then Gatsby or Next (Static Site Generation) creates a production build of your site using ReactDOMServer, a React server-side API to generate HTML from React. When someone visits your website the first thing they'll see is the HTML generated from the server. JavaScript then loads after the initial page load and the &lt;a href="https://reactjs.org/docs/react-dom.html#hydrate"&gt;ReactDOM.hydrate() API&lt;/a&gt; kicks in to hydrate the HTML page that was rendered from the server with JavaScript. After Hydration the &lt;a href="https://reactjs.org/docs/reconciliation.html"&gt;React reconciler APIs&lt;/a&gt; take over and the site becomes interactive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Toggling JavaScript: SSR vs. CSR
&lt;/h2&gt;

&lt;p&gt;Let's compare how a Server-Side and Client-Side rendered applications appear when JavaScript is enabled or disabled. For these two examples, I used Gatsby and Create React App for these technologies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--46grey1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xoy5vy37hhkjmuajpvx6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--46grey1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xoy5vy37hhkjmuajpvx6.gif" alt="gif of enabling/disabling JavaScript on Gatsby site"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above image is of a Gatsby site, where when JavaScript is toggled on/off there is very little visible change aside from the image loading as most of the HTML was available without JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jUDpkVwg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j2n5dvx71v1pjjhetcd4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jUDpkVwg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j2n5dvx71v1pjjhetcd4.gif" alt="gif of enabling/disabling JavaScript for site built with create-react-app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In contrast, in the above image of a Create-React-App which uses client-side rendering and the browser is responsible for constructing the initial HTML. Due to this we just see the bare-bones HTML as opposed to a full HTML document when JavaScript is disabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  My server-side app looks great in development...What could go wrong? 😅
&lt;/h2&gt;

&lt;p&gt;We just looked at an example of Server-Side rendering that looked great in production both with or without JavaScript! What could go wrong? There are some common issues you might run into with Server-Side rendered applications that only occur during the initial hydration process in production such as layout shifts or errors that only appear at build-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Missing Data on Server-Side
&lt;/h3&gt;

&lt;p&gt;Something helpful to keep in mind is that some data just is not available in the static server context like user or browser-specific data. For example, window size, authentication status, local storage, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yA82tsOX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/egoh9o4wzg0ldbtjdikj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yA82tsOX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/egoh9o4wzg0ldbtjdikj.gif" alt="screenshot of target.com navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above image of Target's navigation, you'll see that the store location data, my name, and items in the shopping cart were not available on the initial page load. Once the data was available it hydrated on the page without shifting the layout. Loading patterns like this can be common on server-side rendered applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Unavailable JavaScript
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hWLifDv4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/id45omy4asgk6q7cxpta.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hWLifDv4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/id45omy4asgk6q7cxpta.gif" alt="screenshot of my site header loading with disjointed icons and shifting layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's debug the above hydration issue that caused my site to have multiple unnecessary rendering changes during load. Something huge that is not available on initial load and can cause issues in server-side rendered applications is JavaScript! It's considered a best practice to load CSS before JavaScript therefore you need to consider how the HTML and CSS on a page load BEFORE JavaScript is available since JavaScript is not required for the page to load.&lt;/p&gt;

&lt;p&gt;You may end up noticing weird changes on the initial page load that change too quickly to properly inspect - especially if you have a faster internet connection. But there are ways to slow down and really see what is going on. In particular, I'd recommend disabling JavaScript in your browser or using a site like &lt;a href="https://www.webpagetest.org/"&gt;web page test&lt;/a&gt; to generate film strip thumbnails that show you exactly how the page is loading step by step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tqkoXkCY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/758m64stigryqcgby8rk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tqkoXkCY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/758m64stigryqcgby8rk.png" alt="filmstrips of my site loading with rendering issue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above is the waterfall I took of the issue on my site before it was resolved. You can see one of the issues is that the size of the FontAwesome icons changes drastically between 96% and 99% loaded which can be a disjointing experience.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---tPhdy1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dszqxfr7yw7tqx11h9nn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---tPhdy1h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dszqxfr7yw7tqx11h9nn.png" alt="crossed out JavaScript icon transitioning to CSS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The solution for getting rid of the resizing of the icons during load involved replicating the final styling with local CSS and removing any dependency on FontAwesome's external CSS which required JavaScript to be available.&lt;/p&gt;

&lt;p&gt;I disabled JavaScript which allowed me to see in development that the ways the icons look before they were fully loaded mirrored the app without JavaScript. This led me to realize Font Awesome was using its own styling that was coming in through JS that conflicted with my local CSS style. Since CSS loads before JS, disabling Font Awesome's external CSS (loaded via JavaScript) and replicating the CSS styles I wanted locally resolved the issue&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AuzefWfG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nb7b0y0nab4ycljpe7vx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AuzefWfG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nb7b0y0nab4ycljpe7vx.png" alt="film strip of my site loading without layout  shifts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice after (above image) removing the dependency on Font Awesome's CSS that the styling of the icons remains consistent as the application loads. &lt;a href="https://www.aboutmonica.com/blog/less-javascript-is-more"&gt;I wrote an article&lt;/a&gt; with more information about my experience resolving the Font Awesome rendering issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Immutable Layout
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4h66dLOM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9wemj8fx9g2jx1jakw1p.gif%23center" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4h66dLOM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9wemj8fx9g2jx1jakw1p.gif%23center" alt="gif of colorful shifting blocks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The previous issue of changing styles is related to a much larger issue of handling layouts on the server-side. Generally, you should avoid unnecessary layout shifts during page load by implementing layouts with placeholder/gap for expected client-side content and avoiding using JavaScript to position or style content instead of CSS. It is common for some data to be unavailable as the page loads, however, you can develop in a way that can handle missing data by leaving room in the UI for the data to load. In the Target navigation example you can see there is no shift as the user/store specific data is loaded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yA82tsOX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/egoh9o4wzg0ldbtjdikj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yA82tsOX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/egoh9o4wzg0ldbtjdikj.gif" alt="screenshot of target navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Strange Conditional Rendering in Server Context
&lt;/h3&gt;

&lt;p&gt;If you write React you may have conditionally rendered content like the below code snippet based on screen size using the MatchMedia API. However, this approach might lead to some unnecessary frustration...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;small&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MobileApp&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DesktopApp&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;matchMedia()&lt;/code&gt; API can't reliably detect the browser or device size in the server context which can lead to some strange rendering issues as the page loads if the originally set media size doesn't match the actual browser.&lt;/p&gt;

&lt;p&gt;It's preferable to use CSS or a library like fresnel which wraps all &lt;code&gt;Media&lt;/code&gt; components in CSS instead of MatchMedia in Server-Side rendered applications to layout content. Since CSS loads before JS, styles applied via CSS, unlike JavaScript should visibly match what you expect on page load.&lt;/p&gt;

&lt;p&gt;Below is an example of how Fresnel can be used. First, you need to import createMedia from Fresnel then define the breakpoints and export MediaContextProvider from the object created from createMedia to wrap the entire app. Then you can use Fresnel's Media component throughout your app to render components based on the predefined breakpoints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMedia&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@artsy/fresnel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MediaContextProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Media&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;breakpoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MediaContextProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Media&lt;/span&gt; &lt;span class="nx"&gt;at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MobileApp&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Media&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Media&lt;/span&gt; &lt;span class="nx"&gt;greaterThan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DesktopApp&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Media&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/MediaContextProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The final step is inject the CSS in the server by passing mediaStyle into a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag in the head of the document so that CSS can be generated from fresnel markup and be rendered on the server. You can read more about setting up Fresnel for SSR in the &lt;a href="https://github.com/artsy/fresnel#server-side-rendering-ssr-usage"&gt;Fresnel docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Error: Window is undefined
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jetkEdwh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c9kqkctdbz4jlwmnlpkd.gif%23center" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jetkEdwh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c9kqkctdbz4jlwmnlpkd.gif%23center" alt="gif homer simpson looking under couch cushions looking for something"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you attempt to access browser-specific elements in a server context JavaScript will not be able to resolve those elements.&lt;/p&gt;

&lt;p&gt;When building a site you might run into the &lt;code&gt;window is undefined&lt;/code&gt; or &lt;code&gt;document is undefined&lt;/code&gt; error. This happens when logic within an app assumes the &lt;strong&gt;browser&lt;/strong&gt; window is defined in a &lt;strong&gt;server&lt;/strong&gt; and reference browser-specific elements in the server.&lt;/p&gt;

&lt;p&gt;Your first inclination to resolve the undefined Window error might be to write something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="c1"&gt;//render component : // return null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, if your app is using the ReactDOM.hydrate API to transform the site from HTML to the virtual DOM you need to be aware of ReactDOM.hydrate's constraint. ReactDOM.hydrate():&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;👯‍♂️ expects that the rendered content is &lt;strong&gt;identical&lt;/strong&gt; between the server and the client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🙅🏾‍♀️ does not guarantee that attribute differences will be patched up in case of mismatches.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Hydrate API that converts HTML to full-fledged React &lt;strong&gt;expects that the content is always identical between the server and client&lt;/strong&gt; and does not guarantee that matches will be patched up in case of mismatches. Due to this lack of guarantee, it is NOT a good idea to conditionally render based on elements that will differ between the server and client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out &lt;a href="https://joshwcomeau.com/react/the-perils-of-rehydration/"&gt; this article &lt;/a&gt; by Josh W Comeau for examples of visual discrepancies that can occur when&lt;br&gt;
React.Hydrate() fails to reconcile an unexpected difference.{" "}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Safely accessing browser elements enables you to&lt;br&gt;
avoid reconciliation errors when ReactDOM.hydrates a site from HTML to React. In order to avoid issues with the hydration reconciliation process, you can wrap any side effects that rely on the Window or Document in a &lt;a href="https://reactjs.org/docs/hooks-effect.html"&gt;useEffect&lt;/a&gt; hook since that only fires after the component has mounted.&lt;/p&gt;

&lt;p&gt;useEffect() Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`You clicked &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times`&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is an example from the &lt;a href="https://reactjs.org/docs/hooks-effect.html"&gt;React Docs&lt;/a&gt; of referencing a browser element, &lt;code&gt;document.title&lt;/code&gt; within &lt;code&gt;useEffect()&lt;/code&gt;. This code will never be executed on the server as it executes after the React Virtual DOM is available and therefore avoids running into issues with React.Hydrate().&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule of Least Power
&lt;/h2&gt;

&lt;p&gt;With JavaScript comes great responsibility, sometimes JavaScript just isn't the right tool for the job:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"JavaScript is a powerful language that can do some incredible things, but it’s incredibly easy to jump to using it too early in development when you could be using HTML and CSS instead. Consider &lt;strong&gt;the rule of least power&lt;/strong&gt;: Don’t use the more powerful language (JavaScript) until you’ve exhausted the capabilities of less powerful languages (HTML)." - Iain Bean, Your blog doesn’t need a JavaScript framework&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v7hXDay1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8z6dgcpt6jifbizcqi37.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v7hXDay1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8z6dgcpt6jifbizcqi37.gif" alt="image of my site header dynamically changing headshot images based on the screen size"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently used the rule of least power to speed up the initial load time of my header and eliminate relying on JavaScript to dynamically load different headers images on my site based on screen size.&lt;/p&gt;

&lt;p&gt;I was looking into how to display different images based on screen size and stumbled up HTML art direction which can be used to dynamically load images based on the screen size using HTML &lt;code&gt;srcset&lt;/code&gt; attributes instead of JavaScript. Swapping images at different screen sizes can be done with JavaScript or CSS instead of native HTML attributes however using HTML can improve page loading performance as it prevents unnecessarily preloading two images.&lt;/p&gt;

&lt;p&gt;The cool thing about the HTML approach is that it can improve page loading performance as it allows the browser to only preload the image that is visible within the viewport. This can be especially beneficial if you need to display multiple images at various places within a site depending on the screen size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(min-width: 625px)"&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"animonica-full.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"animonica-headshot-cropped.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"animonica-full.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Illustrated Monica"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to set up this functionality in HTML you can use the picture attribute and set media queries on each source image. It will return the first condition the is true and as a fall back it'll return the image from the img tag.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's also possible to use the art-direction API in Gatsby with gatsby-image which is Gatsby's package for loading and transforming images from GraphQL. I wrote &lt;a href="https://www.aboutmonica.com/blog/2020-06-24-exploring-art-direction-in-gatsby/"&gt;an article&lt;/a&gt; with more information about my exploration into using art direction with Gatsby.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In a Server-Side Rendered context it's important to consider &lt;em&gt;how&lt;/em&gt; the page loads both when data is and is not available.&lt;/li&gt;
&lt;li&gt;CSS is the right tool for handling layout, especially in a Server-Side Rendered Application. Using JavaScript for styling in SSR apps can lead to strange loading experiences for some users.&lt;/li&gt;
&lt;li&gt;It's important to guard references to browser-specific elements like &lt;code&gt;document&lt;/code&gt; or &lt;code&gt;window&lt;/code&gt; within &lt;code&gt;useEffect()&lt;/code&gt; to avoid reconciliation error as the page hydrates to transform SSR apps from HTML to React.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resources &amp;amp; Further Reading
&lt;/h3&gt;

&lt;p&gt;Below are some resources I recommend if you're looking to further explore the rendering process for server-side rendered React applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/basic-features/pages#server-side-rendering"&gt;https://nextjs.org/docs/basic-features/pages#server-side-rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/docs/reconciliation.html"&gt;https://reactjs.org/docs/reconciliation.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gatsbyjs.org/docs/react-hydration/"&gt;https://www.gatsbyjs.org/docs/react-hydration/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://joshwcomeau.com/react/the-perils-of-rehydration/"&gt;https://joshwcomeau.com/react/the-perils-of-rehydration/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.webpagetest.org/"&gt;https://www.webpagetest.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/artsy/fresnel"&gt;https://github.com/artsy/fresnel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.speedpatterns.com/patterns/immutable_layout.html"&gt;https://www.speedpatterns.com/patterns/immutable_layout.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>ssr</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>How to Make Your VSCode Sparkle</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sat, 12 Sep 2020 13:17:46 +0000</pubDate>
      <link>https://forem.com/m0nica/how-to-make-your-vscode-sparkle-5h8j</link>
      <guid>https://forem.com/m0nica/how-to-make-your-vscode-sparkle-5h8j</guid>
      <description>&lt;p&gt;This article shows you how to customize your VSCode set up to display animated sparkles while you are typing. There's a VSCode extension, &lt;a href="https://marketplace.visualstudio.com/items?itemName=hoovercj.vscode-power-mode"&gt;Power Mode&lt;/a&gt; that adds animated flair while you're typing. It has a few different default animations but none of them quite sparkle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4P9jYY3q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jjkntk4salxdw0eybhej.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4P9jYY3q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jjkntk4salxdw0eybhej.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Above is a GIF of animated sparkles in my VSCode. The editor's theme is Night Owl and the font is Dank Mono. You can learn more about my VSCode setup on my &lt;a href="https://www.aboutmonica.com/uses"&gt;uses&lt;/a&gt; page.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're not using VSCode, check out these &lt;a href="https://github.com/codeinthedark/awesome-power-mode"&gt;Power Mode extensions&lt;/a&gt; for various code editors. The implementation of each differ but some of them support customized animations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Power Mode Extension
&lt;/h2&gt;

&lt;p&gt;In order to add animations to your VSCode first you need to    &lt;a href="https://marketplace.visualstudio.com/items?itemName=hoovercj.vscode-power-mode"&gt;install Power Mode&lt;br&gt;
&lt;/a&gt; and enable it by updating your &lt;a href="https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations"&gt;VSCode settings&lt;/a&gt; to include the following:&lt;br&gt;
&lt;code&gt;"powermode.enabled": true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Depending on your operation system the VSCode settings file is located here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    Windows - %APPDATA%\Code\User\settings.json
  &lt;/li&gt;
  &lt;li&gt;
    macOS - $HOME/Library/Application
    Support/Code/User/settings.json
  &lt;/li&gt;
  &lt;li&gt;
    Linux - $HOME/.config/Code/User/settings.json
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Customize Power Mode
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;"powermode.enabled"&lt;/code&gt; turns on the extension's default animations when you're typing but if you want sparkles then some additional customization is required.&lt;br&gt;
In particular, you need to configure &lt;code&gt;"powermode.customExplosions"&lt;/code&gt; in settings and pass in your own animation to be used for the explosions. This setting supports base64 encoded gifs, absolute file path, or https image URLs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"powermode.customExplosions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;absolute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;✨&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;GIF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;computer&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"/Users/monica/Dev/power-mode-sparkles/sparkles.gif"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you are interested in other animation ideas aside from sparkles check out the &lt;a href="https://github.com/hoovercj/vscode-power-mode/issues/1"&gt;vscode-power-mode/Help wanted: explosion gifs&lt;/a&gt; issue on GitHub. In fact, this issue is where I found the image for my sparkles ✨ thanks to &lt;a href="https://github.com/hoovercj/vscode-power-mode/issues/1#issuecomment-643829082"&gt;federicca&lt;/a&gt;. You can download the Sparkle GIF I used for my configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Final Power Mode VSCode Configuration
&lt;/h2&gt;

&lt;p&gt;My VSCode &lt;code&gt;settings.json&lt;/code&gt; includes the following keys and values after configuring Power Mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;turn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;powermode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;🚨&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"powermode.enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"powermode.customExplosions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;absolute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;✨&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;GIF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;computer&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"/Users/monica/Dev/power-mode-sparkles/sparkles.gif"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enableShake&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;which&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;causes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;text/screen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;shake,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;disables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"powermode.enableShake"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tweaking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;amount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;explosions&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"powermode.maxExplosions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"powermode.explosionFrequency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//backgroundMode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;animation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;matches&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;syntax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;color&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//backgroundMode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;displays&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;animation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;original&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;colors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;image&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"powermode.backgroundMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mask"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Optimizing Power Mode
&lt;/h3&gt;

&lt;p&gt;Power Mode recommends tweaking some of the default settings to reduce the frequency of animations if the extension is causing your editor to slow down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sparkle GIF to Download
&lt;/h2&gt;

&lt;p&gt;Right-click and save the below image to your computer if you're ready to start adding more sparkles to your development workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kIgEBUiw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/joxe6uc9t933l1vv27yw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kIgEBUiw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/joxe6uc9t933l1vv27yw.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
    </item>
    <item>
      <title>6 Transformative Tech Conference Talks</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sun, 06 Sep 2020 11:51:37 +0000</pubDate>
      <link>https://forem.com/m0nica/6-transformative-tech-conference-talks-j4k</link>
      <guid>https://forem.com/m0nica/6-transformative-tech-conference-talks-j4k</guid>
      <description>&lt;p&gt;Here's a round-up of some of my favorite conference talks that have shaped the way that I think about web technologies, the workplace and community organizing. I hope some of these talks will also cause you to reflect and in some ways become a better technologist.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Glue Talk by Tanya Reilly
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/KClAPipnKqw"&gt;
&lt;/iframe&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had the pleasure of hearing Tanya Reilly give this talk at a Write/Speak/Code event in NYC. She walks through how to approach "the less glamorous - and often less-promotable - work that needs to happen to make a team successful" through a strategic lens. Often the burden of performing less-promotable work falls on the shoulders of marginalized folks within technology. Her talk is an actionable guide to navigating conversations with your manager to ensure you're contributing to the type of projects that will be recognized and reduce the chance of any surprises during formal reviews. I (unfortunately) have had to recommend this talk to a lot of women in technology who have experienced being delegated to do a significant share of glue work. You can check out the slides and sketch notes on Tanya's site: &lt;a href="https://noidea.dog/glue" rel="noopener noreferrer"&gt;https://noidea.dog/glue&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript is AsynchroWAT? By Crystal Martin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/el9fhSbby5E"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Crystal Martin breaks down how asynchronous JavaScript works. I feel like this is a topic that a lot of folks new to JavaScript may have difficulty understanding and Crystal assures folks that don't yet fully understand asynchronous JavaScript that they're not alone. I found her talk very relatable and informative. I especially appreciated her bring in examples of an intense (hair) wash day to describe how JavaScript functions work.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to Build a Magical Living Room by Saron Yitbarek&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/nOscsODuol4"&gt;
&lt;/iframe&gt;
&lt;br&gt;
Saron Yitbarek, the founder of CodeNewbie is not only a prolific podcaster but also a phenomenal community organizer and one of my heroes! Her keynote at RubyConf is a master class in building inclusive communities. Saron shares what she's learned about building a magical living room to make people feel like they're welcome in your community. You'll walk away from this talk with actionable advice for becoming a stronger community leader.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tautology and Business Value Presented by Heidi Waterhouse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://yougotthis.io/talks/tautology-business-value/" rel="noopener noreferrer"&gt;&lt;br&gt;
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqc7bs1cj4mlyncriykmn.png"&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Heidi presented this talk at You Got This 2020: From Home. I was able to see a live version at Adulting.dev. Heidi talks through how to strategically understand your value within a business context. I think this talk is especially crucial for folks who have not worked through a recession and/or need additional resources and tips to advocate for themselves in the workplace.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a Custom React Renderer by Sophie Alpert&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CGpMlWVcHok"&gt;
&lt;/iframe&gt;
&lt;br&gt;
One of the coolest talks I've seen live was Sophie Alpert walking through how to use the npm package react-reconciler to you build your own React renderer. It inspired me to one day (far away) attempt to give a technical talk with just a text editor. I felt that I had a better understanding of the React reconciliation process after listening to her talk.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let’s Program Like It’s 1999 by Lee Byron&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/vG8WpLr6y_U"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Lee Bryon also gave a phenomenal talk at React Conf where afterward I felt like I traveled a bit through time. He provided an overview of how much the web has not changed over the last 20 years. As a JavaScript developer who has only dabbled in PHP, I found it especially fascinating to learn how many of the PHP and LAMP Stack abstractions and mental models have found their way into the modern JavaScript development ecosystem. More often than not developers discuss how rapidly web development changes so it was helpful for Lee to share some of the principles that have, so far, stood the test of time (a.k.a the past 30 years) through various technical implementations.&lt;/p&gt;

&lt;p&gt;What conference talk has most inspired you? What's the most interesting presentation you've seen so far? Share your favorite conference talks with me on Twitter: &lt;a href="https://twitter.com/waterproofheart" rel="noopener noreferrer"&gt;@waterproofheart&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>conferences</category>
      <category>javascript</category>
      <category>business</category>
      <category>community</category>
    </item>
    <item>
      <title>Adding Environment Variables To GitHub Actions</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Mon, 24 Aug 2020 14:32:29 +0000</pubDate>
      <link>https://forem.com/m0nica/adding-environment-variables-to-github-actions-1628</link>
      <guid>https://forem.com/m0nica/adding-environment-variables-to-github-actions-1628</guid>
      <description>&lt;p&gt;This article walks through how to pass environment variables to &lt;a href="https://github.com/features/actions"&gt;GitHub Action&lt;/a&gt; Workflows. I recently set up GitHub actions on this site to automatically run unit tests whenever I open a new Pull Request to ensure that changes to the site were not introduction breaking changes to unit tests under the radar.&lt;/p&gt;

&lt;p&gt;I ran into some hiccups when setting it up so that the workflow could install the Font Awesome dependency which requires an NPM token. I went through a few of my GitHub Actions build minutes while testing how to properly pass environment variables to my &lt;code&gt;.github/workflow/test.yml&lt;/code&gt; file. Hopefully this article saves you some time and build minutes the next time you set up environment variables for GitHub Actions.&lt;/p&gt;

&lt;p&gt;In order to setup my GitHub Action, I modeled my new GitHub Action workflow after similar functional workflows and expected everything to run smoothly. However, I merged the pull request with my changes and saw on the Pull Request that the step of the GitHub Action workflow that installed dependencies failed with the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error An unexpected error occurred: "Failed to replace env in config: $
{FONTAWESOME_NPM_AUTH_TOKEN}"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then I remembered 💡 my site requires an environment variable to build and deploy. Locally I have &lt;a href="https://docs.npmjs.com/configuring-npm/npmrc.html"&gt;&lt;code&gt;.npmrc&lt;/code&gt;&lt;/a&gt; file that sets up the the npm configuration to pass in the appropriate environment variable for my site and looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@fortawesome:registry=https://npm.fontawesome.com/
//npm.fontawesome.com/:_authToken=${FONTAWESOME_NPM_AUTH_TOKEN}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In particular the GitHub Action workflow did not have access to the &lt;code&gt;FONTAWESOME_NPM_AUTH_TOKEN&lt;/code&gt; which I have set in my &lt;em&gt;local&lt;/em&gt; bash profile and passed into the &lt;code&gt;.npmrc&lt;/code&gt; file. So I needed to give the GitHub repository that is running this actions access to the environment variable by going to its settings page. You can access settings by clicking "Settings" in the repository's navigation. The url to update secrets for a repository (at the time of this writing) looks like: &lt;a href="https://github.com/username/repo/settings/secrets"&gt;https://github.com/username/repo/settings/secrets&lt;/a&gt; where username and repo should be replaced with the username and repo of the desired repository and clicking "new secret".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GR01EfX3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k0ypm40kknkvgx5tbaea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GR01EfX3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k0ypm40kknkvgx5tbaea.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above is a screenshot of what the secrets page under my repository settings looked like once I added the &lt;code&gt;FONTAWESOME_NPM_AUTH_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, that my repository had access to the environment variable I needed to update each job within my action to also have access to the variables. Before adding the environment variable to my repository my GitHub Action the job that installed dependencies looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
      &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;after adding the environment variable I updated the dependency installation job to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
      &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;npm config set //npm.fontawesome.com/:_authToken=${FONTAWESOME_NPM_AUTH_TOKEN}&lt;/span&gt;
        &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;FONTAWESOME_NPM_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npm config set&lt;/code&gt; allowed me to manually set the npm configuration outside of the &lt;code&gt;.npmrc&lt;/code&gt; file and pass in the appropriate environment variable. I also updated &lt;code&gt;npm install&lt;/code&gt; to &lt;code&gt;npm ci&lt;/code&gt; which installs a project with a clean slate and is better suited for a CI environment. Finally after the &lt;code&gt;run&lt;/code&gt; values I passed in a &lt;code&gt;env&lt;/code&gt; key that contained &lt;code&gt;FONTAWESOME_NPM_AUTH_TOKEN&lt;/code&gt; which referenced &lt;code&gt;${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}&lt;/code&gt; a.k.a the &lt;code&gt;secrets&lt;/code&gt; from &lt;em&gt;this&lt;/em&gt; GitHub repository.&lt;/p&gt;

&lt;p&gt;The full GitHub action workflow I ended up using to install all dependencies (including Font Awesome which required a token ) and running unit tests looked like the below. Note: the test command also needed access to the same environment variable and needed it to be set separately in order for the GitHub Action to succesfully run without running into the error we saw earlier with retrieving the environment variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="c1"&gt;# will run on all PRs that are opened or updated (synchronized)&lt;/span&gt;
&lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;synchronize&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reopened&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;CI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js 13.x&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;13.x&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# run multiple commands&lt;/span&gt;
        &lt;span class="s"&gt;npm config set //npm.fontawesome.com/:_authToken=${FONTAWESOME_NPM_AUTH_TOKEN}&lt;/span&gt;
        &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;FONTAWESOME_NPM_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# run multiple commands&lt;/span&gt;
        &lt;span class="s"&gt;npm config set //npm.fontawesome.com/:_authToken=${FONTAWESOME_NPM_AUTH_TOKEN}&lt;/span&gt;
        &lt;span class="s"&gt;npm run test&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;FONTAWESOME_NPM_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>github</category>
      <category>actions</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How To Create A GitHub Profile README</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sat, 11 Jul 2020 12:42:47 +0000</pubDate>
      <link>https://forem.com/m0nica/how-to-create-a-github-profile-readme-1paj</link>
      <guid>https://forem.com/m0nica/how-to-create-a-github-profile-readme-1paj</guid>
      <description>&lt;p&gt;GitHub recently released a feature that allows users to create a profile-level README to display prominently on their GitHub profile. This article walksthrough how to access this new feature. I'll also be sharing some fun GitHub profiles I've seen so far. I'd love it if you shared yours with me on Twitter &lt;a href="https://twitter.com/waterproofheart" rel="noopener noreferrer"&gt;@waterproofheart&lt;/a&gt;.&lt;br&gt;
&lt;em&gt;The header GIF shows what my README looks like at the time of this writing. You may notice I was recently selected to be &lt;a href="https://stars.github.com/" rel="noopener noreferrer"&gt;GitHub star&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why READMEs?
&lt;/h2&gt;

&lt;p&gt;The GitHub profile-level README feature allows more content than the profile bio, supports markdown which means you can play around with the content more visually (Did someone say GIFs!?) and the README is significantally more visible as it is placed above pinned repositories and takes up as much space above the fold of the webpage as you like.&lt;/p&gt;

&lt;p&gt;A solid README is a core-component of well-documented software and often encourages collaboration by sharing helpful context with contributors. In my opinion, a profile-level README seems like a great extension of a convention a lot of GitHub users are already familiar with. If you're looking to make project-level READMEs more awesome and helpful check out &lt;a href="https://github.com/matiassingers/awesome-readme" rel="noopener noreferrer"&gt;matiassingers/awesome-readme&lt;/a&gt; for resources and examples of compelling READMEs.&lt;/p&gt;
&lt;h2&gt;
  
  
  How do I create a profile README?
&lt;/h2&gt;

&lt;p&gt;The profile README is created by creating a new repository that’s the same name as your username. For example, my GitHub username is m0nica so I created a new repository with the name m0nica. Note: at the time of this writing, in order to access the profile README feature, the letter-casing &lt;strong&gt;must&lt;/strong&gt; match your GitHub username.&lt;/p&gt;

&lt;p&gt;If you already have a project in a repo-named username/username and are interested in setting up a profile-level README, then I recommend either &lt;a href="https://docs.github.com/en/github/administering-a-repository/renaming-a-repository" rel="noopener noreferrer"&gt;re-naming that repository&lt;/a&gt; or re-purposing the existing project's README based on what makes the most sense in your particular situation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new repository with the same name (including casing) as your GitHub username: &lt;a href="https://github.com/new" rel="noopener noreferrer"&gt;https://github.com/new&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a README.md file inside the new repo with content (text, GIFs, images, emojis, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Commit your fancy new README!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you're on GitHub's web interface you can choose to commit directly to the repo's main branch (i.e., &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt;) which will make it immediately visible on your profile)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Push changes to GitHub (if you made changes locally i.e., on your computer and not github.com)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsvjfhmm6drebvvojnfxp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsvjfhmm6drebvvojnfxp.jpg" alt="screenshot of the GitHub page for creating new repositories"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Fun READMEs
&lt;/h2&gt;

&lt;p&gt;The GitHub README profiles are written in Markdown which means you aren't just limited to texts and links, you can include GIFs and images.  Need to brush up on Markdown Syntax? &lt;a href="https://guides.github.com/pdfs/markdown-cheatsheet-online.pdf" rel="noopener noreferrer"&gt;Check out this Markdown Cheatsheet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1281026687103168512-344" src="https://platform.twitter.com/embed/Tweet.html?id=1281026687103168512"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1281026687103168512-344');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1281026687103168512&amp;amp;theme=dark"
  }



&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1281231777475026945-795" src="https://platform.twitter.com/embed/Tweet.html?id=1281231777475026945"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1281231777475026945-795');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1281231777475026945&amp;amp;theme=dark"
  }



&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1281111778290786310-954" src="https://platform.twitter.com/embed/Tweet.html?id=1281111778290786310"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1281111778290786310-954');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1281111778290786310&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;If you're really ambitious you can use &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub actions&lt;/a&gt; or other automation like bdougieYO or simonw to dynamically pull data into your README:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1281699715466199040-44" src="https://platform.twitter.com/embed/Tweet.html?id=1281699715466199040"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1281699715466199040-44');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1281699715466199040&amp;amp;theme=dark"
  }



&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1281435464474324993-466" src="https://platform.twitter.com/embed/Tweet.html?id=1281435464474324993"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1281435464474324993-466');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1281435464474324993&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Serverless functions can also be used to dynamically generate information (for example your current Spotify activity):&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1282326538990563329-719" src="https://platform.twitter.com/embed/Tweet.html?id=1282326538990563329"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1282326538990563329-719');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1282326538990563329&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I'm a huge proponent that folks should maintain a website they have complete ownership over (even if it's a no-code website solution) but this is tempting...&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1281590275660537858-923" src="https://platform.twitter.com/embed/Tweet.html?id=1281590275660537858"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1281590275660537858-923');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1281590275660537858&amp;amp;theme=dark"
  }



&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1265773172520914944-44" src="https://platform.twitter.com/embed/Tweet.html?id=1265773172520914944"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1265773172520914944-44');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1265773172520914944&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;I've been inspired by the creative READMEs I've seen so far and am looking forward to seeing all kinds of profiles in the upcoming months.&lt;/p&gt;

</description>
      <category>github</category>
      <category>branding</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Exploring Art Direction to Dynamically Load Images</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sun, 05 Jul 2020 20:03:43 +0000</pubDate>
      <link>https://forem.com/m0nica/exploring-art-direction-to-dynamically-load-images-5dol</link>
      <guid>https://forem.com/m0nica/exploring-art-direction-to-dynamically-load-images-5dol</guid>
      <description>&lt;p&gt;While updating &lt;a href="https://www.aboutmonica.com/"&gt;my homepage&lt;/a&gt; to include my newly-commission illustration from &lt;a href="https://toondoon1010.carbonmade.com/"&gt;Aishwarya Tandon&lt;/a&gt;, I wanted to load different versions of the image based on screen-size in a performant way. For my header image, I use &lt;a href="https://www.gatsbyjs.org/packages/gatsby-image"&gt;gatsby-image&lt;/a&gt;, an official GatsbyJS plugin that optimizes images that makes it straightforward to control how images are progressively enhanced on page load. One of my favorite built-in Gatsby image effects is &lt;a href="https://using-gatsby-image.gatsbyjs.org/traced-svg/"&gt;traced SVGs&lt;/a&gt;, which renders an SVG tracing of an image, in a pre-determined color before the image fully loads. You can explore all of gatsby-image's built-in loading effects on the &lt;a href="https://using-gatsby-image.gatsbyjs.org/"&gt;using-gatsby-image&lt;/a&gt; site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cB9GLGdZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hgh3424t181r19opkiu7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cB9GLGdZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hgh3424t181r19opkiu7.gif" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The above GIF illustrates how gatsby-image transitions from traced SVG to the loaded image&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While looking into how to load different images at different breakpoints without unnecessarily downloading files I discovered gatsby-image's built-in support for this feature which is known as &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#Art_direction"&gt;art direction&lt;/a&gt;. Modern HTML can be used to dynamically load of images based on screen size using &lt;code&gt;srcset&lt;/code&gt; attributes with &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; instead of JavaScript. Swapping images at different screen sizes can be done with JavaScript or CSS instead of native HTML attributes however using the HTML attributes can improve page loading performance as it prevents unnecessarily preloading two images when only one image from the &lt;code&gt;srcset&lt;/code&gt; needs to be visible within the viewport on load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--orsjb-K5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fq9lmocgvaultj88mjif.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--orsjb-K5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fq9lmocgvaultj88mjif.gif" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The above GIF shows the transition between different images loaded with art direction within gatsby-image&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All images that use the gatsby-image plugin need to be constructed using a GraphQL query. Below is a slightly modified version of the &lt;code&gt;useStaticQuery()&lt;/code&gt; I used to load image files into gatsby-image's &lt;code&gt;Img&lt;/code&gt;. Within &lt;code&gt;useStaticQuery()&lt;/code&gt; I wrote two named queries &lt;code&gt;mobileImage&lt;/code&gt; and &lt;code&gt;desktopImage&lt;/code&gt; to load both versions of the image I wanted on mobile as well as the desktop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useStaticQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Img&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby-image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Avatar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStaticQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
    query {
      mobileImage: file(
        relativePath: { eq: "animonica-headshot-cropped.png" }
      ) {
        childImageSharp {
          fluid(maxWidth: 300, quality: 100) {
            ...GatsbyImageSharpFluid_tracedSVG
          }
        }
      }
      desktopImage: file(relativePath: { eq: "animonica-full.png" }) {
        childImageSharp {
          fluid(maxWidth: 300, quality: 100) {
            ...GatsbyImageSharpFluid_tracedSVG
          }
        }
      }
    }
  `&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mobileImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;childImageSharp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fluid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desktopImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;childImageSharp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fluid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`(min-width: 625px)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Img&lt;/span&gt; &lt;span class="na"&gt;fluid&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sources&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Illustrated Monica"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Avatar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you inspect my site's header using Dev Tools you'll notice there's two &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; sections, one that includes the tracedSVGs that are generated by &lt;code&gt;GatsbyImageSharpFluid_tracedSVG&lt;/code&gt; in the image query and another with the &lt;code&gt;.png&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;The HTML that ultimately renders to load the .png files from the earlier use of gatsby-image resembles the below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(min-width: 625px)"&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"animonica-full.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"animonica-headshot-cropped.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"animonica-full.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Illustrated Monica"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The media attribute in the &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements, within &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;, determines which image &lt;code&gt;srcset&lt;/code&gt; is displayed. The first condition that is met will be displayed, in the case where neither media condition is true &lt;em&gt;or&lt;/em&gt; the browser doesn't support the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element it will return the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element from within the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;. You can view current browser compatability for &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; at &lt;a href="https://caniuse.com/#feat=picture"&gt;Can I use this?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a recap, within &lt;code&gt;gatsby-image&lt;/code&gt; we can pass an array of images to generate HTML's art direction related attributes. Using this approach instead of CSS or JavaScript reduces the number of assets that need to be preloaded in the browser. My current Gatsby site, displays a complete HTML page from the server to the client on the initial load without requiring JavaScript therefore I've found it helpful to avoid delegating certain tasks to JavaScript that HTML/CSS can handle in a more performant way. I've written more about this topic in my article &lt;a href="https://www.aboutmonica.com/blog/less-javascript-is-more"&gt;Less JavaScript Makes Font Awesome More Awesome&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The article was originally published at &lt;a href="https://www.aboutmonica.com"&gt;aboutmonica.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>graphql</category>
      <category>css</category>
      <category>design</category>
    </item>
    <item>
      <title>Give Your CSS Superpowers with CSS Variables</title>
      <dc:creator>Monica Powell</dc:creator>
      <pubDate>Sat, 23 May 2020 22:44:02 +0000</pubDate>
      <link>https://forem.com/m0nica/getting-started-with-css-variables-2jh4</link>
      <guid>https://forem.com/m0nica/getting-started-with-css-variables-2jh4</guid>
      <description>&lt;h2&gt;
  
  
  What are CSS variables?
&lt;/h2&gt;

&lt;p&gt;CSS variables or CSS custom properties are a way to declare reusable values within a CSS project. CSS variables can greatly reduce the repetition of code and allow us to reference more semantically meaningful names throughout our stylesheets like "--accent-color" versus the actual value they represent "#b5838d".&lt;/p&gt;

&lt;p&gt;Most modern browsers support CSS variables. If you need to know whether or not CSS variables are supported in a particular browser without a polyfill it's a best-practice to reference browser-compatibility specifications on sites like &lt;a href="https://caniuse.com/#feat=css-variables"&gt;Can I Use?&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Web"&gt;MDN web docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kcjZb6Ji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g8lscdk2zeg3qnyo7me8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kcjZb6Ji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g8lscdk2zeg3qnyo7me8.png" alt="screenshot of CSS variable compatibility"&gt;&lt;/a&gt;&lt;br&gt;
Current CSS Variables Browser Support (Source: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties"&gt;MDN Web Docs&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;
  
  
  How to declare CSS variables
&lt;/h2&gt;

&lt;p&gt;In order to use CSS variables you should create a CSS custom property, which is a string prepended with a double hyphen &lt;code&gt;--&lt;/code&gt;. These properties are scoped and available based on their selector. Generally, it is recommended to make the selector the pseudoselector &lt;code&gt;:root&lt;/code&gt; so that it will apply throughout an entire site. If you select a more specific selector then the scope of where you can access the value of the variable changes accordingly.&lt;/p&gt;

&lt;p&gt;Below is an example showing 5 different CSS variables being declared to represent different colors within a stylesheet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--white&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--accent-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#b5838d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--dark-accent-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#a6757f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--main-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#6d6875&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--dark-main-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#56505f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to access the these CSS values throughout our CSS we can use the &lt;code&gt;var()&lt;/code&gt; method like &lt;code&gt;var(--accent-color)&lt;/code&gt;. The following example selects the element with the &lt;code&gt;signup&lt;/code&gt; class and changes its background-color to &lt;code&gt;#b5838d&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.signup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--accent-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since the value of &lt;code&gt;--accent-color&lt;/code&gt; is being set with a CSS variable if we later decide to change the value of &lt;code&gt;var(--accent-color)&lt;/code&gt; we only have to change it in one place, where the variables value is declared. Once the value of the variable is updated its new value will automatically be reflected everywhere &lt;code&gt;var(--accent-color)&lt;/code&gt; is referenced. Being able to change the color in one place for a multitude of unrelated elements that are only coupled by color is powerful. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of CSS Variables
&lt;/h2&gt;

&lt;p&gt;CSS variables allow you to quickly play around with a color scheme and tweak the same color everywhere it is referenced without having to do a find and replace. Additionally, setting up CSS variables can improve the developer experience when creating color schemes, as you can switch the variable declaration values between themes without having to explicitly change the values within the rest of the stylesheet.&lt;/p&gt;

&lt;p&gt;The two screenshots below show the difference in appearance when one line in the CSS file is changed from &lt;code&gt;--accent-color: orange;&lt;/code&gt; to &lt;code&gt;--accent-color: #b5838d;&lt;/code&gt; which is used in two completely separate places -- on the card's border-top property and the background color for the signup button. This can be very useful as stylesheets grow and values are re-used throughout. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;--accent-color: orange;&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;--accent-color: #b5838d;&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZhNxYcIZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h8b5sje08m97frpb2st5.png" alt=""&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gvuuWWr5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tjkn167s3l6w8gikk5a6.png" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Explore CSS variables!
&lt;/h2&gt;

&lt;p&gt;Play around with the CSS variable values by &lt;a href="https://codepen.io/M0nica/pen/jObpJma"&gt;editing the below Codepen&lt;/a&gt; to see CSS variables in action! &lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/M0nica/embed/jObpJma?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This article was originally published on &lt;a href="https://www.aboutmonica.com/blog/give-your-css-superpowers-with-css-variables"&gt;www.aboutmonica.com&lt;/a&gt;. Head over there if you like this post and want to read others like it. &lt;/p&gt;

</description>
      <category>css</category>
      <category>codepen</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
