1- import { languageKeys } from '../languages.js'
1+ import assert from 'assert'
2+ import fs from 'fs/promises'
3+ import path from 'path'
4+ import { isPromise } from 'util/types'
5+ import { fileURLToPath } from 'url'
6+
27import readJsonFile from '../read-json-file.js'
38import { latest } from '../../lib/enterprise-server-releases.js'
49import getExceptionRedirects from './exception-redirects.js'
5- const developerRedirects = readJsonFile ( './lib/redirects/static/developer.json' )
6- const latestDevRedirects = { }
7-
8- // Replace hardcoded 'latest' with real value in the redirected path
9- Object . entries ( developerRedirects ) . forEach ( ( [ oldPath , newPath ] ) => {
10- latestDevRedirects [ oldPath ] = newPath . replace (
11- 'enterprise-server@latest' ,
12- `enterprise-server@${ latest } `
13- )
14- } )
10+ import { languageKeys } from '../languages.js'
11+
12+ function diskMemoize ( filePath , asyncFn , maxAgeSeconds = 60 * 60 ) {
13+ return async ( ...args ) => {
14+ try {
15+ const stats = await fs . stat ( filePath )
16+ const ageSeconds = ( new Date ( ) . getTime ( ) - stats . mtime . getTime ( ) ) / 1000
17+ if ( ageSeconds < maxAgeSeconds ) {
18+ const value = JSON . parse ( await fs . readFile ( filePath , 'utf-8' ) )
19+ console . log ( `Redirects disk-cache HIT on ${ filePath } ` )
20+ return value
21+ }
22+ console . log ( `Redirects disk-cache ${ filePath } too old` )
23+ } catch ( err ) {
24+ if ( err . code !== 'ENOENT' ) throw err
25+ }
26+ console . log ( `Redirects disk-cache MISS on ${ filePath } ` )
27+ const promise = asyncFn ( ...args )
28+ assert ( isPromise ( promise ) , "memoized function didn't return a promise" )
29+ return promise . then ( async ( value ) => {
30+ await fs . writeFile ( filePath , JSON . stringify ( value ) , 'utf-8' )
31+ return value
32+ } )
33+ }
34+ }
35+
36+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) )
37+ const DISK_CACHE_FILEPATH = path . join ( __dirname , `.redirects-cache_${ languageKeys . join ( '_' ) } .json` )
1538
1639// This function runs at server warmup and precompiles possible redirect routes.
1740// It outputs them in key-value pairs within a neat Javascript object: { oldPath: newPath }
18- export default async function precompileRedirects ( pageList ) {
19- const allRedirects = Object . assign ( { } , latestDevRedirects )
41+ const precompileRedirects = diskMemoize ( DISK_CACHE_FILEPATH , async ( pageList ) => {
42+ const allRedirects = readJsonFile ( './lib/redirects/static/developer.json' )
43+
44+ // Replace hardcoded 'latest' with real value in the redirected path
45+ Object . entries ( allRedirects ) . forEach ( ( [ oldPath , newPath ] ) => {
46+ allRedirects [ oldPath ] = newPath . replace (
47+ 'enterprise-server@latest' ,
48+ `enterprise-server@${ latest } `
49+ )
50+ } )
2051
2152 // Exception redirects are those that are essentially unicorn one-offs.
2253 // For example, we have redirects for documents that used to be on
@@ -35,9 +66,8 @@ export default async function precompileRedirects(pageList) {
3566
3667 // CURRENT PAGES PERMALINKS AND FRONTMATTER
3768 // create backwards-compatible old paths for page permalinks and frontmatter redirects
38- await Promise . all (
39- pageList . map ( async ( page ) => Object . assign ( allRedirects , page . buildRedirects ( ) ) )
40- )
69+ pageList . forEach ( ( page ) => Object . assign ( allRedirects , page . buildRedirects ( ) ) )
4170
4271 return allRedirects
43- }
72+ } )
73+ export default precompileRedirects
0 commit comments