webx

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2025 License: MIT Imports: 36 Imported by: 0

README

WebX

A Non-Framework written in Go.

What is a non-framework? It's a minimal framework that does not rely on itself as a core dependency. This framework generates static HTML from an easy to use template engine.

This project is useful for building a new prototype when you have not decided on a big framework for the project yet. Because it uses vanilla HTML, it becomes easier to migrate your project to a bigger framework later on when your ready.

It can also be useful for anyone who simply doesn't like big frameworks, or simply has a smaller project.

Under the hood, the optional server uses gofiber, with automatically generated ssl certificates. The framework can also support dynamic page templates with embedded variables. You can even enable a Content Security Policy with the csp.yml file, and enable or disable it for each page or globally by default. Script nonce keys will automatically be randomly generated and embedded into your script tags within the template at compile time (before any variables are embedded).

This freamwork also optionally compiles markdown files.

Installation

go get github.com/tkdeng/webx

Usage


import (
  "github.com/tkdeng/webx"
)

func main(){
  app, err := webx.New("./app")
  
  // note: pages will automatically be rendered
  app.Use("/api", func(c fiber.Ctx) error {
    // use app.Render to render template pages
    // note: using `@` for dynamic pages matches the file name within the pages directory
    return app.Render(c, "@api", Map{
      "myvar": "example value",
    })
  })

  app.Use("/error", func(c fiber.Ctx) error {
    // use app.Error to render error pages
    // this will default to `@error.html`
    // but will first try `@404.html` or whatever error status is being used
    return app.Error(c, 404, "Page Not Found")
  })

  app.Listen()
}

  • Page Head: head.html || head.md (embedded into the <head> of the document)
  • Page Body: body.html || body.md (embedded into the <body> of the document)
  • Child Pages: #page.html || #page.md (used as the default for child pages, without modifying the current directory of pages)
  • Dynamic Pages: @api.html || @api.md (will not render by default, but can be called by your apis)
  • Content Security Policy: csp.yml (only available in root of pages directory)

<!-- embed html or md file -->
{@header}

<div class="widget">
  <!-- dynamic pages can also be statically embedded -->
  {@api}
</div>

<!-- {variables} will escape html by default -->
<div class="{myclass}">
  {myvar}
</div>

