You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js开发模式下静态博客文章内存缓存失效问题如何解决?

问题原因
  • 开发模式下的模块热重载(HMR)机制:你使用的静态博客框架(Next.js、Astro、VitePress这类常见SSG工具都有该特性)在dev模式下默认会开启热替换,路由跳转、页面重载甚至项目文件无修改的场景下,框架都可能主动清除Node模块缓存、重新加载post.ts模块,存在模块顶层的posts数组和postsGenerated标记会随模块重新执行被重置,你观察到的模块多次加载就是该机制导致的。
  • 框架dev模式的执行逻辑:多数SSG框架在dev环境下不会复用服务端模块单例,每次触发页面渲染请求时都会重新执行相关服务端代码,模块不会像生产构建那样仅加载一次,顶层缓存自然无法复用。
  • 现有代码存在竞态缺陷:你在进入else分支后立刻将postsGenerated设为true,但此时所有文章的异步解析逻辑还未执行完成,如果此时有第二个请求进入,会直接返回还未填充完成的posts数组,也会表现为缓存失效。
优化方案

方案1:使用全局内存缓存绕开模块重载

把缓存挂载到不会随模块重载被重置的Node.jsglobal对象上,同时优化异步逻辑解决竞态问题,修改后的代码参考:

import fs from 'fs'
import path from 'path'
// ...

// 全局挂载缓存容器
const globalForPosts = global as unknown as {
  posts: Post[]
  postsGenerated: boolean
  postsPromise?: Promise<Post[]>
}

// 初始化缓存,仅第一次加载模块时执行
if (!globalForPosts.posts) {
  globalForPosts.posts = []
  globalForPosts.postsGenerated = false
}

const posts = globalForPosts.posts
let postsGenerated = globalForPosts.postsGenerated
let postsPromise = globalForPosts.postsPromise

export async function getSortedPostsData(): Promise<Post[]> {
  // 已有缓存直接返回
  if (postsGenerated && postsPromise) {
    console.log('+++++ Using cache ')
    return postsPromise
  }
  console.log('==== Calculating all')
  const pendings: Promise<any>[] = []
  traverseDir('content/blog', (path) => {
    if (path.includes('.md')) { 
      // 原有md文件解析逻辑,将异步任务push到pendings数组
    }
  })
  // 缓存整个异步任务,并发请求只会执行一次生成逻辑
  postsPromise = Promise.all(pendings).then(() => {
    postsGenerated = true
    // 同步更新全局缓存标记
    globalForPosts.postsGenerated = true
    globalForPosts.postsPromise = postsPromise
    return sortPostsByDate(posts)
  })
  return postsPromise
}

方案2:搭配文件监听实现缓存自动更新

如果需要修改md文件后自动刷新缓存,可以在dev模式下额外添加文件监听逻辑:

if (process.env.NODE_ENV === 'development') {
  fs.watch('content/blog', (eventType, filename) => {
    if (filename?.endsWith('.md')) {
      // 检测到md文件变化时重置缓存,下次请求自动重新生成
      globalForPosts.posts = []
      globalForPosts.postsGenerated = false
      globalForPosts.postsPromise = undefined
      console.log('博客内容更新,缓存已重置')
    }
  })
}

方案3:使用框架原生缓存能力

如果使用特定框架可以直接适配原生能力减少代码侵入:

  • Next.js可以使用unstable_cache方法包裹文章生成逻辑,或者把预处理逻辑放在generateStaticParams中,dev模式下默认会复用缓存
  • Astro/VitePress可以在配置文件中提前预处理所有文章,把结果存在全局配置项中,页面直接读取配置即可

内容的提问来源于stack exchange,提问作者Nicolas Zozol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 14:15:06