Setup / Tutorial

Build a free blog on Azure with NodeJS, Azure StaticWebApps & AzureDevops Pipelines.

December 16, 20228 min read
Free Blog hosted with AzureStaticWebApp
Diagram by Microsoft

Intro

The Gatsby framework allows people to easily make websites built from templates based on NodeJS. What isn't easy however is deploying this into Azure, this guide seeks to solve that problem! This setup tutorial aims to help you deploy an automated blog to AzureStaticWebApp with the following features:

  • A local development environment on your laptop for editing NodeJS Gatsby blog templates
  • Free Azure hosting infrastructure for hosting blogs
  • A CI/CD pipeline to automatically build and deploy the web app from the source files stored in a repository to an Azure environment.

This took me some troubleshooting to get working. The issue is that the documentation from Microsoft with the AzureDevops pipeline task that builds and deploys the site to Azure does not function correctly. The fix for this was to create a deployment pipeline that builds the web app from the source files separately and then use the AzureStaticWebApp pipeline task to just deploy the built web app from an artefact from the build pipeline.

Let's get started...

Pre-Requisites

To follow along with this guide you will need the following:

Install Local Software

Start by downloading the needed software onto your laptop by copying the below commands. This is specifically for macOS, but if you are on Windows these utilities can be installed using scoop. For this guide, I am using Visual Studio Code as my IDE as it integrates nicely with AzureDevops.

brew install azure-cli
  • Powershell7
brew install powershell
  • NPM (node package manager)
brew install node
  • git
brew install git

Configure git

To be able to push locally commited files to a repository from your client you are going to need to configure the default git commands.

You can verify this is configured correctly with the commands git config --list.

Make Folders

Copy and execute in your shell terminal the below commands. This is to create the local folders needed for the web site source files on your client.

