<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Performant]]></title><description><![CDATA[Performant Web Development Blog]]></description><link>https://blog.performantweb.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 05 Jun 2026 20:36:30 GMT</lastBuildDate><atom:link href="https://blog.performantweb.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Replace koa-shopify-graphql-proxy When Going Cookieless]]></title><description><![CDATA[Recently I was migrating an embedded Shopify app from using cookie based authentication to use session tokens. The app was using koa-shopify-graphql-proxy to proxy requests from the frontend, to Shopify's GraphQL API. I wanted to use shopify-api inst...]]></description><link>https://blog.performantweb.dev/replace-koa-shopify-graphql-proxy-when-going-cookieless</link><guid isPermaLink="true">https://blog.performantweb.dev/replace-koa-shopify-graphql-proxy-when-going-cookieless</guid><category><![CDATA[shopify]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Mike@Performant]]></dc:creator><pubDate>Tue, 03 May 2022 22:29:57 GMT</pubDate><content:encoded><![CDATA[<p>Recently I was migrating an embedded Shopify app from using cookie based authentication to use <a target="_blank" href="https://shopify.dev/apps/auth/oauth/session-tokens">session tokens</a>. The app was using <a target="_blank" href="https://www.npmjs.com/package/@shopify/koa-shopify-graphql-proxy">koa-shopify-graphql-proxy</a> to proxy requests from the frontend, to Shopify's GraphQL API. I wanted to use <a target="_blank" href="https://www.npmjs.com/package/@shopify/shopify-api">shopify-api</a> instead.</p>
<p>On the frontend I had Apollo Client setup to use authenticatedFetch to send requests to the backend. I needed to use verifyRequest to check the incoming session tokens in the authorization header. </p>
<p>The following were required;</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Koa = <span class="hljs-built_in">require</span>(<span class="hljs-string">'koa'</span>);
<span class="hljs-keyword">const</span> { <span class="hljs-attr">default</span>: createShopifyAuth } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@shopify/koa-shopify-auth'</span>);
<span class="hljs-keyword">const</span> { verifyRequest } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@shopify/koa-shopify-auth'</span>);
<span class="hljs-keyword">const</span> Router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'koa-router'</span>);
<span class="hljs-keyword">const</span> koaBody = <span class="hljs-built_in">require</span>(<span class="hljs-string">'koa-body'</span>);
<span class="hljs-keyword">const</span> Shopify = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@shopify/shopify-api'</span>).Shopify;
</code></pre>
<p>Initialized server and router;</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> Koa()
    <span class="hljs-keyword">const</span> router = <span class="hljs-keyword">new</span> Router()
