Skip to content

Commit

Permalink
fix: Respect pageExtensions config setting (#2073)
Browse files Browse the repository at this point in the history
Co-authored-by: LekoArts <lekoarts@gmail.com>
  • Loading branch information
RohitRajendran and LekoArts committed Apr 27, 2023
1 parent 75ed977 commit 940cbbc
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 14 deletions.
9 changes: 6 additions & 3 deletions packages/runtime/src/helpers/files.ts
Expand Up @@ -18,7 +18,6 @@ import { Rewrites, RoutesManifest } from './types'
import { findModuleFromBase } from './utils'

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

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

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

// Next.js already defines a default `pageExtensions` array in its `required-server-files.json` file
// In case it gets `undefined`, this is a fallback
const SOURCE_FILE_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx']

/**
* Find the source file for a given page route
*/
export const getSourceFileForPage = (page: string, roots: string[]) => {
export const getSourceFileForPage = (page: string, roots: string[], pageExtensions = SOURCE_FILE_EXTENSIONS) => {
for (const root of roots) {
for (const extension of SOURCE_FILE_EXTENSIONS) {
for (const extension of pageExtensions) {
const file = join(root, `${page}.${extension}`)
if (existsSync(file)) {
return file
Expand Down
16 changes: 12 additions & 4 deletions packages/runtime/src/helpers/functions.ts
Expand Up @@ -199,7 +199,11 @@ export const setupImageFunction = async ({
/**
* Look for API routes, and extract the config from the source file.
*/
export const getApiRouteConfigs = async (publish: string, baseDir: string): Promise<Array<ApiRouteConfig>> => {
export const getApiRouteConfigs = async (
publish: string,
baseDir: string,
pageExtensions: string[],
): Promise<Array<ApiRouteConfig>> => {
const pages = await readJSON(join(publish, 'server', 'pages-manifest.json'))
const apiRoutes = Object.keys(pages).filter((page) => page.startsWith('/api/'))
// two possible places
Expand All @@ -209,7 +213,7 @@ export const getApiRouteConfigs = async (publish: string, baseDir: string): Prom

return await Promise.all(
apiRoutes.map(async (apiRoute) => {
const filePath = getSourceFileForPage(apiRoute, [pagesDir, srcPagesDir])
const filePath = getSourceFileForPage(apiRoute, [pagesDir, srcPagesDir], pageExtensions)
return { route: apiRoute, config: await extractConfigFromFile(filePath), compiled: pages[apiRoute] }
}),
)
Expand All @@ -218,8 +222,12 @@ export const getApiRouteConfigs = async (publish: string, baseDir: string): Prom
/**
* Looks for extended API routes (background and scheduled functions) and extract the config from the source file.
*/
export const getExtendedApiRouteConfigs = async (publish: string, baseDir: string): Promise<Array<ApiRouteConfig>> => {
const settledApiRoutes = await getApiRouteConfigs(publish, baseDir)
export const getExtendedApiRouteConfigs = async (
publish: string,
baseDir: string,
pageExtensions: string[],
): Promise<Array<ApiRouteConfig>> => {
const settledApiRoutes = await getApiRouteConfigs(publish, baseDir, pageExtensions)

// We only want to return the API routes that are background or scheduled functions
return settledApiRoutes.filter((apiRoute) => apiRoute.config.type !== undefined)
Expand Down
24 changes: 18 additions & 6 deletions packages/runtime/src/index.ts
Expand Up @@ -65,6 +65,7 @@ const plugin: NetlifyPlugin = {
netlifyConfig.build.environment.NEXT_PRIVATE_TARGET = 'server'
},

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

checkNextSiteHasBuilt({ publish, failBuild })

const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental, routesManifest } =
await getNextConfig({
publish,
failBuild,
})
const {
appDir,
basePath,
i18n,
images,
target,
ignore,
trailingSlash,
outdir,
experimental,
routesManifest,
pageExtensions,
} = await getNextConfig({
publish,
failBuild,
})
await cleanupEdgeFunctions(constants)

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

await configureHandlerFunctions({ netlifyConfig, ignore, publish: relative(process.cwd(), publish) })
const apiRoutes = await getExtendedApiRouteConfigs(publish, appDir)
const apiRoutes = await getExtendedApiRouteConfigs(publish, appDir, pageExtensions)

await generateFunctions(constants, appDir, apiRoutes)
await generatePagesResolver(constants)
Expand Down
@@ -0,0 +1 @@
// noop
1 change: 1 addition & 0 deletions test/fixtures/page-extensions/default/pages/api/default.js
@@ -0,0 +1 @@
// noop
25 changes: 24 additions & 1 deletion test/helpers/files.spec.ts
Expand Up @@ -6,6 +6,7 @@ import {
patchNextFiles,
unpatchNextFiles,
getDependenciesOfFile,
getSourceFileForPage,
} from "../../packages/runtime/src/helpers/files"
import {
readFileSync,
Expand All @@ -19,6 +20,8 @@ import { join } from "pathe"
import { Rewrites } from "../../packages/runtime/src/helpers/types"
import { describeCwdTmpDir, moveNextDist } from "../test-utils"

const TEST_DIR = resolve(__dirname, '..')

const REDIRECTS: Rewrites = [
{
source: '/:file((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+)/',
Expand Down Expand Up @@ -215,7 +218,27 @@ describe('dependency tracing', () => {
it('generates dependency list from a source file', async () => {
const dependencies = await getDependenciesOfFile(resolve(__dirname, '../fixtures/analysis/background.js'))
expect(dependencies).toEqual(
['test/webpack-api-runtime.js', 'package.json'].map((dep) => resolve(dirname(resolve(__dirname, '..')), dep)),
['test/webpack-api-runtime.js', 'package.json'].map((dep) => resolve(dirname(TEST_DIR), dep)),
)
})
})

describe('getSourceFileForPage', () => {
it('handles default pageExtensions', () => {
const pagesDir = resolve(__dirname, '../fixtures/page-extensions/default/pages')
const apiRoute = '/api/default'

const filePath = getSourceFileForPage(apiRoute, [pagesDir])

expect(filePath.replace(TEST_DIR, '')).toBe('/fixtures/page-extensions/default/pages/api/default.js')
})

it('handles custom pageExtensions', () => {
const pagesDir = resolve(__dirname, '../fixtures/page-extensions/custom/pages')
const apiRoute = '/api/custom'

const filePath = getSourceFileForPage(apiRoute, [pagesDir], ['api.js'])

expect(filePath.replace(TEST_DIR, '')).toBe('/fixtures/page-extensions/custom/pages/api/custom.api.js')
})
})

0 comments on commit 940cbbc

Please sign in to comment.