@sentry/nextjs
Version:
Official Sentry SDK for Next.js
576 lines (573 loc) • 27.1 kB
JavaScript
import { escapeStringForRegex, parseSemver, loadModule, debug } from '@sentry/core';
import * as fs from 'fs';
import { createRequire } from 'module';
import * as path from 'path';
import { normalizePathForGlob, getBuildPluginOptions } from './getBuildPluginOptions.js';
import { sentryOrchestrionWebpackPlugin } from '@sentry/server-utils/orchestrion/webpack';
import { getNextjsVersion, getPackageModules } from './util.js';
let showedMissingGlobalErrorWarningMsg = false;
function constructWebpackConfigFunction({
userNextConfig = {},
userSentryOptions = {},
releaseName,
routeManifest,
nextJsVersion,
useRunAfterProductionCompileHook,
vercelCronsConfigResult
}) {
return function newWebpackFunction(incomingConfig, buildContext) {
const { isServer, dev: isDev, dir: projectDir } = buildContext;
const runtime = isServer ? buildContext.nextRuntime === "edge" ? "edge" : "server" : "client";
const pageExtensions = userNextConfig.pageExtensions || ["tsx", "ts", "jsx", "js"];
const dotPrefixedPageExtensions = pageExtensions.map((ext) => `.${ext}`);
const pageExtensionRegex = pageExtensions.map(escapeStringForRegex).join("|");
const nextVersion = nextJsVersion || getNextjsVersion();
const { major } = parseSemver(nextVersion || "");
const instrumentationFile = getInstrumentationFile(projectDir, dotPrefixedPageExtensions.concat([".ts", ".js"]));
if (runtime !== "client") {
warnAboutDeprecatedConfigFiles(projectDir, instrumentationFile, runtime);
}
if (runtime === "server") {
if (major && major >= 15) {
warnAboutMissingOnRequestErrorHandler(instrumentationFile);
}
}
let rawNewConfig = { ...incomingConfig };
if ("webpack" in userNextConfig && typeof userNextConfig.webpack === "function") {
rawNewConfig = userNextConfig.webpack(rawNewConfig, buildContext);
}
const newConfig = setUpModuleRules(rawNewConfig);
const { strategy: cronsStrategy, config: cronsConfig } = vercelCronsConfigResult;
const vercelCronsConfigForGlobal = cronsStrategy === "spans" ? cronsConfig : void 0;
const vercelCronsConfigForWrapper = cronsStrategy === "wrapper" ? cronsConfig : void 0;
addValueInjectionLoader({
newConfig,
userNextConfig,
userSentryOptions,
buildContext,
releaseName,
routeManifest,
nextJsVersion,
vercelCronsConfig: vercelCronsConfigForGlobal
});
addOtelWarningIgnoreRule(newConfig);
if (major && major === 13 && runtime === "edge" && isDev) {
addEdgeRuntimePolyfills(newConfig, buildContext);
}
let pagesDirPath;
const maybePagesDirPath = path.join(projectDir, "pages");
const maybeSrcPagesDirPath = path.join(projectDir, "src", "pages");
if (fs.existsSync(maybePagesDirPath) && fs.lstatSync(maybePagesDirPath).isDirectory()) {
pagesDirPath = maybePagesDirPath;
} else if (fs.existsSync(maybeSrcPagesDirPath) && fs.lstatSync(maybeSrcPagesDirPath).isDirectory()) {
pagesDirPath = maybeSrcPagesDirPath;
}
let appDirPath;
const maybeAppDirPath = path.join(projectDir, "app");
const maybeSrcAppDirPath = path.join(projectDir, "src", "app");
if (fs.existsSync(maybeAppDirPath) && fs.lstatSync(maybeAppDirPath).isDirectory()) {
appDirPath = maybeAppDirPath;
} else if (fs.existsSync(maybeSrcAppDirPath) && fs.lstatSync(maybeSrcAppDirPath).isDirectory()) {
appDirPath = maybeSrcAppDirPath;
}
const apiRoutesPath = pagesDirPath ? path.join(pagesDirPath, "api") : void 0;
const middlewareLocationFolder = pagesDirPath ? path.join(pagesDirPath, "..") : appDirPath ? path.join(appDirPath, "..") : projectDir;
const staticWrappingLoaderOptions = {
appDir: appDirPath,
pagesDir: pagesDirPath,
pageExtensionRegex,
excludeServerRoutes: userSentryOptions.webpack?.excludeServerRoutes,
nextjsRequestAsyncStorageModulePath: getRequestAsyncStorageModuleLocation(
projectDir,
rawNewConfig.resolve?.modules
),
isDev
};
const normalizeLoaderResourcePath = (resourcePath) => {
let absoluteResourcePath;
if (path.isAbsolute(resourcePath)) {
absoluteResourcePath = resourcePath;
} else {
absoluteResourcePath = path.join(projectDir, resourcePath);
}
return path.normalize(absoluteResourcePath);
};
const isPageResource = (resourcePath) => {
const normalizedAbsoluteResourcePath = normalizeLoaderResourcePath(resourcePath);
return pagesDirPath !== void 0 && normalizedAbsoluteResourcePath.startsWith(pagesDirPath + path.sep) && !normalizedAbsoluteResourcePath.startsWith(apiRoutesPath + path.sep) && dotPrefixedPageExtensions.some((ext) => normalizedAbsoluteResourcePath.endsWith(ext));
};
const isApiRouteResource = (resourcePath) => {
const normalizedAbsoluteResourcePath = normalizeLoaderResourcePath(resourcePath);
return normalizedAbsoluteResourcePath.startsWith(apiRoutesPath + path.sep) && dotPrefixedPageExtensions.some((ext) => normalizedAbsoluteResourcePath.endsWith(ext));
};
const possibleMiddlewareLocations = pageExtensions.flatMap((middlewareFileEnding) => {
return [
path.join(middlewareLocationFolder, `middleware.${middlewareFileEnding}`),
path.join(middlewareLocationFolder, `proxy.${middlewareFileEnding}`)
];
});
const isMiddlewareResource = (resourcePath) => {
const normalizedAbsoluteResourcePath = normalizeLoaderResourcePath(resourcePath);
return possibleMiddlewareLocations.includes(normalizedAbsoluteResourcePath);
};
const isServerComponentResource = (resourcePath) => {
const normalizedAbsoluteResourcePath = normalizeLoaderResourcePath(resourcePath);
return appDirPath !== void 0 && normalizedAbsoluteResourcePath.startsWith(appDirPath + path.sep) && !!normalizedAbsoluteResourcePath.match(
// oxlint-disable-next-line sdk/no-regexp-constructor
new RegExp(`[\\\\/](page|layout|loading|head|not-found)\\.(${pageExtensionRegex})$`)
);
};
const isRouteHandlerResource = (resourcePath) => {
const normalizedAbsoluteResourcePath = normalizeLoaderResourcePath(resourcePath);
return appDirPath !== void 0 && normalizedAbsoluteResourcePath.startsWith(appDirPath + path.sep) && !!normalizedAbsoluteResourcePath.match(
// oxlint-disable-next-line sdk/no-regexp-constructor
new RegExp(`[\\\\/]route\\.(${pageExtensionRegex})$`)
);
};
if (isServer && userSentryOptions.webpack?.autoInstrumentServerFunctions !== false) {
newConfig.module.rules.unshift({
test: isPageResource,
use: [
{
loader: path.resolve(__dirname, "loaders", "wrappingLoader.js"),
options: {
...staticWrappingLoaderOptions,
wrappingTargetKind: "page"
}
}
]
});
newConfig.module.rules.unshift({
test: isApiRouteResource,
use: [
{
loader: path.resolve(__dirname, "loaders", "wrappingLoader.js"),
options: {
...staticWrappingLoaderOptions,
vercelCronsConfig: vercelCronsConfigForWrapper,
wrappingTargetKind: "api-route"
}
}
]
});
const canWrapStandaloneMiddleware = userNextConfig.output !== "standalone" || !major || major < 16;
if ((userSentryOptions.webpack?.autoInstrumentMiddleware ?? true) && canWrapStandaloneMiddleware) {
newConfig.module.rules.unshift({
test: isMiddlewareResource,
use: [
{
loader: path.resolve(__dirname, "loaders", "wrappingLoader.js"),
options: {
...staticWrappingLoaderOptions,
wrappingTargetKind: "middleware"
}
}
]
});
}
}
if (isServer && userSentryOptions.webpack?.autoInstrumentAppDirectory !== false) {
newConfig.module.rules.unshift({
test: isServerComponentResource,
use: [
{
loader: path.resolve(__dirname, "loaders", "wrappingLoader.js"),
options: {
...staticWrappingLoaderOptions,
wrappingTargetKind: "server-component"
}
}
]
});
newConfig.module.rules.unshift({
test: isRouteHandlerResource,
use: [
{
loader: path.resolve(__dirname, "loaders", "wrappingLoader.js"),
options: {
...staticWrappingLoaderOptions,
wrappingTargetKind: "route-handler"
}
}
]
});
}
if (appDirPath) {
const hasGlobalErrorFile = pageExtensions.map((extension) => `global-error.${extension}`).some((globalErrorFile) => fs.existsSync(path.join(appDirPath, globalErrorFile)));
if (!hasGlobalErrorFile && !showedMissingGlobalErrorWarningMsg && !process.env.SENTRY_SUPPRESS_GLOBAL_ERROR_HANDLER_FILE_WARNING) {
console.log(
"[@sentry/nextjs] It seems like you don't have a global error handler set up. It is recommended that you add a 'global-error.js' file with Sentry instrumentation so that React rendering errors are reported to Sentry. Read more: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#react-render-errors-in-app-router (you can suppress this warning by setting SENTRY_SUPPRESS_GLOBAL_ERROR_HANDLER_FILE_WARNING=1 as environment variable)"
);
showedMissingGlobalErrorWarningMsg = true;
}
}
if (!isServer) {
const origEntryProperty = newConfig.entry;
newConfig.entry = async () => addSentryToClientEntryProperty(origEntryProperty, buildContext);
const clientSentryConfigFileName = getClientSentryConfigFile(projectDir);
if (clientSentryConfigFileName) {
console.warn(
`[@sentry/nextjs] DEPRECATION WARNING: It is recommended renaming your \`${clientSentryConfigFileName}\` file, or moving its content to \`instrumentation-client.ts\`. When using Turbopack \`${clientSentryConfigFileName}\` will no longer work. Read more about the \`instrumentation-client.ts\` file: https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation-client`
);
}
}
const isStaticExport = userNextConfig?.output === "export";
if (!(isDev || isStaticExport && isServer)) {
const { sentryWebpackPlugin } = loadModule("@sentry/webpack-plugin", module) ?? {};
if (sentryWebpackPlugin) {
if (!userSentryOptions.sourcemaps?.disable) {
if (!newConfig.devtool) {
debug.log(`[@sentry/nextjs] Automatically enabling source map generation for ${runtime} build.`);
if (isServer) {
newConfig.devtool = "source-map";
} else {
newConfig.devtool = "hidden-source-map";
}
}
if (!isServer && userSentryOptions.sourcemaps?.deleteSourcemapsAfterUpload === void 0) {
debug.warn(
"[@sentry/nextjs] Source maps will be automatically deleted after being uploaded to Sentry. If you want to keep the source maps, set the `sourcemaps.deleteSourcemapsAfterUpload` option to false in `withSentryConfig()`. If you do not want to generate and upload sourcemaps at all, set the `sourcemaps.disable` option to true."
);
userSentryOptions.sourcemaps = {
...userSentryOptions.sourcemaps,
deleteSourcemapsAfterUpload: true
};
}
}
newConfig.plugins = newConfig.plugins || [];
const { config: userNextConfig2, dir, nextRuntime } = buildContext;
const buildTool = isServer ? nextRuntime === "edge" ? "webpack-edge" : "webpack-nodejs" : "webpack-client";
const projectDir2 = normalizePathForGlob(dir);
const distDir = normalizePathForGlob(userNextConfig2.distDir ?? ".next");
const distDirAbsPath = path.posix.join(projectDir2, distDir);
const sentryWebpackPluginInstance = sentryWebpackPlugin(
getBuildPluginOptions({
sentryBuildOptions: userSentryOptions,
releaseName,
distDirAbsPath,
buildTool,
useRunAfterProductionCompileHook
})
);
sentryWebpackPluginInstance._name = "sentry-webpack-plugin";
newConfig.plugins.push(sentryWebpackPluginInstance);
}
}
if (userSentryOptions.webpack?.treeshake) {
setupTreeshakingFromConfig(userSentryOptions, newConfig, buildContext);
}
newConfig.plugins = newConfig.plugins || [];
newConfig.plugins.push(
new buildContext.webpack.DefinePlugin({
__SENTRY_SERVER_MODULES__: JSON.stringify(getPackageModules(projectDir))
})
);
if (runtime === "server" && userSentryOptions._experimental?.useDiagnosticsChannelInjection) {
newConfig.plugins.push(sentryOrchestrionWebpackPlugin());
}
return newConfig;
};
}
async function addSentryToClientEntryProperty(currentEntryProperty, buildContext) {
const { dir: projectDir, dev: isDevMode } = buildContext;
const newEntryProperty = typeof currentEntryProperty === "function" ? await currentEntryProperty() : { ...currentEntryProperty };
const clientSentryConfigFileName = getClientSentryConfigFile(projectDir);
const instrumentationClientFileName = getInstrumentationClientFile(projectDir);
const filesToInject = [];
if (clientSentryConfigFileName) {
filesToInject.push(`./${clientSentryConfigFileName}`);
}
if (instrumentationClientFileName) {
filesToInject.push(`./${instrumentationClientFileName}`);
}
for (const entryPointName in newEntryProperty) {
if (entryPointName === "pages/_app" || // entrypoint for `/app` pages
entryPointName === "main-app") {
addFilesToWebpackEntryPoint(newEntryProperty, entryPointName, filesToInject, isDevMode);
}
}
return newEntryProperty;
}
function getInstrumentationFile(projectDir, dotPrefixedExtensions) {
const paths = dotPrefixedExtensions.flatMap((extension) => [
["src", `instrumentation${extension}`],
[`instrumentation${extension}`]
]);
for (const pathSegments of paths) {
try {
return fs.readFileSync(path.resolve(projectDir, ...pathSegments), { encoding: "utf-8" });
} catch {
}
}
return null;
}
function warnAboutMissingOnRequestErrorHandler(instrumentationFile) {
if (!instrumentationFile) {
if (!process.env.SENTRY_SUPPRESS_INSTRUMENTATION_FILE_WARNING) {
console.warn(
"[@sentry/nextjs] Could not find a Next.js instrumentation file. This indicates an incomplete configuration of the Sentry SDK. An instrumentation file is required for the Sentry SDK to be initialized on the server: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#create-initialization-config-files (you can suppress this warning by setting SENTRY_SUPPRESS_INSTRUMENTATION_FILE_WARNING=1 as environment variable)"
);
}
return;
}
if (!instrumentationFile.includes("onRequestError")) {
console.warn(
"[@sentry/nextjs] Could not find `onRequestError` hook in instrumentation file. This indicates outdated configuration of the Sentry SDK. Use `Sentry.captureRequestError` to instrument the `onRequestError` hook: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#errors-from-nested-react-server-components"
);
}
}
function warnAboutDeprecatedConfigFiles(projectDir, instrumentationFile, platform) {
const hasInstrumentationHookWithIndicationsOfSentry = instrumentationFile && (instrumentationFile.includes("@sentry/") || instrumentationFile.match(/sentry\.(server|edge)\.config(\.(ts|js))?/));
if (hasInstrumentationHookWithIndicationsOfSentry) {
return;
}
for (const filename of [`sentry.${platform}.config.ts`, `sentry.${platform}.config.js`]) {
if (fs.existsSync(path.resolve(projectDir, filename))) {
console.warn(
`[@sentry/nextjs] It appears you've configured a \`${filename}\` file. Please ensure to put this file's content into the \`register()\` function of a Next.js instrumentation file instead. To ensure correct functionality of the SDK, \`Sentry.init\` must be called inside of an instrumentation file. Learn more about setting up an instrumentation file in Next.js: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation. You can safely delete the \`${filename}\` file afterward.`
);
}
}
}
function getClientSentryConfigFile(projectDir) {
const possibilities = ["sentry.client.config.ts", "sentry.client.config.js"];
for (const filename of possibilities) {
if (fs.existsSync(path.resolve(projectDir, filename))) {
return filename;
}
}
}
function getInstrumentationClientFile(projectDir) {
const possibilities = [
["src", "instrumentation-client.js"],
["src", "instrumentation-client.ts"],
["instrumentation-client.js"],
["instrumentation-client.ts"]
];
for (const pathParts of possibilities) {
if (fs.existsSync(path.resolve(projectDir, ...pathParts))) {
return path.join(...pathParts);
}
}
}
function addFilesToWebpackEntryPoint(entryProperty, entryPointName, filesToInsert, isDevMode) {
const currentEntryPoint = entryProperty[entryPointName];
let newEntryPoint = currentEntryPoint;
if (typeof currentEntryPoint === "string" || Array.isArray(currentEntryPoint)) {
newEntryPoint = Array.isArray(currentEntryPoint) ? currentEntryPoint : [currentEntryPoint];
if (newEntryPoint.some((entry) => filesToInsert.includes(entry))) {
return;
}
if (isDevMode) {
newEntryPoint.push(...filesToInsert);
} else {
newEntryPoint.unshift(...filesToInsert);
}
} else if (typeof currentEntryPoint === "object" && "import" in currentEntryPoint) {
const currentImportValue = currentEntryPoint.import;
const newImportValue = Array.isArray(currentImportValue) ? currentImportValue : [currentImportValue];
if (newImportValue.some((entry) => filesToInsert.includes(entry))) {
return;
}
if (isDevMode) {
newImportValue.push(...filesToInsert);
} else {
newImportValue.unshift(...filesToInsert);
}
newEntryPoint = {
...currentEntryPoint,
import: newImportValue
};
} else {
console.error(
"Sentry Logger [Error]:",
`Could not inject SDK initialization code into entry point ${entryPointName}, as its current value is not in a recognized format.
`,
"Expected: string | Array<string> | { [key:string]: any, import: string | Array<string> }\n",
`Got: ${currentEntryPoint}`
);
}
if (newEntryPoint) {
entryProperty[entryPointName] = newEntryPoint;
}
}
function setUpModuleRules(newConfig) {
newConfig.module = {
...newConfig.module,
rules: [...newConfig.module?.rules || []]
};
return newConfig;
}
function addValueInjectionLoader({
newConfig,
userNextConfig,
userSentryOptions,
buildContext,
releaseName,
routeManifest,
nextJsVersion,
vercelCronsConfig
}) {
const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || "";
const shouldCreateRelease = userSentryOptions.release?.create !== false;
const releaseToInject = releaseName && shouldCreateRelease ? releaseName : void 0;
const isomorphicValues = {
// `rewritesTunnel` set by the user in Next.js config
_sentryRewritesTunnelPath: userSentryOptions.tunnelRoute !== void 0 && userNextConfig.output !== "export" && typeof userSentryOptions.tunnelRoute === "string" ? `${userNextConfig.basePath ?? ""}${userSentryOptions.tunnelRoute}` : void 0,
// The webpack plugin's release injection breaks the `app` directory so we inject the release manually here instead.
// Having a release defined in dev-mode spams releases in Sentry so we only set one in non-dev mode
// Only inject if release creation is not explicitly disabled (to maintain build determinism)
SENTRY_RELEASE: releaseToInject && !buildContext.dev ? { id: releaseToInject } : void 0,
_sentryBasePath: buildContext.dev ? userNextConfig.basePath : void 0,
// This is used to determine version-based dev-symbolication behavior
_sentryNextJsVersion: nextJsVersion
};
const serverValues = {
...isomorphicValues,
// Make sure that if we have a windows path, the backslashes are interpreted as such (rather than as escape
// characters)
_sentryRewriteFramesDistDir: userNextConfig.distDir?.replace(/\\/g, "\\\\") || ".next",
// Inject Vercel crons config for server-side cron auto-instrumentation
_sentryVercelCronsConfig: vercelCronsConfig ? JSON.stringify(vercelCronsConfig) : void 0
};
const clientValues = {
...isomorphicValues,
// Get the path part of `assetPrefix`, minus any trailing slash. (We use a placeholder for the origin if
// `assetPrefix` doesn't include one. Since we only care about the path, it doesn't matter what it is.)
_sentryRewriteFramesAssetPrefixPath: assetPrefix ? new URL(assetPrefix, "http://dogs.are.great").pathname.replace(/\/$/, "") : "",
_sentryAssetPrefix: userNextConfig.assetPrefix,
_sentryExperimentalThirdPartyOriginStackFrames: userSentryOptions._experimental?.thirdPartyOriginStackFrames ? "true" : void 0,
_sentryRouteManifest: JSON.stringify(routeManifest)
};
if (buildContext.isServer) {
newConfig.module.rules.push({
// TODO: Find a more bulletproof way of matching. For now this is fine and doesn't hurt anyone. It merely sets some globals.
test: /(src[\\/])?instrumentation.(js|ts)/,
use: [
{
loader: path.resolve(__dirname, "loaders/valueInjectionLoader.js"),
options: {
values: serverValues
}
}
]
});
} else {
newConfig.module.rules.push({
test: /(?:sentry\.client\.config\.(jsx?|tsx?)|(?:src[\\/])?instrumentation-client\.(js|ts))$/,
use: [
{
loader: path.resolve(__dirname, "loaders/valueInjectionLoader.js"),
options: {
values: clientValues
}
}
]
});
}
}
function resolveNextPackageDirFromDirectory(basedir) {
try {
return path.dirname(createRequire(`${basedir}/`).resolve("next/package.json"));
} catch {
return void 0;
}
}
const POTENTIAL_REQUEST_ASYNC_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",
// Introduced in Next.js 15.0.0-canary.180
// https://github.com/vercel/next.js/blob/541167b9b0fed6af9f36472e632863ffec41f18c/packages/next/src/server/app-render/work-unit-async-storage.external.ts
"next/dist/server/app-render/work-unit-async-storage.external.js",
// Introduced in Next.js 15.0.0-canary.182
// https://github.com/vercel/next.js/blob/f35159e5e80138ca7373f57b47edcaae3bcf1728/packages/next/src/client/components/work-unit-async-storage.external.ts
"next/dist/client/components/work-unit-async-storage.external.js"
];
function getRequestAsyncStorageModuleLocation(webpackContextDir, webpackResolvableModuleLocations) {
if (webpackResolvableModuleLocations === void 0) {
return void 0;
}
const absoluteWebpackResolvableModuleLocations = webpackResolvableModuleLocations.map(
(loc) => path.resolve(webpackContextDir, loc)
);
for (const webpackResolvableLocation of absoluteWebpackResolvableModuleLocations) {
const nextPackageDir = resolveNextPackageDirFromDirectory(webpackResolvableLocation);
if (nextPackageDir) {
const asyncLocalStorageLocation = POTENTIAL_REQUEST_ASYNC_STORAGE_LOCATIONS.find(
(loc) => fs.existsSync(path.join(nextPackageDir, "..", loc))
);
if (asyncLocalStorageLocation) {
return asyncLocalStorageLocation;
}
}
}
return void 0;
}
function addOtelWarningIgnoreRule(newConfig) {
const ignoreRules = [
// Inspired by @matmannion: https://github.com/getsentry/sentry-javascript/issues/12077#issuecomment-2180307072
(warning, compilation) => {
try {
if (!warning.module) {
return false;
}
const isDependencyThatMayRaiseCriticalDependencyMessage = /@opentelemetry\/instrumentation/.test(warning.module.readableIdentifier(compilation.requestShortener)) || /@prisma\/instrumentation/.test(warning.module.readableIdentifier(compilation.requestShortener));
const isCriticalDependencyMessage = /Critical dependency/.test(warning.message);
return isDependencyThatMayRaiseCriticalDependencyMessage && isCriticalDependencyMessage;
} catch {
return false;
}
},
// We provide these objects in addition to the hook above to provide redundancy in case the hook fails.
{ module: /@opentelemetry\/instrumentation/, message: /Critical dependency/ },
{ module: /@prisma\/instrumentation/, message: /Critical dependency/ },
{ module: /require-in-the-middle/, message: /Critical dependency/ }
];
if (newConfig.ignoreWarnings === void 0) {
newConfig.ignoreWarnings = ignoreRules;
} else if (Array.isArray(newConfig.ignoreWarnings)) {
newConfig.ignoreWarnings.push(...ignoreRules);
}
}
function addEdgeRuntimePolyfills(newConfig, buildContext) {
newConfig.plugins = newConfig.plugins || [];
newConfig.plugins.push(
new buildContext.webpack.ProvidePlugin({
performance: [path.resolve(__dirname, "polyfills", "perf_hooks.js"), "performance"]
})
);
newConfig.resolve = newConfig.resolve || {};
newConfig.resolve.alias = {
...newConfig.resolve.alias,
// Redirect perf_hooks imports to a polyfilled version
perf_hooks: path.resolve(__dirname, "polyfills", "perf_hooks.js")
};
}
function setupTreeshakingFromConfig(userSentryOptions, newConfig, buildContext) {
const defines = {};
newConfig.plugins = newConfig.plugins || [];
if (userSentryOptions.webpack?.treeshake?.removeDebugLogging) {
defines.__SENTRY_DEBUG__ = false;
}
if (userSentryOptions.webpack?.treeshake?.removeTracing) {
defines.__SENTRY_TRACING__ = false;
}
if (userSentryOptions.webpack?.treeshake?.excludeReplayIframe) {
defines.__RRWEB_EXCLUDE_IFRAME__ = true;
}
if (userSentryOptions.webpack?.treeshake?.excludeReplayShadowDOM) {
defines.__RRWEB_EXCLUDE_SHADOW_DOM__ = true;
}
if (userSentryOptions.webpack?.treeshake?.excludeReplayCompressionWorker) {
defines.__SENTRY_EXCLUDE_REPLAY_WORKER__ = true;
}
if (Object.keys(defines).length > 0) {
newConfig.plugins.push(new buildContext.webpack.DefinePlugin(defines));
}
}
export { constructWebpackConfigFunction };
//# sourceMappingURL=webpack.js.map