Skip to content

Commit

Permalink
Serve single-page apps
Browse files Browse the repository at this point in the history
  • Loading branch information
tschaub committed Nov 9, 2024
1 parent fe414ec commit cdefa51
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
12 changes: 10 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Serve struct {
Cors bool `help:"Include CORS support (on by default)." default:"true" negatable:""`
Dot bool `help:"Serve dot files (files prefixed with a '.')." default:"false"`
ExplicitIndex bool `help:"Only serve index.html files if URL path includes it." default:"false"`
Spa bool `help:"Serve the index.html file for all unknown paths." default:"false"`
}

func normalizePrefix(base string, prefix string) (string, error) {
Expand Down Expand Up @@ -66,7 +67,7 @@ func (s *Serve) handler() http.Handler {
dir := http.Dir(s.Dir)
mux.Handle(s.Prefix, http.StripPrefix(s.Prefix, http.FileServer(dir)))

handler := withIndex(string(dir), s.Prefix, s.Dot, s.ExplicitIndex, http.Handler(mux))
handler := withIndex(string(dir), s.Prefix, s.Dot, s.ExplicitIndex, s.Spa, http.Handler(mux))
if !s.Dot {
handler = excludeDot(handler)
}
Expand Down Expand Up @@ -110,7 +111,7 @@ const (
//go:embed index.html
var indexHtml string

func withIndex(dir string, prefix string, dot bool, explicitIndex bool, handler http.Handler) http.Handler {
func withIndex(dir string, prefix string, dot bool, explicitIndex bool, spa bool, handler http.Handler) http.Handler {
indexTemplate := template.Must(template.New("index").Parse(indexHtml))
base := filepath.Base(dir)
return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
Expand Down Expand Up @@ -145,6 +146,13 @@ func withIndex(dir string, prefix string, dot bool, explicitIndex bool, handler
}

if !strings.HasSuffix(urlPath, "/") {
if spa {
// if not found, serve dir/index.html
if _, err := os.Stat(path.Join(dir, urlPath)); errors.Is(err, os.ErrNotExist) {
http.ServeFile(response, request, path.Join(dir, "index.html"))
return
}
}
handler.ServeHTTP(response, request)
return
}
Expand Down
12 changes: 11 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
Serve files via HTTP.

```
Usage: serve <dir>
Usage: serve <dir> [flags]
Arguments:
<dir> Serve files from this directory.
Flags:
-h, --help Show context-sensitive help.
--port=4000 Listen on this port.
--prefix="/" Prefix all URL paths with this value.
--[no-]cors Include CORS support (on by default).
--dot Serve dot files (files prefixed with a '.').
--explicit-index Only serve index.html files if URL path includes it.
--spa Serve the index.html file for all unknown paths.
```

The `serve <dir>` command can be used to browse files in a directory via HTTP. For example, `serve .` starts a server for browsing the files in the current working directory. See below for more detail on the [usage](#usage).
Expand Down Expand Up @@ -41,6 +43,10 @@ By default, files are served on port 4000 (e.g. `http://localhost:4000`). To ha

By default, files are served with [CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). To turn off this behavior, use the `--no-cors` argument (e.g. `serve --no-cors .`).

### `--prefix`

Strip a prefix from the URL path. For example `--prefix foo` will make it so a request for a url like `http://localhost:4000/foo/bar.html` serves the `bar.html` file in the configured `dir` (instead of `foo/bar.html`).

### `--dot`

By default, files and directories starting with a `.` will not be listed or served. To allow browsing `.`-prefixed files, use the `--dot` argument (e.g. `serve --dot .`).
Expand All @@ -55,3 +61,7 @@ You can use the `--explicit-index` argument to make it so an existing `index.htm
| ------------------------- | --------------------------------- | --------------------------------- |
| `/path/to/dir/` | existing `index.html` is served | directory listing is served |
| `/path/to/dir/index.html` | redirect to `/path/to/dir/` | existing `index.html` is served |

### `--spa`

Serve a single-page app. The `--spa` flag makes it so requests for paths that don't exist in the configured `dir` will be served with the `index.html` page. This allows for client-side routing.

0 comments on commit cdefa51

Please sign in to comment.