html

package module
v0.0.0-...-5746e46 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2024 License: MIT Imports: 0 Imported by: 0

README

HTML-Go -- Packages for Generating HTML from Go

HTML-Go defines a basic interface for appending HTML content to a byte slice, and then provides a number of types that implement this interface that can efficiently generate HTML in a Go web application.

A Simple Login Form Example

The following uses the github.com/swdunlop/html-go/tag packge to create a simple login form:

tag.New(`main#main`).Add(
    tag.New(`h1`).Text(`Welcome to Example Co!`),
    p.Text(
        `Example Co is in private beta, you have been invited to participate in the beta by "`, inviter, `".`,
    ),
    p.Text(`Since this is your first here, we will need to create an account, but you must read and agree to the`).
        Add(tag.New(`a[href='/terms']`).Text(`terms of service`)).
        Text(`before we can do that.`),
    tag.New(`form`).Set(`action`, `/invite/`+token).Add(
        tag.New(`input[type=hidden][name=csrf]`).Set(`value`, requestCSRF(w, r)),
        tag.New(`input[type=hidden][name=token]`).Set(`value`, token),
        tag.New(`input[type=text][name=username][placeholder="Your-User-Name"]`),
        tag.New(`input[type=checkbox][name=accept][required]`),
        tag.New(`input[type=submit][value="Create Account"]`),
    ),
)

This form implements the html-go.Content interface, which is simply defined as:

type Content interface {
    AppendHTML(dst []byte) []byte
}

The html-go package also includes a number of lower level types that implement this interface, such as:

  • html.Text -- A text string which escapes HTML special characters when used as content.
  • html.HTML -- A byte slice which is assumed to already be valid HTML and simply appends itself as content.
  • html.Group -- A slice of other HTML content that can be used as content.

Usage Tips

The tag package was derived from the m(selector, attributes, children) function in the Mithril JavaScript framework and shares some usage patterns:

  • Avoid dynamically generating the selector -- instead, use the Set, Add, and Text methods to add dynamic content to the selector.
  • Tags can be reused, each method returns a copy of the tag with the necessary changes applied. This is meant to make it easy to build up a library of common tags.
  • Be careful around HTML tags with really strange rules about their content -- specifically style and script that do not support the use of entities or comments, and textarea. HTML5 is not as uniform as you may expect.

In addition, html.HTML is very literal about its contents, it is common and expected that you might concatenate a number of HTML elements into a single static html.HTML value. You can use the higher level tag package to build a series of complex HTML elements and then use html.Static to convert that element to a static html.HTML value.

Generating CDN Tags with Unpkg

This repository also includes cmd/unpkg, a simple command line utility for generating script and link tags for the unpkg.com CDN with SRIs. Unpkg is great, but it can be a little dicey to figure out the correct request path, which is important if you also use SRI hashes to ensure the integrity of your dependencies.

go run ./cmd/unpkg htmx.org@1.9.2 htmx.org@1.9.1/dist/ext/sse.js hyperscript.org@0.9.8 chota
<script defer src="https://unpkg.com/htmx.org@1.9.2/dist/htmx.min.js" integrity="sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://unpkg.com/htmx.org@1.9.1/dist/ext/sse.js" integrity="sha384-wQMrQ8lhjmPC6O2HZmiTsqEHeO4hD9lX2A4Q46YGtlaagNrRYVcuf9aJ3y/VN2hs" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://unpkg.com/hyperscript.org@0.9.8/dist/_hyperscript.min.js" integrity="sha384-1u4t3o4KScBpVyJ8r7E1vifF4H/GMUeZjN7CYA3v2xMXifSTac20oOseU3Irrup2" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://unpkg.com/chota@0.9.2/dist/chota.min.css" integrity="sha384-A2UBIkgVTcNWgv+snhw7PKvU/L9N0JqHwgwDwyNcbsLiVhGG5KAuR64N4wuDYd99" referrerpolicy="no-referrer" />

Rendering Go Values Using Dataview

The dataview package provides a simple way to render Go values as HTML tables if the values can be represented as JSON. See examples/dataview for a simple example.

Dataview Example

Simplified HTTP Logging With Chi and Zerolog

This module includes the hog package as an alternative to the httplog package. Hog is less verbose than httplog and adds a per-request logger to the request context for use by request handlers using http.Request.WithContext with zerolog.WithContext and zerolog.Ctx.