</code></pre>
<p>You will need to have <a target="_blank" href="https://shopify.dev/apps/auth/oauth">implemented OAuth</a> with Shopify. Shopify <a target="_blank" href="https://shopify.dev/apps/tools/app-bridge">App Bridge</a> is used to make authenticated requests from the frontend, attaching valid session tokens in the authorization header.</p>
<p>For the incoming requests to /graphql;</p>
<pre><code class="lang-javascript">  router.post(<span class="hljs-string">'/graphql'</span>, koaBody(), verifyRequest({<span class="hljs-attr">returnHeader</span>: <span class="hljs-literal">true</span>}), <span class="hljs-keyword">async</span> (ctx) =&gt; {
    <span class="hljs-keyword">const</span> session = <span class="hljs-keyword">await</span> Shopify.Utils.loadCurrentSession(ctx.request, ctx.response, <span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> { shop, accessToken } = session;
    <span class="hljs-keyword">const</span> options = {
      <span class="hljs-attr">data</span>: ctx.request.body,
    };
    <span class="hljs-keyword">const</span> client = <span class="hljs-keyword">new</span> Shopify.Clients.Graphql(shop, accessToken);
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> client.query(options);
    ctx.status = <span class="hljs-number">200</span>;
    ctx.body = response.body
  }
);
</code></pre>
<p>I used koaBody from <a target="_blank" href="https://www.npmjs.com/package/koa-body">koa-body</a> to parse the request body, and then pass it to the shopify-api GraphQL client.</p>
]]></content:encoded></item><item><title><![CDATA[Keep Static Site up to Date With Hashnode Blog]]></title><description><![CDATA[Two of the best features of Hashnode are it's GraphQL API, and the ability to automatically backup copies of your blog posts, and store them as markdown files in your own GitHub repo.
Sure you can setup a custom domain and add your own styling to you...]]></description><link>https://blog.performantweb.dev/keep-static-site-up-to-date-with-hashnode-blog</link><guid isPermaLink="true">https://blog.performantweb.dev/keep-static-site-up-to-date-with-hashnode-blog</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[Netlify]]></category><dc:creator><![CDATA[Mike@Performant]]></dc:creator><pubDate>Thu, 24 Feb 2022 20:41:45 GMT</pubDate><content:encoded><![CDATA[<p>Two of the best features of Hashnode are it's GraphQL API, and the ability to automatically backup copies of your blog posts, and store them as markdown files in your own GitHub repo.</p>
<p>Sure you can setup a custom domain and add your own styling to your blog, but for full control I prefer to <a target="_blank" href="https://catalins.tech/hashnode-api-how-to-display-your-blog-articles-on-your-portfolio-page">grab data from the Hashnode GraphQL API</a>, to display it on my portfolio.</p>
<h3 id="heading-what-about-other-hosts">What about other hosts?</h3>
<p>My portfolio is a static site hosted on Netlify, but this same general idea should be applicable to most static site hosts, with minor changes.</p>
<p>The following assumes you have a static site pulling data from Hashnode's API, and you have setup your blog to <a target="_blank" href="https://support.hashnode.com/docs/github-backup">automatically backup all your posts to GitHub</a>.</p>
<h3 id="heading-netlify-build-hook">Netlify Build Hook</h3>
<ol>
<li>Login to your Netlify account </li>
<li>Select the site you want to build</li>
<li>Select <code>Site settings</code></li>
<li>In the sidebar select <code>Build &amp; deploy</code></li>
<li>Scroll down to "Build hooks"</li>
<li>Select <code>Add build hook</code></li>
<li>Enter a hook name</li>
<li>Select branch to build</li>
<li>Copy the build hook url</li>
</ol>
<h3 id="heading-github-actions">GitHub Actions</h3>
<p>In the repo you created to backup your markdown files, you should create a YAML file in ./github/workflows/. For example I use</p>
<pre><code>.github/workflows<span class="hljs-operator">/</span>build.yml
</code></pre><p>And place the following into the file</p>
<pre><code><span class="hljs-attribute">name</span>: Netlify Build

<span class="less"><span class="hljs-attribute">on</span>:
  <span class="hljs-attribute">push</span>:
    <span class="hljs-attribute">branches</span>: [ main ]

<span class="hljs-attribute">jobs</span>:
  <span class="hljs-attribute">build</span>:
    <span class="hljs-attribute">name</span>: Request Netlify Webhook
    <span class="hljs-attribute">runs-on</span>: ubuntu-latest
    <span class="hljs-attribute">steps</span>:
      - <span class="hljs-attribute">name</span>: Curl request
        <span class="hljs-attribute">run</span>: curl -X POST -d {} <span class="hljs-selector-tag">YOUR</span> <span class="hljs-selector-tag">HOOK</span> <span class="hljs-selector-tag">URL</span> <span class="hljs-selector-tag">HERE</span></span>
