Skip to content

Commit 4640fb7

Browse files
committed
fix: skip BC route resolution for 404 path
1 parent 8096cc5 commit 4640fb7

4 files changed

Lines changed: 85 additions & 4 deletions

File tree

core/app/global-not-found.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { Metadata } from 'next';
2+
import { Inter } from 'next/font/google';
3+
4+
const inter = Inter({ subsets: ['latin'] });
5+
6+
export const metadata: Metadata = {
7+
title: '404 - Page Not Found',
8+
description: 'The page you are looking for does not exist.',
9+
};;
10+
11+
export default function GlobalNotFound() {
12+
return (
13+
<html className={inter.className} lang="en">
14+
<body>
15+
<h1>404 - Page Not Found Global</h1>
16+
<p>This page does not exist.</p>
17+
</body>
18+
</html>
19+
);
20+
}
21+

core/app/not-found.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function NotFound() {
2+
return (
3+
<div>
4+
<h1>Not Found</h1>
5+
6+
<p>The page you are looking for does not exist.</p>
7+
</div>
8+
);
9+
}

core/middlewares/with-routes.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { z } from 'zod';
44
import { client } from '~/client';
55
import { graphql } from '~/client/graphql';
66
import { revalidate } from '~/client/revalidate-target';
7+
import { defaultLocale } from '~/i18n/locales';
78
import { getVisitIdCookie, getVisitorIdCookie } from '~/lib/analytics/bigcommerce';
89
import { sendProductViewedEvent } from '~/lib/analytics/bigcommerce/data-events';
910
import { kvKey, STORE_STATUS_KEY } from '~/lib/kv/keys';
@@ -248,6 +249,15 @@ const getRouteInfo = async (request: NextRequest, event: NextFetchEvent) => {
248249
// For route resolution parity, we need to also include query params, otherwise certain redirects will not work.
249250
const pathname = clearLocaleFromPath(request.nextUrl.pathname + request.nextUrl.search, locale);
250251

252+
// Skip BigCommerce route resolution for /404 paths to avoid GraphQL 400 errors
253+
// This is a defensive check in case the early return in withRoutes doesn't catch it
254+
if (pathname === '/404' || pathname === '/404/' || pathname.startsWith('/404?')) {
255+
return {
256+
route: undefined,
257+
status: undefined,
258+
};
259+
}
260+
251261
let [routeCache, statusCache] = await kv.mget<RouteCache | StorefrontStatusCache>(
252262
kvKey(pathname, channelId),
253263
kvKey(STORE_STATUS_KEY, channelId),
@@ -290,6 +300,50 @@ export const withRoutes: MiddlewareFactory = () => {
290300
return async (request, event) => {
291301
const locale = request.headers.get('x-bc-locale') ?? '';
292302

303+
// Check the original pathname BEFORE any locale processing
304+
// This catches /404 paths regardless of locale prefix
305+
const originalPathname = request.nextUrl.pathname;
306+
const pathnameWithQuery = request.nextUrl.pathname + request.nextUrl.search;
307+
308+
// Skip BigCommerce route resolution for /404 path to avoid GraphQL 400 errors on Vercel
309+
// This path should be handled by Next.js's not-found page via the catch-all route
310+
// Check the original pathname to catch /404 before locale processing
311+
// Also check the pathname after locale processing in case withIntl rewrote it
312+
const is404Path =
313+
originalPathname === '/404' ||
314+
originalPathname === '/404/' ||
315+
originalPathname.endsWith('/404') ||
316+
originalPathname.endsWith('/404/') ||
317+
pathnameWithQuery.startsWith('/404') ||
318+
pathnameWithQuery.startsWith('/404/');
319+
320+
if (is404Path) {
321+
// Use the locale from header, or default locale if not set
322+
const targetLocale = locale || defaultLocale;
323+
const url404 = new URL(`/${targetLocale}/404`, request.url);
324+
325+
url404.search = request.nextUrl.search;
326+
327+
return NextResponse.rewrite(url404);
328+
}
329+
330+
// Also check after locale processing in case withIntl already rewrote the URL
331+
const { pathname: processedPathname } = new URL(request.url);
332+
const processedCleanPathName = clearLocaleFromPath(processedPathname, locale);
333+
334+
if (processedCleanPathName === '/404' || processedCleanPathName === '/404/') {
335+
const targetLocale = locale || defaultLocale;
336+
const url404 = new URL(`/${targetLocale}/404`, request.url);
337+
338+
url404.search = request.nextUrl.search;
339+
340+
return NextResponse.rewrite(url404);
341+
}
342+
343+
// Get pathname for route processing (reuse processedPathname as pathname)
344+
const pathname = processedPathname;
345+
const cleanPathName = processedCleanPathName;
346+
293347
const { route, status } = await getRouteInfo(request, event);
294348

295349
if (status === 'MAINTENANCE') {
@@ -403,10 +457,6 @@ export const withRoutes: MiddlewareFactory = () => {
403457
}
404458

405459
default: {
406-
const { pathname } = new URL(request.url);
407-
408-
const cleanPathName = clearLocaleFromPath(pathname, locale);
409-
410460
url = `/${locale}${cleanPathName}`;
411461
}
412462
}

core/next.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export default async (): Promise<NextConfig> => {
6464
reactStrictMode: true,
6565
experimental: {
6666
optimizePackageImports: ['@icons-pack/react-simple-icons'],
67+
globalNotFound: true,
6768
},
6869
typescript: {
6970
ignoreBuildErrors: !!process.env.CI,

0 commit comments

Comments
 (0)