sg

package module
v0.0.0-...-6e58e89 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2026 License: MPL-2.0 Imports: 31 Imported by: 0

README

sg - another shitty static site generator

See github.com/ml8/ml8.github.io for an example.

Input site structure:

  • sg.yaml -- Site config. Fields defined in Site.

  • templates/ -- Directory of html templates. Use Go's html/template. Fields available to templates are those in RenderContext (and transitive references therefrom).

  • pages/ -- Directory of pages. Pages are either raw HTML (that may include template code), markdown files that are rendered, or plain files.

    • Markdown files must include some frontmatter (fields from Page) metadata.

To generate the site, supply the input directory containing the site structure and an output directory to render to. Optionally supply -w to watch the input directory or -s to serve a preview locally after rendering (-w implies -s):

sg -i input_dir -o output_dir

Renderer can be used directly. OfflineRenderer renders a site in one-shot, while OnlineRenderer watches an input directory and renders as files arrive.

Documentation

Overview

Package sg is a static site generator that reads markdown and HTML pages with YAML frontmatter, applies Go HTML templates, and outputs a rendered site. It supports both one-shot rendering (OfflineRenderer) and watch-mode rendering (OnlineRenderer) with filesystem watching and a built-in HTTP server.

Index

Constants

View Source
const LiveReloadScript = `` /* 356-byte string literal not displayed */

LiveReloadScript is the JavaScript snippet injected into served HTML pages. It connects to the WebSocket endpoint and reloads the page on receiving a message.

Variables

View Source
var (
	// Rendering errors
	ErrTemplateNotFound = errors.New("template not found")
	ErrSlugNotFound     = errors.New("slug not found")
	ErrPathNotFound     = errors.New("path not found")
	ErrTagNotFound      = errors.New("tag not found")
	ErrTypeNotFound     = errors.New("type not found")

	// Page validation/parsing errors.
	ErrMissingSlug        = errors.New("invalid slug")
	ErrMissingType        = errors.New("invalid type")
	ErrMissingPath        = errors.New("missing path")
	ErrMissingTitle       = errors.New("missing title")
	ErrMissingFrontmatter = errors.New("missing frontmatter")

	// Frontmatter delimiter
	FrontmatterDelimiter = []byte("---")
)

Functions

func InjectLiveReload

func InjectLiveReload(next http.Handler) http.Handler

InjectLiveReload wraps an http.Handler to inject the LiveReload script into HTML responses before the closing </body> tag.

func SetLogger

func SetLogger(l *zap.SugaredLogger)

SetLogger sets the package-level logger. If l is nil, a no-op logger is used.

func ToChannel

func ToChannel(ctx RenderContext, s *Site) rss.Channel

func ToItem

func ToItem(ctx RenderContext, p *Page) (rss.Item, error)

Types

type ColorFormatter

type ColorFormatter struct {
	// contains filtered or unexported fields
}

ColorFormatter prints colored, symbol-prefixed output.

func NewColorFormatter

func NewColorFormatter() *ColorFormatter

func (*ColorFormatter) FormatError

func (f *ColorFormatter) FormatError(err error)

func (*ColorFormatter) FormatMessage

func (f *ColorFormatter) FormatMessage(m Message)

type Config

type Config struct {
	InputDir        string
	OutputDir       string
	UseLocalRootUrl bool               // if true, use the local root url for serving
	QuiescentSecs   int                // period to wait before re-rendering pages on a template change
	Logger          *zap.SugaredLogger // optional; nil means no-op
	Drafts          bool               // if true, include draft pages in the rendered output
	Port            int                // port for the local server; used to construct localRootUrl
}

Config holds the configuration for site rendering.

type LiveReload

type LiveReload struct {
	// contains filtered or unexported fields
}

LiveReload manages WebSocket connections for automatic browser refresh.

func NewLiveReload

func NewLiveReload() *LiveReload

NewLiveReload creates a new LiveReload instance.

func (*LiveReload) Reload

func (lr *LiveReload) Reload()

Reload sends a reload message to all connected WebSocket clients.

func (*LiveReload) ServeHTTP

func (lr *LiveReload) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles the WebSocket upgrade handshake using the standard library.

type Message

type Message struct {
	Kind MsgKind
	Text string
}

Message is a typed watch-mode message.

type MsgKind

type MsgKind int

MsgKind describes the category of a watch-mode message.

const (
	MsgRendered      MsgKind = iota // page was rendered
	MsgCopied                       // file was copied as-is
	MsgTemplateAdded                // template was added/updated
	MsgIgnored                      // file was ignored
	MsgDeleted                      // file was deleted
)

type OfflineRenderer

type OfflineRenderer struct {
	Config Config
}

OfflineRenderer renders a site in one-shot mode.

func (*OfflineRenderer) Render

func (r *OfflineRenderer) Render() error

Renders the site and returns any error generated during rendering. Renders in one-shot and returns when rendering is complete.

type OnlineRenderer

type OnlineRenderer struct {
	Config Config

	// OnReload is called after a successful render. Use this to trigger
	// LiveReload notifications.
	OnReload func()

	// Formatter controls how watch-mode messages are printed. If nil, a
	// PlainFormatter is used.
	Formatter OutputFormatter
	// contains filtered or unexported fields
}

Renders a site in online mode. Watches the input directory for changes and renders them as files are changed. When a template changes, all pages are re-rendered currently. Re-rendering after a template change waits for a quiescence period to allow time for intital rendering of the site.

