npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gofront

v1.0.0

Published

A Go-inspired language that transpiles to JavaScript

Downloads

1,289

Readme

About

Go for the backend: simple, type-safe, no nonsense. JavaScript for the frontend: runs everywhere, no setup. The problem is JavaScript's loose typing — and TypeScript never quite felt like home either.

So I built GoFront. Go syntax and type safety, compiling to plain ES modules. One language front and back, no runtime, no framework, no tsconfig.json.

With built-in support for declarative DOM rendering via the gom standard library, JSX-like .templ files, and seamless integration with external JavaScript libraries through TypeScript definition files (.d.ts), GoFront is designed specifically as a frontend development target. Build complex, reactive user interfaces entirely in Go.

Probably not useful. Definitely fun to build.

package main

type Todo struct {
    id   int
    text string
    done bool
}

var todos []Todo

func addTodo(text string) {
    todos = append(todos, Todo{id: len(todos), text: text, done: false})
    render()
}

func main() {
    btn := document.getElementById("add-btn")
    btn.addEventListener("click", func() {
        addTodo(document.getElementById("input").value)
    })
}

Compiles to clean, readable JavaScript — no runtime, no framework.

GoFront source files use the .go extension so editors automatically apply Go syntax highlighting, bracket matching, and indentation rules without any extra configuration.


Install

npm install -g gofront

Requires Node.js 20+.


How it works

GoFront is a four-stage compiler written in pure Node.js (no dependencies). Every stage operates on the same AST (abstract syntax tree), running in a single pass per stage:

source text (.go files)
  → Lexer          tokenize + Go-style semicolon insertion
  → Parser         recursive-descent → AST
  → Type Checker   annotate AST with types + collect errors
  → Code Gen       AST → JavaScript string

source text (.templ files)
  → TemplLexer     dual-mode: Go mode for declarations, HTML mode inside templ bodies
  → TemplParser    extends Parser; produces TemplDecl AST nodes with TemplNode children
  → Type Checker   registers each templ component as func(...) gom.Node
  → Code Gen       TemplDecl → direct DOM calls (createElement / setAttribute / appendChild)

1. Lexer (src/lexer.js)

Tokenises the source into a stream of tokens. Implements Go's semicolon insertion rules: a semicolon is automatically inserted after a line's final token if that token is an identifier, literal, ), ], }, or certain keywords (return, break, continue, fallthrough). This is why Go doesn't need explicit semicolons — and neither does GoFront.

2. Parser (src/parser.js)

A hand-written recursive-descent parser. No parser generators, no grammar files — just straightforward top-down parsing. Produces an AST where every node is a plain JS object with a kind field ("FuncDecl", "IfStmt", "BinaryExpr", etc.).

Operator precedence is handled via a Pratt-style expression parser with numeric precedence levels.

3. Type Checker (src/typechecker.js)

Three-pass type checker operating on the AST:

  1. Pass 1 — collect types: register all type declarations (structs, interfaces, named types) so they can be referenced before definition.
  2. Pass 2 — collect functions & vars: register function signatures and package-level variables. Resolve embedded struct fields and promote methods.
  3. Pass 3 — check bodies: walk every function body, infer expression types, verify assignments and call arguments, and report errors with source location.

Types are plain JS objects ({ kind: "basic", name: "int" }, { kind: "slice", elem: ... }, etc.). The special any type acts as a recovery/escape hatch — any operation on it is silently permitted, preventing cascading errors.

4. Code Generator (src/codegen.js)

Walks the typed AST and emits clean, readable JavaScript. No intermediate representation — the codegen writes directly to an output buffer with indentation tracking.

Runtime helpers (__len, __append, __s, __sprintf, __equal, __cmul, __cdiv, __error, __errorIs, __timeFmt, __timeParse, __pathClean) are tree-shaken: only emitted when actually used. Optional inline source maps are supported via VLQ-encoded mappings.


Go → JavaScript mapping

Every Go construct compiles to a specific JavaScript pattern. The output is designed to be readable and debuggable — no name mangling, no opaque wrappers.

Data structures

| Go | JavaScript | Notes | |---|---|---| | struct | ES6 class | Single destructured-object constructor: new Point({ X: 1, Y: 2 }) | | Methods | Class instance methods | Receiver is this | | Embedded structs | Flattened fields + delegation stubs | Greet(...a) { return Base.prototype.Greet.call(this, ...a); } | | []T (slice) | Array | append → spread, len.length | | map[K]V | Plain object {} | Key access via [], iteration via Object.entries() | | nil | null | | | error | __error object | error("msg")__error("msg"), .Error() → real method call. toString() for string context compat | | Pointers (*T) | { value: T } | new(T) allocates a boxed zero value |

