ThinkAloud
Projects
ThinkAloud
  1. 01Projects21 ready to build and explain
Browse projects
Theme

Projects from Coding Challenges by John Crickett

Projects/Static Site Generator

Build your own static site generator

A command-line tool in the style of Hugo that sets up a site project, keeps each page as Markdown and the look in a theme, builds them into plain HTML files ready for any web host, and runs a development server that refreshes the browser on every save. Building it teaches why content, presentation and output are kept apart, why a template must escape the text it inserts, what a Markdown converter does underneath, and how a build decides what to redo when one file changes.

From Coding Challenges #77 ↗ by John Crickett

  • Challenge #77
  • Beginner
  • 7 concepts
  • 6 steps + 1 optional
  • Not yet checked
Start Static Site Generator

No sign-up. You tell the mentor your language: Java, Python or Node.js.

What you'll learn · 7 concepts

The concepts behind Static Site Generator

In the order the steps use them. Each one links to the best places to learn it, and you explain it in your own words once its steps are built.

  1. 1Generating a folder tree you can safely run twiceStep 2

    Step 1 creates the project folder and its homepage. Steps 2 and 3 then add commands that create more folders and files inside a project the user is already editing.

    Covers: creating parent folders before files · joining paths with the system's own rules · never overwriting the user's work · exclusive create instead of check, then write · commands that are safe to run twice · writing a file whole or not at all

    open(2), Linux manual page (O_CREAT and O_EXCL) ↗ · rename(2), Linux manual page ↗ · Hugo: hugo new project ↗

  2. 2Separating content, presentation and outputStep 4

    Step 2 moves the homepage into a theme and step 3 takes its words out into Markdown, which leaves the theme with layout only. From step 4 the output folder is written by the build and by nothing else.

    Covers: content: what a page says · presentation: how every page looks · output: generated, never edited by hand · one layout for many pages · changing one part without touching the others · which files are the source of truth

    Separation of content and presentation (Wikipedia) ↗ · Static site generator (Wikipedia) ↗ · CSS Zen Garden ↗

  3. 3From page names to files, URLs and linksStep 4

    Step 3's new page command turns a typed name into a file in the content folder, and from step 4 that file name becomes the page's address. Menus and a sitemap in the optional step need links that work from every page and full addresses.

    Covers: the output tree is the URL tree · index pages as a folder's default · turning a typed name into a safe slug · names that try to leave the folder · case-insensitive file systems · relative, root-relative and absolute links · a site served from a subfolder

    RFC 3986, section 5: Reference Resolution ↗ · Clean URL (Wikipedia), including slugs ↗ · What is GitHub Pages? (GitHub Docs), types of sites ↗

  4. 4Templates, and why plain substitution needs escapingStep 5

    Step 4 fills the theme's title and content placeholders. The title is plain text taken from a heading and the content is HTML from the converter, so the two need opposite treatment.

    Covers: a layout with named holes · text versus markup · escaping special characters · the place a value goes decides the escaping · trusted HTML inserted raw on purpose · filling every placeholder in one pass · placeholders left unfilled

    OWASP Cross Site Scripting Prevention Cheat Sheet ↗ · mustache(5): Logic-less templates ↗

  5. 5Converting Markdown to HTML: what a parser doesStep 5

    Step 4 converts every page to HTML and uses its first top-level heading as the title, which only works reliably from the parsed structure.

    Covers: block structure first, inline structure second · a tree of blocks and inline elements · rendering the tree as HTML · why line-by-line replacing breaks · CommonMark and the many dialects · raw HTML passing through · the title as a heading's plain text

    CommonMark Spec, Appendix A: A parsing strategy ↗ · Markdown: Syntax (John Gruber) ↗ · GitHub Flavored Markdown Spec ↗

  6. 6The build pipeline and deciding what to rebuildStep 6

    Step 4 builds every page each time, which is fine for two pages. Step 5 rebuilds while you edit, so the tool has to know which outputs each change affects, including a page that was deleted or renamed.

    Covers: inputs, outputs and the dependencies between them · one page's input versus a shared input · timestamps versus content hashes · dependencies found only while building · outputs left behind by deleted inputs · the same inputs give the same output

    GNU make manual: How make Processes a Makefile ↗ · Hugo: Basic usage (Build your project) ↗ · Reproducible Builds: Definitions ↗

  7. 7Watching files and the live-reload loopStep 6

    Step 5 asks for a server that updates the site in the browser whenever a page or the theme changes, which is exactly this loop.

    Covers: polling versus change notifications · watching folders, not single files · editors that save in several steps · debouncing a burst of events · not watching your own output · pushing a reload to the browser · surviving a failed build

    inotify(7), Linux manual page ↗ · Debouncing and Throttling Explained Through Examples (CSS-Tricks) ↗ · Using server-sent events (MDN) ↗