TODO: only re-render when a page is affected by the template change.

func (*OnlineRenderer) Render

func (r *OnlineRenderer) Render() (err error)

Start rendering. Watches the filesystem for any updates and renders updates as they arrive. Does not return unless rendering failed to start.

type OutputFormatter

type OutputFormatter interface {
	FormatMessage(Message)
	FormatError(error)
}

OutputFormatter formats watch-mode messages and errors for display.

type Page

type Page struct {
	// Required fields.
	FilePath  string // filename relative to the input directory
	UrlPath   string // url relative to the site root
	Slug      string `yaml:"slug"`
	Title     string `yaml:"title"`
	Type      string `yaml:"type"`
	IsRaw     bool
	OrderHint int

	// Fields for markdown pages.
	Draft       bool      `yaml:"draft"`
	Date        time.Time `yaml:"date"`
	Tags        []string  `yaml:"tags"`
	Ordering    string    `yaml:"ordering"`
	Description string    `yaml:"description"`
	// contains filtered or unexported fields
}

Page represents a single page in the site. Markdown pages are parsed from files with YAML frontmatter; raw pages (HTML, images, etc.) are copied directly.

func (*Page) Content

func (p *Page) Content() (template.HTML, error)

Return the content of the page, converted to HTML. Reads page from filesystem.

func (*Page) RawContent

func (p *Page) RawContent() ([]byte, error)

Get the raw content from the file. Reads the file each call.

type PlainFormatter

type PlainFormatter struct {
	// contains filtered or unexported fields
}

PlainFormatter prints plain-text output (no color, no symbols).

func NewPlainFormatter

func NewPlainFormatter() *PlainFormatter

func (*PlainFormatter) FormatError

func (f *PlainFormatter) FormatError(err error)

func (*PlainFormatter) FormatMessage

func (f *PlainFormatter) FormatMessage(m Message)

type RenderContext

type RenderContext struct {
	Site *Site

	// Used for rendering a single page; set by RenderPage.
	Page *Page
	// contains filtered or unexported fields
}

Context within which a page is rendered and defines top-level functions that can be called from the template.

func (RenderContext) PageReference

func (ctx RenderContext) PageReference(slug string) (*Page, error)

Get a page, given a slug.

func (RenderContext) Pages

func (ctx RenderContext) Pages() []*Page

All pages from the site.

func (RenderContext) RenderFeed

func (ctx RenderContext) RenderFeed() ([]byte, error)

func (RenderContext) RenderPage

func (ctx RenderContext) RenderPage(p *Page) ([]byte, error)

func (RenderContext) SlugURL

func (ctx RenderContext) SlugURL(slug string) (string, error)

URL for a given slug.

func (RenderContext) Tags

func (ctx RenderContext) Tags() []string

All tags from the site.

func (RenderContext) WriteFeed

func (ctx RenderContext) WriteFeed(fs *fsutil) error

type Renderer

type Renderer interface {
	Render() error
}

Renderer is the interface for site renderers.

type Set

type Set[T comparable] struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Set is a generic, concurrency-safe set implementation.

func NewSet

func NewSet[T comparable]() *Set[T]

func (*Set[T]) Add

func (s *Set[T]) Add(k T)

func (*Set[T]) AddAll

func (s *Set[T]) AddAll(k ...T)

func (*Set[T]) Elements

func (s *Set[T]) Elements() iter.Seq[T]

func (*Set[T]) Has

func (s *Set[T]) Has(k T) bool

func (*Set[T]) Remove

func (s *Set[T]) Remove(k T) bool

func (*Set[T]) Size

func (s *Set[T]) Size() int

func (*Set[T]) Slice

func (s *Set[T]) Slice() []T

type Site

type Site struct {
	sync.Mutex

	Title   string `yaml:"title"`
	RootUrl string `yaml:"root_url"`

	Description string `yaml:"description"`

	// Relative to Site root, optional.
	FeedUrl string `yaml:"feed_url"`
	FeedTag string `yaml:"feed_tag"`
	// contains filtered or unexported fields
}

Site holds the state of a parsed site, including all pages, templates, and indexes by slug, path, tag, and type. It is safe for concurrent use.

func (*Site) AddPage

func (s *Site) AddPage(p *Page)

Add a page to the site.

func (*Site) AddTemplate

func (s *Site) AddTemplate(key string, byts []byte) error

Add a template keyed by the given string.

func (*Site) PageByPath

func (s *Site) PageByPath(path string) (*Page, error)

Lookup page by input path.

func (*Site) PageBySlug

func (s *Site) PageBySlug(slug string) (*Page, error)

Lookup page by slug.

func (*Site) Pages

func (s *Site) Pages() []*Page

Retrieve all pages.

func (*Site) RemovePageByPath

func (s *Site) RemovePageByPath(path string) *Page

Remove the page with the given path and return the removed page. If page does not exist, returns nil.

func (*Site) Tag

func (s *Site) Tag(tag string) ([]*Page, error)

Get all pages with the given tag.

func (*Site) Tags

func (s *Site) Tags() []string

Retrieve all tags.

func (*Site) Template

func (s *Site) Template(key string) (*template.Template, error)

Look up the template associated with the given key.

func (*Site) Type

func (s *Site) Type(typ string) ([]*Page, error)

Get all pages with the given type.

Directories

Path Synopsis
Package rss provides types for representing RSS 2.0 feeds.
Package rss provides types for representing RSS 2.0 feeds.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL