1
+ import type { NetlifyConfig } from '@netlify/build'
1
2
import { readJSON , writeJSON } from 'fs-extra'
3
+ import type { Header } from 'next/dist/lib/load-custom-routes'
2
4
import type { NextConfigComplete } from 'next/dist/server/config-shared'
3
5
import { join , dirname , relative } from 'pathe'
4
6
import slash from 'slash'
5
7
6
8
import { HANDLER_FUNCTION_NAME , ODB_FUNCTION_NAME } from '../constants'
7
9
10
+ const ROUTES_MANIFEST_FILE = 'routes-manifest.json'
11
+
12
+ type NetlifyHeaders = NetlifyConfig [ 'headers' ]
13
+
14
+ // This is the minimal amount of typing required for now
15
+ // add other properties as needed from the routes-manifest.json
16
+ export type RoutesManifest = { headers : Header [ ] }
17
+
8
18
export interface RequiredServerFiles {
9
19
version ?: number
10
20
config ?: NextConfigComplete
@@ -13,7 +23,10 @@ export interface RequiredServerFiles {
13
23
ignore ?: string [ ]
14
24
}
15
25
16
- export type NextConfig = Pick < RequiredServerFiles , 'appDir' | 'ignore' > & NextConfigComplete
26
+ export type NextConfig = Pick < RequiredServerFiles , 'appDir' | 'ignore' > &
27
+ NextConfigComplete & {
28
+ routesManifest ?: RoutesManifest
29
+ }
17
30
18
31
const defaultFailBuild = ( message : string , { error } ) : never => {
19
32
throw new Error ( `${ message } \n${ error && error . stack } ` )
@@ -24,13 +37,19 @@ export const getNextConfig = async function getNextConfig({
24
37
failBuild = defaultFailBuild ,
25
38
} ) : Promise < NextConfig > {
26
39
try {
27
- const { config, appDir, ignore } : RequiredServerFiles = await readJSON ( join ( publish , 'required-server-files.json' ) )
40
+ const { config, appDir, ignore, files } : RequiredServerFiles = await readJSON (
41
+ join ( publish , 'required-server-files.json' ) ,
42
+ )
28
43
if ( ! config ) {
29
44
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
30
45
// @ts -ignore
31
46
return failBuild ( 'Error loading your Next config' )
32
47
}
33
- return { ...config , appDir, ignore }
48
+
49
+ const routesManifest = ( await readJSON ( files . find ( ( f ) => f . endsWith ( ROUTES_MANIFEST_FILE ) ) ) ) as RoutesManifest
50
+
51
+ // If you need access to other manifest files, you can add them here as well
52
+ return { ...config , appDir, ignore, routesManifest }
34
53
} catch ( error : unknown ) {
35
54
return failBuild ( 'Error loading your Next config' , { error } )
36
55
}
@@ -108,3 +127,22 @@ export const configureHandlerFunctions = ({ netlifyConfig, publish, ignore = []
108
127
} )
109
128
} )
110
129
}
130
+
131
+ /**
132
+ * Persist NEXT.js custom headers to the Netlify configuration so the headers work with static files
133
+ *
134
+ * @param customHeaders - Custom headers defined in the Next.js configuration
135
+ * @param netlifyHeaders - Existing headers that are already configured in the Netlify configuration
136
+ */
137
+ export const generateCustomHeaders = ( customHeaders : Header [ ] = [ ] , netlifyHeaders : NetlifyHeaders = [ ] ) => {
138
+ for ( const { source, headers } of customHeaders ) {
139
+ netlifyHeaders . push ( {
140
+ for : source ,
141
+ values : headers . reduce ( ( builtHeaders , { key, value } ) => {
142
+ builtHeaders [ key ] = value
143
+
144
+ return builtHeaders
145
+ } , { } ) ,
146
+ } )
147
+ }
148
+ }
0 commit comments