Skip to content

Commit

Permalink
Port precompute-pageinfo.js to TypeScript (#48749)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterbe committed Jan 18, 2024
1 parent 26a776d commit d9007de
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"playwright-test": "playwright test --config src/fixtures/playwright.config.ts --project=\"Google Chrome\"",
"post-lints": "node src/content-linter/scripts/post-lints.js",
"postinstall": "cp package-lock.json .installed.package-lock.json && echo \"Updated .installed.package-lock.json\" # see husky/post-checkout and husky/post-merge",
"precompute-pageinfo": "node src/pageinfo/scripts/precompute-pageinfo.js",
"precompute-pageinfo": "tsx src/pageinfo/scripts/precompute-pageinfo.ts",
"prepare": "husky install src/workflows/husky",
"prettier": "prettier -w \"**/*.{ts,tsx,js,mjs,scss,yml,yaml}\"",
"prettier-check": "prettier -c \"**/*.{ts,tsx,js,mjs,scss,yml,yaml}\"",
Expand Down
10 changes: 5 additions & 5 deletions src/frame/lib/page-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand All @@ -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
Expand Down Expand Up @@ -295,15 +295,15 @@ 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")
}
const rawTree = unversionedTree || (await loadUnversionedTree(languagesOnly))
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)
}),
)
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/pageinfo/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
65 changes: 53 additions & 12 deletions src/pageinfo/scripts/precompute-pageinfo.js → src/pageinfo/scripts/precompute-pageinfo.ts
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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 {
Expand All @@ -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}`,
),
)
}

0 comments on commit d9007de

Please sign in to comment.