Skip to content

Commit f6a2422

Browse files
authored
Merge branch 'tangly1024:main' into main
2 parents 36f44c1 + 766c1f8 commit f6a2422

16 files changed

Lines changed: 500 additions & 351 deletions

File tree

lib/build/prefetch.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// lib/build/prefetch.js
2+
import pLimit from 'p-limit'
3+
import { fetchNotionPageBlocks } from '@/lib/db/notion/getPostBlocks'
4+
import {
5+
getDataFromCache,
6+
setDataToCache
7+
8+
} from '@/lib/cache/cache_manager'
9+
10+
11+
// lib/build/prefetch.js 中新增,或单独放 lib/build/buildUtils.js
12+
13+
/**
14+
* 获取优先预生成的页面
15+
* - 最新5篇(按发布时间倒序)
16+
* - 默认排序前5篇(allPages 原始顺序)
17+
* - 两者合并去重
18+
*/
19+
export function getPriorityPages(allPages) {
20+
const published = (allPages ?? []).filter(
21+
p => p.type === 'Post' && p.status === 'Published'
22+
)
23+
24+
// 默认排序前5
25+
const top5Default = published.slice(0, 5)
26+
27+
// 按发布时间最新5
28+
const top5Latest = [...published]
29+
.sort((a, b) => new Date(b.publishDate) - new Date(a.publishDate))
30+
.slice(0, 5)
31+
32+
// 合并去重
33+
const seen = new Set()
34+
return [...top5Default, ...top5Latest].filter(p => {
35+
if (seen.has(p.id)) return false
36+
seen.add(p.id)
37+
return true
38+
})
39+
}
40+
41+
/**
42+
* 预热所有页面的 block 数据
43+
* @param {*} allPages 页面列表
44+
* @param {*} concurrency 并发数
45+
*/
46+
export async function prefetchAllBlockMaps(allPages, concurrency = 8) {
47+
const limit = pLimit(concurrency)
48+
let hit = 0, fetched = 0, failed = 0
49+
50+
console.log(`[Prefetch] 开始预热 ${allPages.length} 个页面 block`)
51+
const start = Date.now()
52+
53+
await Promise.all(
54+
allPages.map(page =>
55+
limit(async () => {
56+
const cacheKey = `page_block_${page.id}`
57+
58+
// 已有缓存跳过
59+
if (await getDataFromCache(cacheKey)) {
60+
hit++
61+
return
62+
}
63+
64+
try {
65+
const block = await fetchNotionPageBlocks(page.id, 'prefetch')
66+
await setDataToCache(cacheKey, block, 1000 * 60 * 60 * 2) // 2小时
67+
fetched++
68+
} catch (e) {
69+
console.warn('[Prefetch Failed]', page.id, e.message)
70+
failed++
71+
}
72+
})
73+
)
74+
)
75+
76+
const elapsed = ((Date.now() - start) / 1000).toFixed(1)
77+
console.log(`[Prefetch] 完成: 命中缓存=${hit} 新拉取=${fetched} 失败=${failed} 耗时=${elapsed}s`)
78+
}

