Skip to content

Commit 34fe273

Browse files
committed
Add isSSGFallbackInitialBuild prop for all pages and properly handle the SSG fallback mode
1 parent d5a27ec commit 34fe273

File tree

3 files changed

+49
-16
lines changed

3 files changed

+49
-16
lines changed

src/components/appBootstrap/MultiversalAppBootstrap.tsx

+17-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { isBrowser } from '@unly/utils';
33
import { createLogger } from '@unly/utils-simple-logger';
44
import { ThemeProvider } from 'emotion-theming';
55
import { i18n } from 'i18next';
6-
import React from 'react';
6+
import isEmpty from 'lodash.isempty';
7+
import React, { useState } from 'react';
78
import ErrorPage from '../../pages/_error';
89
import customerContext from '../../stores/customerContext';
910
import i18nContext from '../../stores/i18nContext';
@@ -14,6 +15,7 @@ import { SSGPageProps } from '../../types/pageProps/SSGPageProps';
1415
import { SSRPageProps } from '../../types/pageProps/SSRPageProps';
1516
import { initCustomerTheme } from '../../utils/data/theme';
1617
import i18nextLocize from '../../utils/i18n/i18nextLocize';
18+
import Loader from '../animations/Loader';
1719
import DefaultErrorLayout from '../errors/DefaultErrorLayout';
1820
import BrowserPageBootstrap, { BrowserPageBootstrapProps } from './BrowserPageBootstrap';
1921
import ServerPageBootstrap, { ServerPageBootstrapProps } from './ServerPageBootstrap';
@@ -37,7 +39,10 @@ export type Props = MultiversalAppBootstrapProps<SSGPageProps> | MultiversalAppB
3739
const MultiversalAppBootstrap: React.FunctionComponent<Props> = (props): JSX.Element => {
3840
const {
3941
pageProps,
42+
router,
4043
} = props;
44+
// When using SSG with "fallback: true" and the page hasn't been generated yet then isSSGFallbackInitialBuild is true
45+
const [isSSGFallbackInitialBuild] = useState<boolean>(isEmpty(pageProps) && router?.isFallback === true);
4146

4247
Sentry.addBreadcrumb({ // See https://docs.sentry.io/enriching-error-data/breadcrumbs
4348
category: fileLabel,
@@ -49,6 +54,13 @@ const MultiversalAppBootstrap: React.FunctionComponent<Props> = (props): JSX.Ele
4954
console.debug('MultiversalAppBootstrap.props', props);
5055
}
5156

57+
// Display a loader (we could use a skeleton too) when this happens, so that the user doesn't face a white page until the page is generated and displayed
58+
if (isSSGFallbackInitialBuild && router.isFallback) { // When router.isFallback becomes "false", then it'll mean the page has been generated and rendered and we can display it, instead of the loader
59+
return (
60+
<Loader />
61+
);
62+
}
63+
5264
if (pageProps.isReadyToRender || pageProps.statusCode === 404) {
5365
console.info('MultiversalAppBootstrap - App is ready, rendering...');
5466
const {
@@ -109,18 +121,22 @@ const MultiversalAppBootstrap: React.FunctionComponent<Props> = (props): JSX.Ele
109121
if (isBrowser()) {
110122
browserPageBootstrapProps = {
111123
...props,
124+
router,
112125
pageProps: {
113126
...pageProps,
114127
i18nextInstance,
128+
isSSGFallbackInitialBuild: isSSGFallbackInitialBuild,
115129
theme,
116130
},
117131
};
118132
} else {
119133
serverPageBootstrapProps = {
120134
...props,
135+
router,
121136
pageProps: {
122137
...pageProps,
123138
i18nextInstance,
139+
isSSGFallbackInitialBuild: isSSGFallbackInitialBuild,
124140
theme,
125141
},
126142
};

src/pages/[locale]/examples/native-features/example-with-ssg-and-fallback/[albumId].tsx

+31-15
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
/** @jsx jsx */
2-
import { jsx, css } from '@emotion/core';
2+
import { css, jsx } from '@emotion/core';
33
import { createLogger } from '@unly/utils-simple-logger';
44
import deepmerge from 'deepmerge';
55
import map from 'lodash.map';
66
import { GetStaticPaths, GetStaticProps, NextPage } from 'next';
7-
import { NextRouter, useRouter } from 'next/router';
87
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
9-
import React, { useState } from 'react';
8+
import React from 'react';
109
import { Alert, Button } from 'reactstrap';
1110
import I18nLink from '../../../../../components/i18n/I18nLink';
1211
import DefaultLayout from '../../../../../components/pageLayouts/DefaultLayout';
@@ -50,6 +49,8 @@ export const getStaticProps: GetStaticProps<SSGPageProps, StaticParams> = async
5049

5150
if (songId > songs.length - 1) { // Handle overflow
5251
songId = 0;
52+
} else if (songId < 0) {
53+
songId = 0;
5354
}
5455

5556
// Simulates an API response
@@ -112,24 +113,31 @@ type Props = {
112113
} & SSGPageProps<Partial<OnlyBrowserPageProps>>;
113114

114115
const ExampleWithSSGAndFallbackAlbumPage: NextPage<Props> = (props): JSX.Element => {
115-
const { albumId, album } = props;
116-
const router: NextRouter = useRouter();
116+
const { albumId, album, isSSGFallbackInitialBuild } = props;
117117
const { locale } = useI18n();
118-
const [hasUsedFallbackRendering] = useState<boolean>(router.isFallback);
119118
const { id, title, awaitedForMs } = album;
120119

121120
return (
122121
<DefaultLayout
123122
{...props}
124123
pageName={'example-with-ssg-and-fallback/[albumId]'}
125124
headProps={{
126-
title: `Album N°${albumId} (SSG, ${hasUsedFallbackRendering ? 'using fallback' : 'not using fallback'}) - Next Right Now`,
125+
title: `Album N°${albumId} (SSG, ${isSSGFallbackInitialBuild ? 'using fallback' : 'not using fallback'}) - Next Right Now`,
127126
}}
128127
>
128+
<h1>Example, using SSG with fallback option</h1>
129+
129130
<div>
130131
<Alert color={'info'} tag={'div'}>
132+
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 />
133+
<br />
134+
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 />
135+
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 />
136+
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 />
137+
<br />
138+
131139
{
132-
hasUsedFallbackRendering ? (
140+
isSSGFallbackInitialBuild ? (
133141
<p>
134142
This page <b>has</b> used fallback rendering (it <b>hadn't</b> been generated previously).
135143
</p>
@@ -152,12 +160,16 @@ const ExampleWithSSGAndFallbackAlbumPage: NextPage<Props> = (props): JSX.Element
152160
justify-content: center;
153161
`}
154162
>
155-
<I18nLink
156-
href={'/examples/native-features/example-with-ssg-and-fallback/[albumId]'}
157-
as={`/${locale}/examples/native-features/example-with-ssg-and-fallback/${id - 1}`}
158-
>
159-
<Button color={'link'}>Go to previous album</Button>
160-
</I18nLink>
163+
{
164+
id > 0 && (
165+
<I18nLink
166+
href={'/examples/native-features/example-with-ssg-and-fallback/[albumId]'}
167+
as={`/${locale}/examples/native-features/example-with-ssg-and-fallback/${id - 1}`}
168+
>
169+
<Button color={'link'}>Go to previous album</Button>
170+
</I18nLink>
171+
)
172+
}
161173

162174
<I18nLink
163175
href={'/examples/native-features/example-with-ssg-and-fallback/[albumId]'}
@@ -175,9 +187,13 @@ const ExampleWithSSGAndFallbackAlbumPage: NextPage<Props> = (props): JSX.Element
175187
<br />
176188
<br />
177189

190+
<Alert color={'success'}>
191+
In order to simplify things, NRN sets the <code>isSSGFallbackInitialBuild</code> variable, available in all pages as props.
192+
</Alert>
193+
178194
<Alert color={'warning'}>
179195
In development mode, it is not possible to simulate <code>fallback</code> mode properly.<br />
180-
Each page refresh will completely refresh the page, any previous build will be ignored.
196+
Each page refresh will completely refresh the page, any previous build will be ignored, and all page refresh will have <code>isSSGFallbackInitialBuild: true</code>.
181197
</Alert>
182198
</div>
183199

src/types/nextjs/MultiversalAppBootstrapPageProps.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ import { Theme } from '../data/Theme';
66
*/
77
export type MultiversalAppBootstrapPageProps = {
88
i18nextInstance: i18n;
9+
isSSGFallbackInitialBuild: boolean; // When true, means the app is loading a SSG page, with fallback mode enabled, and this page hasn't been built before
910
theme: Theme;
1011
}

0 commit comments

Comments
 (0)