Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions site/nextrouter/nextrouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,7 @@ func Handler(fileSystem fs.FS, options *Options) (http.Handler, error) {
}

// Fallback to static file server for non-HTML files
// Non-HTML files don't have special routing rules, so we can just leverage
// the built-in http.FileServer for it.
fileHandler := http.FileServer(http.FS(fileSystem))
router.NotFound(fileHandler.ServeHTTP)
router.NotFound(FileHandler(fileSystem))

// Finally, if there is a 404.html available, serve that
err = register404(fileSystem, router, *options)
Expand All @@ -64,6 +61,31 @@ func Handler(fileSystem fs.FS, options *Options) (http.Handler, error) {
return router, nil
}

// FileHandler serves static content, additionally adding immutable
// cache-control headers for Next.js content
func FileHandler(fileSystem fs.FS) func(writer http.ResponseWriter, request *http.Request) {
// Non-HTML files don't have special routing rules, so we can just leverage
// the built-in http.FileServer for it.
fileHandler := http.FileServer(http.FS(fileSystem))

return func(writer http.ResponseWriter, request *http.Request) {
// From the Next.js documentation:
//
// "Caching improves response times and reduces the number
// of requests to external services. Next.js automatically
// adds caching headers to immutable assets served from
// /_next/static including JavaScript, CSS, static images,
// and other media."
//
// See: https://nextjs.org/docs/going-to-production
if strings.HasPrefix(request.URL.Path, "/_next/static/") {
writer.Header().Add("Cache-Control", "public, max-age=31536000, immutable")
}
Comment on lines +81 to +83
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thanks for bringing this over @jawnsy 👍


fileHandler.ServeHTTP(writer, request)
}
}

// registerRoutes recursively traverses the file-system, building routes
// as appropriate for respecting NextJS dynamic rules.
func registerRoutes(rtr chi.Router, fileSystem fs.FS, options Options) error {
Expand Down
36 changes: 36 additions & 0 deletions site/nextrouter/nextrouter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,42 @@ func TestNextRouter(t *testing.T) {
require.EqualValues(t, "test-create", body)
})

t.Run("Caching headers for _next resources", func(t *testing.T) {
t.Parallel()

rootFS := fstest.MapFS{
"index.html": &fstest.MapFile{
Data: []byte("test-root"),
},
"_next/static/test.js": &fstest.MapFile{
Data: []byte("test.js cached forever"),
},
"_next/static/chunks/app/test.css": &fstest.MapFile{
Data: []byte("test.css cached forever"),
},
}

router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)

server := httptest.NewServer(router)
t.Cleanup(server.Close)

res, err := request(server, "/index.html")
require.NoError(t, err)
require.NoError(t, res.Body.Close())
Comment on lines +400 to +402
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice tests 👍


require.Equal(t, http.StatusOK, res.StatusCode)
require.Empty(t, res.Header.Get("Cache-Control"))

res, err = request(server, "/_next/static/test.js")
require.NoError(t, err)
require.NoError(t, res.Body.Close())

require.Equal(t, http.StatusOK, res.StatusCode)
require.Equal(t, "public, max-age=31536000, immutable", res.Header.Get("Cache-Control"))
})

t.Run("Injects template parameters", func(t *testing.T) {
t.Parallel()

Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy