John Reilly MacGyver turned Dev 🌻❤️ TypeScript / ts-loader / fork-ts-checker-webpack-plugin / DefinitelyTyped: The Movie

Working with Azure Static Web Apps: A Netlify alternative

4 min read 1381

Working With Azure Static Web Apps: A Netlify Alternative

Jamstack sites have taken the world by storm, as evidenced by the fierce competition between offerings such as Netlify and Cloudflare. Azure recently threw its hat into this highly competitive ring with its new Static Web Apps (SWAs) offering.

In this tutorial, we’ll show you how to work with Static Web Apps and demonstrate how to deploy one using GitHub Actions.

Jamstack and Azure Static Web Apps

Jamstack stands for JavaScript, API and Markup. In Jamstack websites, the application logic typically resides on the client side. These clients are most often built as single-page applications and often have HTML files statically generated for every possible path to support search engine optimization.

Azure Static Web Apps was released for general use in May 2021. Its features include:

  • Globally distributed content for production apps
  • Autoprovisioned preview environments
  • Custom domain configuration and free SSL certificates
  • Built-in access to a variety of authentication providers
  • Route-based authorization
  • Custom routing
  • Integration with serverless APIs powered by Azure Functions
  • A custom Visual Studio Code developer extension

Significantly, these features are available to use for free. With Netlify, there is also a free tier; however, it’s quite easy to exceed the build limits of the free tier and land yourself with an unexpected bill. By combining Azure Static Web Apps with GitHub Actions, we can build comparable experiences and save ourselves money!

So let’s build ourselves a simple SWA and deploy it with GitHub Actions.

Creating a Docusaurus site

Inside the root of our repository, we’re going to create a Docusaurus site. Docusaurus is a good example of a static site, the kind that is a natural fit for Jamstack. We could also use something else, such as Hugo.

At the command line, we’ll enter:

npx [email protected] website classic

This will cause Docusaurus to create a new site in the website directory.

Let’s commit and push this and turn our attention to Azure.

Creating a Static Web App in Azure

There’s a number of ways to create a Static Web App in Azure. It’s possible to use infrastructure as code with a language such as Bicep. But for this tutorial, we’ll use the Azure Portal instead.

If you don’t have an account already, you can set one up for free very quickly.

Once you’ve logged in, click Create a resource and look up Static Web App:

Azure Static Web Apps: Create A Resource

Click Create and you’ll be take to the creation dialog:

Azure Static Web Apps Creating Dialog

You’ll need to create a resource group for your SWA to live in. Give the app a name, choose the free plan, and enter GitHub as the deployment source.

Click the Sign in with GitHub button and authorize Azure to access your GitHub account for Static Web Apps.

Azure Static Web Apps: Sign In With GitHub

At this point, Azure will query GitHub on your behalf and look up the organizations and repositories you have access to. Select the repository to which you’d like to deploy to your Static Web App and select the branch you’d like to deploy.

You also need to provide Azure with some build details to help it understand how your app is built. We’ll provide a preset of Custom. We’ll set the App location (the root of our frontend app) to be "/website" to tally up with the application we just created.

We’ll leave API location blank and set the output location to be "build" — this is the directory under website where Docusaurus will create our site.

Finally, click Review + create and then Create.



Azure will now:

  • Create an Azure Static Web app resource in Azure
  • Update your repository to add a GitHub Actions workflow to deploy your static web app
  • Kick off a first run of the GitHub Actions workflow to deploy your SWA.

Pretty amazing, right?

When you look at the resource in Azure, it will look something like this:

Azure Static Web Apps: Resources

If you click on the GitHub Action runs, you’ll be presented with your GitHub Action:

Azure Static Web Apps: GitHub Action

When that finishes running, you’ll be able to see your deployed Static Web App by clicking on the URL in the Azure Portal:

Azure Static Web Apps: SWA Deployed

We’ve gone from having nothing to having a brand new website in Azure, shipped via continuous deployment in GitHub Actions in a matter of minutes. This is low-friction and high-value!

Authentication

Now that we’ve done our initial deployment, let’s take it a step further and add authentication.

One of the great things about Static Web Apps is that authentication is available out of the box. We can pick from GitHub, Azure Active Directory, and Twitter as identity providers.

Let’s roll with GitHub and amend our website/src/pages/index.js to support authentication:

