diff --git a/packages/now-next/src/index.ts b/packages/now-next/src/index.ts
index 6b7e73e91ff..7df103f7e9d 100644
--- a/packages/now-next/src/index.ts
+++ b/packages/now-next/src/index.ts
@@ -1658,6 +1658,10 @@ export const build = async ({
);
}
+ const isNotFound = prerenderManifest.notFoundRoutes.includes(
+ routeFileNoExt
+ );
+
const htmlFsRef = isBlocking
? // Blocking pages do not have an HTML fallback
null
@@ -1745,7 +1749,7 @@ export const build = async ({
lambda = lambdas[outputSrcPathPage];
}
- if (initialRevalidate === false) {
+ if (!isNotFound && initialRevalidate === false) {
if (htmlFsRef == null || jsonFsRef == null) {
throw new NowBuildError({
code: 'NEXT_HTMLFSREF_JSONFSREF',
@@ -1760,7 +1764,7 @@ export const build = async ({
}
}
- if (prerenders[outputPathPage] == null) {
+ if (prerenders[outputPathPage] == null && !isNotFound) {
if (lambda == null) {
throw new NowBuildError({
code: 'NEXT_MISSING_LAMBDA',
diff --git a/packages/now-next/src/utils.ts b/packages/now-next/src/utils.ts
index e19f86753ef..2b00e85a812 100644
--- a/packages/now-next/src/utils.ts
+++ b/packages/now-next/src/utils.ts
@@ -752,6 +752,8 @@ export type NextPrerenderedRoutes = {
};
omittedRoutes: string[];
+
+ notFoundRoutes: string[];
};
export async function getExportIntent(
@@ -842,6 +844,7 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: null,
omittedRoutes: [],
+ notFoundRoutes: [],
};
}
@@ -887,6 +890,7 @@ export async function getPrerenderManifest(
preview: {
previewModeId: string;
};
+ notFoundRoutes?: string[];
} = JSON.parse(await fs.readFile(pathPrerenderManifest, 'utf8'));
switch (manifest.version) {
@@ -901,6 +905,7 @@ export async function getPrerenderManifest(
bypassToken:
(manifest.preview && manifest.preview.previewModeId) || null,
omittedRoutes: [],
+ notFoundRoutes: [],
};
routes.forEach(route => {
@@ -955,8 +960,13 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: manifest.preview.previewModeId,
omittedRoutes: [],
+ notFoundRoutes: [],
};
+ if (manifest.notFoundRoutes) {
+ ret.notFoundRoutes.push(...manifest.notFoundRoutes);
+ }
+
routes.forEach(route => {
const {
initialRevalidateSeconds,
@@ -1010,6 +1020,7 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: null,
omittedRoutes: [],
+ notFoundRoutes: [],
};
}
}
diff --git a/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/next.config.js b/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/next.config.js
index 4f05fa39ab8..249131fd3fe 100644
--- a/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/next.config.js
+++ b/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/next.config.js
@@ -1,4 +1,7 @@
module.exports = {
+ generateBuildId() {
+ return 'testing-build-id';
+ },
experimental: {
i18n: {
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en-US', 'en'],
diff --git a/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/not-found/fallback/[slug].js b/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/not-found/fallback/[slug].js
new file mode 100644
index 00000000000..992fec8c387
--- /dev/null
+++ b/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/not-found/fallback/[slug].js
@@ -0,0 +1,50 @@
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+
+export default function Page(props) {
+ const router = useRouter();
+
+ if (router.isFallback) return 'Loading...';
+
+ 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 {
+ unstable_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: true,
+ };
+};
diff --git a/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/not-found/index.js b/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/not-found/index.js
new file mode 100644
index 00000000000..111218ca7c3
--- /dev/null
+++ b/packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/not-found/index.js
@@ -0,0 +1,37 @@
+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 = ({ locale, locales }) => {
+ if (locale === 'en' || locale === 'nl') {
+ return {
+ unstable_notFound: true,
+ };
+ }
+
+ return {
+ props: {
+ locale,
+ locales,
+ },
+ };
+};
diff --git a/packages/now-next/test/fixtures/00-i18n-support/next.config.js b/packages/now-next/test/fixtures/00-i18n-support/next.config.js
index 4f05fa39ab8..249131fd3fe 100644
--- a/packages/now-next/test/fixtures/00-i18n-support/next.config.js
+++ b/packages/now-next/test/fixtures/00-i18n-support/next.config.js
@@ -1,4 +1,7 @@
module.exports = {
+ generateBuildId() {
+ return 'testing-build-id';
+ },
experimental: {
i18n: {
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en-US', 'en'],
diff --git a/packages/now-next/test/fixtures/00-i18n-support/now.json b/packages/now-next/test/fixtures/00-i18n-support/now.json
index 8ca9d6b615b..fefc2020392 100644
--- a/packages/now-next/test/fixtures/00-i18n-support/now.json
+++ b/packages/now-next/test/fixtures/00-i18n-support/now.json
@@ -310,6 +310,81 @@
"path": "/fr/gssp/first",
"status": 200,
"mustContain": "slug\":\"first\""
+ },
+
+ // TODO: update when directory listing is disabled
+ // and these are proper 404s
+ {
+ "path": "/en/not-found",
+ "status": 200,
+ "mustContain": "Index of"
+ },
+ {
+ "path": "/nl/not-found",
+ "status": 200,
+ "mustContain": "Index of"
+ },
+ {
+ "path": "/en-US/not-found",
+ "status": 200,
+ "mustContain": "lang=\"en-US\""
+ },
+ {
+ "path": "/nl-NL/not-found",
+ "status": 200,
+ "mustContain": "lang=\"nl-NL\""
+ },
+ {
+ "path": "/fr/not-found",
+ "status": 200,
+ "mustContain": "lang=\"fr\""
+ },
+
+ // this will always be a 200 unless fallback: blocking is used
+ // since the static fallback page is served before the 404
+ // page is rendered
+ {
+ "path": "/en/not-found/fallback/first",
+ "status": 200,
+ "mustContain": "lang=\"en\""
+ },
+ {
+ "path": "/en/not-found/fallback/first",
+ "status": 200,
+ "mustNotContain": "gsp page"
+ },
+ {
+ "path": "/_next/data/testing-build-id/en/not-found/fallback/first.json",
+ "status": 404
+ },
+ {
+ "path": "/en/not-found/fallback/first",
+ "status": 200,
+ "mustContain": "lang=\"en\""
+ },
+ {
+ "path": "/en/not-found/fallback/first",
+ "status": 200,
+ "mustNotContain": "gsp page"
+ },
+ {
+ "path": "/fr/not-found/fallback/first",
+ "status": 200,
+ "mustContain": "lang=\"fr\""
+ },
+ {
+ "path": "/_next/data/testing-build-id/fr/not-found/fallback/first.json",
+ "status": 200
+ },
+ {
+ "path": "/fr/not-found/fallback/first",
+ "status": 200,
+ "mustContain": "lang=\"fr\""
+ },
+ {
+ "path": "/fr/not-found/fallback/first",
+ "status": 200,
+ "mustContain": "gsp page"
}
]
}
diff --git a/packages/now-next/test/fixtures/00-i18n-support/pages/not-found/fallback/[slug].js b/packages/now-next/test/fixtures/00-i18n-support/pages/not-found/fallback/[slug].js
new file mode 100644
index 00000000000..992fec8c387
--- /dev/null
+++ b/packages/now-next/test/fixtures/00-i18n-support/pages/not-found/fallback/[slug].js
@@ -0,0 +1,50 @@
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+
+export default function Page(props) {
+ const router = useRouter();
+
+ if (router.isFallback) return 'Loading...';
+
+ 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 {
+ unstable_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: true,
+ };
+};
diff --git a/packages/now-next/test/fixtures/00-i18n-support/pages/not-found/index.js b/packages/now-next/test/fixtures/00-i18n-support/pages/not-found/index.js
new file mode 100644
index 00000000000..111218ca7c3
--- /dev/null
+++ b/packages/now-next/test/fixtures/00-i18n-support/pages/not-found/index.js
@@ -0,0 +1,37 @@
+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 = ({ locale, locales }) => {
+ if (locale === 'en' || locale === 'nl') {
+ return {
+ unstable_notFound: true,
+ };
+ }
+
+ return {
+ props: {
+ locale,
+ locales,
+ },
+ };
+};