Functions

| Go | JavaScript | |---|---| | func f(a int) int | function f(a) | | Multiple returns return a, b | return [a, b] — destructured at call site: let [a, b] = f() | | Named returns | Variables pre-declared; bare return returns them | | Variadic func f(xs ...int) | function f(...xs) | | func literal (closure) | Arrow or function expression | | async func / await | async function / await | | init() | Emitted as (function() { ... })() immediately-invoked | | defer | try { ... } finally { deferred() } |

Control flow

| Go | JavaScript | |---|---| | for init; cond; post {} | for (init; cond; post) {} | | for cond {} | while (cond) {} | | for {} | while (true) {} | | for i, v := range slice | for (const [i, v] of arr.entries()) | | for k, v := range map | for (const [k, v] of Object.entries(m)) | | for i, r := range str | for (const [i, r] of Array.from(s, (c, i) => [i, c.codePointAt(0)]))r is a rune integer | | for i := range n | for (let i = 0; i < n; i++) | | switch / fallthrough | switch / case fall-through | | switch v := x.(type) | if/else if with typeof / instanceof checks | | panic(msg) | throw new Error(msg) | | recover() | Captured in defer via try/catch |

Builtins

| Go | JavaScript | |---|---| | len(x) | __len(x) (tree-shaken helper) or Object.keys(x).length for maps | | cap(x) | x.length | | append(s, elems...) | [...s, ...elems] | | copy(dst, src) | Inline splice helper | | make([]T, n) | new Array(n).fill(zero) | | make(map[K]V) | {} | | delete(m, k) | delete m[k] | | new(T) | { value: zeroOf(T) } | | min / max | Math.min / Math.max | | clear(x) | .length = 0 (slice) or delete-loop (map) | | print / println | console.log | | complex(r, i) | { re: r, im: i } | | real(z) / imag(z) | z.re / z.im | | fmt.Sprintf | __sprintf tree-shaken helper |

Type system at runtime

All type checking happens at compile time. At runtime, types are erased — there are no type tags, no reflection, no runtime overhead. Sized integers (int8int64, uint8uint64) are all number at runtime. float32 is number. Generic type parameters are erased completely — func Map[T, U any](...) compiles to function Map(...). The type checker enforces correctness; JavaScript doesn't need to know.


Examples — Todo App

There are four example apps — all implement the same todo app to show different aspects of GoFront.

Simple (vanilla DOM)

The default example. Zero dependencies, clean 1:1 compiled JS output. Showcases GoFront's core language features with straightforward DOM manipulation.

example/simple/
  src/
    types.go      ← Todo struct · FilterAll/Active/Completed iota · Priority iota
    store.go      ← state as plain variables · add/toggle/remove/clear · visibleTodos()
                     · stats() with named returns · defer/recover · async persistence
    render.go     ← render() updates DOM via innerHTML · renderTodo() · renderFilterBar()
    styles.go     ← injectStyles() creates <style> element with all CSS
    main.go       ← createApp() builds DOM shell · setupEvents() · event delegation
    utils/
      utils.go    ← Plural() · generic Filter — cross-package import demo
    browser.d.ts  ← minimal external type declarations (sleep)
  index.html      ← bare HTML shell, loads app.js as ES module
  app.js          ← generated output

Reactive (signals + d.ts imports)

Same app rebuilt with reactive.js, a tiny signals-based reactive framework. Demonstrates how GoFront integrates with external JS libraries via .d.ts type declarations — the entire reactive API surface is typed via a hand-written browser.d.ts shim and exercised from GoFront source.

example/reactive/
  src/
    types.go      ← Todo, Stats, AppElements structs
    store.go      ← reactive state: Signals.create/computed/computedAsync/batch/update
    render.go     ← Reactive.Component lifecycle · ctx.bind* · setupStatsBar
    styles.go     ← per-section cssClass() scoped styles
    main.go       ← async boot, Reactive.mount loading placeholder, signal.subscribe/once
    utils/
      utils.go    ← Plural() · generic Filter
    browser.d.ts  ← Signal · ComponentContext · Signals/Reactive namespaces · htmlTag
  reactive.js     ← signals framework (from microtastic)
  index.html      ← loads reactive.js, exposes helpers, imports app.js
  app.js          ← generated output