import React, { useState, useEffect } from 'react';
import clsx from 'clsx';
import Layout from '@theme/Layout';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import styles from './index.module.css';

/**
 * @typedef {object} UserInfo
 * @prop {"github"} identityProvider
 * @prop {string} userId
 * @prop {string} userDetails
 * @prop {string[]} userRoles
 */

/**
 * @return {UserInfo | null}
 */
function useUserInfo() {
  const [userInfo, setUserInfo] = useState(null);

  useEffect(() => {
    async function getUserInfo() {
      const response = await fetch('/.auth/me');
      const payload = await response.json();
      const { clientPrincipal } = payload;
      return clientPrincipal;
    }

    getUserInfo().then((ui) => setUserInfo(ui));
  }, []);

  return userInfo;
}

export default function Home() {
  const { siteConfig } = useDocusaurusContext();
  const userInfo = useUserInfo();

  return (
    <Layout
      title={`Hello from ${siteConfig.title}`}
      description="Description will go into a meta tag in <head />"
    >
      <header className={clsx('hero hero--primary', styles.heroBanner)}>
        <div className="container">
          <h1 className="hero__title">{siteConfig.title}</h1>
          <p className="hero__subtitle">{siteConfig.tagline}</p>
          <div className={styles.buttons}>
            {userInfo ? (
              <p>Hello {userInfo.userDetails}</p>
            ) : (
              <a
                className="button button--secondary button--lg"
                href="/.auth/login/github"
              >
                Click here to login
              </a>
            )}
          </div>
        </div>
      </header>
    </Layout>
  );
}

The above code does the following:

  • Implements a React hook named useUserInfo, which calls the /.auth/me endpoint of your SWA. This returns null when not authenticated and the UserInfo when authenticated
  • Displays a link button for users who are not authenticated. The link directs to /.auth/login/github, thus triggering the GitHub authentication flow
  • For users who are authenticated, displays the user’s userDetails, the GitHub username

Let’s commit and push this and, when our build has finished running, browse to our Static Web App once again:

Azure Static Web Apps Authentication

If we click to login, we’re taken through the GitHub authentication flow:

Azure Static Web Apps Authentication Flow

Once you’ve authorized and granted consent, you’ll be redirected to your app and see that you’re logged in:

Azure Static Web Apps: Logged In

If we pop open the devtools of Chrome, we’ll see what comes back from the /.auth/me endpoint:

Azure Static Web Apps Chrome DevTools

{
  "clientPrincipal": {
    "identityProvider": "github",
    "userId": "1f5b4b7de7d445e29dd6188bcc7ee052",
    "userDetails": "johnnyreilly",
    "userRoles": ["anonymous", "authenticated"]
  }
}

We’ve now implemented and demonstrated authentication with Azure Static Web Apps with very little effort. This is tremendous!

Staging environments

Finally, let’s look at a super cool feature that Static Web Apps provides by default. If you take a look at the Environments tab of your SWA you’ll see this:

Azure Static Web Apps Resource Environment Portal

Staging

Open pull requests against the linked repository to create a staging environment.

Let’s try that out! We’ll create a new branch:

git checkout -b feat/show-me-staging

In our index.js, we’ll add an arbitrary piece of text:

<p>I'm a staging environment!</p>

Then, we’ll commit and push our branch to GitHub and create a pull request. This triggers our GitHub Action to run once again.

Time, rather than publishing over our existing Static Web App, it’s going to spin up a brand new one with our changes in. It will also display a link for us in our GitHub pull request so we can browse straight to it:

Azure Static Web Apps Staging Environment

This is the equivalent of Netlify Deploy Previews, implemented with Azure Static Web Apps and GitHub Actions. The allowance for GitHub Actions currently sits at 2,000 free minutes per month, compared to Netlify’s 300 free minutes per month, so you’re much less likely to receive a bill for using Static Web Apps.

This staging environment will last only until the pull request is closed. At that point, the environment is torn down by the GitHub Action.


More great articles from LogRocket:


Conclusion

In this tutorial, we deployed a website to a Static Web App using GitHub Actions and implemented authentication. We also demonstrated Azure’s equivalent to Netlify’s deploy previews and how to set up staging environments.

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

.
John Reilly MacGyver turned Dev 🌻❤️ TypeScript / ts-loader / fork-ts-checker-webpack-plugin / DefinitelyTyped: The Movie

Leave a Reply