From cf40e08db601bc44b4e44d228a9c6bf1c76d4d9f Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 18 Jul 2024 23:02:47 +0100 Subject: [PATCH 01/25] implement route scoping solution --- .changeset/thirty-birds-build.md | 32 +++++ .../dedupeEdgeFunctions.ts | 136 +++++++++++++++--- .../templates/_worker.js/index.ts | 2 + .../templates/_worker.js/routesIsolation.ts | 91 ++++++++++++ 4 files changed, 245 insertions(+), 16 deletions(-) create mode 100644 .changeset/thirty-birds-build.md create mode 100644 packages/next-on-pages/templates/_worker.js/routesIsolation.ts diff --git a/.changeset/thirty-birds-build.md b/.changeset/thirty-birds-build.md new file mode 100644 index 000000000..54893f1bc --- /dev/null +++ b/.changeset/thirty-birds-build.md @@ -0,0 +1,32 @@ +--- +'@cloudflare/next-on-pages': patch +--- + +fix: implement route specific global scoping strategy + +currently routes all share the same global scope, this can be problematic and cause +race conditions and failures + +One example of this is the following code that is present in route function files: + +```ts +self.webpackChunk_N_E = ... +``` + +and + +```ts +self.webpackChunk_N_E.push(...) +``` + +this indicates that an in-memory global collection of the webpack chunks is shared by all routes, +this combined with the fact that chunks can have their own module state this can easily cause routes +to conflict with each other at runtime. + +So, in order to solve the above issue wrap every route function in a function wrapper which +accepts as parameters, thus overrides, the `self`, `globalThis` and `global` symbols. The symbols +are then to be resolved with proxies that redirect setters to route-scoped in-memory maps and +getters to the above mentioned map's values and fallback to the original symbol values otherwise +(i.e. `globalThis` will be overridden by a proxy that, when setting values, sets them in a separate +location and, when getting values, gets them from said location if present there or from the real +`globalThis` otherwise) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index f3295237b..fbbe824ec 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -101,13 +101,20 @@ async function processFunctionIdentifiers( if (importPath) { // Dedupe and update collected imports. - const { updatedContents } = await processImportIdentifier( - { type, identifier, start, end, importPath, info: identifierInfo }, - { fileContents, entrypoint, newFnLocation, fnConfig: fnInfo.config }, - opts, - ); + const { updatedContents, newImportToPrepend } = + await processImportIdentifier( + { type, identifier, start, end, importPath, info: identifierInfo }, + { + fileContents, + entrypoint, + newFnLocation, + fnConfig: fnInfo.config, + }, + opts, + ); fileContents = updatedContents; + importsToPrepend.push(newImportToPrepend); } else if (identifierInfo.consumers.length > 1) { // Only dedupe code blocks if there are multiple consumers. const { updatedContents, newFilePath, newImport, wasmImports } = @@ -143,9 +150,10 @@ async function processFunctionIdentifiers( // Build the identifier files before building the function's file. await Promise.all( - [...identifierPathsToBuild].map(async path => - buildFile(await readFile(path, 'utf8'), path), - ), + [...identifierPathsToBuild].map(async path => { + const fileContents = await functionifyFileContent(path); + return buildFile(fileContents, path); + }), ); // If wasm identifier is used in code block, prepend the import to the code block's file. @@ -168,6 +176,32 @@ async function processFunctionIdentifiers( await Promise.all(functionBuildPromises); } +/** + * Given a standard ESM file (without imports) it converts it to a function call that returns + * an object with the various exports set as its fields + * + * The function allows us to override global symbols such as `self`, `globalThis` and `global` + * (which are used as the function's parameter names) + * + * @param path the path of the ESM file + * @returns the converted file content + */ +async function functionifyFileContent(path: string) { + let fileContents = await readFile(path, 'utf8'); + fileContents = `const namedExports = {};${fileContents}`; + fileContents = fileContents.replace( + /export const (\S+) =/g, + 'namedExports["$1"] =', + ); + fileContents = ` + export const getNamedExports = ((self, globalThis, global) => { + ${fileContents}; + return namedExports; + }); + `; + return fileContents; +} + /** * Builds a new file for an Edge function. * @@ -193,7 +227,16 @@ async function buildFunctionFile( return acc; }, new Map()); + let chunkMapIdx = 0; + const chunksExportsMap = new Map>(); + groupedImports.forEach((keys, path) => { + if (path.endsWith('.wasm')) { + // we don't need/want to apply any code transformation for wasm imports + functionImports += `import ${keys} from "${path}"`; + return; + } + const relativeImportPath = getRelativePathToAncestor({ from: newFnLocation, relativeTo: nopDistDir, @@ -202,12 +245,19 @@ async function buildFunctionFile( join(relativeImportPath, addLeadingSlash(path)), ); - functionImports += `import { ${keys} } from '${importPath}';\n`; + const namedExportsId = `getNamedExports_${chunkMapIdx++}`; + chunksExportsMap.set(namedExportsId, new Set([...keys.split(',')])); + functionImports += `import { getNamedExports as ${namedExportsId} } from '${importPath}';\n`; }); fnInfo.outputPath = relative(workerJsDir, newFnPath); - const finalFileContents = `${functionImports}${fileContents}`; + const finalFileContents = iffefyFunctionFile( + fileContents, + functionImports, + fnInfo, + chunksExportsMap, + ); const buildPromise = buildFile(finalFileContents, newFnPath, { relativeTo: nopDistDir, }).then(async () => { @@ -225,6 +275,53 @@ type BuildFunctionFileOpts = { newFnPath: string; }; +/** + * Given the content of a function file it converts/wraps it into an iife that overrides the function's contents with an iffe call that + * overrides global symbols with route-specific proxies (for more details see: templates/_worker.js/routesIsolation.ts) + * + * @param fileContents the function file's contents + * @param functionImports the imports that need to be added to the file + * @param fnInfo the function's information + * @param chunksExportsMap a map containing getters and chunks identifiers being used by the function + * @returns the updated/iifefied file content + */ +function iffefyFunctionFile( + fileContents: string, + functionImports: string, + fnInfo: FunctionInfo, + chunksExportsMap: Map>, +): string { + const wrappedContent = ` + export default ((self, globalThis, global) => { + ${fileContents + // it looks like there can be direct references to _ENTRIES (i.e. `_ENTRIES` instead of `globalThis._ENTRIES` etc...) + // we have to update all such references otherwise our proxying won't take effect on those + .replace(/([^.])_ENTRIES/g, '$1globalThis._ENTRIES') + // the default export needs to become the return value of the iife, which is then re-exported as default + .replace(/export default /g, 'return ')} + })(proxy, proxy, proxy); + `; + + const proxyCall = `const proxy = globalThis.__nextOnPagesRoutesIsolation.getProxyFor('${ + fnInfo.route?.path ?? '' + }');`; + + const chunksExtraction = [...chunksExportsMap].flatMap( + ([getNamedExportsId, keys]) => { + return [ + `const exportsOf${getNamedExportsId} = ${getNamedExportsId}(proxy, proxy, proxy);`, + ...[...keys].map( + key => `const ${key} = exportsOf${getNamedExportsId}["${key}"]`, + ), + ]; + }, + ); + + return [functionImports, proxyCall, ...chunksExtraction, wrappedContent].join( + ';', + ); +} + /** * Prepends Wasm imports to a code block's built file. * @@ -268,12 +365,13 @@ async function prependWasmImportsToCodeBlocks( * Processes an import path identifier. * * - Moves the imported file to the new location if it doesn't exist. - * - Updates the file contents to import from the new location. + * - Updates the file contents to remove the import. + * - Returns the information for the new import. * * @param ident The import path identifier to process. * @param processOpts Contents of the function's file, the function's entrypoint, and the new path. * @param opts Options for processing the function. - * @returns The updated file contents. + * @returns The updated file contents alongside the new import information. */ async function processImportIdentifier( ident: RawIdentifierWithImport & { info: IdentifierInfo }, @@ -284,7 +382,7 @@ async function processImportIdentifier( fnConfig, }: ProcessImportIdentifierOpts, { nopDistDir, workerJsDir }: ProcessVercelFunctionsOpts, -): Promise<{ updatedContents: string }> { +): Promise<{ updatedContents: string; newImportToPrepend: NewImportInfo }> { const { type, identifier, start, end, importPath, info } = ident; let updatedContents = fileContents; @@ -320,14 +418,20 @@ async function processImportIdentifier( }); const newImportPath = normalizePath(join(relativeImportPath, info.newDest)); - const newVal = `import ${identifier} from "${newImportPath}";`; + // let's remove the original import since it will be re-added later when appropriate updatedContents = replaceLastSubstringInstance( updatedContents, codeBlock, - newVal, + '', ); - return { updatedContents }; + return { + updatedContents, + newImportToPrepend: { + key: identifier, + path: newImportPath, + }, + }; } type ProcessImportIdentifierOpts = { diff --git a/packages/next-on-pages/templates/_worker.js/index.ts b/packages/next-on-pages/templates/_worker.js/index.ts index cf29e2d39..50cf212af 100644 --- a/packages/next-on-pages/templates/_worker.js/index.ts +++ b/packages/next-on-pages/templates/_worker.js/index.ts @@ -1,5 +1,6 @@ import { SUSPENSE_CACHE_URL } from '../cache'; import { handleRequest } from './handleRequest'; +import { setupRoutesIsolation } from './routesIsolation'; import { adjustRequestForVercel, handleImageResizingRequest, @@ -22,6 +23,7 @@ declare const __ALSes_PROMISE__: Promise(); + + return new Proxy(globalThis, { + get: (_, property) => { + if (overrides.has(property)) { + return overrides.get(property); + } + return Reflect.get(globalThis, property); + }, + set: (_, property, value) => { + if (sharedGlobalProperties.has(property)) { + // this property should be shared across all routes + return Reflect.set(globalThis, property, value); + } + overrides.set(property, value); + return true; + }, + }); +} + +/** + * There are some properties that do need to be shared across all different routes, so we collect + * them in this set and skip the global scope proxying for them + */ +const sharedGlobalProperties = new Set([ + '_nextOriginalFetch', + 'fetch', + '__incrementalCache', +]); + +type RoutesIsolation = { + _map: Map; + getProxyFor: (route: string) => unknown; +}; + +declare global { + // eslint-disable-next-line no-var + var __nextOnPagesRoutesIsolation: RoutesIsolation; +} From 131893804aade6ae9b009f953693a023c3aba985 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Tue, 30 Jul 2024 12:17:34 +0100 Subject: [PATCH 02/25] remove unused variable --- pages-e2e/features/_utils/getAssertVisible.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages-e2e/features/_utils/getAssertVisible.ts b/pages-e2e/features/_utils/getAssertVisible.ts index a7f7fbe35..2119f6f86 100644 --- a/pages-e2e/features/_utils/getAssertVisible.ts +++ b/pages-e2e/features/_utils/getAssertVisible.ts @@ -19,7 +19,6 @@ async function assertVisible( page: Page, ...[selector, options]: Parameters ): Promise { - let isVisible = false; for (const _attempt of [0, 1, 2, 3, 4, 5]) { const locator = page.locator(selector, options); try { From 33e7842f4903cea3149dd6458c8b65ff66b190aa Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Tue, 30 Jul 2024 15:15:39 +0100 Subject: [PATCH 03/25] remove appServerActions feature from app14.0.0 fixture --- pages-e2e/fixtures/app14.0.0/main.fixture | 1 - 1 file changed, 1 deletion(-) diff --git a/pages-e2e/fixtures/app14.0.0/main.fixture b/pages-e2e/fixtures/app14.0.0/main.fixture index 4b0cc891d..cdf6a29e9 100644 --- a/pages-e2e/fixtures/app14.0.0/main.fixture +++ b/pages-e2e/fixtures/app14.0.0/main.fixture @@ -4,7 +4,6 @@ "appRouting", "appConfigsTrailingSlashTrue", "appWasm", - "appServerActions", "appGetRequestContext" ], "localSetup": "npm install", From ef3df464e7cf484a758c3fa0dbcde6ac29f2a23d Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 31 Jul 2024 22:30:14 +0100 Subject: [PATCH 04/25] fixup! implement route scoping solution update changeset --- .changeset/thirty-birds-build.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.changeset/thirty-birds-build.md b/.changeset/thirty-birds-build.md index 54893f1bc..3bf269368 100644 --- a/.changeset/thirty-birds-build.md +++ b/.changeset/thirty-birds-build.md @@ -20,12 +20,10 @@ self.webpackChunk_N_E.push(...) ``` this indicates that an in-memory global collection of the webpack chunks is shared by all routes, -this combined with the fact that chunks can have their own module state this can easily cause routes -to conflict with each other at runtime. +this combined with the fact that chunks can have their own module state this can easily cause routes to conflict with each other at runtime. -So, in order to solve the above issue wrap every route function in a function wrapper which -accepts as parameters, thus overrides, the `self`, `globalThis` and `global` symbols. The symbols -are then to be resolved with proxies that redirect setters to route-scoped in-memory maps and +So, in order to solve the above issue, all route functions are wrapped in a function which accepts as parameters, thus overrides, the `self`, `globalThis` and `global` symbols. The symbols +will be resolved with proxies that redirect setters to route-scoped in-memory maps and getters to the above mentioned map's values and fallback to the original symbol values otherwise (i.e. `globalThis` will be overridden by a proxy that, when setting values, sets them in a separate location and, when getting values, gets them from said location if present there or from the real From f4428c2ad6ab0c149131b9065d798a8416d046a2 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 31 Jul 2024 22:32:39 +0100 Subject: [PATCH 05/25] fixup! implement route scoping solution update regex --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index fbbe824ec..0e31ff629 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -190,7 +190,7 @@ async function functionifyFileContent(path: string) { let fileContents = await readFile(path, 'utf8'); fileContents = `const namedExports = {};${fileContents}`; fileContents = fileContents.replace( - /export const (\S+) =/g, + /export\s+const\s+(\S+)\s*=/g, 'namedExports["$1"] =', ); fileContents = ` From eec1d6fbab9e7b123b2196a634039c8ece9d4b23 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 31 Jul 2024 22:35:08 +0100 Subject: [PATCH 06/25] fixup! implement route scoping solution use a single return statement instead of updating fileContents --- .../dedupeEdgeFunctions.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 0e31ff629..4c5403c42 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -187,19 +187,19 @@ async function processFunctionIdentifiers( * @returns the converted file content */ async function functionifyFileContent(path: string) { - let fileContents = await readFile(path, 'utf8'); - fileContents = `const namedExports = {};${fileContents}`; - fileContents = fileContents.replace( - /export\s+const\s+(\S+)\s*=/g, - 'namedExports["$1"] =', - ); - fileContents = ` + const originalFileContents = await readFile(path, 'utf8'); + return ` + const namedExports = {}; export const getNamedExports = ((self, globalThis, global) => { - ${fileContents}; + ${ + originalFileContents.replace( + /export\s+const\s+(\S+)\s*=/g, + 'namedExports["$1"] =', + ) + } return namedExports; }); `; - return fileContents; } /** From 435c53a8ee6f2ac2f77423d5790077b5b125c7ea Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 31 Jul 2024 22:36:18 +0100 Subject: [PATCH 07/25] fixup! implement route scoping solution add missing semicolon --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 4c5403c42..a8ddb00f4 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -233,7 +233,7 @@ async function buildFunctionFile( groupedImports.forEach((keys, path) => { if (path.endsWith('.wasm')) { // we don't need/want to apply any code transformation for wasm imports - functionImports += `import ${keys} from "${path}"`; + functionImports += `import ${keys} from "${path}";`; return; } From a09e7d8a9aa1b69d54dbf4d27ada6931c433bb2f Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 31 Jul 2024 22:37:49 +0100 Subject: [PATCH 08/25] fixup! implement route scoping solution avoid unnecessary spreading --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index a8ddb00f4..42c23dfe9 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -246,7 +246,7 @@ async function buildFunctionFile( ); const namedExportsId = `getNamedExports_${chunkMapIdx++}`; - chunksExportsMap.set(namedExportsId, new Set([...keys.split(',')])); + chunksExportsMap.set(namedExportsId, new Set(keys.split(','))); functionImports += `import { getNamedExports as ${namedExportsId} } from '${importPath}';\n`; }); From c1f56502fb518143aa468453f1efd8a2bcc1dc1a Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Wed, 31 Jul 2024 22:40:09 +0100 Subject: [PATCH 09/25] fixup! implement route scoping solution format code --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 42c23dfe9..8ea6f67ff 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -191,12 +191,10 @@ async function functionifyFileContent(path: string) { return ` const namedExports = {}; export const getNamedExports = ((self, globalThis, global) => { - ${ - originalFileContents.replace( - /export\s+const\s+(\S+)\s*=/g, - 'namedExports["$1"] =', - ) - } + ${originalFileContents.replace( + /export\s+const\s+(\S+)\s*=/g, + 'namedExports["$1"] =', + )} return namedExports; }); `; From 9a65f29aa810a28cf600f7c4cc2363e1b63a32d3 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 10:25:04 +0100 Subject: [PATCH 10/25] fixup! implement route scoping solution generalize regex --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 8ea6f67ff..54b190c33 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -296,7 +296,7 @@ function iffefyFunctionFile( // we have to update all such references otherwise our proxying won't take effect on those .replace(/([^.])_ENTRIES/g, '$1globalThis._ENTRIES') // the default export needs to become the return value of the iife, which is then re-exported as default - .replace(/export default /g, 'return ')} + .replace(/export\s+default\s+/g, 'return ')} })(proxy, proxy, proxy); `; From 8a3686154991c7adeb91dbb30a33a39c661a7313 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 10:45:07 +0100 Subject: [PATCH 11/25] fixup! implement route scoping solution improve buildFunctionFile code and make it more clear --- .../dedupeEdgeFunctions.ts | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 54b190c33..a4bdccb47 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -228,23 +228,27 @@ async function buildFunctionFile( let chunkMapIdx = 0; const chunksExportsMap = new Map>(); - groupedImports.forEach((keys, path) => { - if (path.endsWith('.wasm')) { - // we don't need/want to apply any code transformation for wasm imports - functionImports += `import ${keys} from "${path}";`; - return; - } + const relativeImportPath = getRelativePathToAncestor({ + from: newFnLocation, + relativeTo: nopDistDir, + }); - const relativeImportPath = getRelativePathToAncestor({ - from: newFnLocation, - relativeTo: nopDistDir, - }); + groupedImports.forEach((exports, path) => { const importPath = normalizePath( join(relativeImportPath, addLeadingSlash(path)), ); + if (path.endsWith('.wasm')) { + // if we're dealing with a wasm file there is a single default export to deal with + const defaultExport = exports; + // we don't need/want to apply any code transformation for wasm imports + functionImports += `import ${defaultExport} from "${path}";`; + return; + } + const namedExportsId = `getNamedExports_${chunkMapIdx++}`; - chunksExportsMap.set(namedExportsId, new Set(keys.split(','))); + const exportKeys = exports.split(','); + chunksExportsMap.set(namedExportsId, new Set(exportKeys)); functionImports += `import { getNamedExports as ${namedExportsId} } from '${importPath}';\n`; }); From d82a5585c6f24fe6bada024deafc03058773a194 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 10:48:00 +0100 Subject: [PATCH 12/25] fixup! implement route scoping solution add entries() --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index a4bdccb47..9e07343f1 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -308,11 +308,11 @@ function iffefyFunctionFile( fnInfo.route?.path ?? '' }');`; - const chunksExtraction = [...chunksExportsMap].flatMap( + const chunksExtraction = [...chunksExportsMap.entries()].flatMap( ([getNamedExportsId, keys]) => { return [ `const exportsOf${getNamedExportsId} = ${getNamedExportsId}(proxy, proxy, proxy);`, - ...[...keys].map( + ...[...keys.entries()].map( key => `const ${key} = exportsOf${getNamedExportsId}["${key}"]`, ), ]; From c064ecc0860c5ac9f78fc6db97bd9a95eec5c8f5 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 11:30:15 +0100 Subject: [PATCH 13/25] fixup! implement route scoping solution avoid string concatenation for functionImports --- .../dedupeEdgeFunctions.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 9e07343f1..a8015ec07 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -216,7 +216,7 @@ async function buildFunctionFile( { importsToPrepend }: { importsToPrepend: NewImportInfo[] }, { workerJsDir, nopDistDir }: ProcessVercelFunctionsOpts, ): Promise<{ buildPromise: Promise }> { - let functionImports = ''; + const functionImports: string[] = []; // Group the identifier imports by the keys for each path. const groupedImports = importsToPrepend.reduce((acc, { key, path }) => { @@ -242,14 +242,16 @@ async function buildFunctionFile( // if we're dealing with a wasm file there is a single default export to deal with const defaultExport = exports; // we don't need/want to apply any code transformation for wasm imports - functionImports += `import ${defaultExport} from "${path}";`; + functionImports.push(`import ${defaultExport} from "${path}"`); return; } const namedExportsId = `getNamedExports_${chunkMapIdx++}`; const exportKeys = exports.split(','); chunksExportsMap.set(namedExportsId, new Set(exportKeys)); - functionImports += `import { getNamedExports as ${namedExportsId} } from '${importPath}';\n`; + functionImports.push( + `import { getNamedExports as ${namedExportsId} } from '${importPath}'`, + ); }); fnInfo.outputPath = relative(workerJsDir, newFnPath); @@ -289,7 +291,7 @@ type BuildFunctionFileOpts = { */ function iffefyFunctionFile( fileContents: string, - functionImports: string, + functionImports: string[], fnInfo: FunctionInfo, chunksExportsMap: Map>, ): string { @@ -319,9 +321,12 @@ function iffefyFunctionFile( }, ); - return [functionImports, proxyCall, ...chunksExtraction, wrappedContent].join( - ';', - ); + return [ + ...functionImports, + proxyCall, + ...chunksExtraction, + wrappedContent, + ].join(';'); } /** From ceee48f8f68358062d035174339050896bbbc607 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 11:32:24 +0100 Subject: [PATCH 14/25] avoid string concatenation for warm function imports --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index a8015ec07..0d8220f78 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -350,7 +350,7 @@ async function prependWasmImportsToCodeBlocks( relativeTo: nopDistDir, }); - let functionImports = ''; + const functionImports: string[] = []; for (const identifier of wasmImports) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -358,11 +358,14 @@ async function prependWasmImportsToCodeBlocks( const wasmImportPath = normalizePath( join(relativeImportPath, newDest as string), ); - functionImports += `import ${identifier} from "${wasmImportPath}";\n`; + functionImports.push(`import ${identifier} from "${wasmImportPath}"`); } const oldContents = await readFile(filePath); - await writeFile(filePath, `${functionImports}${oldContents}`); + await writeFile( + filePath, + `${functionImports.join(';')};${oldContents}`, + ); }, ), ); From d6c149ed540f500bb231cfdb0fef2dfc7c389199 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 12:00:29 +0100 Subject: [PATCH 15/25] fixup! implement route scoping solution fix incorrect entries call --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 0d8220f78..261496092 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -314,7 +314,7 @@ function iffefyFunctionFile( ([getNamedExportsId, keys]) => { return [ `const exportsOf${getNamedExportsId} = ${getNamedExportsId}(proxy, proxy, proxy);`, - ...[...keys.entries()].map( + ...[...keys.keys()].map( key => `const ${key} = exportsOf${getNamedExportsId}["${key}"]`, ), ]; From b13338aebe83572a3e34a9cf9221e765afaf0547 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 17:23:58 +0100 Subject: [PATCH 16/25] fixup! implement route scoping solution avoid introducing named esm exports for then regex-replace them --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 261496092..6d8c9bf38 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -190,13 +190,7 @@ async function functionifyFileContent(path: string) { const originalFileContents = await readFile(path, 'utf8'); return ` const namedExports = {}; - export const getNamedExports = ((self, globalThis, global) => { - ${originalFileContents.replace( - /export\s+const\s+(\S+)\s*=/g, - 'namedExports["$1"] =', - )} - return namedExports; - }); + export const getNamedExports = ((self, globalThis, global) => { ${originalFileContents} return namedExports; }); `; } @@ -296,6 +290,11 @@ function iffefyFunctionFile( chunksExportsMap: Map>, ): string { const wrappedContent = ` + ${ + /* Note: we need to make sure that the namedExports object is defined since that is used inside the file contents instead + of standard ESM named exports */ '' + } + const namedExports = {}; export default ((self, globalThis, global) => { ${fileContents // it looks like there can be direct references to _ENTRIES (i.e. `_ENTRIES` instead of `globalThis._ENTRIES` etc...) @@ -497,7 +496,7 @@ async function processCodeBlockIdentifier( .forEach(key => wasmImports.push(key)); const buffer = Buffer.from( - `export const ${identifierKey} = ${codeBlock}\n`, + `namedExports["${identifierKey}"] = ${codeBlock}\n`, 'utf8', ); From a98cf6c343f0ac69c8c82c8595fb7fd984d8ceaf Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 17:24:50 +0100 Subject: [PATCH 17/25] fixup! implement route scoping solution fix typo --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 6d8c9bf38..f972ef34a 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -250,7 +250,7 @@ async function buildFunctionFile( fnInfo.outputPath = relative(workerJsDir, newFnPath); - const finalFileContents = iffefyFunctionFile( + const finalFileContents = iifefyFunctionFile( fileContents, functionImports, fnInfo, @@ -283,7 +283,7 @@ type BuildFunctionFileOpts = { * @param chunksExportsMap a map containing getters and chunks identifiers being used by the function * @returns the updated/iifefied file content */ -function iffefyFunctionFile( +function iifefyFunctionFile( fileContents: string, functionImports: string[], fnInfo: FunctionInfo, From 2ccf8cc0b72e7af3e03ce9718ff4800b0f462430 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 17:53:45 +0100 Subject: [PATCH 18/25] fixup! implement route scoping solution introduce namedExportsObjectName to make solution less ugly/brittle --- .../dedupeEdgeFunctions.ts | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index f972ef34a..0f195f78b 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -189,8 +189,11 @@ async function processFunctionIdentifiers( async function functionifyFileContent(path: string) { const originalFileContents = await readFile(path, 'utf8'); return ` - const namedExports = {}; - export const getNamedExports = ((self, globalThis, global) => { ${originalFileContents} return namedExports; }); + ${ + /* Note: we need to make sure that the named exports object is defined since that is used inside the file */ '' + } + const ${namedExportsObjectName} = {}; + export const getNamedExports = ((self, globalThis, global) => { ${originalFileContents} return ${namedExportsObjectName}; }); `; } @@ -291,10 +294,9 @@ function iifefyFunctionFile( ): string { const wrappedContent = ` ${ - /* Note: we need to make sure that the namedExports object is defined since that is used inside the file contents instead - of standard ESM named exports */ '' + /* Note: we need to make sure that the named exports object is defined since that is used inside the file */ '' } - const namedExports = {}; + const ${namedExportsObjectName} = {}; export default ((self, globalThis, global) => { ${fileContents // it looks like there can be direct references to _ENTRIES (i.e. `_ENTRIES` instead of `globalThis._ENTRIES` etc...) @@ -496,7 +498,7 @@ async function processCodeBlockIdentifier( .forEach(key => wasmImports.push(key)); const buffer = Buffer.from( - `namedExports["${identifierKey}"] = ${codeBlock}\n`, + `${namedExportsObjectName}["${identifierKey}"] = ${codeBlock}\n`, 'utf8', ); @@ -667,3 +669,25 @@ async function processBundledAssets( } } } + +/** + * When performing the various code tweaking we never introduce standard named ESM exports, since those would + * be invalid anyways since each js file content gets wrapped into a function anyways. + * + * Instead of standard named exports we simply set named exports onto an object which gets then returned by the + * file wrapper function. + * + * Example: + * when introducing a new export, instead of introducing: + * ``` + * export const a = ... + * ``` + * we introduce something like: + * ``` + * NAMED_EXPORTS_OBJECT["a"] = ... + * ``` + * and make sure that such object is always declared and returned by the function wrapping the file's contents. + * + * This is the name of the object used for such exports. + */ +const namedExportsObjectName = '__next-on-pages-named_exports_object__'; From ed5a72142ed31485abb306b99d66d786094ef33d Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 18:08:18 +0100 Subject: [PATCH 19/25] fixup! implement route scoping solution fix wrong namedExportsObjectName name --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 0f195f78b..d8b049eaa 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -690,4 +690,4 @@ async function processBundledAssets( * * This is the name of the object used for such exports. */ -const namedExportsObjectName = '__next-on-pages-named_exports_object__'; +const namedExportsObjectName = '__next_on_pages__named_exports_object__'; From 6c0951f8b468e0eaa808f9cb907bd6348214363e Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 18:12:14 +0100 Subject: [PATCH 20/25] fixup! implement route scoping solution update namedExportsObjectName name (for consistency) --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index d8b049eaa..0702e893d 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -690,4 +690,4 @@ async function processBundledAssets( * * This is the name of the object used for such exports. */ -const namedExportsObjectName = '__next_on_pages__named_exports_object__'; +const namedExportsObjectName = '__nextOnPagesNamedExportsObject'; From 3a79e892f98c85d67c8d34d0a6723c05522a7f1b Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 19:19:40 +0100 Subject: [PATCH 21/25] fixup! implement route scoping solution improve named exports solution a bit further --- .../dedupeEdgeFunctions.ts | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 0702e893d..d8989bf5e 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -193,7 +193,7 @@ async function functionifyFileContent(path: string) { /* Note: we need to make sure that the named exports object is defined since that is used inside the file */ '' } const ${namedExportsObjectName} = {}; - export const getNamedExports = ((self, globalThis, global) => { ${originalFileContents} return ${namedExportsObjectName}; }); + export const ${getNamedExportsFunctionName} = ((self, globalThis, global) => { ${originalFileContents} return ${namedExportsObjectName}; }); `; } @@ -243,11 +243,11 @@ async function buildFunctionFile( return; } - const namedExportsId = `getNamedExports_${chunkMapIdx++}`; + const getNamedExportsFunctionWithId = `${getNamedExportsFunctionName}_${chunkMapIdx++}`; const exportKeys = exports.split(','); - chunksExportsMap.set(namedExportsId, new Set(exportKeys)); + chunksExportsMap.set(getNamedExportsFunctionWithId, new Set(exportKeys)); functionImports.push( - `import { getNamedExports as ${namedExportsId} } from '${importPath}'`, + `import { ${getNamedExportsFunctionName} as ${getNamedExportsFunctionWithId} } from '${importPath}'`, ); }); @@ -293,10 +293,6 @@ function iifefyFunctionFile( chunksExportsMap: Map>, ): string { const wrappedContent = ` - ${ - /* Note: we need to make sure that the named exports object is defined since that is used inside the file */ '' - } - const ${namedExportsObjectName} = {}; export default ((self, globalThis, global) => { ${fileContents // it looks like there can be direct references to _ENTRIES (i.e. `_ENTRIES` instead of `globalThis._ENTRIES` etc...) @@ -312,11 +308,12 @@ function iifefyFunctionFile( }');`; const chunksExtraction = [...chunksExportsMap.entries()].flatMap( - ([getNamedExportsId, keys]) => { + ([getNamedExportsFunctionWithId, keys]) => { + const namedExportsObjectWithId = `__exportsOf${getNamedExportsFunctionWithId}`; return [ - `const exportsOf${getNamedExportsId} = ${getNamedExportsId}(proxy, proxy, proxy);`, + `const ${namedExportsObjectWithId} = ${getNamedExportsFunctionWithId}(proxy, proxy, proxy);`, ...[...keys.keys()].map( - key => `const ${key} = exportsOf${getNamedExportsId}["${key}"]`, + key => `const ${key} = ${namedExportsObjectWithId}["${key}"]`, ), ]; }, @@ -674,9 +671,13 @@ async function processBundledAssets( * When performing the various code tweaking we never introduce standard named ESM exports, since those would * be invalid anyways since each js file content gets wrapped into a function anyways. * + * Note: route function files don't have named exports to this is only needed for the other files such + * as the manifest ones and the webpack chunks ones + * * Instead of standard named exports we simply set named exports onto an object which gets then returned by the * file wrapper function. * + * * Example: * when introducing a new export, instead of introducing: * ``` @@ -690,4 +691,18 @@ async function processBundledAssets( * * This is the name of the object used for such exports. */ -const namedExportsObjectName = '__nextOnPagesNamedExportsObject'; +const namedExportsObjectName = '__namedExportsObject'; + +/** + * The strategy of exporting exports via an returned object relies on the fact that there is a function that returns such object. + * + * Example: + * ``` + * import { __getNamedExports } from '...'; + * const obj = __getNamedExports(...); + * // obj contains the various exports as standard object properties + * ``` + * + * This is the name of such function. + */ +const getNamedExportsFunctionName = '__getNamedExports'; From e2ff7d64751a9bf8ef61bba733e8b54d0de6190e Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Thu, 1 Aug 2024 23:50:56 +0100 Subject: [PATCH 22/25] add missing ts-nocheck comment to e2e custom-entrypoint --- pages-e2e/features/customEntrypoint/assets/custom-entrypoint.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/pages-e2e/features/customEntrypoint/assets/custom-entrypoint.ts b/pages-e2e/features/customEntrypoint/assets/custom-entrypoint.ts index 991dfa56a..3884220a9 100644 --- a/pages-e2e/features/customEntrypoint/assets/custom-entrypoint.ts +++ b/pages-e2e/features/customEntrypoint/assets/custom-entrypoint.ts @@ -1,3 +1,4 @@ +//@ts-nocheck import nextOnPagesHandler from '@cloudflare/next-on-pages/fetch-handler'; export default { From b37bce2686d0cd1ced18176addc1ef238b7a1760 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 2 Aug 2024 10:36:46 +0100 Subject: [PATCH 23/25] fixup! implement route scoping solution make sure solution works with older versions of the Vercel CLI --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index d8989bf5e..5e572ecda 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -297,7 +297,10 @@ function iifefyFunctionFile( ${fileContents // it looks like there can be direct references to _ENTRIES (i.e. `_ENTRIES` instead of `globalThis._ENTRIES` etc...) // we have to update all such references otherwise our proxying won't take effect on those - .replace(/([^.])_ENTRIES/g, '$1globalThis._ENTRIES') + // (note: older versions of the Vercel CLI (v31 and older) used to declare _ENTRIES as "let _ENTRIES = {};", so we do + // need to make sure that we don't add `globalThis.` in these cases (if we were to drop support for those older versions + // the below line to: ".replace(/([^.])_ENTRIES/g, '$1globalThis._ENTRIES')") + .replace(/(? Date: Fri, 2 Aug 2024 12:11:07 +0100 Subject: [PATCH 24/25] fixup! implement route scoping solution use more consistent param names --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index 5e572ecda..d1f91bd0d 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -282,14 +282,14 @@ type BuildFunctionFileOpts = { * * @param fileContents the function file's contents * @param functionImports the imports that need to be added to the file - * @param fnInfo the function's information + * @param functionInfo the function's information * @param chunksExportsMap a map containing getters and chunks identifiers being used by the function * @returns the updated/iifefied file content */ function iifefyFunctionFile( fileContents: string, functionImports: string[], - fnInfo: FunctionInfo, + functionInfo: FunctionInfo, chunksExportsMap: Map>, ): string { const wrappedContent = ` @@ -307,7 +307,7 @@ function iifefyFunctionFile( `; const proxyCall = `const proxy = globalThis.__nextOnPagesRoutesIsolation.getProxyFor('${ - fnInfo.route?.path ?? '' + functionInfo.route?.path ?? '' }');`; const chunksExtraction = [...chunksExportsMap.entries()].flatMap( From ca1ab060623fc512a158f41b6daae4e9b4c047d8 Mon Sep 17 00:00:00 2001 From: Dario Piotrowicz Date: Fri, 2 Aug 2024 12:16:45 +0100 Subject: [PATCH 25/25] fixup! implement route scoping solution join using newlines instead of semicolons --- .../processVercelFunctions/dedupeEdgeFunctions.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts index d1f91bd0d..5a9721c6c 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/dedupeEdgeFunctions.ts @@ -239,7 +239,7 @@ async function buildFunctionFile( // if we're dealing with a wasm file there is a single default export to deal with const defaultExport = exports; // we don't need/want to apply any code transformation for wasm imports - functionImports.push(`import ${defaultExport} from "${path}"`); + functionImports.push(`import ${defaultExport} from '${path}';`); return; } @@ -247,7 +247,7 @@ async function buildFunctionFile( const exportKeys = exports.split(','); chunksExportsMap.set(getNamedExportsFunctionWithId, new Set(exportKeys)); functionImports.push( - `import { ${getNamedExportsFunctionName} as ${getNamedExportsFunctionWithId} } from '${importPath}'`, + `import { ${getNamedExportsFunctionName} as ${getNamedExportsFunctionWithId} } from '${importPath}';`, ); }); @@ -316,7 +316,7 @@ function iifefyFunctionFile( return [ `const ${namedExportsObjectWithId} = ${getNamedExportsFunctionWithId}(proxy, proxy, proxy);`, ...[...keys.keys()].map( - key => `const ${key} = ${namedExportsObjectWithId}["${key}"]`, + key => `const ${key} = ${namedExportsObjectWithId}["${key}"];`, ), ]; }, @@ -327,7 +327,7 @@ function iifefyFunctionFile( proxyCall, ...chunksExtraction, wrappedContent, - ].join(';'); + ].join('\n'); } /**