The reactive example covers the full reactive.js API surface:

| Category | Features used | |---|---| | HTML helpers | html tagged template (via htmlTag), trusted, join | | CSS | cssClass scoped styles with nested & selectors | | Signals | create, computed, computedAsync, batch, get, peek, set, update, subscribe, once | | Reactive namespace | mount (loading placeholder), createComponent, scan | | Component context | bind, bindAttr, bindBoolAttr, bindClass, bindText, bindStyle, bindMultiple, computed | | Component lifecycle | state, template, styles, mount, mountTo, appendTo, refs (via data-ref) | | Component instance | signal, effect, on (auto-cleanup event listeners) | | Scan attributes | data-model, data-text, data-html, data-if, data-visible, data-class-*, data-attr-*, data-bool-*, data-on-*, data-ref |

templ (template files + direct DOM codegen)

Same todo app using GoFront's .templ file format — a JSX-like syntax embedded directly in .go packages. templ declarations compile to direct document.createElement calls with no intermediate representation, producing {Mount(p){}} objects that are fully compatible with the gom.Node interface.

example/templ/
  src/
    render.templ  ← UI as templ declarations: TodoItem, TodoList, Header, InputRow, StatsBar, AppView, …
    render.go     ← helper functions (todoItemClass, filterLabel, …) + render() entry point
    types.go      ← Todo struct, filter/priority constants
    store.go      ← state, mutations, localStorage persistence
    styles.go     ← appStyles() CSS string
    main.go       ← event setup, entry point
    utils/        ← Filter[T], Plural, HasText
  app.js          ← generated output
  index.html      ← HTML shell

.templ syntax at a glance:

templ TodoItem(t Todo) {
    <li class={ todoItemClass(t) } draggable="true" data-id={ t.id }>
        <input type="checkbox" checked?={ t.done }/>
        <span class="todo-text">{ t.text }</span>
        if t.isUrgent() {
            <span class="badge">urgent</span>
        }
    </li>
}

templ AppView() {
    <div class="card">
        @Header(highCount(), syncMsg, syncCls)
        @TodoList(visibleTodos())
    </div>
}

Key syntax features:

  • { expr } — interpolate any Go expression (strings auto-cast, others use String())
  • attr={ expr } — dynamic attribute value (expression)
  • attr?={ expr } — boolean attribute (present/absent based on truthiness)
  • @Component(args) — call another templ component and mount it as a child
  • if cond { } else if cond { } else { } — conditional rendering (arbitrary depth)
  • for _, v := range slice { } — loop rendering inside template bodies
  • switch expr { case v: ... default: ... } — switch rendering inside template bodies
  • @templ.Raw(htmlStr) — inject raw/trusted HTML (uses insertAdjacentHTML)
  • Components are called like regular functions (AppView(), TodoItem(t)) and return a gom.Node-compatible object, so gom.Mount("#app", AppView()) works directly.

gom (stdlib component library + todo app)

Browser-native declarative DOM components inspired by gomponents. gom is a built-in stdlib package — no import path needed, available in every GoFront program just like fmt or strings. It uses methods on named non-struct types so that plain functions and slices can satisfy the Node interface without any struct boilerplate.

example/gom/
  src/
    types.go  ← Todo struct, filter/priority constants
    store.go  ← state, mutations, localStorage persistence
    render.go ← gom node builders (pure node tree, no innerHTML)
    styles.go ← appStyles() CSS string
    main.go   ← event setup, submitInput, entry point
    utils/    ← Filter[T], Plural, HasText
  app.js      ← generated output
  index.html  ← HTML shell

Key types and functions (all accessed as gom.*, no import needed):

  • gom.Node — interface with a single Mount(parent any) method
  • gom.NodeFunctype NodeFunc func(parent any) with Mount method; any function becomes a Node
  • gom.Grouptype Group []Node with Mount method; composes children in order
  • gom.El(tag, children...) — creates an element node
  • gom.Text(s) — creates a text node
  • gom.Attr(name, val) — generic attribute node; named shortcuts: gom.Class, gom.Href, gom.Type, etc.
  • gom.If(cond, node) — conditionally renders a node
  • gom.Map(slice, fn) — maps a slice to a Group of nodes
  • gom.Style(css) — returns a Node that injects a <style> element; styles are part of the node tree
  • gom.Mount(selector, n) — mounts a node into the DOM, replacing the element's content
  • gom.MountTo(selector, n) — appends a node without clearing; used to inject styles into <head>
  • HTML element helpers: gom.Div, gom.Span, gom.Button, gom.Input, gom.Ul, gom.Li, … (full HTML element set)

