Skip to content

Commit 8360704

Browse files
committed
Skip internal routes in middleware
1 parent b5eba8f commit 8360704

File tree

10 files changed

+97
-29
lines changed

10 files changed

+97
-29
lines changed

packages/next/src/build/entries.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
isInstrumentationHookFilename,
4646
} from './utils'
4747
import { getPageStaticInfo } from './analysis/get-page-static-info'
48+
import { getDefaultMiddlewareMatcher } from '../shared/lib/router/utils/get-default-middleware-matcher'
4849
import { normalizePathSep } from '../shared/lib/page-path/normalize-path-sep'
4950
import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path'
5051
import type { ServerRuntime } from '../types'
@@ -898,7 +899,7 @@ export async function createEntrypoints(
898899

899900
if (isMiddlewareFile(page)) {
900901
middlewareMatchers = staticInfo.middleware?.matchers ?? [
901-
{ regexp: '.*', originalSource: '/:path*' },
902+
getDefaultMiddlewareMatcher(params.config),
902903
]
903904
}
904905

packages/next/src/build/index.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ import { isEdgeRuntime } from '../lib/is-edge-runtime'
150150
import { recursiveCopy } from '../lib/recursive-copy'
151151
import { lockfilePatchPromise, teardownTraceSubscriber } from './swc'
152152
import { getNamedRouteRegex } from '../shared/lib/router/utils/route-regex'
153+
import { getDefaultMiddlewareMatcher } from '../shared/lib/router/utils/get-default-middleware-matcher'
153154
import { getFilesInDir } from '../lib/get-files-in-dir'
154155
import { eventSwcPlugins } from '../telemetry/events/swc-plugins'
155156
import { normalizeAppPath } from '../shared/lib/router/utils/app-paths'
@@ -2580,10 +2581,7 @@ export default async function build(
25802581
functionsConfigManifest.functions['/_middleware'] = {
25812582
runtime: staticInfo.runtime,
25822583
matchers: staticInfo.middleware?.matchers ?? [
2583-
{
2584-
regexp: '^.*$',
2585-
originalSource: '/:path*',
2586-
},
2584+
getDefaultMiddlewareMatcher(config),
25872585
],
25882586
}
25892587

packages/next/src/build/webpack-config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,7 @@ export default async function getBaseWebpackConfig(
20812081
dev,
20822082
sriEnabled: !dev && !!config.experimental.sri?.algorithm,
20832083
rewrites,
2084+
nextConfig: config,
20842085
edgeEnvironments: {
20852086
__NEXT_BUILD_ID: buildId,
20862087
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY: encryptionKey,

packages/next/src/build/webpack/plugins/middleware-plugin.ts

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
import type { EdgeSSRMeta } from '../loaders/get-module-build-info'
66
import type { MiddlewareMatcher } from '../../analysis/get-page-static-info'
77
import { getNamedMiddlewareRegex } from '../../../shared/lib/router/utils/route-regex'
8+
import { getDefaultMiddlewareMatcher } from '../../../shared/lib/router/utils/get-default-middleware-matcher'
89
import { getModuleBuildInfo } from '../loaders/get-module-build-info'
910
import { getSortedRoutes } from '../../../shared/lib/router/utils'
1011
import { webpack, sources } from 'next/dist/compiled/webpack/webpack'
@@ -36,6 +37,7 @@ import type { CustomRoutes } from '../../../lib/load-custom-routes'
3637
import { isInterceptionRouteRewrite } from '../../../lib/generate-interception-routes-rewrites'
3738
import { getDynamicCodeEvaluationError } from './wellknown-errors-plugin/parse-dynamic-code-evaluation-error'
3839
import { getModuleReferencesInOrder } from '../utils'
40+
import type { NextConfigComplete } from '../../../server/config-shared'
3941

4042
const KNOWN_SAFE_DYNAMIC_PACKAGES =
4143
require('../../../lib/known-edge-safe-packages.json') as string[]
@@ -195,21 +197,29 @@ function getCreateAssets(params: {
195197
continue
196198
}
197199

198-
const matcherSource = metadata.edgeSSR?.isAppDir
199-
? normalizeAppPath(page)
200-
: page
201-
202-
const catchAll = !metadata.edgeSSR && !metadata.edgeApiFunction
203-
204-
const { namedRegex } = getNamedMiddlewareRegex(matcherSource, {
205-
catchAll,
206-
})
207-
const matchers = metadata?.edgeMiddleware?.matchers ?? [
208-
{
209-
regexp: namedRegex,
210-
originalSource: page === '/' && catchAll ? '/:path*' : matcherSource,
211-
},
212-
]
200+
let matchers: MiddlewareMatcher[]
201+
if (metadata?.edgeMiddleware?.matchers) {
202+
matchers = metadata.edgeMiddleware.matchers
203+
} else {
204+
// For middleware at root with no explicit matchers, use getDefaultMiddlewareMatcher
205+
// which respects skipMiddlewareNextInternalRoutes config
206+
const catchAll = !metadata.edgeSSR && !metadata.edgeApiFunction
207+
if (page === '/' && catchAll) {
208+
matchers = [getDefaultMiddlewareMatcher(opts.nextConfig)]
209+
} else {
210+
const matcherSource = metadata.edgeSSR?.isAppDir
211+
? normalizeAppPath(page)
212+
: page
213+
matchers = [
214+
{
215+
regexp: getNamedMiddlewareRegex(matcherSource, {
216+
catchAll,
217+
}).namedRegex,
218+
originalSource: matcherSource,
219+
},
220+
]
221+
}
222+
}
213223

214224
const isEdgeFunction = !!(metadata.edgeApiFunction || metadata.edgeSSR)
215225
const edgeFunctionDefinition: EdgeFunctionDefinition = {
@@ -818,19 +828,28 @@ interface Options {
818828
sriEnabled: boolean
819829
rewrites: CustomRoutes['rewrites']
820830
edgeEnvironments: EdgeRuntimeEnvironments
831+
nextConfig: NextConfigComplete
821832
}
822833

823834
export default class MiddlewarePlugin {
824835
private readonly dev: Options['dev']
825836
private readonly sriEnabled: Options['sriEnabled']
826837
private readonly rewrites: Options['rewrites']
827838
private readonly edgeEnvironments: EdgeRuntimeEnvironments
828-
829-
constructor({ dev, sriEnabled, rewrites, edgeEnvironments }: Options) {
839+
private readonly nextConfig: Options['nextConfig']
840+
841+
constructor({
842+
dev,
843+
sriEnabled,
844+
rewrites,
845+
edgeEnvironments,
846+
nextConfig,
847+
}: Options) {
830848
this.dev = dev
831849
this.sriEnabled = sriEnabled
832850
this.rewrites = rewrites
833851
this.edgeEnvironments = edgeEnvironments
852+
this.nextConfig = nextConfig
834853
}
835854

836855
public apply(compiler: webpack.Compiler) {
@@ -886,6 +905,7 @@ export default class MiddlewarePlugin {
886905
rewrites: this.rewrites,
887906
edgeEnvironments: this.edgeEnvironments,
888907
dev: this.dev,
908+
nextConfig: this.nextConfig,
889909
},
890910
})
891911
)

packages/next/src/server/config-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
676676
serverExternalPackages: z.array(z.string()).optional(),
677677
serverRuntimeConfig: z.record(z.string(), z.any()).optional(),
678678
skipMiddlewareUrlNormalize: z.boolean().optional(),
679+
skipMiddlewareNextInternalRoutes: z.boolean().optional(),
679680
skipTrailingSlashRedirect: z.boolean().optional(),
680681
staticPageGenerationTimeout: z.number().optional(),
681682
expireTime: z.number().optional(),

packages/next/src/server/config-shared.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,12 @@ export interface NextConfig {
12361236

12371237
skipMiddlewareUrlNormalize?: boolean
12381238

1239+
/**
1240+
* Skip Next.js internals route `/_next` from middleware.
1241+
* @default true
1242+
*/
1243+
skipMiddlewareNextInternalRoutes?: boolean
1244+
12391245
skipTrailingSlashRedirect?: boolean
12401246

12411247
modularizeImports?: Record<
@@ -1515,6 +1521,7 @@ export const defaultConfig = Object.freeze({
15151521
},
15161522
htmlLimitedBots: undefined,
15171523
bundlePagesRouterDependencies: false,
1524+
skipMiddlewareNextInternalRoutes: true,
15181525
} satisfies NextConfig)
15191526

15201527
export async function normalizeConfig(phase: string, config: any) {

packages/next/src/server/lib/router-utils/filesystem.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { pathHasPrefix } from '../../../shared/lib/router/utils/path-has-prefix'
3131
import { normalizeLocalePath } from '../../../shared/lib/i18n/normalize-locale-path'
3232
import { removePathPrefix } from '../../../shared/lib/router/utils/remove-path-prefix'
3333
import { getMiddlewareRouteMatcher } from '../../../shared/lib/router/utils/middleware-route-matcher'
34+
import { getDefaultMiddlewareMatcher } from '../../../shared/lib/router/utils/get-default-middleware-matcher'
3435
import {
3536
APP_PATH_ROUTES_MANIFEST,
3637
BUILD_ID_FILE,
@@ -314,7 +315,7 @@ export async function setupFsCheck(opts: {
314315
} else if (functionsConfigManifest?.functions['/_middleware']) {
315316
middlewareMatcher = getMiddlewareRouteMatcher(
316317
functionsConfigManifest.functions['/_middleware'].matchers ?? [
317-
{ regexp: '.*', originalSource: '/:path*' },
318+
getDefaultMiddlewareMatcher(opts.config),
318319
]
319320
)
320321
}

packages/next/src/server/lib/router-utils/setup-dev-bundler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
} from '../../../shared/lib/constants'
4949

5050
import { getMiddlewareRouteMatcher } from '../../../shared/lib/router/utils/middleware-route-matcher'
51+
import { getDefaultMiddlewareMatcher } from '../../../shared/lib/router/utils/get-default-middleware-matcher'
5152

5253
import {
5354
isMiddlewareFile,
@@ -472,7 +473,7 @@ async function startWatcher(
472473
serverFields.actualMiddlewareFile
473474
)
474475
middlewareMatchers = staticInfo.middleware?.matchers || [
475-
{ regexp: '^/.*$', originalSource: '/:path*' },
476+
getDefaultMiddlewareMatcher(opts.nextConfig),
476477
]
477478
continue
478479
}

packages/next/src/server/next-server.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import type { LoadComponentsReturnType } from './load-components'
7171
import isError, { getProperError } from '../lib/is-error'
7272
import { splitCookiesString, toNodeOutgoingHttpHeaders } from './web/utils'
7373
import { getMiddlewareRouteMatcher } from '../shared/lib/router/utils/middleware-route-matcher'
74+
import { getDefaultMiddlewareMatcher } from '../shared/lib/router/utils/get-default-middleware-matcher'
7475
import { loadEnvConfig } from '@next/env'
7576
import { urlQueryToSearchParams } from '../shared/lib/router/utils/querystring'
7677
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
@@ -1455,13 +1456,13 @@ export default class NextNodeServer extends BaseServer<
14551456
const middlewareModule = await this.loadNodeMiddleware()
14561457

14571458
if (middlewareModule) {
1459+
const matchers = middlewareModule.config?.matchers || [
1460+
getDefaultMiddlewareMatcher(this.nextConfig),
1461+
]
14581462
return {
1459-
match: getMiddlewareRouteMatcher(
1460-
middlewareModule.config?.matchers || [
1461-
{ regexp: '.*', originalSource: '/:path*' },
1462-
]
1463-
),
1463+
match: getMiddlewareRouteMatcher(matchers),
14641464
page: '/',
1465+
matchers,
14651466
}
14661467
}
14671468

@@ -1471,6 +1472,7 @@ export default class NextNodeServer extends BaseServer<
14711472
return {
14721473
match: getMiddlewareMatcher(middleware),
14731474
page: '/',
1475+
matchers: middleware.matchers,
14741476
}
14751477
}
14761478

@@ -1679,6 +1681,7 @@ export default class NextNodeServer extends BaseServer<
16791681
return { finished: false }
16801682
}
16811683

1684+
16821685
await this.ensureMiddleware(params.request.url)
16831686
const middlewareInfo = this.getEdgeFunctionInfo({
16841687
page: middleware.page,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { NextConfig } from '../../../../types'
2+
import type { MiddlewareMatcher } from '../../../../build/analysis/get-page-static-info'
3+
4+
export function getDefaultMiddlewareMatcher({
5+
skipMiddlewareNextInternalRoutes,
6+
basePath,
7+
}: Pick<
8+
NextConfig,
9+
'skipMiddlewareNextInternalRoutes' | 'basePath'
10+
>): MiddlewareMatcher {
11+
const skipInternal = skipMiddlewareNextInternalRoutes !== false
12+
13+
if (skipInternal) {
14+
// Allow middleware to run on all routes except Next.js internal routes (/_next/*)
15+
// Exception: still match /_next/data/* routes since they're used for client-side navigation
16+
// When basePath is configured, the pattern includes the basePath prefix
17+
if (basePath) {
18+
return {
19+
// Escape special characters in basePath
20+
regexp: `^${basePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?!\\/\\_next\\/(?!data\\/)).*`,
21+
originalSource: '/:path*',
22+
}
23+
}
24+
25+
return {
26+
regexp: '^(?!\\/\\_next\\/(?!data\\/)).*',
27+
originalSource: '/:path*',
28+
}
29+
}
30+
31+
return {
32+
regexp: '.*',
33+
originalSource: '/:path*',
34+
}
35+
}

0 commit comments

Comments
 (0)