From 619f289ac0414fe977045242f80ac62c6ee22095 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 17 Mar 2023 14:43:43 -0500 Subject: [PATCH 01/14] fix: moving functionmetadata over --- package-lock.json | 16 +++ package.json | 1 + packages/runtime/src/constants.ts | 6 +- packages/runtime/src/helpers/config.ts | 2 +- packages/runtime/src/helpers/functions.ts | 19 +++- .../runtime/src/helpers/functionsMetaData.ts | 44 ++++++++ test/functionsMetaData.spec.ts | 105 ++++++++++++++++++ 7 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 packages/runtime/src/helpers/functionsMetaData.ts create mode 100644 test/functionsMetaData.spec.ts diff --git a/package-lock.json b/package-lock.json index 9a1c087eaa..3d81be8005 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,6 +51,7 @@ "jest-extended": "^3.2.0", "jest-fetch-mock": "^3.0.3", "jest-junit": "^14.0.1", + "mock-fs": "^5.2.0", "netlify-plugin-cypress": "^2.2.1", "npm-run-all": "^4.1.5", "playwright-chromium": "^1.26.1", @@ -17995,6 +17996,15 @@ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, + "node_modules/mock-fs": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", + "integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/module-definition": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-4.0.0.tgz", @@ -37525,6 +37535,12 @@ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, + "mock-fs": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", + "integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", + "dev": true + }, "module-definition": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-4.0.0.tgz", diff --git a/package.json b/package.json index 0309cf1f61..c2c0f05ec6 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "jest-extended": "^3.2.0", "jest-fetch-mock": "^3.0.3", "jest-junit": "^14.0.1", + "mock-fs": "^5.2.0", "netlify-plugin-cypress": "^2.2.1", "npm-run-all": "^4.1.5", "playwright-chromium": "^1.26.1", diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index 179ae16302..d93ceeaa02 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -1,7 +1,11 @@ export const HANDLER_FUNCTION_NAME = '___netlify-handler' export const ODB_FUNCTION_NAME = '___netlify-odb-handler' export const IMAGE_FUNCTION_NAME = '_ipx' - +export const NEXT_PLUGIN_NAME = '@netlify/next-runtime' +export const NEXT_PLUGIN = '@netlify/plugin-nextjs' +export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler' +export const ODB_FUNCTION_TITLE = 'Next.js ISR handler' +export const IMAGE_FUNCTION_TITLE = "'next/image handler'" // These are paths in .next that shouldn't be publicly accessible export const HIDDEN_PATHS = [ '/cache/*', diff --git a/packages/runtime/src/helpers/config.ts b/packages/runtime/src/helpers/config.ts index 83be5ada51..f35637a71d 100644 --- a/packages/runtime/src/helpers/config.ts +++ b/packages/runtime/src/helpers/config.ts @@ -71,7 +71,7 @@ export const updateRequiredServerFiles = async (publish: string, modifiedConfig: await writeJSON(configFile, modifiedConfig) } -const resolveModuleRoot = (moduleName) => { +export const resolveModuleRoot = (moduleName) => { try { return dirname(relative(process.cwd(), require.resolve(`${moduleName}/package.json`, { paths: [process.cwd()] }))) } catch { diff --git a/packages/runtime/src/helpers/functions.ts b/packages/runtime/src/helpers/functions.ts index f451abb321..e46859e6bb 100644 --- a/packages/runtime/src/helpers/functions.ts +++ b/packages/runtime/src/helpers/functions.ts @@ -7,13 +7,22 @@ import type { ImageConfigComplete, RemotePattern } from 'next/dist/shared/lib/im import { outdent } from 'outdent' import { join, relative, resolve } from 'pathe' -import { HANDLER_FUNCTION_NAME, ODB_FUNCTION_NAME, IMAGE_FUNCTION_NAME, DEFAULT_FUNCTIONS_SRC } from '../constants' +import { + HANDLER_FUNCTION_NAME, + ODB_FUNCTION_NAME, + IMAGE_FUNCTION_NAME, + DEFAULT_FUNCTIONS_SRC, + HANDLER_FUNCTION_TITLE, + ODB_FUNCTION_TITLE, + IMAGE_FUNCTION_TITLE, +} from '../constants' import { getApiHandler } from '../templates/getApiHandler' import { getHandler } from '../templates/getHandler' import { getResolverForPages, getResolverForSourceFiles } from '../templates/getPageResolver' import { ApiConfig, ApiRouteType, extractConfigFromFile } from './analysis' import { getSourceFileForPage } from './files' +import { writeFunctionConfiguration } from './functionsMetaData' import { getFunctionNameForPage } from './utils' export interface ApiRouteConfig { @@ -62,7 +71,7 @@ export const generateFunctions = async ( await writeFile(join(functionsDir, functionName, 'pages.js'), resolverSource) } - const writeHandler = async (functionName: string, isODB: boolean) => { + const writeHandler = async (functionName: string, functionTitle: string, isODB: boolean) => { const handlerSource = await getHandler({ isODB, publishDir, appDir: relative(functionDir, appDir) }) await ensureDir(join(functionsDir, functionName)) await writeFile(join(functionsDir, functionName, `${functionName}.js`), handlerSource) @@ -71,10 +80,11 @@ export const generateFunctions = async ( join(__dirname, '..', '..', 'lib', 'templates', 'handlerUtils.js'), join(functionsDir, functionName, 'handlerUtils.js'), ) + writeFunctionConfiguration(functionName, functionTitle, functionsDir) } - await writeHandler(HANDLER_FUNCTION_NAME, false) - await writeHandler(ODB_FUNCTION_NAME, true) + await writeHandler(HANDLER_FUNCTION_NAME, HANDLER_FUNCTION_TITLE, false) + await writeHandler(ODB_FUNCTION_NAME, ODB_FUNCTION_TITLE, true) } /** @@ -138,6 +148,7 @@ export const setupImageFunction = async ({ }) await copyFile(join(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), join(functionDirectory, functionName)) + writeFunctionConfiguration(functionName.replace('.js', ''), IMAGE_FUNCTION_TITLE, functionsPath) // If we have edge functions then the request will have already been rewritten // so this won't match. This is matched if edge is disabled or unavailable. diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts new file mode 100644 index 0000000000..6e5a9559e9 --- /dev/null +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -0,0 +1,44 @@ +import { existsSync, readJSON, writeFile } from 'fs-extra' +import { join } from 'pathe' + +import { NEXT_PLUGIN, NEXT_PLUGIN_NAME } from '../constants' + +import { resolveModuleRoot } from './config' + +const checkForPackage = async (packageDir: string, nodeModule: boolean) => { + const packagePlugin = existsSync(packageDir) ? await readJSON(packageDir) : null + let nextPlugin + if (!nodeModule && packagePlugin) { + nextPlugin = packagePlugin.dependencies[NEXT_PLUGIN] ? packagePlugin.dependencies[NEXT_PLUGIN] : null + } else if (nodeModule && packagePlugin) { + nextPlugin = packagePlugin.version ? packagePlugin.version : null + } + + return nextPlugin +} + +/** + * Creates a function configuration file for the given function + * + * @param functionName The name of the function, e.g. `___netlify-handler` + * @param functionTitle The name of the function that will be displayed in logs, e.g. `Next.js SSR handler` + * @param functionsDir The directory where the function is located, e.g. `.netlify/functions` + */ +export const writeFunctionConfiguration = async (functionName: string, functionTitle: string, functionsDir: string) => { + const pluginPackagePath = '.netlify/plugins/package.json' + const ProjDir = resolveModuleRoot(NEXT_PLUGIN) + const nodeModulesPath = `${ProjDir}/package.json` + + const nextPluginVersion = + (await checkForPackage(nodeModulesPath, true)) || (await checkForPackage(pluginPackagePath, false)) + + const metadata = { + config: { + name: functionTitle, + generator: nextPluginVersion ? `${NEXT_PLUGIN_NAME}@${nextPluginVersion}` : 'Next Runtime Version Not Found', + }, + version: 1, + } + + await writeFile(join(functionsDir, functionName, `${functionName}.json`), JSON.stringify(metadata)) +} diff --git a/test/functionsMetaData.spec.ts b/test/functionsMetaData.spec.ts new file mode 100644 index 0000000000..4b39ad3ef5 --- /dev/null +++ b/test/functionsMetaData.spec.ts @@ -0,0 +1,105 @@ +import { readJSON } from 'fs-extra' +import mock from 'mock-fs' +import { join } from 'pathe' +import { NEXT_PLUGIN_NAME } from '../packages/runtime/src/constants' +import { writeFunctionConfiguration } from '../packages/runtime/src/helpers/functionsMetaData' + +describe('writeFunctionConfiguration', () => { + afterEach(() => { + mock.restore() + }) + + it('should write the configuration for a function using node modules version of @netlify/plugin-nextjs', async () => { + const nextRuntimeVersion = '23.4.5' + + mock({ + '.netlify/plugins/package.json': JSON.stringify({ + name: 'test', + version: '1.0.0', + dependencies: { + '@netlify/plugin-nextjs': '29.3.4', + }, + }), + 'node_modules/@netlify/plugin-nextjs/package.json': JSON.stringify({ + name: '@netlify/plugin-nextjs', + version: nextRuntimeVersion, + }), + '.netlify/functions/some-folder/someFunctionName': {}, + }) + + const functionName = 'someFunctionName' + const functionTitle = 'some function title' + const functionsDir = '.netlify/functions/some-folder' + + const expected = { + config: { + name: functionTitle, + generator: `${NEXT_PLUGIN_NAME}@${nextRuntimeVersion}`, + }, + version: 1, + } + + const filePathToSaveTo = join(functionsDir, functionName, `${functionName}.json`) + await writeFunctionConfiguration(functionName, functionTitle, functionsDir) + const actual = await readJSON(filePathToSaveTo) + + expect(actual).toEqual(expected) + }) + + it('should write the configuration for a function using version of @netlify/plugin-nextjs in package.json', async () => { + const nextRuntimeVersion = '23.4.5' + + mock({ + '.netlify/plugins/package.json': JSON.stringify({ + name: 'test', + version: '1.0.0', + dependencies: { + '@netlify/plugin-nextjs': nextRuntimeVersion, + }, + }), + '.netlify/functions/some-folder/someFunctionName': {}, + }) + + const functionName = 'someFunctionName' + const functionTitle = 'some function title' + const functionsDir = '.netlify/functions/some-folder' + + const expected = { + config: { + name: functionTitle, + generator: `${NEXT_PLUGIN_NAME}@${nextRuntimeVersion}`, + }, + version: 1, + } + + const filePathToSaveTo = join(functionsDir, functionName, `${functionName}.json`) + await writeFunctionConfiguration(functionName, functionTitle, functionsDir) + const actual = await readJSON(filePathToSaveTo) + + expect(actual).toEqual(expected) + }) + + it('should write the configuration for a function with runtime version not found', async () => { + mock({ + '.netlify/functions/some-folder/someFunctionName': {}, + }) + + const functionName = 'someFunctionName' + const functionTitle = 'some function title' + const functionsDir = '.netlify/functions/some-folder' + + const expected = { + config: { + name: functionTitle, + generator: 'Next Runtime Version Not Found', + }, + version: 1, + } + + const filePathToSaveTo = join(functionsDir, functionName, `${functionName}.json`) + await writeFunctionConfiguration(functionName, functionTitle, functionsDir) + const actual = await readJSON(filePathToSaveTo) + + expect(actual).toEqual(expected) + }) +}) From 6acb8325f8175f1665d25892fe83ceca6156eb88 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 17 Mar 2023 15:49:20 -0500 Subject: [PATCH 02/14] chore: updated naming for file and when version not found --- packages/runtime/src/constants.ts | 2 +- packages/runtime/src/helpers/functions.ts | 2 +- packages/runtime/src/helpers/functionsMetaData.ts | 2 +- test/functionsMetaData.spec.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index d93ceeaa02..db3fcd4adc 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -5,7 +5,7 @@ export const NEXT_PLUGIN_NAME = '@netlify/next-runtime' export const NEXT_PLUGIN = '@netlify/plugin-nextjs' export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler' export const ODB_FUNCTION_TITLE = 'Next.js ISR handler' -export const IMAGE_FUNCTION_TITLE = "'next/image handler'" +export const IMAGE_FUNCTION_TITLE = "next/image handler" // These are paths in .next that shouldn't be publicly accessible export const HIDDEN_PATHS = [ '/cache/*', diff --git a/packages/runtime/src/helpers/functions.ts b/packages/runtime/src/helpers/functions.ts index e46859e6bb..135efaac03 100644 --- a/packages/runtime/src/helpers/functions.ts +++ b/packages/runtime/src/helpers/functions.ts @@ -22,7 +22,7 @@ import { getResolverForPages, getResolverForSourceFiles } from '../templates/get import { ApiConfig, ApiRouteType, extractConfigFromFile } from './analysis' import { getSourceFileForPage } from './files' -import { writeFunctionConfiguration } from './functionsMetaData' +import { writeFunctionConfiguration } from './functionsMetadata' import { getFunctionNameForPage } from './utils' export interface ApiRouteConfig { diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 6e5a9559e9..1dd4524077 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -35,7 +35,7 @@ export const writeFunctionConfiguration = async (functionName: string, functionT const metadata = { config: { name: functionTitle, - generator: nextPluginVersion ? `${NEXT_PLUGIN_NAME}@${nextPluginVersion}` : 'Next Runtime Version Not Found', + generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion || 'version-not-found'}`, }, version: 1, } diff --git a/test/functionsMetaData.spec.ts b/test/functionsMetaData.spec.ts index 4b39ad3ef5..be90034fd6 100644 --- a/test/functionsMetaData.spec.ts +++ b/test/functionsMetaData.spec.ts @@ -2,7 +2,7 @@ import { readJSON } from 'fs-extra' import mock from 'mock-fs' import { join } from 'pathe' import { NEXT_PLUGIN_NAME } from '../packages/runtime/src/constants' -import { writeFunctionConfiguration } from '../packages/runtime/src/helpers/functionsMetaData' +import { writeFunctionConfiguration } from '../packages/runtime/src/helpers/functionsMetadata' describe('writeFunctionConfiguration', () => { afterEach(() => { @@ -91,7 +91,7 @@ describe('writeFunctionConfiguration', () => { const expected = { config: { name: functionTitle, - generator: 'Next Runtime Version Not Found', + generator: '@netlify/next-runtime@version-not-found', }, version: 1, } From 75d46b40995578b27f68aa1234f2369af570aedc Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 17 Mar 2023 15:51:00 -0500 Subject: [PATCH 03/14] chore: prettier --- packages/runtime/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index db3fcd4adc..d26c5c8e8a 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -5,7 +5,7 @@ export const NEXT_PLUGIN_NAME = '@netlify/next-runtime' export const NEXT_PLUGIN = '@netlify/plugin-nextjs' export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler' export const ODB_FUNCTION_TITLE = 'Next.js ISR handler' -export const IMAGE_FUNCTION_TITLE = "next/image handler" +export const IMAGE_FUNCTION_TITLE = 'next/image handler' // These are paths in .next that shouldn't be publicly accessible export const HIDDEN_PATHS = [ '/cache/*', From ec99ea82d7d44fa13aab166957bc65aaf3f33449 Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 17 Mar 2023 16:12:38 -0500 Subject: [PATCH 04/14] Revert "chore: prettier" This reverts commit 75d46b40995578b27f68aa1234f2369af570aedc. --- packages/runtime/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index d26c5c8e8a..db3fcd4adc 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -5,7 +5,7 @@ export const NEXT_PLUGIN_NAME = '@netlify/next-runtime' export const NEXT_PLUGIN = '@netlify/plugin-nextjs' export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler' export const ODB_FUNCTION_TITLE = 'Next.js ISR handler' -export const IMAGE_FUNCTION_TITLE = 'next/image handler' +export const IMAGE_FUNCTION_TITLE = "next/image handler" // These are paths in .next that shouldn't be publicly accessible export const HIDDEN_PATHS = [ '/cache/*', From 5af790b8dc102b81b00db5592176101774b3826e Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 17 Mar 2023 16:14:37 -0500 Subject: [PATCH 05/14] Revert updated naming for file and when version not found" reverts commit 6acb8325f8175f1665d25892fe83ceca6156eb88. --- packages/runtime/src/constants.ts | 2 +- packages/runtime/src/helpers/functions.ts | 2 +- packages/runtime/src/helpers/functionsMetaData.ts | 2 +- test/functionsMetaData.spec.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index db3fcd4adc..d93ceeaa02 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -5,7 +5,7 @@ export const NEXT_PLUGIN_NAME = '@netlify/next-runtime' export const NEXT_PLUGIN = '@netlify/plugin-nextjs' export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler' export const ODB_FUNCTION_TITLE = 'Next.js ISR handler' -export const IMAGE_FUNCTION_TITLE = "next/image handler" +export const IMAGE_FUNCTION_TITLE = "'next/image handler'" // These are paths in .next that shouldn't be publicly accessible export const HIDDEN_PATHS = [ '/cache/*', diff --git a/packages/runtime/src/helpers/functions.ts b/packages/runtime/src/helpers/functions.ts index 135efaac03..e46859e6bb 100644 --- a/packages/runtime/src/helpers/functions.ts +++ b/packages/runtime/src/helpers/functions.ts @@ -22,7 +22,7 @@ import { getResolverForPages, getResolverForSourceFiles } from '../templates/get import { ApiConfig, ApiRouteType, extractConfigFromFile } from './analysis' import { getSourceFileForPage } from './files' -import { writeFunctionConfiguration } from './functionsMetadata' +import { writeFunctionConfiguration } from './functionsMetaData' import { getFunctionNameForPage } from './utils' export interface ApiRouteConfig { diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 1dd4524077..6e5a9559e9 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -35,7 +35,7 @@ export const writeFunctionConfiguration = async (functionName: string, functionT const metadata = { config: { name: functionTitle, - generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion || 'version-not-found'}`, + generator: nextPluginVersion ? `${NEXT_PLUGIN_NAME}@${nextPluginVersion}` : 'Next Runtime Version Not Found', }, version: 1, } diff --git a/test/functionsMetaData.spec.ts b/test/functionsMetaData.spec.ts index be90034fd6..4b39ad3ef5 100644 --- a/test/functionsMetaData.spec.ts +++ b/test/functionsMetaData.spec.ts @@ -2,7 +2,7 @@ import { readJSON } from 'fs-extra' import mock from 'mock-fs' import { join } from 'pathe' import { NEXT_PLUGIN_NAME } from '../packages/runtime/src/constants' -import { writeFunctionConfiguration } from '../packages/runtime/src/helpers/functionsMetadata' +import { writeFunctionConfiguration } from '../packages/runtime/src/helpers/functionsMetaData' describe('writeFunctionConfiguration', () => { afterEach(() => { @@ -91,7 +91,7 @@ describe('writeFunctionConfiguration', () => { const expected = { config: { name: functionTitle, - generator: '@netlify/next-runtime@version-not-found', + generator: 'Next Runtime Version Not Found', }, version: 1, } From 307955af84d7d2ce14552aa66344d4aa76ee2c5f Mon Sep 17 00:00:00 2001 From: taty2010 Date: Fri, 17 Mar 2023 16:36:37 -0500 Subject: [PATCH 06/14] chore: updating not found mssg + image func title --- packages/runtime/src/constants.ts | 2 +- packages/runtime/src/helpers/functionsMetaData.ts | 2 +- test/functionsMetaData.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index d93ceeaa02..d26c5c8e8a 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -5,7 +5,7 @@ export const NEXT_PLUGIN_NAME = '@netlify/next-runtime' export const NEXT_PLUGIN = '@netlify/plugin-nextjs' export const HANDLER_FUNCTION_TITLE = 'Next.js SSR handler' export const ODB_FUNCTION_TITLE = 'Next.js ISR handler' -export const IMAGE_FUNCTION_TITLE = "'next/image handler'" +export const IMAGE_FUNCTION_TITLE = 'next/image handler' // These are paths in .next that shouldn't be publicly accessible export const HIDDEN_PATHS = [ '/cache/*', diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 6e5a9559e9..1dd4524077 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -35,7 +35,7 @@ export const writeFunctionConfiguration = async (functionName: string, functionT const metadata = { config: { name: functionTitle, - generator: nextPluginVersion ? `${NEXT_PLUGIN_NAME}@${nextPluginVersion}` : 'Next Runtime Version Not Found', + generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion || 'version-not-found'}`, }, version: 1, } diff --git a/test/functionsMetaData.spec.ts b/test/functionsMetaData.spec.ts index 4b39ad3ef5..0883b86091 100644 --- a/test/functionsMetaData.spec.ts +++ b/test/functionsMetaData.spec.ts @@ -91,7 +91,7 @@ describe('writeFunctionConfiguration', () => { const expected = { config: { name: functionTitle, - generator: 'Next Runtime Version Not Found', + generator: '@netlify/next-runtime@version-not-found', }, version: 1, } From 05706a9ad1389072fba9added14b1d2cd17a5885 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 20 Mar 2023 08:34:43 -0400 Subject: [PATCH 07/14] chore: refactor based on feedback --- packages/runtime/src/helpers/functionsMetaData.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 1dd4524077..489bbb86dc 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -26,8 +26,7 @@ const checkForPackage = async (packageDir: string, nodeModule: boolean) => { */ export const writeFunctionConfiguration = async (functionName: string, functionTitle: string, functionsDir: string) => { const pluginPackagePath = '.netlify/plugins/package.json' - const ProjDir = resolveModuleRoot(NEXT_PLUGIN) - const nodeModulesPath = `${ProjDir}/package.json` + const nodeModulesPath = join(resolveModuleRoot(NEXT_PLUGIN), 'package.json') const nextPluginVersion = (await checkForPackage(nodeModulesPath, true)) || (await checkForPackage(pluginPackagePath, false)) From 43f412c3b24d9bff88e2bc393b475bddbb6b470b Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 20 Mar 2023 08:49:05 -0400 Subject: [PATCH 08/14] chore: refactored parameters for writeFunctionConfiguration --- packages/runtime/src/helpers/functions.ts | 8 +++++-- .../runtime/src/helpers/functionsMetaData.ts | 21 ++++++++++++++----- test/functionsMetaData.spec.ts | 6 +++--- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/runtime/src/helpers/functions.ts b/packages/runtime/src/helpers/functions.ts index e46859e6bb..1f0519e18c 100644 --- a/packages/runtime/src/helpers/functions.ts +++ b/packages/runtime/src/helpers/functions.ts @@ -80,7 +80,7 @@ export const generateFunctions = async ( join(__dirname, '..', '..', 'lib', 'templates', 'handlerUtils.js'), join(functionsDir, functionName, 'handlerUtils.js'), ) - writeFunctionConfiguration(functionName, functionTitle, functionsDir) + writeFunctionConfiguration({ functionName, functionTitle, functionsDir }) } await writeHandler(HANDLER_FUNCTION_NAME, HANDLER_FUNCTION_TITLE, false) @@ -148,7 +148,11 @@ export const setupImageFunction = async ({ }) await copyFile(join(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), join(functionDirectory, functionName)) - writeFunctionConfiguration(functionName.replace('.js', ''), IMAGE_FUNCTION_TITLE, functionsPath) + writeFunctionConfiguration({ + functionName: functionName.replace('.js', ''), + functionTitle: IMAGE_FUNCTION_TITLE, + functionsDir: functionsPath, + }) // If we have edge functions then the request will have already been rewritten // so this won't match. This is matched if edge is disabled or unavailable. diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 489bbb86dc..233e6b9167 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -17,14 +17,25 @@ const checkForPackage = async (packageDir: string, nodeModule: boolean) => { return nextPlugin } +// The information needed to create a function configuration file +export interface FunctionInfo { + // The name of the function, e.g. `___netlify-handler` + functionName: string + + // The name of the function that will be displayed in logs, e.g. `Next.js SSR handler` + functionTitle: string + + // The directory where the function is located, e.g. `.netlify/functions` + functionsDir: string +} + /** - * Creates a function configuration file for the given function + * Creates a function configuration file for the given function. * - * @param functionName The name of the function, e.g. `___netlify-handler` - * @param functionTitle The name of the function that will be displayed in logs, e.g. `Next.js SSR handler` - * @param functionsDir The directory where the function is located, e.g. `.netlify/functions` + * @param functionInfo The information needed to create a function configuration file */ -export const writeFunctionConfiguration = async (functionName: string, functionTitle: string, functionsDir: string) => { +export const writeFunctionConfiguration = async (functionInfo: FunctionInfo) => { + const { functionName, functionTitle, functionsDir } = functionInfo const pluginPackagePath = '.netlify/plugins/package.json' const nodeModulesPath = join(resolveModuleRoot(NEXT_PLUGIN), 'package.json') diff --git a/test/functionsMetaData.spec.ts b/test/functionsMetaData.spec.ts index 0883b86091..729826fa25 100644 --- a/test/functionsMetaData.spec.ts +++ b/test/functionsMetaData.spec.ts @@ -40,7 +40,7 @@ describe('writeFunctionConfiguration', () => { } const filePathToSaveTo = join(functionsDir, functionName, `${functionName}.json`) - await writeFunctionConfiguration(functionName, functionTitle, functionsDir) + await writeFunctionConfiguration({ functionName, functionTitle, functionsDir }) const actual = await readJSON(filePathToSaveTo) expect(actual).toEqual(expected) @@ -73,7 +73,7 @@ describe('writeFunctionConfiguration', () => { } const filePathToSaveTo = join(functionsDir, functionName, `${functionName}.json`) - await writeFunctionConfiguration(functionName, functionTitle, functionsDir) + await writeFunctionConfiguration({ functionName, functionTitle, functionsDir }) const actual = await readJSON(filePathToSaveTo) expect(actual).toEqual(expected) @@ -97,7 +97,7 @@ describe('writeFunctionConfiguration', () => { } const filePathToSaveTo = join(functionsDir, functionName, `${functionName}.json`) - await writeFunctionConfiguration(functionName, functionTitle, functionsDir) + await writeFunctionConfiguration({ functionName, functionTitle, functionsDir }) const actual = await readJSON(filePathToSaveTo) expect(actual).toEqual(expected) From 74b67d12e1475ed1c054422ea595438b14f65f65 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 21 Mar 2023 16:16:59 -0400 Subject: [PATCH 09/14] chore: small refactor and renaming --- .../runtime/src/helpers/functionsMetaData.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 233e6b9167..55e0c29e90 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -5,16 +5,14 @@ import { NEXT_PLUGIN, NEXT_PLUGIN_NAME } from '../constants' import { resolveModuleRoot } from './config' -const checkForPackage = async (packageDir: string, nodeModule: boolean) => { - const packagePlugin = existsSync(packageDir) ? await readJSON(packageDir) : null - let nextPlugin - if (!nodeModule && packagePlugin) { - nextPlugin = packagePlugin.dependencies[NEXT_PLUGIN] ? packagePlugin.dependencies[NEXT_PLUGIN] : null - } else if (nodeModule && packagePlugin) { - nextPlugin = packagePlugin.version ? packagePlugin.version : null +const getNextRuntimeVersion = async (packageJsonPath: string, useNodeModulesPath: boolean) => { + if (!existsSync(packageJsonPath)) { + return } - return nextPlugin + const packagePlugin = await readJSON(packageJsonPath) + + return useNodeModulesPath ? packagePlugin.version : packagePlugin.dependencies[NEXT_PLUGIN] } // The information needed to create a function configuration file @@ -40,7 +38,7 @@ export const writeFunctionConfiguration = async (functionInfo: FunctionInfo) => const nodeModulesPath = join(resolveModuleRoot(NEXT_PLUGIN), 'package.json') const nextPluginVersion = - (await checkForPackage(nodeModulesPath, true)) || (await checkForPackage(pluginPackagePath, false)) + (await getNextRuntimeVersion(nodeModulesPath, true)) || (await getNextRuntimeVersion(pluginPackagePath, false)) const metadata = { config: { From 7b480e56e1d0c222f34c9bdc573b890adde5bcbc Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 21 Mar 2023 16:35:36 -0400 Subject: [PATCH 10/14] Update packages/runtime/src/helpers/functionsMetaData.ts --- packages/runtime/src/helpers/functionsMetaData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 55e0c29e90..7dd22669af 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -43,7 +43,7 @@ export const writeFunctionConfiguration = async (functionInfo: FunctionInfo) => const metadata = { config: { name: functionTitle, - generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion || 'version-not-found'}`, + generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion || 'unknown'}`, }, version: 1, } From afe46a2daca1d483efc6cc8bf2ca84a0bd4b632d Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 21 Mar 2023 16:38:54 -0400 Subject: [PATCH 11/14] test: updated test when runtime version is unknown --- test/functionsMetaData.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functionsMetaData.spec.ts b/test/functionsMetaData.spec.ts index 729826fa25..9c130d454f 100644 --- a/test/functionsMetaData.spec.ts +++ b/test/functionsMetaData.spec.ts @@ -91,7 +91,7 @@ describe('writeFunctionConfiguration', () => { const expected = { config: { name: functionTitle, - generator: '@netlify/next-runtime@version-not-found', + generator: '@netlify/next-runtime@unknown', }, version: 1, } From 0447d448b17b5eb3caae8341da09671bc2a4f96e Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 21 Mar 2023 16:41:31 -0400 Subject: [PATCH 12/14] chore: added a comment about returning an unknown version of the next runtime --- packages/runtime/src/helpers/functionsMetaData.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 7dd22669af..27f6404051 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -38,12 +38,15 @@ export const writeFunctionConfiguration = async (functionInfo: FunctionInfo) => const nodeModulesPath = join(resolveModuleRoot(NEXT_PLUGIN), 'package.json') const nextPluginVersion = - (await getNextRuntimeVersion(nodeModulesPath, true)) || (await getNextRuntimeVersion(pluginPackagePath, false)) + (await getNextRuntimeVersion(nodeModulesPath, true)) || + (await getNextRuntimeVersion(pluginPackagePath, false)) || + // The runtime version should always be available, but if it's not, return 'unknown' + 'unknown' const metadata = { config: { name: functionTitle, - generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion || 'unknown'}`, + generator: `${NEXT_PLUGIN_NAME}@${nextPluginVersion}`, }, version: 1, } From de7ba0ff388fe20424c6c2cab58298f9b36a4473 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Wed, 22 Mar 2023 15:25:59 -0400 Subject: [PATCH 13/14] chore: refactor based on PR feedback --- packages/runtime/src/helpers/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/functions.ts b/packages/runtime/src/helpers/functions.ts index 1f0519e18c..00ea9e04ba 100644 --- a/packages/runtime/src/helpers/functions.ts +++ b/packages/runtime/src/helpers/functions.ts @@ -149,7 +149,7 @@ export const setupImageFunction = async ({ await copyFile(join(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), join(functionDirectory, functionName)) writeFunctionConfiguration({ - functionName: functionName.replace('.js', ''), + functionName: IMAGE_FUNCTION_NAME, functionTitle: IMAGE_FUNCTION_TITLE, functionsDir: functionsPath, }) From bc7b5a6a9cb4f7eb8f6be4bfcf36ce90a2355275 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Wed, 22 Mar 2023 16:03:02 -0400 Subject: [PATCH 14/14] chore: fixed an error causing tests to fail --- packages/runtime/src/helpers/functionsMetaData.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/helpers/functionsMetaData.ts b/packages/runtime/src/helpers/functionsMetaData.ts index 27f6404051..c8e0972ded 100644 --- a/packages/runtime/src/helpers/functionsMetaData.ts +++ b/packages/runtime/src/helpers/functionsMetaData.ts @@ -35,7 +35,8 @@ export interface FunctionInfo { export const writeFunctionConfiguration = async (functionInfo: FunctionInfo) => { const { functionName, functionTitle, functionsDir } = functionInfo const pluginPackagePath = '.netlify/plugins/package.json' - const nodeModulesPath = join(resolveModuleRoot(NEXT_PLUGIN), 'package.json') + const moduleRoot = resolveModuleRoot(NEXT_PLUGIN) + const nodeModulesPath = moduleRoot ? join(moduleRoot, 'package.json') : null const nextPluginVersion = (await getNextRuntimeVersion(nodeModulesPath, true)) ||