Features demonstrated

The simple and reactive examples cover: structs & methods, iota constants, named return values, closures, slices, for range, switch, cross-package imports, multi-file same-package compilation, async/await, defer/recover, localStorage persistence, DOM APIs, and generic utility functions (Filter[T], Map[T, U]).

The reactive example additionally demonstrates: external .d.ts type imports, declare namespace patterns for typing JS libraries, the full reactive signal graph (source signals → computed signals → async computed → DOM bindings), reactive UI with no querySelector or getElementById in application code, and Reactive.Component as the primary composition unit (state, template, styles, mount lifecycle, data-ref element refs, auto-cleanup event listeners).

The gom example additionally demonstrates: the gom built-in stdlib package, styles as nodes (gom.Style + gom.MountTo), gom.Map for list rendering, the declarative node-tree pattern (no innerHTML, no querySelector), and full feature parity with the other examples (priority mode, validation, localStorage persistence, sync status, drag-and-drop reordering).

The templ example additionally demonstrates: .templ file compilation, template components with parameters, { expr } interpolation, attr?={} conditional boolean attributes, @Component() calls inside templates, if / else if / else chains, switch blocks, for range loops, and @templ.Raw() for trusted HTML injection — all inside template bodies.

Build and run

npm run build:simple      # → example/simple/app.js
npm run build:reactive    # → example/reactive/app.js
npm run build:gom         # → example/gom/app.js
npm run build:templ       # → example/templ/app.js
# open the respective index.html in a browser

CLI

gofront <file.go>                compile single file → stdout
gofront <dir>                    compile all *.go in directory → stdout
gofront <input> -o out.js        write output to file (prints elapsed compile time e.g. "15ms")
gofront <input> --check                    type-check only
gofront <input> --watch                    watch for changes and recompile
gofront <input> -o out.js --serve          watch + serve with live reload (default port 3000)
gofront <input> -o out.js --serve --port 8080  use a custom port
gofront <input> --source-map               append inline source map (single file or directory; multi-file packages emit per-file mappings)
gofront <input> --minify                   minify output (built-in minifier)
gofront <input> --minify --mangle          minify and rename local identifiers
gofront <file.go> --ast                    dump AST (debug)
gofront <file.go> --tokens                 dump tokens (debug)
gofront init [dir]                         scaffold a new project
gofront --version / -v                     print version
gofront --help / -h                        print this help

Multi-file packages

All .go files in a directory share the same namespace and are compiled as one unit. The compiler (src/compiler.js) orchestrates this:

  1. Parse each .go file in the directory into a separate AST.
  2. Resolve imports: js: d.ts files, npm packages (via node_modules/ and @types/), and local GoFront sub-packages (import "./subpkg") which are compiled recursively.
  3. Run the type checker across all ASTs as a single unit — types, functions, and variables declared in one file are visible in all other files of the same package.
  4. Generate code for each AST and concatenate. Sub-package code is inlined as a preamble.
myapp/
  types.go     ← type Point struct { X, Y int }
  utils.go     ← func distance(a, b Point) float64 { ... }
  main.go      ← func main() { ... }
gofront myapp -o myapp/bundle.js

Cross-package imports are supported via relative paths:

import "./mathpkg"

func main() {
    x := math.Add(1, 2)   // math package inlined into the bundle
}

Type checking

GoFront performs static type checking before emitting any code, accurately tracking source locations in error messages across multiple files:

func greet(name string) {
    console.log("Hello, " + name)
}

greet(42)
// → Type error in src/main.go at line 5:7: cannot use int as string
//     5 | greet(42)
//           ^

External TypeScript type definitions are supported via js: imports:

import "js:./dom.d.ts"

npm package types are resolved automatically from node_modules/ and @types/. The resolver (src/resolver.js) walks up the directory tree to find node_modules, checks package.json "types" / "typings" fields, falls back to index.d.ts, then tries @types/. The .d.ts parser (src/dts-parser.js) extracts type signatures into GoFront's internal type representation.


Language features

Core language

