From 6b0e33f93cc299c0e36d8fa8c0e734487b539d83 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 16 Oct 2023 11:47:01 +0000 Subject: [PATCH] fix(nextjs): Fix resolution of request async storage module --- packages/nextjs/package.json | 2 + packages/nextjs/src/config/webpack.ts | 66 ++++++++++++++++----------- yarn.lock | 11 ++++- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 13237cb5d69d..0aef2f1e380a 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -34,11 +34,13 @@ "@sentry/vercel-edge": "7.74.0", "@sentry/webpack-plugin": "1.20.0", "chalk": "3.0.0", + "resolve": "1.22.8", "rollup": "2.78.0", "stacktrace-parser": "^0.1.10", "tslib": "^2.4.1 || ^1.9.3" }, "devDependencies": { + "@types/resolve": "1.20.3", "@types/webpack": "^4.41.31", "eslint-plugin-react": "^7.31.11", "next": "10.1.3" diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index ffe7091fa74a..9197441410ac 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -6,6 +6,7 @@ import type SentryCliPlugin from '@sentry/webpack-plugin'; import * as chalk from 'chalk'; import * as fs from 'fs'; import * as path from 'path'; +import { sync as resolveSync } from 'resolve'; import type { VercelCronsConfig } from '../common/types'; // Note: If you need to import a type from Webpack, do it in `types.ts` and export it from there. Otherwise, our @@ -126,7 +127,10 @@ export function constructWebpackConfigFunction( pageExtensionRegex, excludeServerRoutes: userSentryOptions.excludeServerRoutes, sentryConfigFilePath: getUserConfigFilePath(projectDir, runtime), - nextjsRequestAsyncStorageModulePath: getRequestAsyncStorageModuleLocation(rawNewConfig.resolve?.modules), + nextjsRequestAsyncStorageModulePath: getRequestAsyncStorageModuleLocation( + projectDir, + rawNewConfig.resolve?.modules, + ), }; const normalizeLoaderResourcePath = (resourcePath: string): string => { @@ -977,39 +981,47 @@ function addValueInjectionLoader( ); } +function resolveNextPackageDirFromDirectory(basedir: string): string | undefined { + try { + return path.dirname(resolveSync('next/package.json', { basedir })); + } catch { + // Should not happen in theory + return undefined; + } +} + +const POTENTIAL_REQUEST_ASNYC_STORAGE_LOCATIONS = [ + // Original location of RequestAsyncStorage + // https://github.com/vercel/next.js/blob/46151dd68b417e7850146d00354f89930d10b43b/packages/next/src/client/components/request-async-storage.ts + 'next/dist/client/components/request-async-storage.js', + // Introduced in Next.js 13.4.20 + // https://github.com/vercel/next.js/blob/e1bc270830f2fc2df3542d4ef4c61b916c802df3/packages/next/src/client/components/request-async-storage.external.ts + 'next/dist/client/components/request-async-storage.external.js', +]; + function getRequestAsyncStorageModuleLocation( + webpackContextDir: string, webpackResolvableModuleLocations: string[] | undefined, ): string | undefined { if (webpackResolvableModuleLocations === undefined) { return undefined; } - const absoluteWebpackResolvableModuleLocations = webpackResolvableModuleLocations.map(m => path.resolve(m)); - const moduleIsWebpackResolvable = (moduleId: string): boolean => { - let requireResolveLocation: string; - try { - // This will throw if the location is not resolvable at all. - // We provide a `paths` filter in order to maximally limit the potential locations to the locations webpack would check. - requireResolveLocation = require.resolve(moduleId, { paths: webpackResolvableModuleLocations }); - } catch { - return false; - } - - // Since the require.resolve approach still looks in "global" node_modules locations like for example "/user/lib/node" - // we further need to filter by locations that start with the locations that webpack would check for. - return absoluteWebpackResolvableModuleLocations.some(resolvableModuleLocation => - requireResolveLocation.startsWith(resolvableModuleLocation), - ); - }; + const absoluteWebpackResolvableModuleLocations = webpackResolvableModuleLocations.map(loc => + path.resolve(webpackContextDir, loc), + ); - const potentialRequestAsyncStorageLocations = [ - // Original location of RequestAsyncStorage - // https://github.com/vercel/next.js/blob/46151dd68b417e7850146d00354f89930d10b43b/packages/next/src/client/components/request-async-storage.ts - 'next/dist/client/components/request-async-storage', - // Introduced in Next.js 13.4.20 - // https://github.com/vercel/next.js/blob/e1bc270830f2fc2df3542d4ef4c61b916c802df3/packages/next/src/client/components/request-async-storage.external.ts - 'next/dist/client/components/request-async-storage.external', - ]; + for (const webpackResolvableLocations of absoluteWebpackResolvableModuleLocations) { + const nextPackageDir = resolveNextPackageDirFromDirectory(webpackResolvableLocations); + if (nextPackageDir) { + const asyncLocalStorageLocation = POTENTIAL_REQUEST_ASNYC_STORAGE_LOCATIONS.find(loc => + fs.existsSync(path.join(nextPackageDir, '..', loc)), + ); + if (asyncLocalStorageLocation) { + return asyncLocalStorageLocation; + } + } + } - return potentialRequestAsyncStorageLocations.find(potentialLocation => moduleIsWebpackResolvable(potentialLocation)); + return undefined; } diff --git a/yarn.lock b/yarn.lock index f64756e09026..6ec29667d394 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6206,7 +6206,7 @@ dependencies: "@types/node" "*" -"@types/resolve@^1.17.0": +"@types/resolve@1.20.3", "@types/resolve@^1.17.0": version "1.20.3" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.3.tgz#066742d69a0bbba8c5d7d517f82e1140ddeb3c3c" integrity sha512-NH5oErHOtHZYcjCtg69t26aXEk4BN2zLWqf7wnDZ+dpe0iR7Rds1SPGEItl3fca21oOe0n3OCnZ4W7jBxu7FOw== @@ -26364,6 +26364,15 @@ resolve@1.20.0: is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@1.22.8: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"