Skip to content

Commit cbcdc0c

Browse files
committed
feat: provide display name for split api routes
1 parent 7ebe1a8 commit cbcdc0c

File tree

5 files changed

+72
-15
lines changed

5 files changed

+72
-15
lines changed

packages/runtime/src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import destr from 'destr'
22

33
export const HANDLER_FUNCTION_NAME = '___netlify-handler'
44
export const ODB_FUNCTION_NAME = '___netlify-odb-handler'
5+
export const API_FUNCTION_NAME = '___netlify-api-handler'
56
export const IMAGE_FUNCTION_NAME = '_ipx'
67
export const NEXT_PLUGIN_NAME = '@netlify/next-runtime'
78
export const NEXT_PLUGIN = '@netlify/plugin-nextjs'
89
export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler'
910
export const ODB_FUNCTION_TITLE = 'Next.js ISR handler'
11+
export const API_FUNCTION_TITLE = 'Next.js API handler'
1012
export const IMAGE_FUNCTION_TITLE = 'next/image handler'
1113
// These are paths in .next that shouldn't be publicly accessible
1214
export const HIDDEN_PATHS = destr(process.env.NEXT_KEEP_METADATA_FILES)

packages/runtime/src/helpers/functions.ts

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
HANDLER_FUNCTION_TITLE,
1717
ODB_FUNCTION_TITLE,
1818
IMAGE_FUNCTION_TITLE,
19+
API_FUNCTION_TITLE,
20+
API_FUNCTION_NAME,
1921
} from '../constants'
2022
import { getApiHandler } from '../templates/getApiHandler'
2123
import { getHandler } from '../templates/getHandler'
@@ -31,6 +33,7 @@ import { getFunctionNameForPage } from './utils'
3133

