Skip to content

Commit

Permalink
[next] Add handling for not found routes with i18n (#5313)
Browse files Browse the repository at this point in the history
* Add handling for not found routes with i18n

* Update prerender lambda check
  • Loading branch information
ijjk committed Oct 23, 2020
1 parent fd5d3b2 commit d0da1ce
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 2 deletions.
8 changes: 6 additions & 2 deletions packages/now-next/src/index.ts
Expand Up @@ -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
Expand Down Expand Up @@ -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',
Expand All @@ -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',
Expand Down
11 changes: 11 additions & 0 deletions packages/now-next/src/utils.ts
Expand Up @@ -752,6 +752,8 @@ export type NextPrerenderedRoutes = {
};

omittedRoutes: string[];

notFoundRoutes: string[];
};

export async function getExportIntent(
Expand Down Expand Up @@ -842,6 +844,7 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: null,
omittedRoutes: [],
notFoundRoutes: [],
};
}

Expand Down Expand Up @@ -887,6 +890,7 @@ export async function getPrerenderManifest(
preview: {
previewModeId: string;
};
notFoundRoutes?: string[];
} = JSON.parse(await fs.readFile(pathPrerenderManifest, 'utf8'));

switch (manifest.version) {
Expand All @@ -901,6 +905,7 @@ export async function getPrerenderManifest(
bypassToken:
(manifest.preview && manifest.preview.previewModeId) || null,
omittedRoutes: [],
notFoundRoutes: [],
};

routes.forEach(route => {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1010,6 +1020,7 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: null,
omittedRoutes: [],
notFoundRoutes: [],
};
}
}
Expand Down
@@ -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'],
Expand Down
@@ -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 (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}

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,
};
};
@@ -0,0 +1,37 @@
import Link from 'next/link';
import { useRouter } from 'next/router';

export default function Page(props) {
const router = useRouter();

return (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}

export const getStaticProps = ({ locale, locales }) => {
if (locale === 'en' || locale === 'nl') {
return {
unstable_notFound: true,
};
}

return {
props: {
locale,
locales,
},
};
};
@@ -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'],
Expand Down
75 changes: 75 additions & 0 deletions packages/now-next/test/fixtures/00-i18n-support/now.json
Expand Up @@ -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"
}
]
}
@@ -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 (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}

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,
};
};
@@ -0,0 +1,37 @@
import Link from 'next/link';
import { useRouter } from 'next/router';

export default function Page(props) {
const router = useRouter();

return (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}

export const getStaticProps = ({ locale, locales }) => {
if (locale === 'en' || locale === 'nl') {
return {
unstable_notFound: true,
};
}

return {
props: {
locale,
locales,
},
};
};

0 comments on commit d0da1ce

Please sign in to comment.