8000 ref(nextjs): Use resolved paths for `require` calls in config code (#… · callumgare/sentry-javascript@7fb0c2a · GitHub
[go: up one dir, main page]

Skip to content

Commit 7fb0c2a

Browse files
authored
ref(nextjs): Use resolved paths for require calls in config code (getsentry#3426)
Currently, we use relative paths for the `require` calls in `syncPluginVersionWithNextVersion`. Though this works most of the time, it depends on the particular structure of the user's `node_modules` directory, which is mostly predictable but not guaranteed. This PR therefore switches to using a combination of `require.resolve` and a recursive search up the file hierarchy to find the `package.json` files we need. Fixes getsentry#3424. Fixes getsentry#3430.
1 parent 7b1c9f1 commit 7fb0c2a

File tree

2 files changed

+62
-16
lines changed

2 files changed

+62
-16
lines changed

packages/next-plugin-sentry/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"engines": {
1010
"node": ">=6"
1111
},
12-
"main": "index.js",
12+
"main": "./src/on-init-server.js",
1313
"publishConfig": {
1414
"access": "public"
1515
},

packages/nextjs/src/utils/config.ts

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,44 @@
1+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2+
/* eslint-disable @typescript-eslint/no-var-requires */
13
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
// import { version as nextVersion } from './node_modules/next/package.json';
34
import { getSentryRelease } from '@sentry/node';
45
import { logger } from '@sentry/utils';
56
import defaultWebpackPlugin, { SentryCliPluginOptions } from '@sentry/webpack-plugin';
67
import * as SentryWebpackPlugin from '@sentry/webpack-plugin';
78
import * as fs from 'fs';
9+
import * as path from 'path';
10+
11+
/**
12+
* Starting at `startPath`, move up one directory at a time, searching for `searchFile`.
13+
*
14+
* @param startPath The location from which to start the search.
15+
* @param searchFile The file to search for
16+
* @returns The absolute path of the file, if it's found, or undefined if it's not
17+
*/
18+
function findUp(startPath: string, searchFile: string): string | undefined {
19+
if (!fs.existsSync(startPath)) {
20+
throw new Error(`The given \`startPath\` value (${startPath}) does not exist.`);
21+
}
22+
23+
// if the last segment of `startPath` is a file, trim it off so that we start looking in its parent directory
24+
let currentDir = fs.statSync(startPath).isFile() ? path.dirname(startPath) : startPath;
25+
// eslint-disable-next-line no-constant-condition
26+
while (true) {
27+
const possiblePath = path.join(currentDir, searchFile);
28+
if (fs.existsSync(possiblePath)) {
29+
return possiblePath;
30+
}
31+
32+
const parentDir = path.resolve(currentDir, '..');
33+
// this means we've gotten to the root
34+
if (currentDir === parentDir) {
35+
break;
36+
}
37+
currentDir = parentDir;
38+
}
39+
40+
return undefined;
41+
}
842

943
/**
1044
* Next requires that plugins be tagged with the same version number as the currently-running `next.js` package, so
@@ -14,27 +48,39 @@ export function syncPluginVersionWithNextVersion(): void {
1448
// TODO Once we get at least to TS 2.9, we can use `"resolveJsonModule": true` in our `compilerOptions` and we'll be
1549
// able to do:
1650
// import { version as nextVersion } from './node_modules/next/package.json';
51+
let nextVersion;
1752

18-
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
19-
const nextVersion = (require('../../../../next/package.json') as any).version;
20-
if (!nextVersion) {
21-
logger.error('[next-plugin-sentry] Cannot read next.js version. Plug-in will not work.');
53+
try {
54+
// `require.resolve` returns the location of the packages `"main"` entry point, as specified in its `package.json`
55+
const nextResolvedMain = require.resolve('next');
56+
// since we don't know where in the package's directory that entry point is, search upward until we find a folder
57+
// containing `package.json`
58+
const nextPackageJsonPath = findUp(nextResolvedMain, 'package.json');
59+
nextVersion = nextPackageJsonPath && (require(nextPackageJsonPath) as { version: string }).version;
60+
} catch (err) {
61+
// eslint-disable-next-line no-console
62+
console.error(`[next-plugin-sentry] Cannot read next.js version. Plug-in will not work.\nReceived error: ${err}`);
2263
return;
2364
}
2465

25-
const pluginPackageDotJsonPath = `../../../next-plugin-sentry/package.json`;
26-
// eslint-disable-next-line @typescript-eslint/no-var-requires
27-
const pluginPackageDotJson = require(pluginPackageDotJsonPath); // see TODO above
28-
if (!pluginPackageDotJson) {
29-
logger.error(`[next-plugin-sentry] Cannot read ${pluginPackageDotJsonPath}. Plug-in will not work.`);
66+
let pluginPackageJsonPath, pluginPackageJson;
67+
68+
try {
69+
const pluginResolvedMain = require.resolve('@sentry/next-plugin-sentry');
70+
// see notes above about why we need to call `findUp`
71+
pluginPackageJsonPath = findUp(pluginResolvedMain, 'package.json');
72+
pluginPackageJson = pluginPackageJsonPath && require(pluginPackageJsonPath);
73+
} catch (err) {
74+
// eslint-disable-next-line no-console
75+
console.error(
76+
`[next-plugin-sentry] Cannot find \`@sentry/next-plugin-sentry\`. Plug-in will not work. ` +
77+
`Please try reinstalling \`@sentry/nextjs\`.\nReceived error: ${err}`,
78+
);
3079
return;
3180
}
3281

33-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
34-
(pluginPackageDotJson as any).version = nextVersion;
35-
// interestingly, the `require` calls above seem to resolve from a different starting point than `fs` does here, which
36-
// is why we can't just use `pluginPackageDotJsonPath` again
37-
fs.writeFileSync('./node_modules/@sentry/next-plugin-sentry/package.json', JSON.stringify(pluginPackageDotJson));
82+
(pluginPackageJson as { version: string }).version = nextVersion!;
83+
fs.writeFileSync(pluginPackageJsonPath!, JSON.stringify(pluginPackageJson));
3884
}
3985

4086
type WebpackConfig = { devtool: string; plugins: Array<{ [key: string]: any }> };

0 commit comments

Comments
 (0)
0