Skip to content

Commit

Permalink
Build 6000 initial pages. Skip them in revalidation
Browse files Browse the repository at this point in the history
Closes #390
  • Loading branch information
stscoundrel committed Nov 16, 2024
1 parent 2104890 commit ff3b405
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 10 deletions.
20 changes: 20 additions & 0 deletions src/lib/services/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface AlphabetLetter {
}

let dictionaryCache: DictionaryEntry[] | null = null
let cachedInitialPages: string[] | null = null

const addSlugs = (words: RawDictionaryEntry[]): DictionaryEntry[] => {
const existingSlugs = {}
Expand Down Expand Up @@ -106,6 +107,25 @@ export const getAlphabet = (): AlphabetLetter[] => {
return formattedLetters
}

/**
* Initial word pages to build are basically 6000
* headword pages based on modulus. Larger number
* can not be deployed in one go.
*/
export const getInitialWordsToBuild = (): string[] => {
if (cachedInitialPages) return cachedInitialPages

const allWords = getAllWords()

const result: string[] = []
for (let i = 0; i < allWords.length; i += 5) {
result.push(allWords[i].slug);
}

cachedInitialPages = result
return cachedInitialPages
}

export default {
getAllWords,
getByLetter,
Expand Down
7 changes: 5 additions & 2 deletions src/pages/api/revalidate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextApiRequest, NextApiResponse } from 'next'
import type { NextApiRequest, NextApiResponse } from 'next'

import { getAllWords } from 'lib/services/dictionary'
import { getAllWords, getInitialWordsToBuild } from 'lib/services/dictionary'
import { getWordPath } from 'lib/utils/links'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
Expand All @@ -18,9 +18,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

try {
const words = getAllWords()
const initialWords = getInitialWordsToBuild()

const { start, end: givenEnd } = req.query
const end = parseInt(givenEnd, 10) <= words.length ? parseInt(givenEnd, 10) : words.length - 1
const revalidates = words
.filter((word) => !initialWords.includes(word.slug))
.sort((a, b) => a.slug.localeCompare(b.slug))
.map((word) => getWordPath(word))
.slice(parseInt(start, 10), end)
Expand Down
27 changes: 25 additions & 2 deletions src/pages/word/[word].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useRouter } from 'next/router'
// Services.
import {
getWord, getAlphabet, type DictionaryEntry, type AlphabetLetter,
getInitialWordsToBuild,
} from 'lib/services/dictionary'
import { getAbbreviations } from 'lib/services/abbreviations'
import { youngerFuthark } from 'riimut'
Expand All @@ -29,9 +30,31 @@ interface WordPageProps {
runes: string,
}

export async function getStaticPaths() {
interface WordPath{
params: {
word: string
}
}

interface WordPageStaticPathsResponseSchema{
paths: WordPath[]
fallback: string | boolean
}

/**
* There are too many word paths for Vercel to build.
* It hits 16 000 file limit.
*
* Build around 6000 pages initially and rest as they are accessed
* or remotely revalidated via API.
*/
export async function getStaticPaths(): Promise<WordPageStaticPathsResponseSchema> {
const initialPages = getInitialWordsToBuild()

return {
paths: [],
paths: initialPages.map((slug) => ({
params: { word: slug },
})),
fallback: 'blocking',
}
}
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/lib/services/dictionary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { isArray } from 'volva'
import { matchesSchema } from 'jafningjar'
import {
getAllWords, getByLetter, getWord, getAlphabet,
getInitialWordsToBuild,
} from 'lib/services/dictionary'

describe('Dictionary tests', () => {
Expand Down Expand Up @@ -109,4 +110,21 @@ describe('Dictionary tests', () => {

expect(foundÖ).toBeTruthy();
})

test('Returns initial batch of pages to build', () => {
const wordsToBuild = getInitialWordsToBuild()

// Correct amount sampled.
expect(wordsToBuild.length).toEqual(5991)

// Deterministic entry slugs, roughly spread through dictionary.
expect(wordsToBuild[0]).toEqual('a')
expect(wordsToBuild[10]).toEqual('afflutningr')
expect(wordsToBuild[100]).toEqual('allfamennr')
expect(wordsToBuild[1000]).toEqual('dvala')
expect(wordsToBuild[2000]).toEqual('handargagn')
expect(wordsToBuild[3000]).toEqual('lausliga')
expect(wordsToBuild[4000]).toEqual('sem')
expect(wordsToBuild[5000]).toEqual('undanhald')
})
})
10 changes: 4 additions & 6 deletions tests/unit/pages/word.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,12 @@ describe('Word page: render & usage', () => {

describe('Word page: data fetching', () => {
test('getStaticPaths works', async () => {
const expected = {
paths: [],
fallback: 'blocking',
}

const result = await getStaticPaths()

expect(result).toMatchObject(expected)
expect(result.fallback).toBe('blocking')

// Should build initial pages.
expect(result.paths.length).toBe(5991)
})

test('getStaticProps works', async () => {
Expand Down

0 comments on commit ff3b405

Please sign in to comment.