@@ -52,97 +52,54 @@ async function analyse({ manifest_path, env }) {
5252 routes : new Map ( )
5353 } ;
5454
55- // analyse nodes
56- for ( const loader of manifest . _ . nodes ) {
57- const node = await loader ( ) ;
55+ const nodes = await Promise . all ( manifest . _ . nodes . map ( ( loader ) => loader ( ) ) ) ;
5856
57+ // analyse nodes
58+ for ( const node of nodes ) {
5959 metadata . nodes [ node . index ] = {
6060 has_server_load : node . server ?. load !== undefined || node . server ?. trailingSlash !== undefined
6161 } ;
6262 }
6363
6464 // analyse routes
6565 for ( const route of manifest . _ . routes ) {
66- /** @type {Array<'GET' | 'POST'> } */
67- const page_methods = [ ] ;
68-
69- /** @type {(import('types').HttpMethod | '*')[] } */
70- const api_methods = [ ] ;
66+ const page =
67+ route . page &&
68+ analyse_page (
69+ route . page . layouts . map ( ( n ) => ( n === undefined ? n : nodes [ n ] ) ) ,
70+ nodes [ route . page . leaf ]
71+ ) ;
7172
72- /** @type {import('types').PrerenderOption | undefined } */
73- let prerender = undefined ;
74- /** @type {any } */
75- let config = undefined ;
76- /** @type {import('types').PrerenderEntryGenerator | undefined } */
77- let entries = undefined ;
73+ const endpoint = route . endpoint && analyse_endpoint ( route , await route . endpoint ( ) ) ;
7874
79- if ( route . endpoint ) {
80- const mod = await route . endpoint ( ) ;
81- if ( mod . prerender !== undefined ) {
82- validate_server_exports ( mod , route . id ) ;
75+ if ( page ?. prerender && endpoint ?. prerender ) {
76+ throw new Error ( `Cannot prerender a route with both +page and +server files (${ route . id } )` ) ;
77+ }
8378
84- if ( mod . prerender && ( mod . POST || mod . PATCH || mod . PUT || mod . DELETE ) ) {
79+ if ( page ?. config && endpoint ?. config ) {
80+ for ( const key in { ...page . config , ...endpoint . config } ) {
81+ if ( JSON . stringify ( page . config [ key ] ) !== JSON . stringify ( endpoint . config [ key ] ) ) {
8582 throw new Error (
86- `Cannot prerender a + server file with POST, PATCH, PUT, or DELETE ( ${ route . id } ) `
83+ `Mismatched route config for ${ route . id } — the +page and + server files must export the same config, if any `
8784 ) ;
8885 }
89-
90- prerender = mod . prerender ;
9186 }
92-
93- Object . values ( mod ) . forEach ( ( /** @type {import('types').HttpMethod } */ method ) => {
94- if ( mod [ method ] && ENDPOINT_METHODS . has ( method ) ) {
95- api_methods . push ( method ) ;
96- } else if ( mod . fallback ) {
97- api_methods . push ( '*' ) ;
98- }
99- } ) ;
100-
101- config = mod . config ;
102- entries = mod . entries ;
10387 }
10488
105- if ( route . page ) {
106- const nodes = await Promise . all (
107- [ ...route . page . layouts , route . page . leaf ] . map ( ( n ) => {
108- if ( n !== undefined ) return manifest . _ . nodes [ n ] ( ) ;
109- } )
110- ) ;
111-
112- const layouts = nodes . slice ( 0 , - 1 ) ;
113- const page = nodes . at ( - 1 ) ;
114-
115- for ( const layout of layouts ) {
116- if ( layout ) {
117- validate_layout_server_exports ( layout . server , layout . server_id ) ;
118- validate_layout_exports ( layout . universal , layout . universal_id ) ;
119- }
120- }
121-
122- if ( page ) {
123- page_methods . push ( 'GET' ) ;
124- if ( page . server ?. actions ) page_methods . push ( 'POST' ) ;
125-
126- validate_page_server_exports ( page . server , page . server_id ) ;
127- validate_page_exports ( page . universal , page . universal_id ) ;
128- }
129-
130- prerender = get_option ( nodes , 'prerender' ) ?? false ;
131-
132- config = get_config ( nodes ) ;
133- entries ??= get_option ( nodes , 'entries' ) ;
134- }
89+ const page_methods = page ?. methods ?? [ ] ;
90+ const api_methods = endpoint ?. methods ?? [ ] ;
91+ const entries = page ?. entries ?? endpoint ?. entries ;
13592
13693 metadata . routes . set ( route . id , {
137- config,
94+ config : page ?. config ?? endpoint ?. config ,
13895 methods : Array . from ( new Set ( [ ...page_methods , ...api_methods ] ) ) ,
13996 page : {
14097 methods : page_methods
14198 } ,
14299 api : {
143100 methods : api_methods
144101 } ,
145- prerender,
102+ prerender : page ?. prerender ?? endpoint ?. prerender ,
146103 entries :
147104 entries && ( await entries ( ) ) . map ( ( entry_object ) => resolvePath ( route . id , entry_object ) )
148105 } ) ;
@@ -151,20 +108,81 @@ async function analyse({ manifest_path, env }) {
151108 return metadata ;
152109}
153110
111+ /**
112+ * @param {import('types').SSRRoute } route
113+ * @param {import('types').SSREndpoint } mod
114+ */
115+ function analyse_endpoint ( route , mod ) {
116+ validate_server_exports ( mod , route . id ) ;
117+
118+ if ( mod . prerender && ( mod . POST || mod . PATCH || mod . PUT || mod . DELETE ) ) {
119+ throw new Error (
120+ `Cannot prerender a +server file with POST, PATCH, PUT, or DELETE (${ route . id } )`
121+ ) ;
122+ }
123+
124+ /** @type {Array<import('types').HttpMethod | '*'> } */
125+ const methods = [ ] ;
126+
127+ Object . values ( mod ) . forEach ( ( /** @type {import('types').HttpMethod } */ method ) => {
128+ if ( mod [ method ] && ENDPOINT_METHODS . has ( method ) ) {
129+ methods . push ( method ) ;
130+ } else if ( mod . fallback ) {
131+ methods . push ( '*' ) ;
132+ }
133+ } ) ;
134+
135+ return {
136+ config : mod . config ,
137+ entries : mod . entries ,
138+ methods,
139+ prerender : mod . prerender ?? false
140+ } ;
141+ }
142+
143+ /**
144+ * @param {Array<import('types').SSRNode | undefined> } layouts
145+ * @param {import('types').SSRNode } leaf
146+ */
147+ function analyse_page ( layouts , leaf ) {
148+ for ( const layout of layouts ) {
149+ if ( layout ) {
150+ validate_layout_server_exports ( layout . server , layout . server_id ) ;
151+ validate_layout_exports ( layout . universal , layout . universal_id ) ;
152+ }
153+ }
154+
155+ /** @type {Array<'GET' | 'POST'> } */
156+ const methods = [ 'GET' ] ;
157+ if ( leaf . server ?. actions ) methods . push ( 'POST' ) ;
158+
159+ validate_page_server_exports ( leaf . server , leaf . server_id ) ;
160+ validate_page_exports ( leaf . universal , leaf . universal_id ) ;
161+
162+ return {
163+ config : get_config ( [ ...layouts , leaf ] ) ,
164+ entries : leaf . universal ?. entries ?? leaf . server ?. entries ,
165+ methods,
166+ prerender : get_option ( [ ...layouts , leaf ] , 'prerender' ) ?? false
167+ } ;
168+ }
169+
154170/**
155171 * Do a shallow merge (first level) of the config object
156172 * @param {Array<import('types').SSRNode | undefined> } nodes
157173 */
158174function get_config ( nodes ) {
175+ /** @type {any } */
159176 let current = { } ;
177+
160178 for ( const node of nodes ) {
161- const config = node ?. universal ?. config ?? node ?. server ?. config ;
162- if ( config ) {
163- current = {
164- ...current ,
165- ...config
166- } ;
167- }
179+ if ( ! node ?. universal ?. config && ! node ?. server ?. config ) continue ;
180+
181+ current = {
182+ ...current ,
183+ ...node ?. universal ?. config ,
184+ ... node ?. server ?. config
185+ } ;
168186 }
169187
170188 return Object . keys ( current ) . length ? current : undefined ;
0 commit comments