| Feature | Status | |---|---| | Variables (var, := short re-declaration) | ✓ | | Constants (const, iota, untyped constants) | ✓ | | Functions, multiple returns, named returns, variadic | ✓ | | init() functions | ✓ | | Closures / function literals | ✓ | | async func / await expressions | ✓ | | defer, panic() / recover() | ✓ | | print / println builtins | ✓ — compile to console.log |

Types & data structures

| Feature | Status | |---|---| | Structs + methods (value & pointer receivers) | ✓ | | Embedded structs (flattened fields + promoted methods) | ✓ | | Anonymous struct types | ✓ — compile to plain JS objects | | Interfaces (with embedding) | ✓ | | Slices (append, len, make) | ✓ | | Maps (make, delete, comma-ok) | ✓ | | Arrays with compile-time enforcement | ✓ — reject append, bounds checking, size matching, [...]T inference, compile-time len() | | Slice → array conversion ([N]T(slice)) | ✓ — Go 1.20 | | Pointers (&x, *p, new(T)) | ✓ — scalar locals boxed as { value: T } for shared mutation | | error type | ✓ — interface { Error() string }; custom error types, errors.Is/Unwrap, %w wrapping | | Complex numbers (complex64, complex128, 3i) | ✓ — complex(), real(), imag() builtins; __cmul/__cdiv helpers | | Type definitions, type aliases (type A = B) | ✓ | | Methods on named non-struct types | ✓ — type T func(...) or type T []E with methods; emitted as ES6 wrapper classes; satisfies interfaces | | Type conversions, type assertions (plain & comma-ok) | ✓ | | Type switch (switch v := x.(type)) | ✓ — compiles to if/else if with typeof / instanceof | | Sized integers (int8int64, uint8uint64, float32) | ✓ — mapped to number at runtime | | Generics (func F[T any], type S[T any] struct) | ✓ — type erasure to JS; generic functions, structs, constraints (any, comparable, interfaces, unions), type inference | | Struct field tags | ✓ — parsed and ignored (no reflection) | | Struct and array equality (a == b) | ✓ — deep comparison via __equal helper |

Control flow

| Feature | Status | |---|---| | if / else if / else (with init statement) | ✓ | | for (C-style, condition-only, infinite, range) | ✓ | | range over slice, map, string, integer | ✓ | | Range over iterator functions (Go 1.23) | ✓ — func(yield func(K, V) bool) protocol; break/continue/return propagation | | switch / fallthrough (with init statement) | ✓ | | break / continue / labeled variants | ✓ | | Terminating statement analysis | ✓ — missing return in non-void functions is a type error |

Expressions & literals

| Feature | Status | |---|---| | Arithmetic, comparison, logical, bitwise operators | ✓ — includes &^ (bit clear) | | Compound assignment, increment / decrement | ✓ | | Slice expressions (s[lo:hi], s[lo:hi:max]) | ✓ | | Variadic spread (f(slice...), append(a, b...)) | ✓ | | Positional struct literals (Point{1, 2}) | ✓ | | Method expressions (T.Method) / method values (x.Method) | ✓ | | Multi-value function forwarding (f(g())) | ✓ | | Raw string literals (backticks), rune literals | ✓ | | Numeric separators (1_000_000), binary/octal/hex literals | ✓ | | []byte(s) / []rune(s) conversions | ✓ |

Standard library shims

