gobeyond

package module
v0.1.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 6 Imported by: 0

README

GoBeyond

GoBeyond is an experimental, MIT-licensed framework for React websites with a Go production server. It compiles a documented portable subset of TSX into a language-neutral rendering plan. Go combines that plan with build-time or request-time props to return meaningful HTML, and React 19.2.8 hydrates the same component tree in the browser.

GoBeyond generates meaningful, crawler-visible dynamic HTML from its documented portable React profile, then hydrates it with a pinned React version—without a Node production runtime.

It is not a TypeScript-to-Go translator, a general JavaScript SSR engine, or an exact Next.js replacement. Node is required for development and builds. The production server artifact is a Go executable plus rendering plans and manifests; browser JavaScript, CSS, images, and fonts belong on a CDN.

Website-first model

Start with the page. Add Go only when the page crosses a request-time boundary.

app/products/[slug]/page.tsx        React content, composition, interaction
app/products/[slug]/page.schema.ts  serializable props contract
app/products/[slug]/actions.ts      browser-visible action contract
app/products/[slug]/page.go         request-time data, status, metadata, cache
app/products/[slug]/actions.go       authorization and mutations
app/api/products/route.go            Go HTTP API
internal/                            shared Go services and policy

page.tsx is the single source of truth for initial markup. The build produces both its browser bundle and its Go rendering plan. Developers do not maintain a second Go template. GoBeyond also creates ignored, managed go.mod sidecars in route folders so gopls can type-check names such as [slug]; production code imports only the generated packages under internal/gobeyondgen/.

What the MVP proves

  • Cross-file project React components compile to versioned rendering plans.
  • Intrinsic HTML/SVG, fragments, props, conditions, keyed lists, forms, deterministic initial state, events, opaque effects, and ClientOnly have a strict portable profile.
  • Portable compilation is attempted below use client. Unsupported render behavior may downgrade only at the nearest marked boundary, is reported in a deterministic manifest, and is transformed at that exact browser call site. Unmarked unsupported code and non-portability failures remain fatal.
  • TypeScript page/action schemas generate deterministic, committed Go types.
  • Go produces full metadata, canonical URLs, JSON-LD, semantic body HTML, hydration data, real redirects, and real 404 responses.
  • Same-origin links use build-aware soft navigation, reconcile SEO metadata, restore history/scroll/focus, and fall back to full documents for redirects and errors. Stale actions are rejected before user code and never replayed.
  • Static build props and metadata are packaged with the Go server and loaded once at startup, so middleware-promoted static pages and soft navigation do not execute Node or fetch rendering data from object storage.
  • The production artifact audit rejects Node/npm executables and dependency trees in dist/server.

The conformance gate renders the same portable fixture with Go, hydrates it in a browser-like DOM using pinned React, asserts zero recoverable hydration errors, and verifies post-hydration interaction.

Try the repository

Requirements: Go 1.24+, Node 22+, and pnpm 10.33.0.

For full-stack development with automatic Go rebuilds and browser reloads:

go run ./cmd/gobeyond dev
go run ./cmd/gobeyond dev --port 4000

The public address defaults to http://localhost:3000. Each change builds a replacement server on a fresh internal port. GoBeyond switches the stable proxy only after the replacement passes readiness, then gracefully drains the old process. Failed builds leave the last working server online and appear in the browser development overlay. Independent build stages overlap: compiler preparation runs with the website type-check, and the browser bundle runs with the Go server build after generated contracts are ready. Editing an existing Go file under app/, server/, or internal/ takes a dependency-aware fast path: GoBeyond reuses the unchanged render plans, hydration contract, static documents, and browser assets, then compiles and swaps only the Go server. Route-owned Go source is projected into generated packages before its candidate is built; shared Go code under internal/ uses the same Go-only path. Structural or frontend changes automatically fall back to a complete staged build. Development also reuses the already-prepared portable compiler until the compiler's own source changes.

pnpm install
go run ./cmd/gobeyond generate
go run ./cmd/gobeyond generate --check
go test ./...
pnpm -r test
go run ./cmd/gobeyond build
./scripts/verify-node-free-server.sh

The build emits:

dist/
  static/   # CDN documents and browser assets
  server/   # Go executable, render plans, runtime manifest
  deploy/   # contracts and artifact manifest

CSS imported by the browser entry graph is emitted with a content-hashed name. The build records that exact URL in both static documents and the runtime manifest, so dynamic Go documents link the same stylesheet. Files under public/ are copied unchanged and listed as staticAssetPaths in the deploy route trie for CDN origin routing.

Environment variables and CSS tooling

gobeyond dev loads .env, .env.development, .env.local, then .env.development.local. gobeyond build uses the same order with production in place of development. A variable already supplied by the process always wins; dotenv loading never mutates the CLI process. The resolved environment is passed to the compiler, Go build, Vite build, and the dev Go runtime.

Vite receives the resolved environment but exposes only VITE_* values to browser modules. Keep Contentful delivery/preview tokens and all other secrets unprefixed; static props and generated route data remain public as well.

Vite owns CSS processing through each project's vite.config.* and optional postcss.config.*. Tailwind v4 is an opt-in project capability: install tailwindcss and @tailwindcss/postcss, add a project-owned PostCSS config, and import Tailwind from your CSS. create-gobeyond --tailwind my-site creates that setup. GoBeyond has no Tailwind runtime dependency or framework config.

Preview the complete built site (static assets plus dynamic Go pages):

go run ./cmd/gobeyond preview

Portable React boundary

SEO-critical initial markup may use project-owned components, schema-backed props, deterministic expressions, typed conditions, and stable keyed maps. Event handlers and effect bodies stay browser JavaScript and are not executed by Go. ClientOnly is available for genuinely browser-only third-party UI and its fallback is optional. Keep content required without JavaScript outside an empty client boundary, or provide a portable fallback explicitly.

Rich HTML is explicit: validate/sanitize it into the schema package's branded SafeHTML value, then render <SafeHTML as="div" value={body} />. Plain strings cannot cross that trust boundary, and the wrapper is identical in the Go document and the hydrated React tree.

The alpha intentionally defers arbitrary render helpers, useContext, useId, useReducer, useMemo, Suspense, streaming, generalized third-party render adapters, ISR, runtime image optimization, and exact arbitrary React SSR compatibility.

Documentation

Status

This is an MVP implementation and compatibility experiment, not a stable release. React compatibility is deliberately pinned to 19.2.8. Expanding the portable profile requires new compiler, Go-renderer, browser-normalization, and hydration conformance cases—not an undocumented compatibility promise.

Documentation

Overview

Package gobeyond defines the public request-time contracts used by GoBeyond page loaders, actions, API handlers, and middleware.

Index

Constants

View Source
const RenderAPIVersion = "gobeyond.render/v1alpha1"

Variables

This section is empty.

Functions

This section is empty.

Types

type ActionContext

type ActionContext struct {
	Context      context.Context
	Request      *http.Request
	PublicOrigin string
	Params       map[string]string
	Values       map[string]any
	BuildID      string
}

type ActionResult

type ActionResult[T any] struct {
	Data          T                 `json:"data,omitempty"`
	FieldErrors   map[string]string `json:"fieldErrors,omitempty"`
	RedirectTo    string            `json:"redirectTo,omitempty"`
	RefreshRoutes []string          `json:"refreshRoutes,omitempty"`
}

type Alternate

type Alternate struct {
	Language string `json:"language"`
	URL      string `json:"url"`
}

type CacheMode

type CacheMode string
const (
	CachePrivateNoStore CacheMode = "private_no_store"
	CachePublic         CacheMode = "public"
)

type CachePolicy

type CachePolicy struct {
	Mode                 CacheMode `json:"mode"`
	MaxAge               int       `json:"maxAge,omitempty"`
	SharedMaxAge         int       `json:"sharedMaxAge,omitempty"`
	StaleWhileRevalidate int       `json:"staleWhileRevalidate,omitempty"`
	StaleIfError         int       `json:"staleIfError,omitempty"`
}

func PublicRevalidate

func PublicRevalidate(fresh, stale, staleIfError time.Duration) CachePolicy

PublicRevalidate returns a public policy that keeps browser responses stale while allowing shared caches to retain and asynchronously refresh them. Non-positive durations disable their corresponding directive.

func (CachePolicy) HeaderValue

func (p CachePolicy) HeaderValue() string

type DeadlinePolicy

type DeadlinePolicy struct {
	Loader time.Duration
	Render time.Duration
	Action time.Duration
	API    time.Duration
}

type Handler

type Handler func(*RequestContext) (Response, error)

type JSONLD

type JSONLD map[string]any

JSONLD is serialized by the document renderer with script-safe escaping. Values must be composed solely of JSON-compatible primitives, arrays, and maps.

type Metadata

type Metadata struct {
	Lang        string      `json:"lang"`
	Title       string      `json:"title"`
	Description string      `json:"description,omitempty"`
	Canonical   string      `json:"canonical,omitempty"`
	Robots      string      `json:"robots,omitempty"`
	OpenGraph   OpenGraph   `json:"openGraph,omitempty"`
	Twitter     Twitter     `json:"twitter,omitempty"`
	Alternates  []Alternate `json:"alternates,omitempty"`
	JSONLD      []JSONLD    `json:"jsonLd,omitempty"`
}

func (Metadata) Validate

func (m Metadata) Validate(publicOrigin string, indexable bool) error

type Middleware

type Middleware func(Handler) Handler

type MiddlewareConfig

type MiddlewareConfig struct {
	Patterns []string
	Methods  []string
}

type OpenGraph

type OpenGraph struct {
	Type        string   `json:"type,omitempty"`
	Title       string   `json:"title,omitempty"`
	Description string   `json:"description,omitempty"`
	URL         string   `json:"url,omitempty"`
	Images      []string `json:"images,omitempty"`
}

