-
-
Notifications
You must be signed in to change notification settings - Fork 111
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
Add type inference for getStaticProps and getServerSideProps #66
Labels
enhancement
New feature or request
Comments
Attempted with the Type inference doesn't seem to properly detect the returned value from /** @jsx jsx */
import { css, jsx } from '@emotion/core';
import { createLogger } from '@unly/utils-simple-logger';
import deepmerge from 'deepmerge';
import map from 'lodash.map';
import { GetStaticPaths, GetStaticProps, NextPage, InferGetStaticPropsType } from 'next';
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
import React from 'react';
import { Alert, Button } from 'reactstrap';
import NativeFeaturesSidebar from '../../../../../components/doc/NativeFeaturesSidebar';
import I18nLink from '../../../../../components/i18n/I18nLink';
import DefaultLayout from '../../../../../components/pageLayouts/DefaultLayout';
import ExternalLink from '../../../../../components/utils/ExternalLink';
import withApollo from '../../../../../hocs/withApollo';
import songs from '../../../../../mocks/songs';
import { GetStaticPropsContext } from '../../../../../types/nextjs/GetStaticPropsContext';
import { StaticParams } from '../../../../../types/nextjs/StaticParams';
import { StaticPath } from '../../../../../types/nextjs/StaticPath';
import { StaticPathsOutput } from '../../../../../types/nextjs/StaticPathsOutput';
import { StaticPropsInput } from '../../../../../types/nextjs/StaticPropsInput';
import { StaticPropsOutput } from '../../../../../types/nextjs/StaticPropsOutput';
import { OnlyBrowserPageProps } from '../../../../../types/pageProps/OnlyBrowserPageProps';
import { SSGPageProps } from '../../../../../types/pageProps/SSGPageProps';
import { getRandomInt } from '../../../../../utils/math/random';
import { getCommonStaticPaths, getCommonStaticProps } from '../../../../../utils/nextjs/SSG';
import waitFor from '../../../../../utils/timers/waitFor';
const fileLabel = 'pages/[locale]/examples/native-features/example-with-ssg-and-fallback/[albumId]';
const logger = createLogger({ // eslint-disable-line no-unused-vars,@typescript-eslint/no-unused-vars
label: fileLabel,
});
/**
* Only executed on the server side at build time
* Necessary when a page has dynamic routes and uses "getStaticProps"
*/
export const getStaticPaths: GetStaticPaths<StaticParams> = async (): Promise<StaticPathsOutput> => {
const commonStaticPaths: StaticPathsOutput = await getCommonStaticPaths();
const { paths } = commonStaticPaths;
const albumIdsToPreBuild = ['1']; // Only '/album-1-with-ssg-and-fallback' is generated at build time, other will be generated on-demand
map(albumIdsToPreBuild, (albumId: string): void => {
map(paths, (path: StaticPath) => {
path.params.albumId = albumId;
});
});
const staticPaths: StaticPathsOutput = {
...commonStaticPaths,
fallback: true,
};
return staticPaths;
};
/**
* Only executed on the server side at build time.
*
* @return Props (as "SSGPageProps") that will be passed to the Page component, as props
*
* @see https://github.com/zeit/next.js/discussions/10949#discussioncomment-6884
* @see https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation
*/
export const getStaticProps: GetStaticProps<SSGPageProps, StaticParams> = async (props: GetStaticPropsContext<StaticParams>): Promise<StaticPropsOutput> => {
const commonStaticProps: StaticPropsOutput = await getCommonStaticProps(props);
const { params: { albumId } } = props;
// Simulate API call by awaiting
const awaitForMs = getRandomInt(1000, 4000);
await waitFor(awaitForMs);
let songId = parseInt(albumId);
if (songId > songs.length - 1) { // Handle overflow
songId = 0;
} else if (songId < 0) {
songId = 0;
}
// Simulates an API response
const album: Album = {
id: songId,
title: songs[songId],
awaitedForMs: awaitForMs,
};
const staticProps = deepmerge(commonStaticProps, {
props: {
album,
albumId,
},
});
return staticProps;
};
type Album = {
id: number;
title: string;
awaitedForMs: number;
};
const ExampleWithSSGAndFallbackAlbumPage: NextPage<InferGetStaticPropsType<typeof getStaticProps>> = (props): JSX.Element => {
const { albumId, album, isSSGFallbackInitialBuild } = props;
const { id, title, awaitedForMs } = album;
return (
<DefaultLayout
{...props}
pageName={'example-with-ssg-and-fallback/[albumId]'}
headProps={{
title: `Album N°${albumId} (SSG, ${isSSGFallbackInitialBuild ? 'using fallback' : 'not using fallback'}) - Next Right Now`,
}}
Sidebar={NativeFeaturesSidebar}
>
<h1>Example, using SSG with fallback option</h1>
<div>
<Alert color={'info'} tag={'div'}>
This page will always be rendered statically, but the static bundle may be built either when deploying the website (AKA "pre-built"), or on-demand.<br />
<br />
This example has been made such as the main page (at /1) is pre-built, while all other pages are built on-demand, dynamically.<br />
Once the static page has been generated, it'll use the static version for all upcoming requests. Only the first user suffers from the waiting due to the build.<br />
When the page hasn't been rendered before (no static build available), then we display the <code>Loader</code> component so that the user can see something is happening instead of a white page.<br />
<br />
{
isSSGFallbackInitialBuild ? (
<p>
This page <b>has</b> used fallback rendering (it <b>hadn't</b> been generated previously).
</p>
) : (
<p>
This page <b>has not</b> used fallback rendering (it <b>had</b> been generated previously).
</p>
)
}
</Alert>
<Alert color={'warning'}>
If you use the below "previous"/"next" button, it'll make you believe pages were pre-rendered, but it's not true.<br />
Next is so smart that it optimize this kind of stuff, using the <code>next/link</code> (or <code>I18nLink</code>) component preload pages and build them before you click on them.<br />
If you want to check for sure if a page has been pre-rendered, you better use the "next +2" link, which uses a <code>a</code> which doesn't have such optimizations.
</Alert>
<div
css={css`
background-color: white;
border-radius: 5px;
padding: 30px;
text-align: center;
`}
>
<h1>Album N°{albumId}</h1>
<div>
Title: {title}<br />
</div>
<div
css={css`
display: flex;
justify-content: center;
`}
>
{
id > 0 && (
<I18nLink
href={'/examples/native-features/example-with-ssg-and-fallback/[albumId]'}
params={{
albumId: id - 1,
}}
>
<Button color={'link'}>Go to previous album</Button>
</I18nLink>
)
}
<I18nLink
href={'/examples/native-features/example-with-ssg-and-fallback/[albumId]'}
params={{
albumId: id + 1,
}}
>
<Button color={'link'}>Go to next album</Button>
</I18nLink>
</div>
<ExternalLink href={`/examples/native-features/example-with-ssg-and-fallback/${id + 2}`}>
<Button color={'link'}>Go to next+2 album (opens new tab)</Button>
</ExternalLink>
<div>
<br />
<i>The request was slowed by <b>{awaitedForMs}ms</b> before being sent to the browser, to simulate a real API call.</i>
</div>
</div>
<br />
<br />
<Alert color={'success'}>
In order to simplify things, NRN sets the <code>isSSGFallbackInitialBuild</code> variable, available in all pages as props.
</Alert>
<Alert color={'warning'}>
In development mode, it is not possible to simulate <code>fallback</code> mode properly.<br />
Each page refresh will completely refresh the page, any previous build will be ignored, and all page refresh will have <code>isSSGFallbackInitialBuild: true</code>.
</Alert>
</div>
</DefaultLayout>
);
};
export default withApollo()(ExampleWithSSGAndFallbackAlbumPage); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Since v9.4.4, type inference is natively supported by Next.js
See vercel/next.js#11842
The main advantage is that it doesn't require to manually write props for pages, but those would be inferred from the return value of getStaticProps or getServerSideProps.
The text was updated successfully, but these errors were encountered: