1
1
import { existsSync } from "fs" ;
2
2
import path from "path" ;
3
3
import { rspack } from "@rspack/core" ;
4
+ import { RouteInfo } from "@rx-lab/common" ;
4
5
import fs from "fs/promises" ;
5
6
import nunjucks from "nunjucks" ;
6
7
import {
7
- VERCEL_SEND_MESSAGE_TEMPLATE ,
8
+ VERCEL_API_ROUTE_TEMPLATE ,
8
9
VERCEL_WEBHOOK_FUNCTION_TEMPLATE ,
9
10
} from "../../../templates/vercel" ;
10
11
@@ -28,53 +29,74 @@ const VERCEL_CONFIG_FILE_NAME = "config.json";
28
29
* @param content
29
30
*/
30
31
async function writeVercelFunctionToDisk ( apiRoute : string , content : string ) {
31
- const functionOutputFolder =
32
- path . resolve ( VERCEL_FUNCTIONS_FOLDER , apiRoute ) + ".func" ;
32
+ try {
33
+ let functionOutputFolder = path . join (
34
+ path . resolve ( VERCEL_FUNCTIONS_FOLDER ) ,
35
+ apiRoute + ".func" ,
36
+ ) ;
33
37
34
- // check if the folder exists
35
- if ( ! existsSync ( functionOutputFolder ) ) {
36
- await fs . mkdir ( functionOutputFolder , { recursive : true } ) ;
37
- }
38
+ // check if the folder exists
39
+ if ( ! existsSync ( functionOutputFolder ) ) {
40
+ await fs . mkdir ( functionOutputFolder , { recursive : true } ) ;
41
+ }
38
42
39
- const configFilePath = path . join (
40
- functionOutputFolder ,
41
- VERCEL_FUNCTION_CONFIG_FILENAME ,
42
- ) ;
43
+ const configFilePath = path . join (
44
+ functionOutputFolder ,
45
+ VERCEL_FUNCTION_CONFIG_FILENAME ,
46
+ ) ;
43
47
44
- await build ( content , VERCEL_FUNCTION_FILE_NAME , functionOutputFolder ) ;
45
- // write config
46
- await fs . writeFile (
47
- configFilePath ,
48
- JSON . stringify (
49
- {
50
- runtime : "nodejs20.x" ,
51
- handler : "index.js" ,
52
- launcherType : "Nodejs" ,
53
- shouldAddHelpers : true ,
54
- } ,
55
- null ,
56
- 2 ,
57
- ) ,
58
- ) ;
48
+ await build ( content , VERCEL_FUNCTION_FILE_NAME , functionOutputFolder ) ;
49
+ // write config
50
+ await fs . writeFile (
51
+ configFilePath ,
52
+ JSON . stringify (
53
+ {
54
+ runtime : "nodejs20.x" ,
55
+ handler : "index.js" ,
56
+ launcherType : "Nodejs" ,
57
+ shouldAddHelpers : true ,
58
+ } ,
59
+ null ,
60
+ 2 ,
61
+ ) ,
62
+ ) ;
63
+ } catch ( e ) {
64
+ console . error ( e ) ;
65
+ throw e ;
66
+ }
59
67
}
60
68
61
69
/**
62
70
* Generate vercel function
63
71
* @param outputDir The generated source code output directory
72
+ * @param route The route information
64
73
* @param type The type of function to generate
65
74
*/
66
75
async function generateVercelFunction (
67
76
outputDir : string ,
68
- type : "webhook" | "send-message" ,
77
+ type : "webhook" | "api" ,
78
+ route ?: RouteInfo ,
69
79
) : Promise < string > {
70
80
switch ( type ) {
71
81
case "webhook" :
72
82
return nunjucks . renderString ( VERCEL_WEBHOOK_FUNCTION_TEMPLATE , {
73
83
outputDir,
74
84
} ) ;
75
- case "send-message" :
76
- return nunjucks . renderString ( VERCEL_SEND_MESSAGE_TEMPLATE , {
85
+ case "api" :
86
+ // import the api
87
+ const api = await route ?. api ! ( ) ;
88
+ const supportedMethods = [ ] ;
89
+ for ( const method of [ "GET" , "POST" , "PUT" , "DELETE" , "PATCH" ] ) {
90
+ //@ts -expect-error
91
+ if ( api [ method ] ) {
92
+ supportedMethods . push ( method ) ;
93
+ }
94
+ }
95
+
96
+ return nunjucks . renderString ( VERCEL_API_ROUTE_TEMPLATE , {
77
97
outputDir,
98
+ methods : supportedMethods ,
99
+ path : route ! . route ,
78
100
} ) ;
79
101
default :
80
102
throw new Error ( `Unsupported function type: ${ type } ` ) ;
@@ -174,18 +196,49 @@ async function writeVercelConfigFile() {
174
196
) ;
175
197
}
176
198
199
+ /**
200
+ * Recursively process routes and generate API functions
201
+ * @param routes Array of route information
202
+ * @param outputFolder Output folder path
203
+ */
204
+ async function processRoutes ( routes : RouteInfo [ ] , outputFolder : string ) {
205
+ for ( const route of routes ) {
206
+ // Generate API function if route has api field
207
+ if ( route . api ) {
208
+ const apiFunction = await generateVercelFunction (
209
+ outputFolder ,
210
+ "api" ,
211
+ route ,
212
+ ) ;
213
+ await writeVercelFunctionToDisk ( route . route , apiFunction ) ;
214
+ }
215
+
216
+ // Recursively process sub-routes if they exist
217
+ if ( route . subRoutes && route . subRoutes . length > 0 ) {
218
+ await processRoutes ( route . subRoutes , outputFolder ) ;
219
+ }
220
+ }
221
+ }
222
+
177
223
export async function buildVercel ( { outputFolder } : Options ) {
178
224
await removeVercelFolder ( ) ;
179
225
// create output folder
180
226
await fs . mkdir ( VERCEL_OUTPUT_FOLDER , { recursive : true } ) ;
227
+ // get route file
228
+ const routeFile = path . resolve ( outputFolder , "main.js" ) ;
229
+ // node require
230
+ const nativeRequire = require ( "module" ) . createRequire ( process . cwd ( ) ) ;
231
+ delete nativeRequire . cache [ nativeRequire . resolve ( routeFile ) ] ;
232
+ // Now import the fresh version
233
+ const { ROUTE_FILE } = nativeRequire ( routeFile ) ;
234
+
181
235
// build webhook function
182
236
const webhookFunction = await generateVercelFunction ( outputFolder , "webhook" ) ;
183
- const sendMessageFunction = await generateVercelFunction (
184
- outputFolder ,
185
- "send-message" ,
186
- ) ;
187
237
// write webhook function to disk
188
238
await writeVercelFunctionToDisk ( "api/webhook" , webhookFunction ) ;
189
- await writeVercelFunctionToDisk ( "api/message" , sendMessageFunction ) ;
239
+
240
+ // Process all routes recursively
241
+ await processRoutes ( ROUTE_FILE . routes , outputFolder ) ;
242
+
190
243
await writeVercelConfigFile ( ) ;
191
244
}
0 commit comments