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.
-
prepare your SPA
index.html
template (such aspublic/index.html
) by adding abase
element, if not done already; set itshref
attribute to./
:<!doctype html> <html lang="en"> <head> <base href="./" /> <!-- ... --> </head> <body> <!-- ... --> </body> </html>
-
In case of CRA (Create React App), set the
homepage
field inpackage.json
to"."
(not the root slash):"/"
{ "homepage": ".", }
-
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(/\/$/, '')
-
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>
-
Make sure that all links (and asset references) are relative, such as
./view2
, et cetera. -
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)
Useful background knowledge when dealing with serving HTTP resources, base(names), et cetera...
-
An elegant solution of deploying React app into a subdirectory (Sergey Kryvets) – a rare competent analysis and introduction to the
base
HTML element. This post shows how to get SPAs working withbase
for a fixed, hardcoded base path. In contrast,spaserver
dynamically rewrites thebase
element when serving an SPA, as needed. -
answer to "Golang. What to use? http.ServeFile(..) or http.FileServer(..)?" (stackoverflow) – and yes,
spaserve
useshttp.FileServer
which supportsfs.FS
via anhttp.FS
adaptor.
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.