Dev Notes: Learning and Building a Fullstack, Real-Time Web App on Azure

Take a peak into my notes! Here's a bunch of links and brief commentary from building my first Azure app: a real-time emoji reaction room.

This is not a how-to guide. I'm sharing it in case some of the links and comments are useful to others (and my future self). It's a bit of a stream of consciousness.

While I'm new to Azure, I have fullstack experience with other cloud providers, so the goal here was for me to learn Azure-specific services, jargon, and conventions by building a demo project.

I'm a HUGE fan of learn-by-doing. I'll pick a project, and try to make it a reality. Sometimes I'll have an idea of what's needed, other times part of the fun is figuring out where to start and how to break it down.

When I go to build projects that are intended to last, I then have a better sense of some of the tools that can be used and whether or not they should be used for that specific problem. Here, the goal was to have fun and learn, so I played with all the things!

What Did I Build?

The GIF at the top shows the app in action, but if you like clicking things, you can check out a deployed version: https://tada.rwoll.dev.

Here's the rough idea:

Jordan is giving a presentation with a hybrid audience. They want to allow folks to react in realtime—just like in Microsoft Teams). The audience should be able to see everyone elses reactions in realtime, too.

So here's what Jordan does:

  1. Goes to https://tada.rwoll.dev.
  2. Creates a new room for their presentation.
  3. Shares the room link with the audience.
  4. Now, everyone in the audience who visits the room link can react with their favorite emoji and watch each of the reactions accumulate.

Fun! Right? (I think so, but I also ❤️ emoji a ridiculous amount!)

Basic Architecture

The UI is hosted on Azure Static Web Apps. When you visit the site, the UI connects to an API and Socket.IO server hosted on Azure App Service. There's no database or persistent storage beyond the lifetime of the running server.

When you click on a reaction button, a message is sent to the server, and then the new reaction count is emitted to all other UIs joined to that room.

After some time, the rooms auto-expire.

Tools, Services, and Packages

I intentionally decided to use more stuff than I'd need for a minimal production project since the goal was to learn.

🍎 Pro Tip 🍎: Most Azure Services have at least two pages when you search for them online. A marketing site (like this) and then a corresponding documentation site (like this). I personally found the service overview on the documentation site to be easier to understand and grok what the service was all about. Given a service name, searching for what is <service name> reliably got me to the documentation site.

So…here's a list of some of the services and tools I used along the way:

Terraform

Programmatically create all the Azure infrastructure.

You'll notice a lengthy list of services below. Most of them you don't realize you're using if you only use the Azure Portal UI. Azure will setup a lot of stuff at the push of a button—including configuring CI/CD pipelines (and the secrets they depend on) in GitHub.

However, I like how Terraform forces me to manually wire services together (among many other benefits), so I opted to use it to develop a deeper understanding. Depending on my mood, if I'm prototyping, I'll skip using Terraform and use the handy UI buttons instead.

Azure is also highly integrated with VSCode if you install the Azure Pack, so you can have it help you generate project files and remote resources directly from within VSCode.

The Terraform docs for each of the Azure resources are really helpful, and show how multiple resources are wired together. For example, check out the documentation for static_site_custom_domain.

Azure Static Web Apps

Host the HTML, CSS, and JS assets.

The GitHub Actions integration for this service is awesome! For each PR I created, the GitHub Action generated a per-PR preview URL for me to view the deployed UI before I merged it. The GitHub Action even commented on the PR with the preview link when it was ready! (Usually within seconds of my pushing!)

This also has a seemless, built-in integration with Azure Functions, but I didn't use those for this project.

If you're building on a recognizable framework (like create-react-app), Static Web Apps is basically zero-config. If you need more customization (e.g. I wanted to add some redirect URL for some image assets), you can configure all sorts of routing logic via a simple JSON file (staticwebapp.config.json). VSCode auto-completed the structure for me, too! (I'm not sure if that's built in, or if it's because I have the Azure Pack Extension installed.)

The Static Web Apps UI and VSCode extension can create and configure the GitHub Action CI/CD workflow for you, but if you want to set it up manually, here's the snippet.

Azure App Service

Backend code hosting.

I used this to host a minimal Node Docker container with my socket server running inside. I didn't actually need to use a Docker container, since the server was a minimal Node app which is supported out of the box without a custom container.

While I'm mentioning Docker, Azure's documentation page Comparing Container Apps with other Azure container options is useful in understanding the number of ways you can run a container within Azure.

Although, these days, you can do a lot without really needing to deal with Docker in the cloud, so first ask: do you need a Docker container?!

I used a GitHub Action to auto-deploy the backend with each push.

Azure Container Registry

Store private (or public) Docker containers.

Useful YAML snippet to build and push a container from your repo's GitHub Action to your registry.

Log Workspace

Store and query logs.

This allowed me to debug the deployed app (i.e. query through log lines I put into the server), and also search throught default HTTP Logs coming from Azure.

Azure DNS

Good ole DNS!

Works perfectly well!

Playwright

End-to-end testing, and video generation.

I wrote a few simple end-to-end tests. What's really neat is, for my app, I needed to have two users each with their own browser session all within one test in order to test the back-and-forth nature of the interaction. Playwright makes this super easy with its built-in test runner and concept of Browser Contexts.

I adapted this guide for multiple contexts within the same test.

Playwright was also useful in programmatically generating screenshots and videos of the app in action. Since I wrote the demo in Playwright code, I could just re-run the script to record a new video as I changed styling last minute!

Typescript

JavaScript, but with types and all sorts of goodies.

All code was written in Typescript (TS). I find, especially when working with new libraries, having the TS compiler and type-checker at my side makes me more productive. And, if I go to work on this project in the future and refactor code, the typechecker will help me pick up where I left off.

Parcel

A zero-config bundler.

I wrote the UI and Server in Typescript (including some JSX/TSX). They shared some common code (e.g. the message protocol between the UI and backend).

I pointed Parcel at the index.html file (which referenced some TS/React code) and it created all the static web assets bundled and optimized.

I also pointed it at the server entry point, and it created the server bundle to be run directly with node.

It's wicked fast and seemless. It takes the pain out of bundling! The built-in dev server with Hot Module Replacement (HMR) support for React (and other libs), is amazing!

Don't take my word for it. Spend a few minutes trying it out.

GitHub Actions

I used GitHub Actions to continuously deploy my code as I iterated. Here's some useful snippets related to this project:

Kapwing Video Editor

In-browser video editor/studio and GIF creator.

This tool made it super easy to overlay multiple videos (i.e. the user on the computer and the user on the phone) and then output everything as a GIF to include! Code or blog posts are great, but a GIF is priceless! 🎉

io-ts

Runtime encoding and decoding.

I used this library to validate the messages sent from the client to the server were well-formed and of expected types. Its Typescript integration is fantastic, but I hadn't done pure functional-style programming in a while, so it felt a little awkward.

Josh Comeau's Gradient Generator

The smoooooooothest gradients!

The tools also links to an interesting post about the science!

Josh Comeau's Shadow Generator

The prettiest shadows!

This also has a post! I love when tools create beautiful outputs, and also provide an explanation of how they work!

OpenMoji

The funnnnnnest emoji graphics!

I just love them!

React

UI framework.

Framer Motion

React library for awesome animations.

The fun button effects were done with this. It can get a lot cooler, though. I want to play more with this. I pretty much used it in place of native CSS Animations, but it can do a lot more.

Visual Studio Code

My favorite editor!

Some useful (or neat) extensions:

🏠 Home