spa package provides a simple and efficient HTTP handler for serving Single Page Applications (SPAs) from embedded file systems.
Overview
The SPA handler serves static files from an embedded file system and falls back to serving an index file for client-side routing. It includes optional gzip compression for optimizing responses.Key Features
- Embedded file system support: Serve assets from Go’s
embed.FS - Client-side routing: Fallback to index file for non-existent routes
- Gzip compression: Optional compression for supported clients
- Static asset serving: Efficient file serving with proper MIME types
- Security: Prevents directory traversal attacks
API Reference
Handler
build: An embedded file system containing the build assetsdir: The directory within the embedded file system where the static files are locatedindex: The name of the index file (usually"index.html")gzip: Iftrue, the response body will be compressed using gzip for clients that support it
http.Handler: Handler that serves the SPA with optional gzip compressionerror: Error if the file system or index file cannot be initialized
/home/daytona/workspace/source/server/spa/handler.go:28
Usage Examples
Basic SPA Server
SPA with API Routes
SPA with Multiplexer
Multiple SPAs
Without Gzip Compression
How It Works
Client-Side Routing
The SPA handler implements intelligent routing to support client-side routing frameworks like React Router, Vue Router, or Angular Router:- Static file exists: Serves the file directly (CSS, JS, images, etc.)
- File not found: Serves the index file, allowing the SPA to handle routing
/home/daytona/workspace/source/server/spa/router.go:19-32
Gzip Compression
When gzip is enabled (gzip: true), the handler automatically compresses responses for clients that support it:
- Checks
Accept-Encodingheader for gzip support - Compresses response body using
github.com/NYTimes/gziphandler - Reduces bandwidth usage and improves load times
- Transparent to the client application
/home/daytona/workspace/source/server/spa/handler.go:45-48
Security Features
The router prevents directory traversal attacks by:- Using Go’s
http.FileSysteminterface - Validating file paths before serving
- Only serving files from the embedded file system
- No direct filesystem access from clients
/home/daytona/workspace/source/server/spa/router.go:9-14
Embedding Build Assets
Use Go’sembed package to include your SPA’s build output in the binary:
Directory Structure Examples
React App:Error Handling
The handler returns errors in the following cases:Missing Directory
Missing Index File
Best Error Handling
Configuration Options
Gzip Compression
Enable gzip (recommended for production):Custom Index File
You can use a different index file name:Best Practices
- Enable gzip in production: Reduces bandwidth and improves load times
- Validate embed paths: Ensure build directory exists before building
- Handle API routes separately: Use a mux to serve API and SPA together
- Use graceful shutdown: Combine with
server/muxfor proper lifecycle management - Set appropriate cache headers: Consider adding cache control middleware for static assets
- Test fallback routing: Verify client-side routes work correctly
- Monitor embedded size: Large assets increase binary size
Performance Considerations
- Binary size: Embedded assets increase binary size
- Memory usage: Files are served from memory (the embedded FS)
- Gzip overhead: Small CPU cost for compression, large bandwidth savings
- Caching: Consider adding cache headers for static assets
Common Patterns
Development vs Production
With Middleware
See Also
- HTTP Multiplexer - Multi-protocol server with graceful shutdown