pwsh
$localrepopath = New-Item -Type Directory -Path ($home+'\cloudseedprojects\automated-azurestaticwebapp\localrepos\')

Create ADO Project and Repo

Start by logging into Azure with the azcli and creating an Azure DevOps project and repository to store the web app source code and host the pipelines.

$devopsorgname = 'your-devops-orgname'
$devopsorgname = ('https://dev.azure.com/'+$devopsorgname)

az login  

$devopsproject = az devops project create --name "azure-blogstaticwebapp" --description "Repository storing the source code for a webapp blog" --org $devopsorgname --source-control git --visibility private | convertfrom-json


$devopsrepo = az repos create --name 'nodejs-gatsby-blog' --org $devopsorgname --project $devopsproject.name | convertfrom-json

Import Blog Template

Find a Gatsby template you like the look of from a site such as gatsbyjs. In this example I am going to use the gatsby starter WordPress template, the source code is found here on github.

When you have the git HTTPS URL of the source repo template, run the below command to import the source files into the azure DevOps repo that was just created.

$repourl = "https://github.com/gatsbyjs/gatsby-starter-wordpress-blog"
az repos import create --git-url $repourl --org $devopsorgname -p $devopsproject.name -r $devopsrepo.name

Clone ADO Repo to Client

Clone the Azure DevOps Repository to your local client, in my case the path is '/Users/alx/cloudseedprojects/automated-azurestaticwebapp/localrepos' with Visual Studio code.

ADO Repo

Install Node Packages Locally

With vscode open in the newly cloned azure DevOps repository, open a terminal and use the below commands to install the gatsby nodejs framework used to run the site locally. Once installed launch a locally running version of the site on your client to check it will build correctly.

  • Install gatsby nodejs framework globally with npm.
npm install gatsby-cli -g
  • Install required nodejs packages locally
npm install 
  • Launch local development server
gatsby develop  

Once you run the gatsby develop command you can open the built site at https://localhost:8000

Create AzureStaticWebApp in Azure

Use the below azcli commands to create an azure static web app resource and extract the needed API key. This is to be able to deploy the web app to the Azure static web app. Edit the variables to select the required region and change the name of the static web app.

$region = 'westeurope'
$yourname = 'alx'
$rg = az group create -l $region -g azurestaticwebapp-blog-test-rg | convertfrom-json
$aswa = az staticwebapp create  -l $region -g $rg.name -n ($yourname+'testblogazurestaticwebappresource') | convertfrom-json
$apikey = (az staticwebapp secrets list --name $aswa.name | convertfrom-json).properties.apikey

You should be able to browse the static web app's default page when you run $aswa.defaultHostname in the terminal. ASWA Default Page

Create Pipelines configurations and Push to AzureDevops

In the local repository project folder create 2 new files for the azure devops pipelines.

The first pipeline file will use an Azure Devops pipeline to boot an ubuntu container. This container will copy the source files from the repo and install nodejs 19.x and all the dependancies used to run the site. The built site will be outputted as an artifact called 'app'.

  • azure-pipelines-build.yml
# Build pipeline
#https://medium.com/version-1/build-and-deploy-angular-application-to-azure-static-web-app-using-azure-devops-264f846d63f5
trigger:
  branches:
    include:
     - main
  paths:
    exclude:
     - readme.md
pool:
  vmImage: ubuntu-latest
steps:
 - task: NodeTool@0
   displayName: 'Use Node 19.x'
   inputs:
     versionSpec: 19.x
 - script: |
     npm install gatsby-cli -g
   displayName: 'install gatsby cli'
 - task: Npm@1
   displayName: 'npm install '
   inputs:
     workingDir: '$(System.DefaultWorkingDirectory)'
     verbose: false
 - task: Npm@1
   displayName: 'npm build'
   inputs:
     command: custom
     workingDir: '$(System.DefaultWorkingDirectory)'
     verbose: false
     customCommand: 'run build'
 - task: PublishBuildArtifacts@1
   inputs:
     PathtoPublish: 'public'
     ArtifactName: 'app'
     publishLocation: 'Container'

The second deployment pipeline will use a container to take the built nodejs site saved as an artifact from the previous pipeline and deploy it to the Azure static webapp using the API token.

  • azure-pipelines-deploy.yml
# Deploy pipeline
#https://github.com/HoussemDellai/Trigger-Pipeline-From-Another-Pipeline
trigger: none
# this pipeline will be triggered by another pipeline
resources:
  pipelines:
  - pipeline: npm-gatsby-blog-build-ci   # Name of the pipeline resource
    source: npm-gatsby-blog-build-ci # Name of the pipeline referenced by the pipeline resource
    trigger: true # enable the trigger
stages:
 - stage: Deploy
   pool:
     vmImage: 'ubuntu-latest'
   jobs:
    - job: DeployWebAppProd
      steps:
       - task: DownloadPipelineArtifact@2
         inputs:
           buildType: 'specific'
           project: '$(project_id)'
           definition: '$(build_pipeline_id)'
           buildVersionToDownload: 'latest'
           artifactName: 'app'
           targetPath: '$(Pipeline.Workspace)'
       - bash: cd $(Pipeline.Workspace); echo $(ls)
       - bash: cd $(Pipeline.Workspace)/app; echo $(ls)
       - task: AzureStaticWebApp@0
         inputs:
           cwd: '$(Pipeline.Workspace)'
           app_location: '/'
           skip_app_build: true
           skip_api_build: true
           verbose: true
         env:
           azure_static_web_apps_api_token: '$(deployment_token)'

Once these files are created in the root of your local cloned repository, commit the files and push them to the main branch in the repo.

Configure the Azure Devops Pipelines

Once the Azure devops pipeline configuration files have been pushed to the azure devops repository the azure devops pipelines can be configured to use the configuration files stored in the repository using the below commands.

$buildpipeline = az pipelines create --org $devopsorgname -p $devopsproject.name --name "npm-gatsby-blog-build-ci" --branch main --description 'Pipeline for build of nodejs site' --repository $devopsrepo.name --yml-path "/azure-pipelines-build.yml" --repository-type tfsgit
$deploypipeline = az pipelines create --org $devopsorgname -p $devopsproject.name --name "npm-gatsby-blog-deploy-cd" --branch main --description 'Pipeline for deployment of nodejs site to azure static web app' --repository $devopsrepo.name --yml-path "/azure-pipelines-deploy.yml" --repository-type tfsgit

For the deployment pipeline to be able to deploy to the Azure Static Web App, the pipeline needs 2 environmental variables called deployment_token and project_id containing the API key of the azure static web app and the GUID of the AzureDevops Project which contains the build artefact. Paste the below command to configure this.

az pipelines variable create --org $devopsorgname -p $devopsproject.name --name "deployment_token" --pipeline-name "npm-gatsby-blog-deploy-cd" --secret "true" --value $apikey
az pipelines variable create --org $devopsorgname -p $devopsproject.name --name "project_id" --pipeline-name "npm-gatsby-blog-deploy-cd" --secret "false" --value ($buildpipeline | ConvertFrom-Json | SELECT -ExpandProperty project).id
az pipelines variable create --org $devopsorgname -p $devopsproject.name --name "build_pipeline_id" --pipeline-name "npm-gatsby-blog-deploy-cd" --secret "false" --value ($buildpipeline | convertfrom-json | select -ExpandProperty definition).id

The pipelines are configured in such a way that the build pipeline is triggered when a new commit is registered on the main branch. The deploy pipeline is then triggered once a successful build pipeline completes to pick up the built web app artefact and deploy it to the azure static web app. Once the deploy pipeline runs you should be able to navigate to the published site and see your newly deployed static blog site! The URL of the site is found in the pipeline deploy run or in the azure static web app resource in azure.

These pipelines allow you to rapidly make changes to your web source files locally and push them to the Azure static web app in an automated way!

And thats all, happy blogging!

Links

Additional sites used for building this post.

AzureGatsbyMarkdownBlogCICDAzure Static Web AppAzure Devops