Skip to content

Commit

Permalink
feat: add caching headers for Next.js static assets (#330)
Browse files Browse the repository at this point in the history
  • Loading branch information
jawnsy committed Feb 19, 2022
1 parent 5ef59e7 commit f7b4849
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
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")
}

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())

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

0 comments on commit f7b4849

Please sign in to comment.