type PageContext

type PageContext struct {
	Context context.Context
	Request *http.Request
	// PublicOrigin is the absolute origin resolved for this request.
	PublicOrigin string
	Params       map[string]string
	Values       map[string]any
	BuildID      string
}

type PageResult

type PageResult[T any] struct {
	Kind       ResultKind        `json:"kind"`
	Props      T                 `json:"props,omitempty"`
	Metadata   Metadata          `json:"metadata,omitempty"`
	Status     int               `json:"status,omitempty"`
	Headers    map[string]string `json:"headers,omitempty"`
	Cache      CachePolicy       `json:"cache"`
	RedirectTo string            `json:"redirectTo,omitempty"`
	ErrorCode  string            `json:"errorCode,omitempty"`
	Message    string            `json:"message,omitempty"`
}

func NotFound

func NotFound[T any](metadata Metadata) PageResult[T]

func OK

func OK[T any](props T, metadata Metadata) PageResult[T]

func Redirect

func Redirect[T any](location string, permanent bool) PageResult[T]

type RequestContext

type RequestContext struct {
	Context      context.Context
	Request      *http.Request
	PublicOrigin string
	Params       map[string]string
	Values       map[string]any
	BuildID      string
}

type Response

type Response struct {
	Status    int
	Headers   http.Header
	Body      []byte
	RewriteTo string
}

func Rewrite

func Rewrite(path string) Response

type ResultKind

type ResultKind string
const (
	ResultOK            ResultKind = "ok"
	ResultRedirect      ResultKind = "redirect"
	ResultNotFound      ResultKind = "not_found"
	ResultPublicError   ResultKind = "public_error"
	ResultInternalError ResultKind = "internal_error"
)

type Twitter

type Twitter struct {
	Card        string   `json:"card,omitempty"`
	Title       string   `json:"title,omitempty"`
	Description string   `json:"description,omitempty"`
	Images      []string `json:"images,omitempty"`
}

Directories

Path Synopsis
adapters
lambda
Package lambdaurl adapts an http.Handler to an AWS Lambda Function URL (payload format 2.0) entrypoint.
Package lambdaurl adapts an http.Handler to an AWS Lambda Function URL (payload format 2.0) entrypoint.
Package browserassets defines the versioned browser bundle manifest emitted by gobeyond build.
Package browserassets defines the versioned browser bundle manifest emitted by gobeyond build.
cmd
gobeyond command
render-fixture command
Command render-fixture is a test-only bridge used by cross-language hydration conformance tests.
Command render-fixture is a test-only bridge used by cross-language hydration conformance tests.
Package codegen decodes GoBeyond value-contract documents and generates the Go types shared by page loaders and actions.
Package codegen decodes GoBeyond value-contract documents and generates the Go types shared by page loaders and actions.
Package document renders the complete SEO and hydration document around a body produced by GoBeyond's portable renderer.
Package document renders the complete SEO and hydration document around a body produced by GoBeyond's portable renderer.
examples
seo-site/app/account
Package account owns request-time props for /account.
Package account owns request-time props for /account.
seo-site/app/api/time
Package apitime owns the fixture's public /api/time endpoint.
Package apitime owns the fixture's public /api/time endpoint.
seo-site/internal/gobeyondgen/routes
Code generated by gobeyond generate; DO NOT EDIT.
Code generated by gobeyond generate; DO NOT EDIT.
seo-site/internal/site
Package shared contains the runtime-independent policy shared by the example's typed page loaders.
Package shared contains the runtime-independent policy shared by the example's typed page loaders.
seo-site/server
Package seosite wires the website-first React fixture to GoBeyond's Go runtime.
Package seosite wires the website-first React fixture to GoBeyond's Go runtime.
imageopt
s3 module
internal
jsvalue
Package jsvalue validates values before Go renders and JSON serializes them for the pinned JavaScript runtime.
Package jsvalue validates values before Go renders and JSON serializes them for the pinned JavaScript runtime.
Package middleware composes statically discoverable GoBeyond middleware.
Package middleware composes statically discoverable GoBeyond middleware.
Package renderer evaluates GoBeyond rendering plans and emits deterministic HTML without executing JavaScript.
Package renderer evaluates GoBeyond rendering plans and emits deterministic HTML without executing JavaScript.
Package renderplan defines the versioned, language-neutral rendering plan consumed by GoBeyond's production renderer.
Package renderplan defines the versioned, language-neutral rendering plan consumed by GoBeyond's production renderer.
Package router implements GoBeyond's deterministic route-pattern matching.
Package router implements GoBeyond's deterministic route-pattern matching.
Package runtime provides GoBeyond's Node-free production HTTP server.
Package runtime provides GoBeyond's Node-free production HTTP server.
Package security contains framework-enforced HTTP boundary protections.
Package security contains framework-enforced HTTP boundary protections.

Jump to

Keyboard shortcuts

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