| Package | Functions | |---|---| | fmt | Sprintf, Printf, Println, Print, Errorf, Fprintf, Fprintln, Fprint — format verbs: %v, %d, %s, %t, %x, %o, %b, %q, %e, %g, %w, width/precision; scanning: Sscan, Sscanln, Sscanf | | strings | Contains, HasPrefix, HasSuffix, Index, LastIndex, Count, Repeat, Replace, ReplaceAll, ToUpper, ToLower, TrimSpace, Trim, TrimPrefix, TrimSuffix, TrimLeft, TrimRight, Split, Join, EqualFold, Fields, Cut, CutPrefix, CutSuffix, SplitN, SplitAfter, SplitAfterN, IndexAny, LastIndexAny, ContainsAny, ContainsRune, IndexRune, IndexByte, LastIndexByte, Map, Title, ToTitle, TrimFunc, TrimLeftFunc, TrimRightFunc, IndexFunc, LastIndexFunc, NewReplacer; Builder type; NewReader → reader shim | | bytes | Contains, HasPrefix, HasSuffix, Index, Join, Split, Replace, ToUpper, ToLower, TrimSpace, Equal, Count, Repeat, ReplaceAll, TrimPrefix, TrimSuffix, TrimLeft, TrimRight, TrimFunc, IndexByte, LastIndex, LastIndexByte, Fields, Cut, ContainsAny, ContainsRune, Map, SplitN; Buffer type; NewReader → reader shim | | strconv | Itoa, Atoi, FormatBool, FormatInt, FormatFloat, ParseFloat, ParseInt, ParseBool, Quote, Unquote, AppendInt, AppendFloat | | sort | Ints, Float64s, Strings, Slice, SliceStable, SliceIsSorted, Search, IntsAreSorted, Float64sAreSorted, StringsAreSorted | | math | Abs, Floor, Ceil, Round, Sqrt, Cbrt, Pow, Log, Log2, Log10, Sin, Cos, Tan, Atan, Atan2, Asin, Acos, Exp, Exp2, Trunc, Hypot, Signbit, Copysign, Dim, Remainder, Min, Max, Mod, Inf, IsNaN, IsInf, NaN + Pi, E, MaxFloat64, SmallestNonzeroFloat64, MaxInt, MinInt | | math/rand | Intn, Float64, Float32, Int, Int63, Int63n, Int31, Int31n, Seed (no-op), Shuffle, Perm | | errors | New, Is, Unwrap — custom error types via interface satisfaction | | time | Nowtime.Time, Since, Sleep, Parse, Unix, Date; time.Time methods: Format, String, Year, Month, Day, Hour, Minute, Second, Weekday, Unix, UnixMilli, Add, Sub, Before, After, Equal; layout constants: RFC3339, RFC3339Nano, DateOnly, TimeOnly, DateTime; duration constants: Millisecond, Second, Minute, Hour; month/weekday constants | | html | EscapeString, UnescapeString | | maps | Keys, Values, Clone, Copy, Equal, EqualFunc, Delete, DeleteFunc | | slices | Contains, Index, Equal, Compare, Sort, SortFunc, SortStableFunc, IsSorted, IsSortedFunc, Reverse, Max, Min, MaxFunc, MinFunc, Clone, Compact, CompactFunc, Concat, Delete, DeleteFunc, Insert, Replace, Grow, Clip | | regexp | MustCompile, Compile, MatchString, QuoteMeta; *Regexp methods: MatchString, FindString, FindStringIndex, FindAllString, FindStringSubmatch, FindAllStringSubmatch, ReplaceAllString, ReplaceAllLiteralString, Split, String. Inline flags ((?i), (?m), (?s)) are extracted automatically into the JS RegExp constructor. | | unicode | IsLetter, IsDigit, IsSpace, IsUpper, IsLower, IsPunct, IsControl, IsPrint, IsGraphic, ToUpper, ToLower | | unicode/utf8 | RuneCountInString, RuneLen, ValidString, ValidRune, DecodeRuneInString, DecodeLastRuneInString, FullRuneInString; constants RuneError, MaxRune, UTFMax | | path | Base, Dir, Ext, Join, Clean, IsAbs, Split, Match; "path/filepath" is an alias | | os | Exit, Args, Getenv | | io | Writer, Reader, ReadWriter, Closer interface types; ReadAll, EOF, Discard, WriteString | | gom | Browser-native declarative DOM component library. Types: Node (interface), NodeFunc, Group. Core: El(tag, children...), Text(s), Mount(sel, node), MountTo(sel, node). Attributes: Attr, Class, Href, Type, Src, Placeholder, DataAttr, Style, For, Name, Value, Target, Rel, Alt, Title, Draggable, Role, AriaLabel, StyleAttr; boolean: Disabled, Checked, Selected, Readonly. Logic: If(cond, node), Map(slice, fn). Elements: full HTML element set (Div, Span, Button, Input, Ul, Li, Table, Form, Img, A, H1H6, …) |

Packages & imports

| Feature | Status | |---|---| | Multi-file packages | ✓ | | Cross-package imports | ✓ | | Import aliases (import m "./pkg") | ✓ | | Side-effect imports (import _ "pkg") | ✓ | | Dot imports (import . "pkg") | ✓ | | Unused import detection | ✓ | | External .d.ts types | ✓ | | npm package type resolution | ✓ | | .templ files in packages | ✓ — mix .go and .templ files freely; templ components visible across the whole package |


Go Compatibility

