diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts
index 013f63562d0a8..5b24329dd36b3 100644
--- a/packages/next/build/webpack/loaders/next-serverless-loader.ts
+++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts
@@ -492,7 +492,7 @@ const nextServerlessLoader: loader.Loader = function () {
export async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) {
let Document
let Error
- let NotFound
+ let notFoundMod
;[
getStaticProps,
getServerSideProps,
@@ -502,7 +502,7 @@ const nextServerlessLoader: loader.Loader = function () {
config,
{ default: Document },
{ default: Error },
- ${absolute404Path ? `{ default: NotFound }, ` : ''}
+ ${absolute404Path ? `notFoundMod, ` : ''}
] = await Promise.all([
getStaticProps,
getServerSideProps,
@@ -772,13 +772,15 @@ const nextServerlessLoader: loader.Loader = function () {
res.statusCode = 404
const NotFoundComponent = ${
- absolute404Path ? 'NotFound' : 'Error'
+ absolute404Path ? 'notFoundMod.default' : 'Error'
}
const errPathname = "${absolute404Path ? '/404' : '/_error'}"
const result = await renderToHTML(req, res, errPathname, parsedUrl.query, Object.assign({}, options, {
- getStaticProps: undefined,
+ getStaticProps: ${
+ absolute404Path ? `notFoundMod.getStaticProps` : 'undefined'
+ },
getStaticPaths: undefined,
getServerSideProps: undefined,
Component: NotFoundComponent,
diff --git a/test/integration/i18n-support/pages/not-found/blocking-fallback/[slug].js b/test/integration/i18n-support/pages/not-found/blocking-fallback/[slug].js
new file mode 100644
index 0000000000000..7257f7422968d
--- /dev/null
+++ b/test/integration/i18n-support/pages/not-found/blocking-fallback/[slug].js
@@ -0,0 +1,48 @@
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+
+export default function Page(props) {
+ const router = useRouter()
+
+ return (
+ <>
+
gsp page
+ {JSON.stringify(props)}
+ {router.locale}
+ {JSON.stringify(router.locales)}
+ {JSON.stringify(router.query)}
+ {router.pathname}
+ {router.asPath}
+
+ to /
+
+
+ >
+ )
+}
+
+export const getStaticProps = ({ params, locale, locales }) => {
+ if (locale === 'en' || locale === 'nl') {
+ return {
+ notFound: true,
+ }
+ }
+
+ return {
+ props: {
+ params,
+ locale,
+ locales,
+ },
+ }
+}
+
+export const getStaticPaths = () => {
+ return {
+ // the default locale will be used since one isn't defined here
+ paths: ['first', 'second'].map((slug) => ({
+ params: { slug },
+ })),
+ fallback: 'blocking',
+ }
+}
diff --git a/test/integration/i18n-support/test/index.test.js b/test/integration/i18n-support/test/index.test.js
index 583d898bd669f..ae28017776676 100644
--- a/test/integration/i18n-support/test/index.test.js
+++ b/test/integration/i18n-support/test/index.test.js
@@ -106,6 +106,16 @@ function runTests(isDev) {
initialRevalidateSeconds: false,
srcRoute: '/gsp/no-fallback/[slug]',
},
+ '/en-US/not-found/blocking-fallback/first': {
+ dataRoute: `/_next/data/${buildId}/en-US/not-found/blocking-fallback/first.json`,
+ initialRevalidateSeconds: false,
+ srcRoute: '/not-found/blocking-fallback/[slug]',
+ },
+ '/en-US/not-found/blocking-fallback/second': {
+ dataRoute: `/_next/data/${buildId}/en-US/not-found/blocking-fallback/second.json`,
+ initialRevalidateSeconds: false,
+ srcRoute: '/not-found/blocking-fallback/[slug]',
+ },
'/en-US/not-found/fallback/first': {
dataRoute: `/_next/data/${buildId}/en-US/not-found/fallback/first.json`,
initialRevalidateSeconds: false,
@@ -157,6 +167,18 @@ function runTests(isDev) {
)}/gsp/no\\-fallback/([^/]+?)\\.json$`
),
},
+ '/not-found/blocking-fallback/[slug]': {
+ dataRoute: `/_next/data/${buildId}/not-found/blocking-fallback/[slug].json`,
+ dataRouteRegex: normalizeRegEx(
+ `^\\/_next\\/data\\/${escapeRegex(
+ buildId
+ )}\\/not\\-found\\/blocking\\-fallback\\/([^\\/]+?)\\.json$`
+ ),
+ fallback: null,
+ routeRegex: normalizeRegEx(
+ `^\\/not\\-found\\/blocking\\-fallback\\/([^\\/]+?)(?:\\/)?$`
+ ),
+ },
'/not-found/fallback/[slug]': {
dataRoute: `/_next/data/${buildId}/not-found/fallback/[slug].json`,
dataRouteRegex: normalizeRegEx(
@@ -957,6 +979,70 @@ function runTests(isDev) {
expect(await browser.eval('window.beforeNav')).toBe(1)
})
+ it('should render 404 for blocking fallback page that returned 404 on client transition', async () => {
+ const browser = await webdriver(appPort, '/en', true, true)
+ await browser.eval(`(function() {
+ next.router.push('/not-found/blocking-fallback/first')
+ })()`)
+ await browser.waitForElementByCss('h1')
+ await browser.eval('window.beforeNav = 1')
+
+ expect(await browser.elementByCss('html').text()).toContain(
+ 'This page could not be found'
+ )
+ const props = JSON.parse(await browser.elementByCss('#props').text())
+
+ expect(props.is404).toBe(true)
+ expect(props.locale).toBe('en')
+ expect(await browser.elementByCss('html').getAttribute('lang')).toBe('en')
+
+ const parsedUrl = url.parse(
+ await browser.eval('window.location.href'),
+ true
+ )
+ expect(parsedUrl.pathname).toBe('/en/not-found/blocking-fallback/first')
+ expect(parsedUrl.query).toEqual({})
+
+ if (isDev) {
+ // make sure page doesn't reload un-necessarily in development
+ await waitFor(10 * 1000)
+ }
+ expect(await browser.eval('window.beforeNav')).toBe(1)
+ })
+
+ it('should render 404 for blocking fallback page that returned 404', async () => {
+ const browser = await webdriver(
+ appPort,
+ '/en/not-found/blocking-fallback/first',
+ true,
+ true
+ )
+ await browser.waitForElementByCss('h1')
+ await browser.eval('window.beforeNav = 1')
+
+ expect(await browser.elementByCss('html').text()).toContain(
+ 'This page could not be found'
+ )
+ const props = JSON.parse(await browser.elementByCss('#props').text())
+
+ expect(props.is404).toBe(true)
+ expect(props.locale).toBe('en')
+ expect(await browser.elementByCss('html').getAttribute('lang')).toBe('en')
+
+ const parsedUrl = url.parse(
+ await browser.eval('window.location.href'),
+ true
+ )
+ expect(parsedUrl.pathname).toBe('/en/not-found/blocking-fallback/first')
+ expect(parsedUrl.query).toEqual({})
+
+ if (isDev) {
+ // make sure page doesn't reload un-necessarily in development
+ await waitFor(10 * 1000)
+ }
+ expect(await browser.eval('window.beforeNav')).toBe(1)
+ })
+
it('should not remove locale prefix for default locale', async () => {
const res = await fetchViaHTTP(appPort, '/en-US', undefined, {
redirect: 'manual',