Help us shape the future of Go! Take the 2026 Go Developer Survey

render

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package render owns the html/template loading and rendering pipeline. S02 ships the helper set that the rest of the project will rely on (safeHTML, relativeTime, pluralize, pathJoin, octicon, csrfToken). S25 will broaden this with the markdown pipeline.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type OcticonResolver

type OcticonResolver func(name string) (template.HTML, bool)

OcticonResolver returns the inline SVG markup for a named octicon. The implementation is provided by the caller; for S02 we ship a tiny built-in set; later sprints can plug in the full Primer octicon catalog.

func BuiltinOcticons

func BuiltinOcticons() OcticonResolver

BuiltinOcticons returns a tiny starter set of octicons. S02 ships only what the chrome needs (mark-github, three-bars, sun, moon, alert). The full Primer catalog is several hundred icons; we vendor on demand rather than bloating the binary.

type Options

type Options struct {
	Octicons OcticonResolver
}

Options configures a renderer.

type Renderer

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

Renderer holds parsed templates indexed by page name.

func New

func New(tmplFS fs.FS, opts Options) (*Renderer, error)

New parses every page template under tmplFS.

Naming contract — read this before adding files to internal/web/templates/:

  • **Pages** are .html files whose basename does NOT begin with an underscore. A page at `repo/tree.html` is registered under the lookup name `repo/tree`. Render that name from a handler.
  • **Partials** are .html files whose basename begins with an underscore (`_layout.html`, `profile/_tabs.html`). Partials are parsed into *every* page so the `{{ define "name" }}` blocks they declare are resolvable from any page template.

Both pages and partials are picked up recursively. Earlier versions of this loader walked only the root for partials, which caused a page that referenced a subdir partial (`profile/_tabs.html`'s `{{ define "tabs" }}`) to render blank — html/template silently ignored the missing-template ref at exec time. We now also validate that every `{{ template "name" }}` action in every parsed page resolves; an undefined ref fails loud at startup with the offending page + the missing name.

func (*Renderer) HTTPError

func (r *Renderer) HTTPError(w http.ResponseWriter, req *http.Request, status int, message string)

HTTPError writes an error page with the appropriate status code. If the named error template doesn't exist a plain-text fallback is written.

func (*Renderer) Render

func (r *Renderer) Render(w io.Writer, name string, data any) error

Render writes the named page to w using data as the template root context.

Prefer RenderPage when a *http.Request is in scope — it auto-injects the viewer (current logged-in user) into map data so partials like _nav.html can branch on .Viewer without every handler remembering to thread it.

When w is an http.ResponseWriter, Render sets Content-Type to `text/html; charset=utf-8` *before* the first body byte. This is load-bearing: a handler that calls WriteHeader(non-200) without pre-setting Content-Type otherwise produces a 4xx/5xx response with no Content-Type, which the browser renders as raw text. Setting it here makes that class of bug structurally impossible.

func (*Renderer) RenderPage

func (r *Renderer) RenderPage(w io.Writer, req *http.Request, name string, data any) error

RenderPage is the request-aware Render: when data is a map[string]any, it injects "Viewer" (from middleware.CurrentUserFromContext) and "CSRFToken" (the per-request token) if the caller hasn't set them. The nav partial's sign-out form uses the token, so every layout-rendered page needs it. Typed-struct callers must include those fields themselves — we don't reflect-mutate to avoid surprising aliasing.

Jump to

Keyboard shortcuts

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