Skip to content

Commit 940cbbc

Browse files
fix: Respect pageExtensions config setting (#2073)
Co-authored-by: LekoArts <[email protected]>
1 parent 75ed977 commit 940cbbc

File tree

6 files changed

+62
-14
lines changed

6 files changed

+62
-14
lines changed

packages/runtime/src/helpers/files.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { Rewrites, RoutesManifest } from './types'
1818
import { findModuleFromBase } from './utils'
1919

2020
const TEST_ROUTE = /(|\/)\[[^/]+?](\/|\.html|$)/
21-
const SOURCE_FILE_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx']
2221

2322
export const isDynamicRoute = (route) => TEST_ROUTE.test(route)
2423

@@ -341,12 +340,16 @@ const getServerFile = (root: string, includeBase = true) => {
341340
return findModuleFromBase({ candidates, paths: [root] })
342341
}
343342

343+
// Next.js already defines a default `pageExtensions` array in its `required-server-files.json` file
344+
// In case it gets `undefined`, this is a fallback
345+
const SOURCE_FILE_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx']
346+
344347
/**
345348
* Find the source file for a given page route
346349
*/
347-
export const getSourceFileForPage = (page: string, roots: string[]) => {
350+
export const getSourceFileForPage = (page: string, roots: string[], pageExtensions = SOURCE_FILE_EXTENSIONS) => {
348351
for (const root of roots) {
349-
for (const extension of SOURCE_FILE_EXTENSIONS) {
352+
for (const extension of pageExtensions) {
350353
const file = join(root, `${page}.${extension}`)
351354
if (existsSync(file)) {
352355
return file

packages/runtime/src/helpers/functions.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,11 @@ export const setupImageFunction = async ({
199199
/**
200200
* Look for API routes, and extract the config from the source file.
201201
*/
202-
export const getApiRouteConfigs = async (publish: string, baseDir: string): Promise<Array<ApiRouteConfig>> => {
202+
export const getApiRouteConfigs = async (
203+
publish: string,
204+
baseDir: string,
205+
pageExtensions: string[],
206+
): Promise<Array<ApiRouteConfig>> => {
203207
const pages = await readJSON(join(publish, 'server', 'pages-manifest.json'))
204208
const apiRoutes = Object.keys(pages).filter((page) => page.startsWith('/api/'))
205209
// two possible places
@@ -209,7 +213,7 @@ export const getApiRouteConfigs = async (publish: string, baseDir: string): Prom
209213

210214
return await Promise.all(
211215
apiRoutes.map(async (apiRoute) => {
212-
const filePath = getSourceFileForPage(apiRoute, [pagesDir, srcPagesDir])
216+
const filePath = getSourceFileForPage(apiRoute, [pagesDir, srcPagesDir], pageExtensions)
213217
return { route: apiRoute, config: await extractConfigFromFile(filePath), compiled: pages[apiRoute] }
214218
}),
215219
)
@@ -218,8 +222,12 @@ export const getApiRouteConfigs = async (publish: string, baseDir: string): Prom
218222
/**
219223
* Looks for extended API routes (background and scheduled functions) and extract the config from the source file.
220224
*/
221-
export const getExtendedApiRouteConfigs = async (publish: string, baseDir: string): Promise<Array<ApiRouteConfig>> => {
222-
const settledApiRoutes = await getApiRouteConfigs(publish, baseDir)
225+
export const getExtendedApiRouteConfigs = async (
226+
publish: string,
227+
baseDir: string,
228+
pageExtensions: string[],
229+
): Promise<Array<ApiRouteConfig>> => {
230+
const settledApiRoutes = await getApiRouteConfigs(publish, baseDir, pageExtensions)
223231

224232
// We only want to return the API routes that are background or scheduled functions
225233
return settledApiRoutes.filter((apiRoute) => apiRoute.config.type !== undefined)

packages/runtime/src/index.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const plugin: NetlifyPlugin = {
6565
netlifyConfig.build.environment.NEXT_PRIVATE_TARGET = 'server'
6666
},
6767

68+
// eslint-disable-next-line max-lines-per-function
6869
async onBuild({
6970
constants,
7071
netlifyConfig,
@@ -79,11 +80,22 @@ const plugin: NetlifyPlugin = {
7980

8081
checkNextSiteHasBuilt({ publish, failBuild })
8182

82-
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental, routesManifest } =
83-
await getNextConfig({
84-
publish,
85-
failBuild,
86-
})
83+
const {
84+
appDir,
85+
basePath,
86+
i18n,
87+
images,
88+
target,
89+
ignore,
90+
trailingSlash,
91+
outdir,
92+
experimental,
93+
routesManifest,
94+
pageExtensions,
95+
} = await getNextConfig({
96+
publish,
97+
failBuild,
98+
})
8799
await cleanupEdgeFunctions(constants)
88100

89101
const middlewareManifest = await loadMiddlewareManifest(netlifyConfig)
@@ -150,7 +162,7 @@ const plugin: NetlifyPlugin = {
150162
const buildId = readFileSync(join(publish, 'BUILD_ID'), 'utf8').trim()
151163

152164
await configureHandlerFunctions({ netlifyConfig, ignore, publish: relative(process.cwd(), publish) })
153-
const apiRoutes = await getExtendedApiRouteConfigs(publish, appDir)
165+
const apiRoutes = await getExtendedApiRouteConfigs(publish, appDir, pageExtensions)
154166

155167
await generateFunctions(constants, appDir, apiRoutes)
156168
await generatePagesResolver(constants)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// noop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// noop

test/helpers/files.spec.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
patchNextFiles,
77
unpatchNextFiles,
88
getDependenciesOfFile,
9+
getSourceFileForPage,
910
} from "../../packages/runtime/src/helpers/files"
1011
import {
1112
readFileSync,
@@ -19,6 +20,8 @@ import { join } from "pathe"
1920
import { Rewrites } from "../../packages/runtime/src/helpers/types"
2021
import { describeCwdTmpDir, moveNextDist } from "../test-utils"
2122

23+
const TEST_DIR = resolve(__dirname, '..')
24+
2225
const REDIRECTS: Rewrites = [
2326
{
2427
source: '/:file((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+)/',
@@ -215,7 +218,27 @@ describe('dependency tracing', () => {
215218
it('generates dependency list from a source file', async () => {
216219
const dependencies = await getDependenciesOfFile(resolve(__dirname, '../fixtures/analysis/background.js'))
217220
expect(dependencies).toEqual(
218-
['test/webpack-api-runtime.js', 'package.json'].map((dep) => resolve(dirname(resolve(__dirname, '..')), dep)),
221+
['test/webpack-api-runtime.js', 'package.json'].map((dep) => resolve(dirname(TEST_DIR), dep)),
219222
)
220223
})
224+
})
225+
226+
describe('getSourceFileForPage', () => {
227+
it('handles default pageExtensions', () => {
228+
const pagesDir = resolve(__dirname, '../fixtures/page-extensions/default/pages')
229+
const apiRoute = '/api/default'
230+
231+
const filePath = getSourceFileForPage(apiRoute, [pagesDir])
232+
233+
expect(filePath.replace(TEST_DIR, '')).toBe('/fixtures/page-extensions/default/pages/api/default.js')
234+
})
235+
236+
it('handles custom pageExtensions', () => {
237+
const pagesDir = resolve(__dirname, '../fixtures/page-extensions/custom/pages')
238+
const apiRoute = '/api/custom'
239+
240+
const filePath = getSourceFileForPage(apiRoute, [pagesDir], ['api.js'])
241+
242+
expect(filePath.replace(TEST_DIR, '')).toBe('/fixtures/page-extensions/custom/pages/api/custom.api.js')
243+
})
221244
})

0 commit comments

Comments
 (0)