What you'll build · 6 steps

Build Static Site Generator step by step

Steps of 30 to 60 minutes, in your own editor and language. Each one has a check, so you know when it works.

  1. 01

    Set up

    Create the project for a command-line tool with subcommands. The page calls it ccssg, but the name is yours. Make sure you have a way to serve a folder over HTTP on your own machine, because the last step needs a development server.

    Works whenThe tool runs from the command line and lists its commands, and you can serve a folder of HTML files on a local port and open it in a browser.

  2. 02

    Initialise a project

    Add a command that creates a new project folder, named by the user, holding a homepage with placeholder headings and text that the user can edit. Running it again must not destroy a homepage the user has already changed.

    Works whenThe command creates a project folder that holds just index.html, and that page opens in a browser with its headings and text.

    Concepts: generating a folder tree you can safely run twice

  3. 03

    Create a theme

    Add a new theme command that creates a themes folder inside the project, with one subfolder named after the theme holding an index.html. Move the homepage's content from the project's own index.html into the theme's.

    Works whenAfter creating a theme called cc, the project tree shows themes/cc/index.html next to the root index.html, and the theme's page holds the homepage.

  4. 04

    Separate content from the theme

    Stop creating a root index.html. A new project now gets a content folder holding index.md, the homepage written in Markdown, and a new page command adds a Markdown file to that folder, so a page called about becomes about.md.

    Works whenAfter creating a project, the cc theme and an about page, the tree holds about.md and index.md in content and index.html in themes/cc, with no index.html at the root.

    Concepts: separating content, presentation and output · from page names to files, URLs and links

  5. 05

    Templates and building

    Turn the theme's index.html into a template with a placeholder for the title and one for the content. Add a build command that converts every Markdown file in content to HTML, puts it into the template with the page's first top-level heading as the title, and writes one HTML file per page into a new public folder, ready to upload to a static host.

    Works whenAfter a build, public holds about.html and index.html. Each shows its page's converted text with its heading as the title, and no placeholder is left in either file.

    Concepts: templates, and why plain substitution needs escaping · converting Markdown to HTML

  6. 06

    Development server with live reload

    Add a command that builds the site, serves it on a local port and keeps watching it. When a page in content or the theme changes, rebuild what the change affects and make an open browser show the new version without a manual refresh.

    Works whenFetching a page over HTTP, editing its Markdown and fetching it again returns the new text within a moment. With the page open in a browser, saving a change to the page or the theme shows up without pressing refresh.

    Concepts: watching files and the live-reload loop · the build pipeline and deciding what to rebuild

  7. +

    Going furtherOptional

    Add features from Hugo that interest you, such as a blog with posts listed by date, a menu that links to every page, more template placeholders, or a sitemap for search engines.

    Works whenEach feature shows in the built site. A menu appears on every page and its links work from any page, and a sitemap lists the full address of every page.

    Concepts: from page names to files, URLs and links

Ready to start Static Site Generator?

Start Static Site Generator

From Coding Challenges #77 ↗ by John Crickett. Notes written in our own words.

Projects from Coding Challenges by John Crickett