lib/build/staticPaths.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
// lib/build/staticPaths.js
3+
import { fetchGlobalAllData } from '@/lib/db/notion'
4+
import { prefetchAllBlockMaps } from '@/lib/build/prefetch'
5+
import { isExport } from '../utils/buildMode'
6+
7+
let _prefetchDone = false // 模块级标记,同一构建进程只预热一次
8+
9+
export async function getStaticPathsBase(filterFn) {
10+
if (!isExport()) {
11+
return { paths: [], fallback: 'blocking' }
12+
}
13+
14+
const { allPages } = await fetchGlobalAllData({ from: 'static-paths' })
15+
16+
// 只在第一个调用的路由文件里执行预热
17+
if (!_prefetchDone) {
18+
_prefetchDone = true
19+
// 预热全部,但优先处理最新5篇
20+
await prefetchAllBlockMaps(allPages)
21+
}
22+
23+
return {
24+
paths: allPages.filter(filterFn).map(pageToParams),
25+
fallback: false
26+
}
27+
}
28+
29+
// 把最新5篇单独导出,供各路由文件复用
30+
export async function getLatestSlugs(allPages, count = 5) {
31+
return [...allPages]
32+
.filter(p => p.type === 'Post' && p.status === 'Published')
33+
.sort((a, b) => new Date(b.publishDate) - new Date(a.publishDate))
34+
.slice(0, count)
35+
}
36+
37+
// 把最新5篇单独导出,供各路由文件复用
38+
export async function getLatestSlugs(allPages, count = 5) {
39+
return [...allPages]
40+
.filter(p => p.type === 'Post' && p.status === 'Published')
41+
.sort((a, b) => new Date(b.publishDate) - new Date(a.publishDate))
42+
.slice(0, count)
43+
}

lib/cache/cache_manager.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import BLOG from '@/blog.config'
22
import FileCache from './local_file_cache'
33
import MemoryCache from './memory_cache'
44
import RedisCache from './redis_cache'
5-
import VercelCache from './vercel_cache'
5+
// import VercelCache from './vercel_cache'
66

77
const cacheStats = {
88
hit: 0,
@@ -17,8 +17,6 @@ const isBuildPhase =
1717
process.env.npm_lifecycle_event === 'build' ||
1818
process.env.npm_lifecycle_event === 'export'
1919

20-
21-
2220
const enableLocalCache = isBuildPhase || !BLOG['isProd']
2321
const hasRedis = !!BLOG.REDIS_URL
2422

@@ -58,7 +56,7 @@ export async function getOrSetDataWithCustomCache(
5856
return inflightMap.get(key)
5957
}
6058

61-
// cacheLog('MISS', key, '缓存未命中,发起真实请求')
59+
cacheLog('MISS', key, '缓存未命中,发起真实请求')
6260

6361
const promise = getDataFunction(...getDataArgs)
6462
.then(async data => {
@@ -71,7 +69,7 @@ export async function getOrSetDataWithCustomCache(
7169
})
7270
.catch(err => {
7371
inflightMap.delete(key)
74-
// cacheLog('ERROR', key, err.message)
72+
cacheLog('ERROR', key, err.message)
7573
throw err
7674
})
7775

@@ -125,7 +123,7 @@ export async function getDataFromCache(key, force) {
125123
console.warn(`[Cache] ${name} get failed key:${key}`, e.message)
126124
}
127125
}
128-
cacheStats.miss++
126+
cacheStats.miss++
129127
return null
130128
}
131129

@@ -143,8 +141,8 @@ export async function delCacheData(key) {
143141

144142
function getCacheType() {
145143
if (hasRedis) return 'redis'
146-
if (isVercelEnv()) return 'vercel'
147144
if (isBuildPhase) return 'file'
145+
// if (isVercelEnv()) return 'vercel'
148146
return 'memory'
149147
}
150148

@@ -154,8 +152,10 @@ export function getApi() {
154152
switch (type) {
155153
case 'redis':
156154
return RedisCache
157-
case 'vercel':
158-
return VercelCache
155+
// case 'vercel':
156+
// VercelCache 目前不稳定(有大小限制),先注释掉
157+
// return VercelCache
158+
// 文件速度和内存消耗存疑
159159
case 'file':
160160
return FileCache
161161
default:
@@ -170,9 +170,9 @@ function getCacheChain() {
170170
chain.push({ name: 'redis', api: RedisCache })
171171
}
172172

173-
if (isVercelEnv()) {
174-
chain.push({ name: 'vercel', api: VercelCache })
175-
}
173+
// if (isVercelEnv()) {
174+
// chain.push({ name: 'vercel', api: VercelCache })
175+
// }
176176

177177
if (isBuildPhase || !BLOG.isProd) {
178178
chain.push({ name: 'file', api: FileCache })

0 commit comments

Comments
 (0)