Skip to content

Commit

Permalink
CI: Static export locale (#7409)
Browse files Browse the repository at this point in the history
* ci: static export locale

* refactor: updated logic in conditions
  • Loading branch information
canerakdas authored Jan 18, 2025
1 parent 1e4fc38 commit 02f5a3e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 25 deletions.
26 changes: 23 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,29 @@ jobs:
# Used for API requests that require GitHub API scopes
NEXT_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}

- name: Build Next.js (Static)
# We only run full static builds within Pull Requests. As they're not needed on `merge_group` or `push` events
- name: Build Next.js (Static All Locales)
# We only run full static builds within Pull Requests. This step is also used to export
# static output in all languages, and it only works on `push` events.
if: github.event_name == 'push'
# We want to enforce that the actual `turbo@latest` package is used instead of a possible hijack from the user
# the `${{ steps.turborepo_arguments.outputs.turbo_args }}` is a string substitution coming from a previous step
run: npx --package=turbo@latest -- turbo deploy ${{ steps.turborepo_arguments.outputs.turbo_args }}
env:
# We want to ensure we have enough RAM allocated to the Node.js process
# this should be a last resort in case by any chances the build memory gets too high
# but in general this should never happen
NODE_OPTIONS: '--max_old_space_size=4096'
# Used for API requests that require GitHub API scopes
NEXT_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
# We want to ensure that static exports for all locales are triggered only on `push` events to save resources
# and time.
NEXT_PUBLIC_STATIC_EXPORT_LOCALE: true

- name: Build Next.js (Static Default Locale)
# We want to generate static output in the default language within Pull Requests
# in order to reduce source wastages and build times.
# Note that we skip full static builds on Crowdin-based Pull Requests as these PRs should only contain translation changes
if: |
(github.event_name == 'push') ||
(github.event_name == 'pull_request_target' &&
github.event.pull_request.head.ref != 'chore/crowdin')
# We want to enforce that the actual `turbo@latest` package is used instead of a possible hijack from the user
Expand All @@ -131,6 +149,8 @@ jobs:
NODE_OPTIONS: '--max_old_space_size=4096'
# Used for API requests that require GitHub API scopes
NEXT_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
# We want to ensure that static exports for all locales do not occur on `pull_request_target` events
NEXT_PUBLIC_STATIC_EXPORT_LOCALE: false

- name: Sync Orama Cloud
# We only want to sync the Orama Cloud production indexes on `push` events.
Expand Down
49 changes: 33 additions & 16 deletions apps/site/app/[locale]/[...path]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
*/

import * as basePage from '@/app/[locale]/page';
import { ENABLE_STATIC_EXPORT } from '@/next.constants.mjs';
import {
ENABLE_STATIC_EXPORT_LOCALE,
ENABLE_STATIC_EXPORT,
} from '@/next.constants.mjs';
import { dynamicRouter } from '@/next.dynamic.mjs';
import { availableLocaleCodes } from '@/next.locales.mjs';
import { availableLocaleCodes, defaultLocale } from '@/next.locales.mjs';

// This is the default Viewport Metadata
// @see https://nextjs.org/docs/app/api-reference/functions/generate-viewport#generateviewport-function
Expand All @@ -20,21 +23,35 @@ export const generateViewport = basePage.generateViewport;
// @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata
export const generateMetadata = basePage.generateMetadata;

// This provides all the possible paths that can be generated statically
// + provides all the paths that we support on the Node.js Website
// Generates all possible static paths based on the locales and environment configuration
// - Returns an empty array if static export is disabled (`ENABLE_STATIC_EXPORT` is false)
// - If `ENABLE_STATIC_EXPORT_LOCALE` is true, generates paths for all available locales
// - Otherwise, generates paths only for the default locale
// @see https://nextjs.org/docs/app/api-reference/functions/generate-static-params
export const generateStaticParams = async () => {
const allAvailableRoutes = await Promise.all(
// Gets all mapped routes to the Next.js Routing Engine by Locale
availableLocaleCodes.map(async (locale: string) => {
const routesForLanguage = await dynamicRouter.getRoutesByLanguage(locale);

return routesForLanguage.map(pathname =>
dynamicRouter.mapPathToRoute(locale, pathname)
);
})
);

return ENABLE_STATIC_EXPORT ? allAvailableRoutes.flat().sort() : [];
// Return an empty array if static export is disabled
if (!ENABLE_STATIC_EXPORT) {
return [];
}

// Helper function to fetch and map routes for a specific locale
const getRoutesForLocale = async (locale: string) => {
const routes = await dynamicRouter.getRoutesByLanguage(locale);

return routes.map(pathname =>
dynamicRouter.mapPathToRoute(locale, pathname)
);
};

// Determine which locales to include in the static export
const locales = ENABLE_STATIC_EXPORT_LOCALE
? availableLocaleCodes
: [defaultLocale.code];

// Generates all possible routes for all available locales
const routes = await Promise.all(locales.map(getRoutesForLocale));

return routes.flat().sort();
};

// Enforces that this route is used as static rendering
Expand Down
28 changes: 22 additions & 6 deletions apps/site/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import type { FC } from 'react';