</code></pre><p>This will trigger a request to the build hook URL you created earlier, any time there are changes pushed to the main branch of the Hashnode backup repository.</p>
<p>Additional information about <a target="_blank" href="https://docs.netlify.com/configure-builds/build-hooks/">Netlify build hooks</a> and <a target="_blank" href="https://docs.github.com/en/actions">GitHub Actions</a> can be found in their supporting documentation.</p>
]]></content:encoded></item><item><title><![CDATA[Transition Animation on Scroll with Chakra UI and React]]></title><description><![CDATA[Chakra UI provides four components to help add transition animations. The components are Fade, ScaleFade, Slide, and SlideFade.
These components can be passed an in prop that accepts a boolean which determines whether or not to show the component and...]]></description><link>https://blog.performantweb.dev/transition-animation-on-scroll-with-chakra-ui-and-react</link><guid isPermaLink="true">https://blog.performantweb.dev/transition-animation-on-scroll-with-chakra-ui-and-react</guid><category><![CDATA[React]]></category><dc:creator><![CDATA[Mike@Performant]]></dc:creator><pubDate>Sun, 13 Feb 2022 04:21:23 GMT</pubDate><content:encoded><![CDATA[<p>Chakra UI provides <a target="_blank" href="https://chakra-ui.com/docs/components/transitions">four components</a> to help add transition animations. The components are <code>Fade</code>, <code>ScaleFade</code>, <code>Slide</code>, and <code>SlideFade</code>.</p>
<p>These components can be passed an <code>in</code> prop that accepts a boolean which determines whether or not to show the component and trigger the enter/exit state.</p>
<p><a target="_blank" href="https://www.npmjs.com/package/react-visibility-sensor">"react-visibility-sensor"</a> is a package that makes it easy to assign a boolean to represent whether or not a DOM element is within the viewport.</p>
<p><a target="_blank" href="https://www.npmjs.com/package/react-intersection-observer">react-intersection-observer</a> provides similar functionality in this use case, and is a newer and actively maintained project with some additional features. Since this package utilizes a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">built in API</a>, it requires no additional dependencies. More on browser compatibility can be found at <a target="_blank" href="https://caniuse.com/intersectionobserver">caniuse.com</a>.</p>
<p>The following assumes you have an existing React project, with Chakra UI setup, but follow these links if you need help "<a target="_blank" href="https://create-react-app.dev/docs/getting-started/">Getting Started with React (CRA)</a>" or "<a target="_blank" href="https://chakra-ui.com/docs/getting-started">Getting Started with Chakra UI</a>"</p>
<h3 id="heading-react-visibility-sensor">react-visibility-sensor</h3>
<p> First off, install react-visibility-sensor in your project;</p>
<pre><code>npm install react<span class="hljs-operator">-</span>visibility<span class="hljs-operator">-</span>sensor
</code></pre><p>Import into your project;</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> VisibilitySensor <span class="hljs-keyword">from</span> <span class="hljs-string">"react-visibility-sensor"</span>
</code></pre>
<p>You can now wrap the element you wish to animate, and the Chakra UI transition component, in the VisibilitySensor component. You can then use an arrow function from within the VisibilitySensor component to access the <code>isVisible</code> variable.</p>
<pre><code class="lang-jsx">&lt;VisibilitySensor offset={{<span class="hljs-attr">bottom</span>:<span class="hljs-number">200</span>}} partialVisibility={<span class="hljs-literal">true</span>}&gt;
    {<span class="hljs-function">(<span class="hljs-params">{isVisible}</span>) =&gt;</span>
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Fade</span> <span class="hljs-attr">in</span>=<span class="hljs-string">{isVisible}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">YourElement</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Fade</span>&gt;</span></span>
     }
