HugoConf 2023 Talk

Presented at HugoConf 2023 by George Phillips from CloudCannon, this talk demonstrates StaticShape migrating a real website to Hugo from scratch.

#Talk breakdown

#The migration problem

Migrating to a static site generator like Hugo gives you a more secure, more reliable, and more maintainable website. The issue is that the migration itself takes time — time you don’t have because you’re still maintaining your current site. StaticShape is designed to bridge that gap.

#Scraping a live site

The first step is downloading a live website into a local directory of static HTML and assets. The talk demonstrates this using SiteScrape (npx sitescrape) on a Dunedin attractions website. The result is a folder of standalone HTML pages — each containing the full document with repeated <head>, navigation, and footer markup.

#Running StaticShape

With the static site downloaded, the next step is running StaticShape:

npx staticshape@latest

StaticShape prompts for the source directory, a configuration file, an output directory, and which SSG to export to. Choosing Hugo produces:

#How variable detection works

The talk walks through a simple example: two pages with different <title> tags. StaticShape compares the element nodes and finds the elements themselves are identical (<title>) but the text children differ (“Home” vs “About”). Since the text values don’t match, the text node is replaced with a variable node and the differing values are extracted as data for each page.

The same process applies to meta tags, OG titles, canonical URLs, and any other text or attribute that varies between pages.

#How loop detection works

The Dunedin attractions site has a “more attractions” section at the bottom of each page — a set of nearly identical cards with different images, links, and text. StaticShape detects these repeated sibling elements using equivalency scoring, generating a score between 0 and 100 for each pair. Elements above the threshold are collapsed into a loop node with a shared template and per-item data.

The talk highlights a nested loop case: each attraction card contains a set of badges (e.g. “Beach”, “Walk”). On one page there are three badges, on another just one. The single element is initially parsed as a plain element, but when merged with a page that has multiple badges (already detected as a loop), StaticShape recognizes the match and converts it into a loop as well — producing a loop within a loop.

#Configuration

The configuration file is where you define which pages belong to which collections and where the content boundaries are. The talk uses a config with two collections: general pages and attractions, each with a content selector to separate page content from the shared layout.

#Future directions

The talk closes with a roadmap of planned features: