mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add caching headers for Next.js static assets (#330)
This commit is contained in:
@@ -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)
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user