&lt;/VisibilitySensor&gt;
</code></pre>
<p>In this example the VisibilitySensor component is passed props for <code>offset</code> and <code>partialVisibility</code>. Check on npm for a <a target="_blank" href="https://www.npmjs.com/package/react-visibility-sensor#props">full list</a> of all the options you can assign.</p>
<h3 id="heading-react-intersection-observer">react-intersection-observer</h3>
<p>First off, install react-intersection-observer in your project;</p>
<pre><code>npm install react<span class="hljs-operator">-</span>intersection<span class="hljs-operator">-</span>observer
</code></pre><p>Import into your project;</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> InView <span class="hljs-keyword">from</span> <span class="hljs-string">"react-intersection-observer"</span>
</code></pre>
<p>You can now wrap the element you wish to animate, and the Chakra UI transition component, in the InView component. You can then use an arrow function from within the InView component to access the <code>inView</code> variable. You must also include a <code>ref</code> prop on the element you will be observing.</p>
<pre><code class="lang-jsx">&lt;InView rootMargin=<span class="hljs-string">"-200px"</span> triggerOnce={<span class="hljs-literal">true</span>}&gt;
    {<span class="hljs-function">(<span class="hljs-params">{inView, ref}</span>) =&gt;</span>
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Fade</span> <span class="hljs-attr">in</span>=<span class="hljs-string">{inView}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">YourElement</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Fade</span>&gt;</span></span>
     }