func main() {
    // Zerolog's default logger uses JSON output, but this makes it more readable (and slower, since zerolog must
    // generate JSON logs as normal and then parse them into text).
    log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).
        With().Timestamp().Logger()

    // For some reason, zerolog.DefaultContextLogger is nil out of the box, and
    // this is the default logger used by zerolog.Ctx (and therefore hog.For) --
    // you must bind it to a logger if you want to see log output at all.
    //
    // Alternately, you can specify the logger in the request context before using
    // hog, but it is generally easier to fix the problem at the source.
    zerolog.DefaultContextLogger = &log.Logger

    r := chi.NewRouter()
    r.Use(hog.Middleware())
    r.Get("/lazy", func(w http.ResponseWriter, r *http.Request) {
        hog.For(r).Info().Msg("taking a nap..")
        time.Sleep(1 * time.Second)
        http.Error(w, "I'm awake!", http.StatusOK)
    })
    http.ListenAndServe(":8080", r)
}
~/swdunlop/html-go> go run ./examples/lazy
10:58PM INF taking a nap.. method=GET remote_addr=127.0.0.1:60899 path=/lazy
10:58PM INF method=GET remote_addr=127.0.0.1:60899 path=/lazy status=200 took=1001 wrote=11

You can access the injected logger with hog.For(r) from a request or hog.From(ctx) from a context. The For, From, and Middleware functions all accept a series of options that can be used to customize the logger.

WARNING: The hog package will include the URL request path (but not the query) in the log output by default. This may be a security concern for handlers like invite links that include sensitive information in the URL path. You will want to avoid using hog.For, hog.From and hog.Middleware for these handlers.

Reloading Web UIs on Reconnect

It is popular to use something like Air to restart a server when source code changes, but if you are using your server to generate the HTML, you may also want to reload the view after restart. The "Dead Man Switch" component gives you a simple net/http.Handler and html.Content that can be combined to reload the view when the server restarts. See deadmanswitch/example for a simple example -- run it, visit http://localhost:8181 and restart the server to see the UI change.

Why?

I found the html/template package frustrating outside of simple use cases and prefer to generate HTML directly in view functions instead. There are a lot of other interesting template languages for Go but they all have their own quirks and I tend to just drop down to writing Go functions anyway.

Everything else in this package is just a collection of utilities for making life easier once you have decided to write your UI in Go.

Documentation

Overview

Package HTML implements very simple model of HTML content that is used to build HTML programmatically.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Append

func Append(buf []byte, elements ...Content) []byte

Append appends the HTML from each of its elements to the provided buffer.

func AppendText

func AppendText(buf []byte, text string) []byte

AppendText appends literal text, escaping the following characters using entities: "<", ">", "&", ";", "'" and '"'

Types

type Content

type Content interface {
	AppendHTML(buf []byte) []byte
}

A Content is something that can be appended as HTML in UTF-8 encoding to a HTML document.

func Static

func Static(elements ...Content) Content

Static merges the provided HTML content into static content, speeding up subsequent addition as HTML.

type Func

type Func func() Content

A Func is content that only generates content when needed.

func (Func) AppendHTML

func (fn Func) AppendHTML(buf []byte) []byte

AppendHTML implements Content by calling the function to get the content.

type Group

type Group []Content

Group is a slice of Content that can be appended as content.

func Map

func Map[S ~[]E, E any](slice S, fn func(E) Content) Group

Map will apply a function to each item in the slice to return content.

func (Group) AppendHTML

func (group Group) AppendHTML(buf []byte) []byte

AppendHTML appends the HTML from each of its elements to the provided buffer.

type HTML

type HTML []byte

HTML is static HTML content.

func (HTML) AppendHTML

func (html HTML) AppendHTML(buf []byte) []byte

AppendHTML simply appends content to the HTML buffer without transformation.

type Text

type Text string

Text is content that escapes the following characters using entities: "<", ">", "&", ";", "'" and '"'

func (Text) AppendHTML

func (text Text) AppendHTML(buf []byte) []byte

AppendHTML implements Element by appending the literal HTML, escaping any characters that could be misunderstood as starting a Tag or Doctype by a parser.

Directories

Path Synopsis
Package alpine adds helper functions for Alpine AJAX applications.
Package alpine adds helper functions for Alpine AJAX applications.
cmd
Package dataview provides a way to view Go values as tabular HTML if the values can be represented as JSON.
Package dataview provides a way to view Go values as tabular HTML if the values can be represented as JSON.
Package deadmanswitch provides a component that can be used to run JavaScript expressions when a Server Sent Events (SSE) connection to a service is lost.
Package deadmanswitch provides a component that can be used to run JavaScript expressions when a Server Sent Events (SSE) connection to a service is lost.
examples
Package hog provides middleware for logging HTTP requests in a service and recovering from panics using zerolog and a minimum of spam.
Package hog provides middleware for logging HTTP requests in a service and recovering from panics using zerolog and a minimum of spam.
Package tag provides an interface for incrementally building HTML tags with content, taking a trick from the "m" function in MithrilJS and running with it in a direction that may be familiar to people who have used Zerolog.
Package tag provides an interface for incrementally building HTML tags with content, taking a trick from the "m" function in MithrilJS and running with it in a direction that may be familiar to people who have used Zerolog.

Jump to

Keyboard shortcuts

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