Modern web development architecture:

Static site generators + JavaScript + Serverless = JAMstack

This blog post covers:

Hugo + jQuery + Azure Functions = JAMstack

JAMstack Recipes

The example used in this blog post is a site for jam recipes.

Example code:

Example site:

JAMstack

Modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup.

Read all about it over at: https://jamstack.org

Three things are needed:

  • JavaScript
  • APIs
  • Markup

In this blog post the JavaScript is written with jQuery, the APIs implemented with Azure Functions and the markup generated with Hugo.

Why?

  • Better Performance
  • Higher Security
  • Cheaper, Easier Scaling
  • Better Developer Experience

Static site generators is The Next Big Thing and it is used At Scale.

Hugo

A fast and modern static website engine

Hugo is a static site generator.

It’s the second most popular according to https://www.staticgen.com

Why Hugo?

  • Extremely fast build times
  • Runs on Windows and is easy to install

Scaffold a Hugo site:

hugo new site .

hugo new site .

Add content:

hugo new recipe/apple-jam.md

hugo new recipe/apple-jam.md

Code

The code for the site:

Configuration for the Hugo site is done in config.toml:

  • Uses the TOML format, located in the root folder
  • The baseURL points to where the site is hosted on GitHub Pages

Data:

  • Uses the TOML format, located in the data folder
  • This example is for the API URLs invoked by the JavaScript

The HTML template for the header:

  • HTML file located in the layouts\partials folder
  • This example uses Bootstrap template with the Narrow jumbotron
  • Custom CSS in app.css, Bootstrap stylesheets from CDN
  • The body tag gets an id with the current page template, will be used in the JavaScript
  • The navigation is populated by pages configured with navigation = true in the front matter

The HTML template for the header:

  • HTML file located in the layouts\partials folder
  • Custom JS in app.js, third-party scripts from CDN

Content:

  • Uses the Markdown format with Front Matter
  • This example is for the Apple Jam page
  • The image and ingredients are stored as variables, available in templates via the Param method

Page Templates:

  • HTML file located in a layouts subfolder
  • Reference the header and footer partials
  • This example is for the recipe pages
  • Data for the JavaScript is stored as attributes in a dedicated element
  • The image and ingredients are accessed via the Param method
  • The page markdown content is accessed with the .Content variable

JavaScript:

  • Located in the static folder
  • This example uses jQuery
  • The recipe page will GET ingredients from a Azure Function
  • The submit page will POST recipes to a Azure Function

Hugo has a theming system, so you don’t have to implement all templates yourself.

Hugo Themes:

Run and Build

Hugo provides its own webserver which builds and serves the site:

hugo server

hugo server

  • In this example you can then browse http://localhost:1313/jamstack/

Build the Hugo site:

hugo --destination ../../docs

hugo --destination ../../docs

  • In this example the site is hosted by GitHub Pages from the docs folder in the git repo.

Troubleshoot the site generation with:

hugo --verbose

GitHub Pages

Get the site hosted on GitHub Pages by:

  1. Pushing the code to GitHub
  2. Configuring a publishing source for GitHub Pages

In this example the docs folder is used as publishing source:

GitHub Pages

Azure Functions

Azure Functions Core Tools is a command line tool for Azure Functions

The Azure Functions Core Tools provide a local development experience for creating, developing, testing, running, and debugging Azure Functions.

Create a function app:

func init

func init

Create a function:

func function create

func function create

If you don’t like the terminal, take a look at Visual Studio 2017 Tools for Azure Functions

Code

The code for the API:

Configuration for a function is done in function.json:

  • The authLevel can be set to anonymous in this example
  • The route and methods are important to know when invoking the function from the JavaScript

The actual function is implemented in run.csx:

  • Uses the scriptcs format
  • This example will return hard coded ingredients for the given recipe

Run

Run the functions locally:

func host start

When running the Hugo site against local functions, specify CORS origins:

func host start --cors http://localhost:1313

func host start --cors http://localhost:1313

Deployment

Get the functions hosted on Azure by:

  1. Pushing the code to GitHub, Bitbucket or Visual Studio Team Services
  2. Log in to the Azure portal
  3. Create a function app
  4. Set up continuous deployment

In this example the Azure Functions code is located in the \src\api\ folder in the git repo.

Therefor deploying with custom script is needed:

.deployment:

  • Run deploy.cmd during deployment

deploy.cmd:

  • Copy files from the \src\api folder to the repository root

During deployment the logs look like this:

Azure Logs

Configuration

Before the Hugo site and the JavaScript can invoke the Azure Functions, Cross-Origin Resource Sharing (CORS) needs to be configured.

In this example these origins are allowed:

  • https://hlaueriksson.github.io
  • http://localhost:1313

Azure CORS

Now the Hugo site can be configured to use these URLs:

  • https://jamstack.azurewebsites.net/api/Ingredients/{recipe}
  • https://jamstack.azurewebsites.net/api/Recipe

Conclusion

  • JAMstack is the modern web development architecture
  • Static site generators is a big thing right now
  • Hugo is fast and awesome
  • jQuery is still useful
  • Serverless is the next big thing
  • Azure Functions is awesome