Skip to main content

@traveloka/core/next

This module handles how we interplay our app with native Next.js interface.

Important files

  • Common next config (next.config.js)

    • packages/core/next/config.js
  • Templates for next special pages: _document and _app.

    • packages/core/next/withTravelokaDocument.tsx — For _document (this governs how we render our HTML page, like what <script> and <meta> tags and to include in the page).
    • packages/core/next/withTravelokaApp.tsx — For _app (note that this includes all the providers that we need on the page).
  • Data-fetching helpers for your page

    • packages/core/next/withTravelokaPage.tsx — Backwards compatibility for pages that still uses getInitialProps (from earlier versions of Next.js). You should no longer use this fuction.
    • packages/core/next/data-fetching/staticProps.ts — Helper function for use with getStaticProps. Note that this internally calls packages/core/next/data-fetching/getSharedStaticProps.ts
    • packages/core/next/data-fetching/getSharedServerProps.ts — Helper function for use with getServerSideProps, with default Next.js behavior.
    • packages/core/next/data-fetching/cacheableServerProps.ts — Helper function for use with getServerSideProps, with caching enabled by default (for your safety, we do not expose user/request-specific data inside the getServerSideProps context, so the page can be cached by CDN). Note that this internally calls packages/core/next/data-fetching/getSharedCacheableServerProps.ts
  • Routing utilities

    • packages/core/next/routing/NextRouter.tsx — replacement of 'next/router` to prevent "dev-only" routes to become accessible to the general public (Next.js does not have this context, and without this helper, using Next's default router will allow client-side navigation to that page)
    • packages/core/next/routing/NextLink.tsx — replacement component for next/link, to address similar issue like the above
    • packages/core/next/routing/usePrefetchJs.ts — Hook for cross-service JS/CSS chunk prefetching. Loads a pre-built manifest (prefetch_js.js) from CDN and injects <link rel="prefetch"> tags for all chunks needed by a target route in another service. For same-service prefetch, delegates to Next.js built-in router.prefetch().

How this module works

Rendering page

Data fetching function is run in this order (top-to-bottom)

  • Your page's data fetching function, e.g. getStaticProps
    • Note that by using our data-fetching helpers like staticProps or cacheableServerProps, we auto-generate additional props (we call it "shared props" that is required on the _app) level.
    • By setting special props like statusCode, you can configure your response
  • getInitialProps inside withTravelokaDeocument
    • Only runs in server-side (not during client-side navigation)
    • Generally it doesn't have something very interesting for us
  • The renderer inside withTravelokaApp
    • This fires some monitoring/telemetry/tracking we have in place
    • This configures the reponse code based on the statusCode props returned
    • This renders the providers and the content of your page.

Shared props

"Shared props" are the shape that withTravelokaApp expects a page props should have. See the definition of SharedPageProps type to see what they are.

App context

"App context" gives the context to how we render a page: which locale/currency it is, what interface it is, which feature controls are active, etc.

We pass this (raw) app context to the getStaticProps data-fetching function of staticProps and cacheableServerProps. For getServerSideProps, you will naturally call getSharedServerProps which returns this object as one of its property.

NOTE: There is "normalized" app context via the use of packages/core/next/normalizeAppContext.ts. Apparently, this is only used inside withTravelokaPage and is most likely only there for backwards-compatibility with early adoption of TVLK5. (?)

Next context

Next exposes a different ctx object depending on the type of data-fetching function object you used (for example, in getStaticProps, ctx.req would be a dummy request object with limited props).

Due to how our internal code depends on certain properties of req (e.g. req.get), and it was a huge effort to make the consumers of this req function aware whether the page is a server-rendered or a static function, we came along to just "normalize" the req functions to have all the properties that we might use (defining a "mock" but sensible value for the static page).

Note that we have different "normalizer" functions depending on whether you are using getStaticProps, getServerSideProps, or cacheableServerProps (see packages/core/next/data-fetching/normalizeNextContext.ts).

  • normalizeNextContext — Isomorphic form for API calls
  • staticCtxToNextCtx — For staticProps
  • serverSideContextToNextContext — For getServerSideProps
  • serverSideContextToCacheableNextContext — For cacheableServerProps