Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[next] Add handling for not found routes with i18n #5313

Merged
merged 2 commits into from Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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,
},
};
};