3234
export interface ApiRouteConfig {
3335
functionName: string
36+
functionTitle?: string
3437
route: string
3538
config: ApiConfig
3639
compiled: string
@@ -39,6 +42,7 @@ export interface ApiRouteConfig {
3942

4043
export interface APILambda {
4144
functionName: string
45+
functionTitle: string
4246
routes: ApiRouteConfig[]
4347
includedFiles: string[]
4448
type?: ApiRouteType
@@ -60,7 +64,7 @@ export const generateFunctions = async (
6064
: undefined
6165

6266
for (const apiLambda of apiLambdas) {
63-
const { functionName, routes, type, includedFiles } = apiLambda
67+
const { functionName, functionTitle, routes, type, includedFiles } = apiLambda
6468

6569
const apiHandlerSource = getApiHandler({
6670
// most api lambdas serve multiple routes, but scheduled functions need to be in separate lambdas.
@@ -102,6 +106,8 @@ export const generateFunctions = async (
102106
})
103107
await writeFile(join(functionsDir, functionName, 'pages.js'), resolverSource)
104108

109+
await writeFunctionConfiguration({ functionName, functionTitle, functionsDir })
110+
105111
const nfInternalFiles = await glob(join(functionsDir, functionName, '**'))
106112
includedFiles.push(...nfInternalFiles)
107113
}
@@ -128,7 +134,7 @@ export const generateFunctions = async (
128134
join(__dirname, '..', '..', 'lib', 'templates', 'handlerUtils.js'),
129135
join(functionsDir, functionName, 'handlerUtils.js'),
130136
)
131-
writeFunctionConfiguration({ functionName, functionTitle, functionsDir })
137+
await writeFunctionConfiguration({ functionName, functionTitle, functionsDir })
132138
}
133139

134140
await writeHandler(HANDLER_FUNCTION_NAME, HANDLER_FUNCTION_TITLE, false)
@@ -334,12 +340,41 @@ export const getAPILambdas = async (
334340

335341
const bins = pack(weighedRoutes, threshold)
336342

337-
return bins.map((bin, index) => ({
338-
functionName: bin.length === 1 ? bin[0].functionName : `api-${index}`,
339-
routes: bin,
340-
includedFiles: [...commonDependencies, ...routes.flatMap((route) => route.includedFiles)],
341-
type,
342-
}))
343+
return bins.map((bin) => {
344+
if (bin.length === 1) {
345+
const [func] = bin
346+
const { functionName, functionTitle, config, includedFiles } = func
347+
return {
348+
functionName,
349+
functionTitle,
350+
routes: [func],
351+
includedFiles: [...commonDependencies, ...includedFiles],
352+
type: config.type,
353+
}
354+
}
355+
356+
const includedFiles = [...commonDependencies, ...bin.flatMap((route) => route.includedFiles)]
357+
const nonSingletonBins = bins.filter((b) => b.length > 1)
358+
if (nonSingletonBins.length === 1) {
359+
return {
360+
functionName: API_FUNCTION_NAME,
361+
functionTitle: API_FUNCTION_TITLE,
362+
includedFiles,
363+
routes: bin,
364+
type,
365+
}
366+
}
367+
368+
const indexInNonSingletonBins = nonSingletonBins.indexOf(bin)
369+
370+
return {
371+
functionName: `${API_FUNCTION_NAME}-${indexInNonSingletonBins + 1}`,
372+
functionTitle: `${API_FUNCTION_TITLE} ${indexInNonSingletonBins + 1}/${nonSingletonBins.length}`,
373+
includedFiles,
374+
routes: bin,
375+
type,
376+
}
377+
})
343378
}
344379

345380
const standardFunctions = apiRoutes.filter(
@@ -381,6 +416,7 @@ export const getApiRouteConfigs = async (
381416
const config = await extractConfigFromFile(filePath, appDir)
382417

383418
const functionName = getFunctionNameForPage(apiRoute, config.type === ApiRouteType.BACKGROUND)
419+
const functionTitle = `${API_FUNCTION_TITLE} ${apiRoute}`
384420

385421
const compiled = pages[apiRoute]
386422
const compiledPath = join(publish, 'server', compiled)
@@ -390,6 +426,7 @@ export const getApiRouteConfigs = async (
390426

391427
return {
392428
functionName,
429+
functionTitle,
393430
route: apiRoute,
394431
config,
395432
compiled,
@@ -415,6 +452,7 @@ export const getExtendedApiRouteConfigs = async (
415452

416453
export const packSingleFunction = (func: ApiRouteConfig): APILambda => ({
417454
functionName: func.functionName,
455+
functionTitle: func.functionTitle,
418456
includedFiles: func.includedFiles,
419457
routes: [func],
420458
type: func.config.type,

test/__snapshots__/index.spec.ts.snap

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,17 +2109,17 @@ Array [
21092109
Object {
21102110
"from": "/api/enterPreview",
21112111
"status": 200,
2112-
"to": "/.netlify/functions/api-0",
2112+
"to": "/.netlify/functions/___netlify-api-handler",
21132113
},
21142114
Object {
21152115
"from": "/api/exitPreview",
21162116
"status": 200,
2117-
"to": "/.netlify/functions/api-0",
2117+
"to": "/.netlify/functions/___netlify-api-handler",
21182118
},
21192119
Object {
21202120
"from": "/api/hello",
21212121
"status": 200,
2122-
"to": "/.netlify/functions/api-0",
2122+
"to": "/.netlify/functions/___netlify-api-handler",
21232123
},
21242124
Object {
21252125
"from": "/api/hello-background",
@@ -2134,17 +2134,17 @@ Array [
21342134
Object {
21352135
"from": "/api/revalidate",
21362136
"status": 200,
2137-
"to": "/.netlify/functions/api-0",
2137+
"to": "/.netlify/functions/___netlify-api-handler",
21382138
},
21392139
Object {
21402140
"from": "/api/shows/:id",
21412141
"status": 200,
2142-
"to": "/.netlify/functions/api-0",
2142+
"to": "/.netlify/functions/___netlify-api-handler",
21432143
},
21442144
Object {
21452145
"from": "/api/shows/:params/*",
21462146
"status": 200,
2147-
"to": "/.netlify/functions/api-0",
2147+
"to": "/.netlify/functions/___netlify-api-handler",
21482148
},
21492149
Object {
21502150
"force": false,

test/helpers/functions.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describeCwdTmpDir('api route file analysis', () => {
7070

7171
it('only shows scheduled/background functions as extended funcs', async () => {
7272
await moveNextDist()
73-
const configs = await getExtendedApiRouteConfigs('.next', process.cwd())
73+
const configs = await getExtendedApiRouteConfigs('.next', process.cwd(), [])
7474
// Using a Set means the order doesn't matter
7575
expect(new Set(configs.map(({ includedFiles, ...rest }) => rest))).toEqual(
7676
new Set([

test/index.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,23 @@ describe('onBuild()', () => {
738738
expect(netlifyConfig.functions['_api_*'].node_bundler).toEqual('nft')
739739
})
740740

741+
it('provides displayname for split api routes', async () => {
742+
await moveNextDist()
743+
await nextRuntime.onBuild(defaultArgs)
744+
745+
const functionsManifest = await readJson(
746+
path.join('.netlify', 'functions-internal', '___netlify-api-handler', '___netlify-api-handler.json'),
747+
)
748+
749+
expect(functionsManifest).toEqual({
750+
config: {
751+
generator: '@netlify/next-runtime@unknown',
752+
name: 'Next.js API handler',
753+
},
754+
version: 1,
755+
})
756+
})
757+
741758
// eslint-disable-next-line jest/expect-expect
742759
it('works when `relativeAppDir` is undefined', async () => {
743760
await moveNextDist()

0 commit comments

Comments
 (0)