import { setClientContext } from '@/client-context';
import WithLayout from '@/components/withLayout';
import { ENABLE_STATIC_EXPORT } from '@/next.constants.mjs';
import {
ENABLE_STATIC_EXPORT_LOCALE,
ENABLE_STATIC_EXPORT,
} from '@/next.constants.mjs';
import { PAGE_VIEWPORT, DYNAMIC_ROUTES } from '@/next.dynamic.constants.mjs';
import { dynamicRouter } from '@/next.dynamic.mjs';
import { allLocaleCodes, availableLocaleCodes } from '@/next.locales.mjs';
Expand All @@ -37,15 +40,28 @@ export const generateMetadata = async (props: DynamicParams) => {
return dynamicRouter.getPageMetadata(locale, pathname);
};

// This provides all the possible paths that can be generated statically
// + provides all the paths that we support on the Node.js Website
// Generates all possible static paths based on the locales and environment configuration
// - Returns an empty array if static export is disabled (`ENABLE_STATIC_EXPORT` is false)
// - If `ENABLE_STATIC_EXPORT_LOCALE` is true, generates paths for all available locales
// - Otherwise, generates paths only for the default locale
// @see https://nextjs.org/docs/app/api-reference/functions/generate-static-params
export const generateStaticParams = async () => {
const allAvailableRoutes = await Promise.all(
// Return an empty array if static export is disabled
if (!ENABLE_STATIC_EXPORT) {
return [];
}

// Determine which locales to include in the static export
const locales = ENABLE_STATIC_EXPORT_LOCALE
? availableLocaleCodes
: [defaultLocale.code];

const routes = await Promise.all(
// Gets all mapped routes to the Next.js Routing Engine by Locale
availableLocaleCodes.map((locale: string) => ({ locale }))
locales.map((locale: string) => ({ locale }))
);

return ENABLE_STATIC_EXPORT ? allAvailableRoutes.flat().sort() : [];
return routes.flat().sort();
};

// This method parses the current pathname and does any sort of modifications needed on the route
Expand Down
11 changes: 11 additions & 0 deletions apps/site/next.constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ export const ENABLE_STATIC_EXPORT =
process.env.NEXT_PUBLIC_STATIC_EXPORT === 'true' ||
process.env.NEXT_PUBLIC_STATIC_EXPORT === true;

/**
* This is used to ensure that pages are Static Export for all locales or only
* in the default (`en`) locale.
*
* Note that this is a manual Environment Variable defined by us during the
* build process in CI.
*/
export const ENABLE_STATIC_EXPORT_LOCALE =
process.env.NEXT_PUBLIC_STATIC_EXPORT_LOCALE === 'true' ||
process.env.NEXT_PUBLIC_STATIC_EXPORT_LOCALE === true;

/**
* This is used for any place that requires the full canonical URL path for the Node.js Website (and its deployment), such as for example, the Node.js RSS Feed.
*
Expand Down
4 changes: 4 additions & 0 deletions apps/site/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"VERCEL_URL",
"VERCEL_REGION",
"NEXT_PUBLIC_STATIC_EXPORT",
"NEXT_PUBLIC_STATIC_EXPORT_LOCALE",
"NEXT_PUBLIC_BASE_URL",
"NEXT_PUBLIC_DIST_URL",
"NEXT_PUBLIC_DOCS_URL",
Expand All @@ -37,6 +38,7 @@
"VERCEL_URL",
"VERCEL_REGION",
"NEXT_PUBLIC_STATIC_EXPORT",
"NEXT_PUBLIC_STATIC_EXPORT_LOCALE",
"NEXT_PUBLIC_BASE_URL",
"NEXT_PUBLIC_DIST_URL",
"NEXT_PUBLIC_DOCS_URL",
Expand All @@ -56,6 +58,7 @@
"VERCEL_URL",
"VERCEL_REGION",
"NEXT_PUBLIC_STATIC_EXPORT",
"NEXT_PUBLIC_STATIC_EXPORT_LOCALE",
"NEXT_PUBLIC_BASE_URL",
"NEXT_PUBLIC_DIST_URL",
"NEXT_PUBLIC_DOCS_URL",
Expand All @@ -81,6 +84,7 @@
"VERCEL_URL",
"VERCEL_REGION",
"NEXT_PUBLIC_STATIC_EXPORT",
"NEXT_PUBLIC_STATIC_EXPORT_LOCALE",
"NEXT_PUBLIC_BASE_URL",
"NEXT_PUBLIC_DIST_URL",
"NEXT_PUBLIC_DOCS_URL",
Expand Down
1 change: 1 addition & 0 deletions packages/i18n/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"VERCEL_URL",
"VERCEL_REGION",
"NEXT_PUBLIC_STATIC_EXPORT",
"NEXT_PUBLIC_STATIC_EXPORT_LOCALE",
"NEXT_PUBLIC_BASE_URL",
"NEXT_PUBLIC_DIST_URL",
"NEXT_PUBLIC_DOCS_URL",
Expand Down

0 comments on commit 02f5a3e

Please sign in to comment.