Skip to content

Commit

Permalink
feat(theme): add fs cache for encrypt and icons
Browse files Browse the repository at this point in the history
  • Loading branch information
pengzhanbo committed Oct 2, 2024
1 parent a6079d6 commit 5f72abb
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 9 deletions.
25 changes: 18 additions & 7 deletions theme/src/node/prepare/prepareEncrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Page } from 'vuepress/core'
import type { PlumeThemeEncrypt, PlumeThemePageData } from '../../shared/index.js'
import { isNumber, isString, random, toArray } from '@pengzhanbo/utils'
import { genSaltSync, hashSync } from 'bcrypt-ts'
import { hash, logger, resolveContent, writeTemp } from '../utils/index.js'
import { createFsCache, type FsCache, hash, logger, resolveContent, writeTemp } from '../utils/index.js'

export type EncryptConfig = readonly [
boolean, // global
Expand All @@ -16,19 +16,30 @@ export type EncryptConfig = readonly [
const isStringLike = (value: unknown): boolean => isString(value) || isNumber(value)
const separator = ':'
let contentHash = ''
let fsCache: FsCache<[string, EncryptConfig]> | null = null

export async function prepareEncrypt(app: App, encrypt?: PlumeThemeEncrypt) {
const start = performance.now()

if (!fsCache && app.env.isDev) {
fsCache = createFsCache(app, 'encrypt')
await fsCache.read()
}
contentHash = fsCache?.data?.[0] ?? ''
let resolvedEncrypt = fsCache?.data?.[1]
const currentHash = encrypt ? hash(JSON.stringify(encrypt)) : ''

if (!contentHash || contentHash !== currentHash) {
if (!contentHash || contentHash !== currentHash || !resolvedEncrypt) {
contentHash = currentHash
const content = resolveContent(app, {
name: 'encrypt',
content: resolveEncrypt(encrypt),
})
await writeTemp(app, 'internal/encrypt.js', content)
resolvedEncrypt = resolveEncrypt(encrypt)
}
await writeTemp(app, 'internal/encrypt.js', resolveContent(app, {
name: 'encrypt',
content: resolvedEncrypt,
}))

fsCache?.write([currentHash, resolvedEncrypt])

if (app.env.isDebug) {
logger.info(`Generate encrypt: ${(performance.now() - start).toFixed(2)}ms`)
}
Expand Down
14 changes: 12 additions & 2 deletions theme/src/node/prepare/prepareIcons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isArray, uniq } from '@pengzhanbo/utils'
import { entries, isLinkAbsolute, isLinkHttp, isPlainObject } from '@vuepress/helper'
import { isPackageExists } from 'local-pkg'
import { fs } from 'vuepress/utils'
import { interopDefault, logger, nanoid, resolveContent, writeTemp } from '../utils/index.js'
import { createFsCache, type FsCache, interopDefault, logger, nanoid, resolveContent, writeTemp } from '../utils/index.js'

interface IconData {
className: string
Expand All @@ -26,6 +26,7 @@ const CSS_FILENAME = 'internal/iconify.css'
const isInstalled = isPackageExists('@iconify/json')
let locate!: ((name: string) => any)

let fsCache: FsCache<IconDataMap> | null = null
// { iconName: { className, content } }
const cache: IconDataMap = {}

Expand All @@ -41,13 +42,21 @@ export async function prepareIcons(app: App, localeOptions: PlumeThemeLocaleOpti
await writeTemp(app, JS_FILENAME, resolveContent(app, { name: 'icons', content: '{}' }))
return
}
if (!fsCache && app.env.isDev) {
fsCache = createFsCache(app, 'iconify')
await fsCache.read()
}

const iconList: string[] = []
app.pages.forEach(page => iconList.push(...getIconsWithPage(page)))
iconList.push(...getIconWithThemeConfig(localeOptions))

const collectMap: CollectMap = {}
uniq(iconList).filter(icon => !cache[icon]).forEach((iconName) => {
uniq(iconList).filter((icon) => {
if (fsCache?.data?.[icon] && !cache[icon])
cache[icon] = fsCache.data[icon]
return !cache[icon]
}).forEach((iconName) => {
const [collect, name] = iconName.split(':')
if (!collectMap[collect])
collectMap[collect] = []
Expand Down Expand Up @@ -94,6 +103,7 @@ export async function prepareIcons(app: App, localeOptions: PlumeThemeLocaleOpti
})),
])

fsCache?.write(cache)
if (app.env.isDebug) {
logger.info(`Generate icons total time: ${(performance.now() - start).toFixed(2)}ms`)
}
Expand Down
65 changes: 65 additions & 0 deletions theme/src/node/utils/createFsCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { App } from 'vuepress'
import fs from 'node:fs/promises'
import path from 'node:path'
import { hash } from 'vuepress/utils'

interface CacheData<T = any> {
hash: string
data: T | null
}

export interface FsCache<T> {
hash: string
data: T | null
read: () => Promise<T | null>
write: (data: T) => Promise<void>
}

const CACHE_BASE = 'markdown'

export function createFsCache<T = any>(app: App, name: string): FsCache<T> {
const filepath = app.dir.cache(`${CACHE_BASE}/${name}.json`)
const cache: CacheData<T> = { hash: '', data: null }

const read = async (): Promise<T | null> => {
if (!cache.data) {
try {
const content = await fs.readFile(filepath, 'utf-8')
if (content) {
const res = JSON.parse(content) as CacheData<T>
cache.data = res.data ?? null
cache.hash = hash(res.hash || '')
}
}
catch {}
}
return cache.data
}

let timer: NodeJS.Timeout | null = null
const write = async (data: T) => {
const currentHash = hash(data)
if (cache.hash && currentHash === cache.hash)
return

cache.data = data
cache.hash = currentHash

timer && clearTimeout(timer)
timer = setTimeout(async () => {
await fs.mkdir(path.dirname(filepath), { recursive: true })
await fs.writeFile(filepath, JSON.stringify(cache), 'utf-8')
}, 300)
}

return {
get hash() {
return cache.hash
},
get data() {
return cache.data
},
read,
write,
}
}
1 change: 1 addition & 0 deletions theme/src/node/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const THEME_NAME = 'vuepress-theme-plume'

export const logger = new Logger(THEME_NAME)

export * from './createFsCache.js'
export * from './deleteAttrs.js'
export * from './hash.js'
export * from './interopDefault.js'
Expand Down

0 comments on commit 5f72abb

Please sign in to comment.