SSG (Static Site Generation)
Theoretically speaking, with Static Site Generation, you can reduce TTFB and server-load in return of relatively slower CI builds and stale pages.
However, we delete page render data (during build) so that we can force Next.js to re-render the page during the first visit, so that we can show different results of a page on staging and production environments.
The staticProps helper
To help with data fetching in SSG, we provide a staticProps function that you can use when exporting getStaticProps. This enforces you to specify current pathname, as well as resource data necessary to render the page.
If your page needs its own data, you can use callAPI as usual inside by passing the context you receive.
import { staticProps, callAPI } from '@traveloka/core';
export default MyPage() {
return <>Hello</>
export const getStaticProps = staticProps({
path: '/some/path',
resources: [MyComponentRQ, MyOtherComponentRQ],
getStaticProps: async (ctx, rawAppContext) => {
const res = await callAPI(ctx, options);
return {
props: {
myData: res.result.data,
},
};
},
});
Page lifecycle
Returning 404 or redirecting
You can use return a special notFound or redirect property inside the staticProps helper function.
export const getStaticProps = staticProps({
path: '/my/page',
async getStaticProps(ctx, appContext) {
if (appContext.featureControl.something?.enabled) {
return { notFound: true };
}
if (otherCondition) {
return {
redirect: {
destination: '/',
permanent: false,
},
};
}
return {
props: {},
};
},
});
Cache duration
By default all response types (success, redirection, and not found) is cached for 10 minutes. You can change it as follows.
// `revalidate` in seconds
// So this one will be in cache for 10 mins
export const getStaticProps = staticProps({
path: '/my/page',
getStaticProps: async (_ctx, rawAppContext) => {
return {
props: {},
revalidate: 10 * 60,
};
},
});
Enumering paths with dynamic routes
If you're route protecting based on locale inside dynamic routes, it's recommended to use getStaticPaths. Alternatively, you can use fallback: 'blocking' and do redirection in getStaticProps.
export const getStaticPaths = ctx => {
return {
paths: enabledLocales.flatMap(locale => {
return pages.map(page => {
return {
params: {},
locale,
};
});
}),
fallback: false,
};
};
Resource Data
Listing resource queries
Previously, in TravelokaApp.getInitialProps, we're doing two-pass render to get the content resource and other resource queries. That's why it works like magic (most of the time) without any additional setup.
With SSG, we no longer have knowledge about component that's being rendered (by our design decision). This is why with SSG, we have to explicitly tell the data-fetching function what resources we need in a page.
You can use the last argument in either getSharedStaticProps or getSharedServerProps to list down your resource queries. It's a rest arguments so you can put however many you like.
Not specifying all resource queries needed for the initial page render will result in Suspense error, unless you have wrapped your page with <Suspense>. You can rely on this behavior to lazily load additional resource data when you lazily load an additional component.
const query1 = { contentResource: { A: { B: '' } } };
const query2 = { imageResource: { A: { B: { link: '' } } } };
const query3 = { imageSlider: { C: { link: '' } } };
export const getStaticProps = staticProps({
resources: [query1, query2, query3],
});
Specifying component resource query
You can export an ComponentNameRQ constant (RQ = "Resource Query") from your component definition file or from inside the resources.ts file (so we can load just the resource definition without loading the component itself).
Alternatively (now no longer recommeded), you can also expose .resourceQuery property with the exported component.
export default function Page() {
return (
<>
<MobileHeaderWithSidebar />
<Component />
</>
);
}
export const getStaticProps = staticProps({
resources: [MobileHeaderWithSidebar.resourceQuery, Component.resourceQuery],
});
Hook behavior differences
We now provide you with cachableServerProps to mitigate staticProps limitations. For example, with cachableServerProps, you can get information about the currency of the page from query string.
Using getStaticProps will cause the following hooks to behave a bit differently during SSR. Hook usages inside useEffect or client-side interactions are not affected.
-
useCurrentRoute— we will make assumption abvout thehostandprotocol(see Routing docs type definition for complete property breakdown). We suggest you to not rely on these properties instead. -
useCurrency— will only return currency based on current locale. We suggest you to stop relying on the "correct" selected currency during SSR. In client-side, the currency value will be updated from cookie if any.