Skip to content

Commit e2522de

Browse files
committed
use helper to ensure newConfig.module.rules exists
1 parent 9015847 commit e2522de

File tree

1 file changed

+35
-19
lines changed

1 file changed

+35
-19
lines changed

packages/nextjs/src/config/webpack.ts

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
UserSentryOptions,
2424
WebpackConfigFunction,
2525
WebpackConfigObject,
26+
WebpackConfigObjectWithModuleRules,
2627
WebpackEntryProperty,
2728
WebpackModuleRule,
2829
WebpackPluginInstance,
@@ -67,35 +68,33 @@ export function constructWebpackConfigFunction(
6768
buildContext: BuildContext,
6869
): WebpackConfigObject {
6970
const { isServer, dev: isDev, dir: projectDir } = buildContext;
70-
let newConfig = { ...incomingConfig };
71+
let rawNewConfig = { ...incomingConfig };
7172

7273
// if user has custom webpack config (which always takes the form of a function), run it so we have actual values to
7374
// work with
7475
if ('webpack' in userNextConfig && typeof userNextConfig.webpack === 'function') {
75-
newConfig = userNextConfig.webpack(newConfig, buildContext);
76+
rawNewConfig = userNextConfig.webpack(rawNewConfig, buildContext);
7677
}
7778

79+
// This mutates `rawNewConfig` in place, but also returns it in order to switch its type to one in which
80+
// `newConfig.module.rules` is required, so we don't have to keep asserting its existence
81+
const newConfig = setUpModuleRules(rawNewConfig);
82+
7883
if (isServer) {
79-
newConfig.module = {
80-
...newConfig.module,
81-
rules: [
82-
...(newConfig.module?.rules || []),
84+
newConfig.module.rules.push({
85+
test: /sentry\.server\.config\.(jsx?|tsx?)/,
86+
use: [
8387
{
84-
test: /sentry\.server\.config\.(jsx?|tsx?)/,
85-
use: [
86-
{
87-
// Support non-default output directories by making the output path (easy to get here at build-time)
88-
// available to the server SDK's default `RewriteFrames` instance (which needs it at runtime), by
89-
// injecting code to attach it to `global`.
90-
loader: path.resolve(__dirname, 'loaders/prefixLoader.js'),
91-
options: {
92-
distDir: userNextConfig.distDir || '.next',
93-
},
94-
},
95-
],
88+
// Support non-default output directories by making the output path (easy to get here at build-time)
89+
// available to the server SDK's default `RewriteFrames` instance (which needs it at runtime), by
90+
// injecting code to attach it to `global`.
91+
loader: path.resolve(__dirname, 'loaders/prefixLoader.js'),
92+
options: {
93+
distDir: userNextConfig.distDir || '.next',
94+
},
9695
},
9796
],
98-
};
97+
});
9998

10099
if (userSentryOptions.autoInstrumentServerFunctions !== false) {
101100
const pagesDir = newConfig.resolve?.alias?.['private-next-pages'] as string;
@@ -628,3 +627,20 @@ function handleSourcemapHidingOptionWarning(userSentryOptions: UserSentryOptions
628627
// );
629628
// }
630629
}
630+
631+
/**
632+
* Ensure that `newConfig.module.rules` exists. Modifies the given config in place but also returns it in order to
633+
* change its type.
634+
*
635+
* @param newConfig A webpack config object which may or may not contain `module` and `module.rules`
636+
* @returns The same object, with an empty `module.rules` array added if necessary
637+
*/
638+
function setUpModuleRules(newConfig: WebpackConfigObject): WebpackConfigObjectWithModuleRules {
639+
newConfig.module = {
640+
...newConfig.module,
641+
rules: [...(newConfig.module?.rules || [])],
642+
};
643+
// Surprising that we have to assert the type here, since we've demonstrably guaranteed the existence of
644+
// `newConfig.module.rules` just above, but ¯\_(ツ)_/¯
645+
return newConfig as WebpackConfigObjectWithModuleRules;
646+
}

0 commit comments

Comments
 (0)