spaserve

package module
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2023 License: Apache-2.0 Imports: 9 Imported by: 2

README

SPA Serve

Go Reference GitHub build and test Go Report Card Coverage

spaserve serves "Single Page Applications" (SPAs) from Go that are using...

  • ...client-side DOM routing,
  • ...varying base paths in different deployments or even within the same deployment because of multiple access paths.

And all this without the need to rebuild your SPA production code just because the (HTML) "base URL" changes.

Usage

  1. prepare your SPA index.html template (such as public/index.html) by adding a base element, if not done already; set its href attribute to ./:

    <!doctype html>
    <html lang="en">
    <head>
        <base href="./" />
        <!-- ... -->
     </head>
     <body>
         <!-- ... -->
     </body>
     </html>
    
  2. In case of CRA (Create React App), set the homepage field in package.json to "." (not the root slash "/"):

    {
      "homepage": ".",
    }
    
  3. add a basename helper to your SPA sources, such as a new file src/util/basename.ts:

    export const basename = new URL(
            ((document.querySelector('base') || {}).href || '/')
        ).pathname.replace(/\/$/, '')
    
  4. in your App.tsx ensure that you tell your client-side DOM router to correctly pick up the basename; this makes reloading the SPA from any route and bookmarking routes possible:

    import { basename } from 'utils/basename'
    
    <Router basename={basename}>
        <!-- your app components here -->
    </Router>
    
  5. Make sure that all links (and asset references) are relative, such as ./view2, et cetera.

  6. in your service, create your HTTP route muxer and set up your API handlers as usual, then create a SPAHandler and register it as the route handler to be used when all other handlers don't match:

    r := mux.NewRouter() // or whatever you prefer
    // (set up all your API routes)
    
    // finally create a suitable fs.FS to be used with the SPAHandler
    // and register it so that it serves on all routes not handled by
    // the more specific (API) handlers. Here, we assume the SPA assets
    // to be rooted in web/build.
    spa := spaserve.NewSPAHandler(os.DirFS("web/build"), "index.html")
    r.PathPrefix("/").Handler(spa)
    

References

Useful background knowledge when dealing with serving HTTP resources, base(names), et cetera...

Go Version Support

spaserve supports versions of Go that are noted by the Go release policy, that is, major versions N and N-1 (where N is the current major version).

spaserve is Copyright 2022-23 Harald Albrecht, and licensed under the Apache License, Version 2.0.

Documentation

Overview

Package spaserve serves “Single Page Applications” (SPAs), supporting client-side DOM routing and varying base paths. And all this without the need to rebuild the SPA production code when the deployment changes.

The SPAHandler type implements http.Handler to serve the SPA and its static resources. The SPAHandler fetches these resources from any resource provider implementing the fs.FS interface. This design even allows to seamlessly embed an SPA into a Go binary.

Index

Constants

View Source
const ForwardedPrefixHeader = "X-Forwarded-Prefix"

ForwardedPrefixHeader, if present, specifies the prefix that need to be preprended to the request's URI path in order to learn the original path when hitting the path rewriting proxy.

View Source
const ForwardedUriHeader = "X-Forwarded-Uri"

ForwardedUriHeader, if present, specifies the original URI (or sometimes only the original URI path) of a request when hitting the first path rewriting proxy.

Variables

This section is empty.

Functions

func NormalizedHttpError

func NormalizedHttpError(w http.ResponseWriter, err error)

NormalizedHttpError writes a normalized HTTP error message and HTTP status code based on the specified error, but not leaking any interesting internal server details from this specified error.

Types

type IndexRewriter

type IndexRewriter func(r *http.Request, index string) string

IndexRewriter rewrites (parts) of an index/SPA file contents to be delivered to a requesting client, after the base element has been updated. It can be optionally activated using the WithIndexRewriter option when creating a new SPAHandler.

type SPAHandler

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

SPAHandler implements an http.Handler that serves only the Index file on (almost) all request paths, except for static assets found in the StaticAssetsPath or any subdirectory thereof. The Index file contents served are automatically adjusted to the correct request base path, based on forwarding proxy headers.

func NewSPAHandler

func NewSPAHandler(fs fs.FS, index string, opts ...SPAHandlerOption) *SPAHandler

NewSPAHandler returns a new HTTP handler serving static resources from the specified fs. It serves the index resource instead whenever no directly matching file can be found on the specified fs. The index resource should be specified as an unrooted, slash-separated path+name to be servable from the given fs; but NewSPAHandler will sanitize the index path anyway.

The index parameter typically is "index.html"; please check with your SPA build environment documentation for the exact file name.

In order to serve the static resources from a directory on the OS file system, use os.DirFS:

h := NewSPAHandler(os.DirFS("/opt/data/myspa"), "index.html")

func (*SPAHandler) ServeHTTP

func (h *SPAHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP either serves a static resource when available inside SPAHandler.StaticAssetsPath or otherwise the specified Index asset inside the static assets everywhere else. This behavior is required for SPAs with client-side DOM routers, as otherwise bookmarking (router) links or reloading an SPA with the current route other than "/" would fail.

type SPAHandlerOption

type SPAHandlerOption func(*SPAHandler)

SPAHandlerOption sets optional properties at the time of creating an SPAHandler.

func WithIndexRewriter

func WithIndexRewriter(rewriter IndexRewriter) SPAHandlerOption

WithIndexRewriter sets the specified IndexRewriter that gets called before delivering the index/SPA file contents to requesting clients, allowing for application-specific changes.

Directories

Path Synopsis
test
httptest
Package httptest wraps the standard library's httptest.ResponseRecorder in order to fail any test doing superfluous response.WriteHeader calls.
Package httptest wraps the standard library's httptest.ResponseRecorder in order to fail any test doing superfluous response.WriteHeader calls.

Jump to

Keyboard shortcuts

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