&lt;/InView &gt;
</code></pre>
<p>In this example the InView component is passed props for <code>rootMargin</code> and <code>triggerOnce</code>. Check on npm for a <a target="_blank" href="https://www.npmjs.com/package/react-intersection-observer#options">full list</a> of all the options you can assign.</p>
<p>And there you have two methods of triggering transition animations using the built-in Chakra UI components.</p>
]]></content:encoded></item><item><title><![CDATA[HTML Essentials - A Quick Overview of HTML]]></title><description><![CDATA[HyperText Markup Language organizes the structure of content, and along with CSS and JavaScript, it is one of the main building blocks of the web. HTML deals with meaning and content rather than styling or functionality, though it plays an important ...]]></description><link>https://blog.performantweb.dev/html-essentials-a-quick-overview-of-html</link><guid isPermaLink="true">https://blog.performantweb.dev/html-essentials-a-quick-overview-of-html</guid><category><![CDATA[HTML]]></category><dc:creator><![CDATA[Mike@Performant]]></dc:creator><pubDate>Thu, 13 Jan 2022 17:35:42 GMT</pubDate><content:encoded><![CDATA[<p><strong>HyperText Markup Language</strong> organizes the structure of content, and along with <strong>CSS</strong> and <strong>JavaScript</strong>, it is one of the main building blocks of the web. HTML deals with <strong>meaning</strong> and <strong>content</strong> rather than styling or functionality, though it plays an important role in both.</p>
<p>HTML is made up of <strong>elements</strong> which tell the browser additional information about the content using a system of opening and closing <strong>tags</strong>. While content is often text based, HTML also allows for the usage of links, scripts, images, audio, video and more.</p>
<h3 id="heading-html-boilerplate">HTML Boilerplate</h3>
<p>When you open up a new <code>.html</code> file in  <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> , you can generate <strong>HTML boilerplate</strong> by typing a single exclamation mark and pressing enter/return.</p>
<p>This template contains the basic structure that an HTML document should follow. It is a good practice to include all of these tags, and only a single html, head, title, and body tag.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The <code>&lt;!DOCTYPE&gt;</code> declaration tells the browser what version of HTML to expect. The <code>&lt;head&gt;</code> tag contains the page title and metadata, and is also the place to link to styles, and certain scripts. The <code>&lt;body&gt;</code> tag is where the content of the HTML document lives, and where JavaScript files are commonly added.</p>
<h3 id="heading-block-vs-inline">Block vs. Inline</h3>
<p>HTML elements generally fall into two categories, inline or block. Block level elements will automatically fill to 100% the width of their parent container, while inline elements are only as wide as the content they hold.</p>
<p>HTML has a general use container for block and inline content. Block level content can be wrapped in a <code>&lt;div&gt;</code> tag, while inline content can be wrapped in a <code>&lt;span&gt;</code> tag.</p>
<p>These generic containers don't provide the browser any information about the content's purpose, and therefore you should <em>always use more appropriate semantic elements</em>, if at all possible.</p>
<h3 id="heading-headings-and-paragraphs">Headings and Paragraphs</h3>
<p>Text content in HTML is often either a <strong>heading</strong> or a <strong>paragraph</strong>. Headings are titles and subtitles that are numbered in order of importance. There are six level's of headings which are shown by the tags; <code>&lt;h1&gt;</code> to <code>&lt;h6&gt;</code>.</p>
<p><code>&lt;h1&gt;</code> is the most important heading, and provides the main title or subject of the page. Only one <code>&lt;h1&gt;</code> tag should be used per page, and tags should exist in order, i.e. <code>&lt;h2&gt;</code> comes after <code>&lt;h1&gt;</code> and so on.</p>
<p>Paragraph's are block level elements which are wrapped in a <code>&lt;p&gt;</code> tag. The main purpose of a <code>&lt;p&gt;</code> tag is to denote a block of text content.</p>
<h3 id="heading-semantics-and-accessibility">Semantics and Accessibility</h3>
<p>One of the best ways to ensure your site is accessible to the largest population of users, is to ensure you <em>always use the correct element</em> for the content you are displaying. HTML includes many descriptive semantic tags such as:</p>
<ul>
<li><code>&lt;main&gt;</code></li>
<li><code>&lt;section&gt;</code></li>
<li><code>&lt;header&gt;</code></li>
<li><code>&lt;footer&gt;</code></li>
<li><code>&lt;nav&gt;</code></li>
<li><code>&lt;article&gt;</code></li>
<li><code>&lt;aside&gt;</code></li>
<li><code>&lt;figure&gt;</code></li>
</ul>
<p>Someone might be viewing your website with a screen reader, or navigating with only a keyboard. It is important that you keep this in mind when creating any HTML document for use by the general public.</p>
<h3 id="heading-attributes-ids-and-classes">Attributes, IDs and Classes</h3>
<p>HTML elements often have settings or options that can be changed by their attributes. Attributes generally follow the <code>name="value"</code> format. Some attributes are required for certain elements, and others are optional.</p>
<p>Two commonly used attributes are <code>id</code> and <code>class</code>. These are names you can assign to elements in order to reference them later, often using CSS or JavaScript. Id's are unique and <em>should not be re-used</em> on different elements, while classes may be used on multiple elements.</p>
<h3 id="heading-images-links-and-lists">Images, Links, and Lists</h3>
<p>It's hard to find a website that doesn't have a single image on it. Images can be added to HTML by using the <code>&lt;img&gt;</code> tag. The image element requires a <code>src</code> attribute that points to the images location. It is highly recommended for accessibility to always include a descriptive <code>alt</code> attribute.</p>
<p>The H in HTML (and http) stands for <strong>Hypertext</strong>, text that contains links. Hypertext was in usage before the invention of the World Wide Web, and has long been a core part of the internet. Text can be wrapped in an <code>&lt;a&gt;</code> or "Anchor" tag which accepts an <code>href</code> attribute as a location.</p>
<p>Lists in HTML can either be ordered <code>&lt;ol&gt;</code> or unordered <code>&lt;ul&gt;</code>. The main difference is the default styling for <code>&lt;ol&gt;</code> uses numbers , while <code>&lt;ul&gt;</code> uses bullets. Use <code>&lt;ol&gt;</code> when the order is important, for example a sequence of events such as a cooking recipe. Both types of lists are made up of <code>&lt;li&gt;</code> elements.</p>
<h3 id="heading-forms-and-input">Forms and Input</h3>
<p>An important part of HTML is the ability to accept a user's input. The <code>&lt;form&gt;</code> element tells a browser this part of the page is for gathering user input. Forms often contain;</p>
<ul>
<li><code>&lt;input&gt;</code></li>
<li><code>&lt;label&gt;</code></li>
<li><code>&lt;button&gt;</code></li>
<li><code>&lt;textarea&gt;</code></li>
<li><code>&lt;select&gt;</code></li>
</ul>
<p><code>&lt;input&gt;</code> elements are differentiated by their type attribute. Some commonly used input types are text, checkbox, button, password, radio, and submit. Associated <code>&lt;labels&gt;</code> are used to add captions to input elements.</p>
]]></content:encoded></item></channel></rss>