From 01b3f3a290527e6dae8be4f3d7c6c251859f9c81 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Wed, 21 Apr 2021 19:45:48 -0700 Subject: [PATCH 1/3] make plugin findable by require.resolve() --- packages/next-plugin-sentry/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json index e0482f6d81e1..f2046e1ecfa7 100644 --- a/packages/next-plugin-sentry/package.json +++ b/packages/next-plugin-sentry/package.json @@ -9,7 +9,7 @@ "engines": { "node": ">=6" }, - "main": "index.js", + "main": "./src/on-init-server.js", "publishConfig": { "access": "public" }, From 79ca8644c3b8012c4ced3a83470ff3b8676a972c Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Wed, 21 Apr 2021 19:46:29 -0700 Subject: [PATCH 2/3] use require.resolve() plus upward search to find relevant files --- packages/nextjs/src/utils/config.ts | 69 ++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/packages/nextjs/src/utils/config.ts b/packages/nextjs/src/utils/config.ts index 34631addb913..0615990eae04 100644 --- a/packages/nextjs/src/utils/config.ts +++ b/packages/nextjs/src/utils/config.ts @@ -1,10 +1,37 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-explicit-any */ -// import { version as nextVersion } from './node_modules/next/package.json'; import { getSentryRelease } from '@sentry/node'; import { logger } from '@sentry/utils'; import defaultWebpackPlugin, { SentryCliPluginOptions } from '@sentry/webpack-plugin'; import * as SentryWebpackPlugin from '@sentry/webpack-plugin'; import * as fs from 'fs'; +import * as path from 'path'; + +/** + * Starting at `startPath`, move up one directory at a time, searching for `searchFile`. + * + * @param startPath The location from which to start the search. + * @param searchFile The file to search for + * @returns The absolute path of the file, if it's found, or undefined if it's not. + */ +function findUp(startPath: string, searchFile: string): string | undefined { + if (!fs.existsSync(startPath)) { + throw new Error(`The given \`startPath\` value (${startPath}) does not exist.`); + } + + let currentDir = fs.statSync(startPath).isFile() ? path.dirname(startPath) : startPath; + while (currentDir !== '/') { + const possiblePath = path.join(currentDir, searchFile); + if (fs.existsSync(possiblePath)) { + return possiblePath; + } + + currentDir = path.join(currentDir, '..'); + } + + return undefined; +} /** * Next requires that plugins be tagged with the same version number as the currently-running `next.js` package, so @@ -14,27 +41,39 @@ export function syncPluginVersionWithNextVersion(): void { // TODO Once we get at least to TS 2.9, we can use `"resolveJsonModule": true` in our `compilerOptions` and we'll be // able to do: // import { version as nextVersion } from './node_modules/next/package.json'; + let nextVersion; - // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access - const nextVersion = (require('../../../../next/package.json') as any).version; - if (!nextVersion) { - logger.error('[next-plugin-sentry] Cannot read next.js version. Plug-in will not work.'); + try { + // `require.resolve` returns the location of the packages `"main"` entry point, as specified in its `package.json` + const nextResolvedMain = require.resolve('next'); + // since we don't know where in the package's directory that entry point is, search upward until we find a folder + // containing `package.json` + const nextPackageJsonPath = findUp(nextResolvedMain, 'package.json'); + nextVersion = nextPackageJsonPath && (require(nextPackageJsonPath) as { version: string }).version; + } catch (err) { + // eslint-disable-next-line no-console + console.error(`[next-plugin-sentry] Cannot read next.js version. Plug-in will not work.\nReceived error: ${err}`); return; } - const pluginPackageDotJsonPath = `../../../next-plugin-sentry/package.json`; - // eslint-disable-next-line @typescript-eslint/no-var-requires - const pluginPackageDotJson = require(pluginPackageDotJsonPath); // see TODO above - if (!pluginPackageDotJson) { - logger.error(`[next-plugin-sentry] Cannot read ${pluginPackageDotJsonPath}. Plug-in will not work.`); + let pluginPackageJsonPath, pluginPackageJson; + + try { + const pluginResolvedMain = require.resolve('@sentry/next-plugin-sentry'); + // see notes above about why we need to call `findUp` + pluginPackageJsonPath = findUp(pluginResolvedMain, 'package.json'); + pluginPackageJson = pluginPackageJsonPath && require(pluginPackageJsonPath); + } catch (err) { + // eslint-disable-next-line no-console + console.error( + `[next-plugin-sentry] Cannot find \`@sentry/next-plugin-sentry\`. Plug-in will not work. ` + + `Please try reinstalling \`@sentry/nextjs\`.\nReceived error: ${err}`, + ); return; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - (pluginPackageDotJson as any).version = nextVersion; - // interestingly, the `require` calls above seem to resolve from a different starting point than `fs` does here, which - // is why we can't just use `pluginPackageDotJsonPath` again - fs.writeFileSync('./node_modules/@sentry/next-plugin-sentry/package.json', JSON.stringify(pluginPackageDotJson)); + (pluginPackageJson as { version: string }).version = nextVersion!; + fs.writeFileSync(pluginPackageJsonPath!, JSON.stringify(pluginPackageJson)); } type WebpackConfig = { devtool: string; plugins: Array<{ [key: string]: any }> }; From 23a0684399842aa72f016649cfbea7261431b4e4 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Thu, 22 Apr 2021 08:55:55 -0700 Subject: [PATCH 3/3] change condition for breaking while loop --- packages/nextjs/src/utils/config.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/nextjs/src/utils/config.ts b/packages/nextjs/src/utils/config.ts index 0615990eae04..6d596d435eb6 100644 --- a/packages/nextjs/src/utils/config.ts +++ b/packages/nextjs/src/utils/config.ts @@ -13,21 +13,28 @@ import * as path from 'path'; * * @param startPath The location from which to start the search. * @param searchFile The file to search for - * @returns The absolute path of the file, if it's found, or undefined if it's not. + * @returns The absolute path of the file, if it's found, or undefined if it's not */ function findUp(startPath: string, searchFile: string): string | undefined { if (!fs.existsSync(startPath)) { throw new Error(`The given \`startPath\` value (${startPath}) does not exist.`); } + // if the last segment of `startPath` is a file, trim it off so that we start looking in its parent directory let currentDir = fs.statSync(startPath).isFile() ? path.dirname(startPath) : startPath; - while (currentDir !== '/') { + // eslint-disable-next-line no-constant-condition + while (true) { const possiblePath = path.join(currentDir, searchFile); if (fs.existsSync(possiblePath)) { return possiblePath; } - currentDir = path.join(currentDir, '..'); + const parentDir = path.resolve(currentDir, '..'); + // this means we've gotten to the root + if (currentDir === parentDir) { + break; + } + currentDir = parentDir; } return undefined;