Skip to main content

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.

warning

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

info

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 the host and protocol (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.