From 8dbdcd79277f1f512c6667a09ec32e771de3712e Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Thu, 16 Nov 2023 12:41:18 +0000 Subject: [PATCH] fix(nextjs): Download CLI binary if it can't be found --- packages/nextjs/package.json | 2 +- packages/nextjs/src/config/webpack.ts | 93 ++++++++++++++++++++------- yarn.lock | 41 +++++++++--- 3 files changed, 100 insertions(+), 36 deletions(-) diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 3bd99545e353..730134ce4351 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -32,7 +32,7 @@ "@sentry/types": "7.80.1", "@sentry/utils": "7.80.1", "@sentry/vercel-edge": "7.80.1", - "@sentry/webpack-plugin": "1.20.0", + "@sentry/webpack-plugin": "1.21.0", "chalk": "3.0.0", "resolve": "1.22.8", "rollup": "2.78.0", diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index c3ff833a4e4c..5816c0bf058c 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -7,6 +7,7 @@ import * as chalk from 'chalk'; import * as fs from 'fs'; import * as path from 'path'; import { sync as resolveSync } from 'resolve'; +import type { Compiler } from 'webpack'; 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 @@ -22,6 +23,7 @@ import type { WebpackConfigObjectWithModuleRules, WebpackEntryProperty, WebpackModuleRule, + WebpackPluginInstance, } from './types'; const RUNTIME_TO_SDK_ENTRYPOINT_MAP = { @@ -35,8 +37,8 @@ const RUNTIME_TO_SDK_ENTRYPOINT_MAP = { let showedMissingAuthTokenErrorMsg = false; let showedMissingOrgSlugErrorMsg = false; let showedMissingProjectSlugErrorMsg = false; -let showedMissingCLiBinaryErrorMsg = false; let showedHiddenSourceMapsWarningMsg = false; +let showedMissingCliBinaryWarningMsg = false; // TODO: merge default SentryWebpackPlugin ignore with their SentryWebpackPlugin ignore or ignoreFile // TODO: merge default SentryWebpackPlugin include with their SentryWebpackPlugin include @@ -376,6 +378,7 @@ export function constructWebpackConfigFunction( const SentryWebpackPlugin = loadModule('@sentry/webpack-plugin'); if (SentryWebpackPlugin) { newConfig.plugins = newConfig.plugins || []; + newConfig.plugins.push(new SentryCliDownloadPlugin()); newConfig.plugins.push( // @ts-expect-error - this exists, the dynamic import just doesn't know about it new SentryWebpackPlugin( @@ -739,6 +742,19 @@ export function getWebpackPluginOptions( if (err) { const errorMessagePrefix = `${chalk.red('error')} -`; + if (err.message.includes('ENOENT')) { + if (!showedMissingCliBinaryWarningMsg) { + // eslint-disable-next-line no-console + console.error( + `\n${errorMessagePrefix} ${chalk.bold( + 'The Sentry binary to upload sourcemaps could not be found.', + )} Source maps will not be uploaded. Please check that post-install scripts are enabled in your package manager when installing your dependencies and please run your build once without any caching to avoid caching issues of dependencies.\n`, + ); + showedMissingCliBinaryWarningMsg = true; + } + return; + } + // Hardcoded way to check for missing auth token until we have a better way of doing this. if (err.message.includes('Authentication credentials were not provided.')) { let msg; @@ -835,30 +851,6 @@ function shouldEnableWebpackPlugin(buildContext: BuildContext, userSentryOptions const { isServer } = buildContext; const { disableServerWebpackPlugin, disableClientWebpackPlugin } = userSentryOptions; - /** Non-negotiable */ - - // This check is necessary because currently, `@sentry/cli` uses a post-install script to download an - // architecture-specific version of the `sentry-cli` binary. If `yarn install`, `npm install`, or `npm ci` are run - // with the `--ignore-scripts` option, this will be blocked and the missing binary will cause an error when users - // try to build their apps. - const SentryWebpackPlugin = loadModule('@sentry/webpack-plugin'); - - // @ts-expect-error - this exists, the dynamic import just doesn't know it - if (!SentryWebpackPlugin || !SentryWebpackPlugin.cliBinaryExists()) { - if (!showedMissingCLiBinaryErrorMsg) { - // eslint-disable-next-line no-console - console.error( - `${chalk.red('error')} - ${chalk.bold( - 'Sentry CLI binary not found.', - )} Source maps will not be uploaded. Please check that postinstall scripts are enabled in your package manager when installing your dependencies and please run your build once without any caching to avoid caching issues of dependencies.\n`, - ); - showedMissingCLiBinaryErrorMsg = true; - } - return false; - } - - /** User override */ - if (isServer && disableServerWebpackPlugin !== undefined) { return !disableServerWebpackPlugin; } else if (!isServer && disableClientWebpackPlugin !== undefined) { @@ -1047,3 +1039,54 @@ function getRequestAsyncStorageModuleLocation( return undefined; } + +let downloadingCliAttempted = false; + +class SentryCliDownloadPlugin implements WebpackPluginInstance { + public apply(compiler: Compiler): void { + compiler.hooks.beforeRun.tapAsync('SentryCliDownloadPlugin', (compiler, callback) => { + const SentryWebpackPlugin = loadModule('@sentry/webpack-plugin'); + if (!SentryWebpackPlugin) { + // Pretty much an invariant. + return callback(); + } + + // @ts-expect-error - this exists, the dynamic import just doesn't know it + if (SentryWebpackPlugin.cliBinaryExists()) { + return callback(); + } + + if (!downloadingCliAttempted) { + downloadingCliAttempted = true; + // eslint-disable-next-line no-console + console.log( + `\n${chalk.cyan('info')} - ${chalk.bold( + 'Sentry binary to upload source maps not found.', + )} Package manager post-install scripts are likely disabled or there is a caching issue. Manually downloading instead...`, + ); + + // @ts-expect-error - this exists, the dynamic import just doesn't know it + const cliDownloadPromise: Promise = SentryWebpackPlugin.downloadCliBinary({ + log: () => { + // No logs from directly from CLI + }, + }); + + cliDownloadPromise.then( + () => { + // eslint-disable-next-line no-console + console.log(`${chalk.cyan('info')} - Sentry binary was successfully downloaded.\n`); + return callback(); + }, + e => { + // eslint-disable-next-line no-console + console.error(`${chalk.red('error')} - Sentry binary download failed:`, e); + return callback(); + }, + ); + } else { + return callback(); + } + }); + } +} diff --git a/yarn.lock b/yarn.lock index 1ee62d9e6a00..d32acb0b89ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5067,7 +5067,7 @@ magic-string "0.27.0" unplugin "1.0.1" -"@sentry/cli@^1.74.4", "@sentry/cli@^1.74.6": +"@sentry/cli@^1.74.4": version "1.74.6" resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.74.6.tgz#c4f276e52c6f5e8c8d692845a965988068ebc6f5" integrity sha512-pJ7JJgozyjKZSTjOGi86chIngZMLUlYt2HOog+OJn+WGvqEkVymu8m462j1DiXAnex9NspB4zLLNuZ/R6rTQHg== @@ -5080,6 +5080,18 @@ proxy-from-env "^1.1.0" which "^2.0.2" +"@sentry/cli@^1.77.1": + version "1.77.1" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.77.1.tgz#ebcf884712ef6c3c75443f491ec16f6a22148aec" + integrity sha512-OtJ7U9LeuPUAY/xow9wwcjM9w42IJIpDtClTKI/RliE685vd/OJUIpiAvebHNthDYpQynvwb/0iuF4fonh+CKw== + dependencies: + https-proxy-agent "^5.0.0" + mkdirp "^0.5.5" + node-fetch "^2.6.7" + progress "^2.0.3" + proxy-from-env "^1.1.0" + which "^2.0.2" + "@sentry/cli@^2.17.0": version "2.17.0" resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.17.0.tgz#fc809ecd721eb5323502625fa904b786af28ad89" @@ -5124,12 +5136,12 @@ dependencies: "@sentry/cli" "^1.74.4" -"@sentry/webpack-plugin@1.20.0": - version "1.20.0" - resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.20.0.tgz#e7add76122708fb6b4ee7951294b521019720e58" - integrity sha512-Ssj1mJVFsfU6vMCOM2d+h+KQR7QHSfeIP16t4l20Uq/neqWXZUQ2yvQfe4S3BjdbJXz/X4Rw8Hfy1Sd0ocunYw== +"@sentry/webpack-plugin@1.21.0": + version "1.21.0" + resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.21.0.tgz#bbe7cb293751f80246a4a56f9a7dd6de00f14b58" + integrity sha512-x0PYIMWcsTauqxgl7vWUY6sANl+XGKtx7DCVnnY7aOIIlIna0jChTAPANTfA2QrK+VK+4I/4JxatCEZBnXh3Og== dependencies: - "@sentry/cli" "^1.74.6" + "@sentry/cli" "^1.77.1" webpack-sources "^2.0.0 || ^3.0.0" "@sideway/address@^4.1.3": @@ -8290,10 +8302,10 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios@1.3.4, axios@^1.2.2: - version "1.3.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" - integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ== +axios@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -8316,6 +8328,15 @@ axios@^1.0.0: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^1.2.2: + version "1.3.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" + integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + b4a@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9"