File tree Expand file tree Collapse file tree 5 files changed +35
-1
lines changed Expand file tree Collapse file tree 5 files changed +35
-1
lines changed Original file line number Diff line number Diff line change @@ -77,6 +77,20 @@ export const copyStaticAssets = async (ctx: PluginContext): Promise<void> => {
7777 } )
7878}
7979
80+ export const setHeadersConfig = async ( ctx : PluginContext ) : Promise < void > => {
81+ // https://nextjs.org/docs/app/api-reference/config/next-config-js/headers#cache-control
82+ // Next.js sets the Cache-Control header of public, max-age=31536000, immutable for truly
83+ // immutable assets. It cannot be overridden. These immutable files contain a SHA-hash in
84+ // the file name, so they can be safely cached indefinitely.
85+ const { basePath } = ctx . buildConfig
86+ ctx . netlifyConfig . headers . push ( {
87+ for : `${ basePath } /_next/static/*` ,
88+ values : {
89+ 'Cache-Control' : 'public, max-age=31536000, immutable' ,
90+ } ,
91+ } )
92+ }
93+
8094export const copyStaticExport = async ( ctx : PluginContext ) : Promise < void > => {
8195 await tracer . withActiveSpan ( 'copyStaticExport' , async ( ) => {
8296 if ( ! ctx . exportDetail ?. outDirectory ) {
Original file line number Diff line number Diff line change @@ -11,6 +11,7 @@ import {
1111 copyStaticContent ,
1212 copyStaticExport ,
1313 publishStaticDir ,
14+ setHeadersConfig ,
1415 unpublishStaticDir ,
1516} from './build/content/static.js'
1617import { clearStaleEdgeHandlers , createEdgeHandlers } from './build/functions/edge.js'
@@ -66,7 +67,7 @@ export const onBuild = async (options: NetlifyPluginOptions) => {
6667
6768 // static exports only need to be uploaded to the CDN and setup /_next/image handler
6869 if ( ctx . buildConfig . output === 'export' ) {
69- return Promise . all ( [ copyStaticExport ( ctx ) , setImageConfig ( ctx ) ] )
70+ return Promise . all ( [ copyStaticExport ( ctx ) , setHeadersConfig ( ctx ) , setImageConfig ( ctx ) ] )
7071 }
7172
7273 await verifyAdvancedAPIRoutes ( ctx )
@@ -78,6 +79,7 @@ export const onBuild = async (options: NetlifyPluginOptions) => {
7879 copyPrerenderedContent ( ctx ) ,
7980 createServerHandler ( ctx ) ,
8081 createEdgeHandlers ( ctx ) ,
82+ setHeadersConfig ( ctx ) ,
8183 setImageConfig ( ctx ) ,
8284 ] )
8385 } )
Original file line number Diff line number Diff line change @@ -300,6 +300,7 @@ export const setCacheControlHeaders = (
300300
301301 if (
302302 cacheControl === null &&
303+ [ 'GET' , 'HEAD' ] . includes ( request . method ) &&
303304 ! headers . has ( 'cdn-cache-control' ) &&
304305 ! headers . has ( 'netlify-cdn-cache-control' ) &&
305306 requestContext . usedFsReadForNonFallback
Original file line number Diff line number Diff line change @@ -207,6 +207,7 @@ export async function runPluginStep(
207207 // INTERNAL_EDGE_FUNCTIONS_SRC: '.netlify/edge-functions',
208208 } ,
209209 netlifyConfig : {
210+ headers : [ ] ,
210211 redirects : [ ] ,
211212 } ,
212213 utils : {
Original file line number Diff line number Diff line change @@ -14,6 +14,7 @@ const makeE2EFixture = (
1414
1515export const test = base . extend <
1616 {
17+ ensureStaticAssetsHaveImmutableCacheControl : void
1718 takeScreenshot : void
1819 pollUntilHeadersMatch : (
1920 url : string ,
@@ -91,4 +92,19 @@ export const test = base.extend<
9192 } ,
9293 { auto : true } ,
9394 ] ,
95+ ensureStaticAssetsHaveImmutableCacheControl : [
96+ async ( { page } , use ) => {
97+ page . on ( 'response' , ( response ) => {
98+ if ( response . url ( ) . includes ( '/_next/static/' ) ) {
99+ expect (
100+ response . headers ( ) [ 'cache-control' ] ,
101+ '_next/static assets should have immutable cache control' ,
102+ ) . toContain ( 'public,max-age=31536000,immutable' )
103+ }
104+ } )
105+
106+ await use ( )
107+ } ,
108+ { auto : true } ,
109+ ] ,
94110} )
You can’t perform that action at this time.
0 commit comments