GoFront implements a practical subset of the Go Language Specification (go1.26). It is not aiming for byte-level parity — it is a Go-inspired language for the JavaScript platform.

GoFront extensions (not in Go)

These features are intentional additions for the JavaScript platform:

| Feature | Purpose | |---|---| | async func / await | First-class async syntax for frontend work. | | Browser globals (document, console, etc.) | Predeclared as any for practical DOM access. | | .d.ts type imports (import "js:./types.d.ts") | Type-safe interop with JavaScript libraries. | | npm package resolution | Import types from node_modules/ and @types/ automatically. |

What's not implemented

| Feature | Reason | Prospect | |---|---|---| | goto | No clean JS translation. Rare in idiomatic Go. | Not planned. | | Goroutines / channels / select | Go's concurrency model has no JS equivalent. A userland scheduler defeats the "no runtime" goal. | Out of scope. | | unsafe, reflect, cgo | Require memory model or runtime type metadata that JS cannot provide. | Out of scope. |

Semantic differences

These features are implemented but behave differently due to fundamental JS runtime constraints. These are not bugs — they are deliberate trade-offs documented here so you know exactly what to expect.

| Feature | GoFront | Go | Why | |---|---|---|---| | Map iteration order | Insertion-order (Object.entries) | Randomised | JS objects preserve insertion order. | | Integer overflow | IEEE 754 float64 semantics | Wraps at type boundary (e.g. int32) | All JS numbers are float64. | | Integer precision | Safe up to 2⁵³ | Full width per type (int64 = 64 bits) | JS number limitation. | | cap() | Always equals len() | May exceed len() | JS arrays have no separate capacity. | | Fixed-size arrays ([n]T) | Compile-time enforcement (bounds, append rejected, size matching); plain JS arrays at runtime | Fixed at compile time, value-type copy semantics | Runtime enforcement adds overhead; compile-time checks catch most errors. | | nil | Maps to null | Typed nil (distinct per type) | JS has no typed nil concept. | | rune / byte | Treated as int | Distinct types with UTF-8 encoding | JS strings are UTF-16. | | range over string | Rune integers via .codePointAt() | Runes (UTF-8 code points) | Close match — indices are byte-sequential, values are code points. | | len() on strings | JS .length (UTF-16 code units) | Byte count (UTF-8) | Matching Go would require TextEncoder on every call. | | error type | Interface { Error() string } with __error runtime objects | Interface { Error() string } | Close match. Custom error types, errors.Is/Unwrap, %w wrapping all work. toString() added for JS string context compat. | | defer | try/finally with a defer stack | Runtime stack unwinding | Covers most cases but not identical to Go internals. | | Struct field tags | Parsed, silently discarded | Available via reflect | No reflection = no use for tag values. | | Pointers (&x, *p) | Address-taken scalars boxed as { value: T }; structs/slices/maps are reference types (no boxing) | True memory indirection | Shared mutation works for scalars; struct fields and slice elements not yet addressable. | | Three-index slice (a[lo:hi:max]) | max is parsed but ignored | Sets result capacity | JS arrays have no capacity. | | Exported / unexported | Enforced for GoFront packages; external .d.ts/npm namespaces are exempt | Access enforced uniformly | External JS APIs use lowercase names by convention. |


Roadmap

See docs/ROADMAP.md for the full roadmap and release history. Design documents for planned features are organised by release under docs/v*/ (e.g. docs/v0.0.8/, docs/v0.0.9/).


Tests

npm run test:unit   # unit tests only (~1118 tests, no browser required)
npm run test:e2e    # E2E tests (Playwright, headless Chromium)
npm run test:all    # both

Unit tests (~1118) cover language features, type errors, edge cases, DOM (jsdom), external .d.ts, npm resolver, multi-file compilation, embedded structs, string formatting, map iteration order, integer overflow semantics, unused variable detection, unused import detection, semantic difference verification, stdlib shim packages, generics, and .templ file compilation (element rendering, interpolation, boolean attrs, component calls, if/else/else-if chains, for range, switch/case/default, @templ.Raw() raw HTML injection, mixed .go+.templ packages).

E2E tests (~104, Playwright) run all four example apps in a real browser and verify CRUD, filtering, priority mode, persistence (reload), drag-and-drop reordering, and sync status. Per-app suites check app-specific behaviour: scoped styles, stats bar, loading placeholder, gom.If conditional rendering, and templ-specific features (if/else priority hint, for loop rendering, conditional bool attributes).