gssg

Package Version Hex Docs

Batteries-not-included, templating library agnostic SSG library for Gleam.

Features

Installation

gleam add gssg

Quick Start

import gleam/dict
import gleam/io
import gleam/string
import lustre/element
import gssg/ssg

pub fn main() -> Nil {
  let result =
    ssg.new("priv", element.to_document_string)
    |> ssg.add_static_route("/", home_view())
    |> ssg.add_static_route("/about", about_view())
    |> ssg.build()

  case result {
    Ok(_) -> io.println("Build successful!")
    Error(e) -> io.println("Build failed: " <> string.inspect(e))
  }
}

fn home_view() {
  element.html([], [
    element.head([], [element.title([], "Home")]),
    element.body([], [element.h1([], [element.text("Welcome!")])]),
  ])
}

fn about_view() {
  element.html([], [
    element.head([], [element.title([], "About")]),
    element.body([], [element.h1([], [element.text("About Us")])]),
  ])
}

This generates:

Usage

Creating a site

Start by creating an SSG instance with an output directory and a render function:

import lustre/element
import gssg/ssg

let site = ssg.new("output", element.to_document_string)

The render function converts your page type to HTML strings. For Lustre elements, use element.to_document_string.

Adding static routes

Add individual pages with add_static_route:

ssg.new("priv", element.to_document_string)
|> ssg.add_static_route("/", home.view())
|> ssg.add_static_route("/projects", projects.view())
|> ssg.add_static_route("/contact", contact.view())

Each route generates a file at {path}/index.html.

Adding dynamic routes

Generate multiple pages from a collection of data:

import gleam/dict
import markup/markup

pub fn main() -> Nil {
  // Parse blog posts from markdown files
  let assert Ok(posts) = markup.parse_dir("data/posts")

  ssg.new("priv", element.to_document_string)
  |> ssg.add_static_route("/", home.view())
  |> ssg.add_static_route("/blog", blog_index.view(posts))
  |> ssg.add_dynamic_route("/blog", dict.from_list(posts), blog_post.view)
  |> ssg.build()
}

If posts contains:

This generates:

Building the site

Call build() to render and write all files:

let result = ssg.build(site)

case result {
  Ok(_) -> io.println("Build successful!")
  Error(ssg.CannotWriteFile(path, reason)) -> {
    io.println("Failed to write: " <> path)
  }
}

Complete Example

Here’s a complete example with static pages and a blog:

import gleam/dict
import gleam/io
import gleam/string
import lustre/element
import markup/markup
import pages/home
import pages/writing/post
import pages/writing/writing
import gssg/ssg

pub fn main() -> Nil {
  let assert Ok(posts) = markup.parse_dir("data/posts")

  let result =
    ssg.new("priv", element.to_document_string)
    |> ssg.add_static_route("/", home.view())
    |> ssg.add_static_route("/projects", markup.from("data/pages/projects.dj"))
    |> ssg.add_static_route("/writing", writing.view(posts))
    |> ssg.add_dynamic_route("/writing", dict.from_list(posts), post.view)
    |> ssg.build()

  case result {
    Ok(_) -> io.println("build successful.")
    Error(e) -> io.println("build failed: " <> string.inspect(e))
  }
}

License

This project is licensed under the Apache-2.0 License.

Search Document