1
0
mirror of synced 2025-12-23 21:07:12 -05:00

Port precompute-pageinfo.js to TypeScript (#48749)

This commit is contained in:
Peter Bengtsson
2024-01-18 12:33:46 -05:00
committed by GitHub
parent 26a776d289
commit d9007decda
4 changed files with 60 additions and 19 deletions

View File

@@ -37,7 +37,7 @@ const translatableFrontmatterKeys = Object.entries(frontmatterSchema.schema.prop
* first since it's the most expensive work. This gets us a nested object with pages attached that we can use
* as the basis for the siteTree after we do some versioning. We can also use it to derive the pageList.
*/
export async function loadUnversionedTree(languagesOnly = null) {
export async function loadUnversionedTree(languagesOnly = []) {
if (languagesOnly && !Array.isArray(languagesOnly)) {
throw new Error("'languagesOnly' has to be an array")
}
@@ -47,7 +47,7 @@ export async function loadUnversionedTree(languagesOnly = null) {
const languagesValues = Object.entries(languages)
.filter(([language]) => {
return !languagesOnly || languagesOnly.includes(language)
return !languagesOnly.length || languagesOnly.includes(language)
})
.map(([, data]) => {
return data
@@ -295,7 +295,7 @@ export async function versionPages(obj, version, langCode) {
}
// Derive a flat array of Page objects in all languages.
export async function loadPageList(unversionedTree, languagesOnly = null) {
export async function loadPageList(unversionedTree, languagesOnly = []) {
if (languagesOnly && !Array.isArray(languagesOnly)) {
throw new Error("'languagesOnly' has to be an array")
}
@@ -303,7 +303,7 @@ export async function loadPageList(unversionedTree, languagesOnly = null) {
const pageList = []
await Promise.all(
(languagesOnly || Object.keys(languages)).map(async (langCode) => {
((languagesOnly.length && languagesOnly) || Object.keys(languages)).map(async (langCode) => {
await addToCollection(rawTree[langCode], pageList)
}),
)
@@ -335,7 +335,7 @@ export function createMapFromArray(pageList) {
return pageMap
}
export async function loadPageMap(pageList, languagesOnly = null) {
export async function loadPageMap(pageList, languagesOnly = []) {
const pages = pageList || (await loadPageList(languagesOnly))
const pageMap = createMapFromArray(pages)
return pageMap

View File

@@ -22,7 +22,7 @@ const router = express.Router()
// Note that if the file does not exist, it will be ignored and
// every pageinfo is computed every time.
// Note! The only reason this variable is exported is so that
// it can be imported by the script scripts/precompute-pageinfo.js
// it can be imported by the script scripts/precompute-pageinfo.ts
export const CACHE_FILE_PATH = '.pageinfo-cache.json.br'
const validationMiddleware = (req, res, next) => {

View File

@@ -13,7 +13,7 @@
* Why cache?: Despite being a fast computation (3 Liquid + Markdown renders),
* it still adds up. And it's safe and cheap to precompute in advance.
*
* Why only the English?: To make the file not too large.
* Why only the English by default?: To make the file not too large.
* Given how good these things compress, we might consider, in the
* future, to do all languages.
*
@@ -29,20 +29,55 @@
import fs from 'fs'
import { brotliCompressSync } from 'zlib'
import { loadPages, loadUnversionedTree } from '#src/frame/lib/page-data.js'
import chalk from 'chalk'
import { program, Option } from 'commander'
import { languageKeys } from 'src/languages/lib/languages.js'
import { loadPages, loadUnversionedTree } from 'src/frame/lib/page-data.js'
import { CACHE_FILE_PATH, getPageInfo } from '../middleware.js'
main()
program
.description('Generates a JSON file with precompute pageinfo data by pathname')
.addOption(
new Option('-l, --language <LANGUAGE...>', 'Which languages to focus on')
.choices(languageKeys)
.default(['en']),
)
.option('-o, --output-file <path>', 'path to output file', CACHE_FILE_PATH)
.parse(process.argv)
type Options = {
outputFile: string
languages: string[]
}
const opts = program.opts()
main({
outputFile: opts.outputFile,
languages: opts.language,
})
const CI = Boolean(JSON.parse(process.env.CI || 'false'))
async function main() {
const unversionedTree = await loadUnversionedTree(['en'])
const pageList = await loadPages(unversionedTree, ['en'])
type PageInfo = {
title: string
intro: string
product: string
}
async function main(options: Options) {
const { outputFile, languages } = options
if (outputFile !== CACHE_FILE_PATH) {
console.warn(chalk.yellow(`Writing to ${outputFile} instead of ${CACHE_FILE_PATH}`))
}
const unversionedTree = await loadUnversionedTree(languages)
const pageList = await loadPages(unversionedTree, languages)
let label = `Compute pageinfos for ${pageList.length.toLocaleString()} pages`
console.time(label)
const pageinfos = {}
const pageinfos: {
[pathname: string]: PageInfo
} = {}
for (const page of pageList) {
const pathname = page.permalinks[0].href
try {
@@ -57,14 +92,20 @@ async function main() {
}
console.timeEnd(label)
label = `Serialize, compress, and write to ${CACHE_FILE_PATH}`
label = `Serialize, compress, and write to ${outputFile}`
console.time(label)
const payload = CI ? JSON.stringify(pageinfos) : JSON.stringify(pageinfos, null, 2)
const payloadBuffer = Buffer.from(payload, 'utf-8')
const payloadCompressed = brotliCompressSync(payloadBuffer)
fs.writeFileSync(CACHE_FILE_PATH, payloadCompressed)
if (outputFile.endsWith('.json')) {
fs.writeFileSync(outputFile, payload)
} else {
const payloadBuffer = Buffer.from(payload, 'utf-8')
const payloadCompressed = brotliCompressSync(payloadBuffer)
fs.writeFileSync(outputFile, payloadCompressed)
}
console.timeEnd(label)
console.log(
`Wrote ${Object.keys(pageinfos).length.toLocaleString()} pageinfos to ${CACHE_FILE_PATH}`,
chalk.green(
`Wrote ${Object.keys(pageinfos).length.toLocaleString()} pageinfos to ${outputFile}`,
),
)
}