<!-- use the '#' prefix to allow html in variables -->
{#htmlvar}

Just Using The Compiler


import (
  "github.com/tkdeng/webx"
)

func main(){
  webx.Compile("./app")
}

In the dist directory, their are different types of files generated.

  • Static Files: index.html, about.html, about/more.html can be rendered equaivalent to the url. Note sometimes these static files will also be compressed with gzip (index.html.gz, about.html.gz).
  • Dynamic Files: @api.html, about/@widget.html can be rendered dyncmically and have variables populated.
  • Static Dynamic Files: #index.html, #login.html are just like static files, but they have basic variables like {nonce} keys prepared for a CSP to populate. Most variables have already been statically compiled.

theme.yml

adding a theme/theme.yml file will automatically generate a theme/config.css file with css variables defined in the root. The config will assume use of oklch color values.

vars:
  myvar: value

font-size: 1.2rem
font:
  sans: "'Roboto', ui-sans-serif, system-ui, sans-serif"
  serif: "Superclarendon, 'Bookman Old Style', 'URW Bookman', 'URW Bookman L', 'Georgia Pro', Georgia, serif"
  mono: "'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace"
  cursive: "'Segoe Print', 'Bradley Hand', Chilanka, TSCu_Comic, casual, cursive"
  logo: "'Comfortaa', 'Comfortaa Regular', 'Varela Round', Seravek, serif"

scheme: dark
force-scheme: no
theme:
  dark:
    bg-chroma: 0
    text-chroma: 0
    fg-chroma: 0.15
    color-chroma: 0.25

    bg-dark: 0
    bg: 5
    bg-light: 10
    fg: 25

    text: 95
    text-muted: 75

  light:
    bg-chroma: 0
    text-chroma: 0
    fg-chroma: 0.15
    color-chroma: 0.25

    bg-dark: 90
    bg: 95
    bg-light: 100
    fg: 80

    text: 5
    text-muted: 25

colors:
  link:
    hue: 220
    light: 55
    dark: 45

  primary:
    hue: 195
    light: 75
    dark: 60

  accent:
    hue: 170
    light: 75
    dark: 60

  confirm:
    hue: 145
    light: 65
    dark: 50

  warn:
    hue: 40
    light: 60
    dark: 45

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DebugCompiler = false

Functions

func Compile

func Compile(root string)

Compile runs the compiler without loading a new server

func EscapeHTML

func EscapeHTML(html []byte, mode ...string) []byte

EscapeHTML escapes HTML characters and HTML arg quotes

@mode (optional):

  • "html": escapes html characters
  • "args": escapes quotes for html args

func GenRsaKey

func GenRsaKey(crtPath string, keyPath string) error

GenRsaKey generates a new ssl certificate and key pair

  • expires: 3 years
  • rsa: 4096
  • x509
  • sha256
  • recommended renewal: once a year

func GenRsaKeyIfNeeded

func GenRsaKeyIfNeeded(crtPath string, keyPath string) error

GenRsaKeyIfNeeded auto detects if the certificates generated by the GenRsaKey method are either

  • not synchronized by date modified
  • are possibly expired (assuming a 1 year renewal)

If it detects this is true, it will automatically regenerate a new certificate

func Gunzip

func Gunzip(path string) ([]byte, error)

Gunzip will decompress a gzip file and return the bytes

func IsBotHeader added in v0.1.0

func IsBotHeader(c fiber.Ctx) bool

IsBotHeader does a lightweight check for any missing or susspicious headers for bots

returns true if it could be a bot

Notice: Do not rely on this check alone. It only preforms a basic check to reduce potential spam.

func PrintMsg

func PrintMsg(color string, msg string, size int, end bool)

PrintMsg prints to console and auto inserts spaces

Types

type App

type App struct {
	*fiber.App
	Config Config
	// contains filtered or unexported fields
}

func New

func New(root string, config ...fiber.Config) (App, error)

New loads a new server

func (*App) BlockBotHeader added in v0.1.1

func (app *App) BlockBotHeader(c fiber.Ctx) error

BlockBotHeader does a lightweight check for any missing or susspicious headers for bots

Notice: Do not rely on this check alone. It only preforms a basic check to reduce potential spam.

func (*App) Error

func (app *App) Error(c fiber.Ctx, status uint16, msg string) error

Error renders an error page

if the page is not found, it will return a default error page

func (*App) Listen

func (app *App) Listen() error

Listen to both http and https ports and auto generate a self signed ssl certificate (will also auto renew every year)

by using self signed certs, you can use a proxy like cloudflare and not have to worry about verifying a certificate athority like lets encrypt

func (App) NewForm added in v0.3.0

func (app App) NewForm(uri string, cb func(c FormCtx) error) *FormHandler

NewForm creates a new form handler.

This method allows easily managing session verification for user forms.

Note: this method assumes forms will be submitted with the client fetch api.

func (*App) Render

func (app *App) Render(c fiber.Ctx, url string, vars ...Map) error

Render a page

if the page is not found, it will return a 404 error

type CSP

type CSP struct {
	DefaultSrc             string
	ScriptSrc              string
	StyleSrc               string
	ImgSrc                 string
	ObjectSrc              string
	FontSrc                string
	ConnectSrc             string
	BaseUri                string
	FormAction             string
	FrameAncestors         string
	RequireTrustedTypesFor string
	ReportUri              string
}

type Config

type Config struct {
	Title    string
	AppTitle string
	Desc     string
	Icon     string

	PublicURI string

	Origins []string
	Proxies []string

	Vars Map

	PortHTTP uint16
	PortSSL  uint16

	DebugMode bool

	Root string

	CSP bool
	// contains filtered or unexported fields
}

type FormCtx added in v0.3.0

type FormCtx struct {
	fiber.Ctx

	Body    map[string]any
	Session *map[string]string
	// contains filtered or unexported fields
}

func (FormCtx) JSON added in v0.3.0

func (ctx FormCtx) JSON(success bool, json ...map[string]any) error

func (FormCtx) Render added in v0.3.0

func (ctx FormCtx) Render(url string, vars ...Map) error

type FormHandler added in v0.3.0

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

func (*FormHandler) API added in v0.3.0

func (handler *FormHandler) API(uri string, cb func(c FormCtx) error)

API verifies and continues a verified form session, and updates the token every request.

Note: this method assumes forms will be submitted with the client fetch api. Your API should include the "session" and updated "token" on every request.

type Map

type Map map[string]string

type Plugin added in v0.2.0

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

func NewPlugin added in v0.2.0

func NewPlugin(name string, defConfig ...map[string]string) *Plugin

func (*Plugin) Asset added in v0.2.0

func (plugin *Plugin) Asset(name string, buf []byte, path ...string)

func (*Plugin) Compile added in v0.3.2

func (plugin *Plugin) Compile(cb func(config *Config))

func (*Plugin) Page added in v0.2.0

func (plugin *Plugin) Page(name string, buf []byte, path ...string)

func (*Plugin) Router added in v0.2.0

func (plugin *Plugin) Router(cb func(app App))

type ThemeConfig added in v0.4.0

type ThemeConfig struct {
	FontSize string
	Font     map[string]string

	Scheme      string
	ForceScheme bool
	Theme       map[string]*struct {
		Scheme string

		BGChroma    float64
		TextChroma  float64
		FGChroma    float64
		ColorChroma float64

		BGDark  uint8
		BG      uint8
		BGLight uint8
		FG      uint8

		Text      uint8
		TextMuted uint8
	}

	Colors map[string]*struct {
		Hue   int16
		Dark  uint8
		Light uint8
	}

	Vars map[string]string
}

Jump to

Keyboard shortcuts

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