虚幻的“预渲染”:SSG到底快在哪
说实话,SSG 的原理说起来不复杂。生出一堆 HTML、CSS、JS,往 CDN 上一扔,用户请求直接返回静态文件。比 SSR 少了运行时拼 HTML 的步骤,也比 CSR 少了浏览器二次渲染的白屏时间。但原理谁都懂,真正的问题是:构建速度。 我见过太多人天真地以为 SSG 就是一把梭。小项目当然爽,50 个页面七八秒构建完。但上了规模呢?一个十万页面的电商站,每个产品页都调 API,每个分类页都有分页。全量构建一次,光 API 调用就可能触发限流,构建时间轻松破小时。 这就引出了 SSG 的核心算法:增量静态再生(ISR)与缓存失效策略。类比一下——传统的 SSG 像是快餐店提前做好所有三明治,不管客人要不要;ISR 则是根据订单实时做,但会把常点的那几款提前备好。更聪明,但管理起来也更恶心。 我做过压测对比。同一个 5000 页的站点,用纯 SSG 全量构建,耗时 38 分钟,构建过程中因为 API 抖动失败 3 次。切换到 ISR 策略,初始构建只生成 Top 200 个高频页面,耗时 2 分钟;剩余页面设置 revalidate 逻辑,在第一次请求时按需生成并缓存,整体构建负载降低了 90%。代价是什么?你要额外维护一套页面的新鲜度状态,还得处理缓存雪崩——比如改个组件,所有页面同时失效,瞬间请求全打到构建服务器上。那感受,就像刚修好一个水龙头,水管又爆了。
构建性能的死亡谷:为什么你的CI/CD在哭泣
别以为有了 ISR 就万事大吉。真正的噩梦才开始——大型项目中,增量构建的“增量”二字藏着无数坑。 核心问题:如何精确判断一个文件改动会影响到哪些页面?你改了一个共享的 Button 组件,理论上所有用到的页面都要重新构建。但如果是纯函数组件、样式没变、接口没变,其实没必要重建。可目前的增量构建工具大多基于文件哈希,只要文件内容变了,哪怕一个空格,所有依赖它的页面统统标记为 dirty。这哪是增量,这明明是“伪增量”。 我花了两周时间优化一个 Gatsby 项目的构建依赖图。原来的方案:一个 monorepo 里有 2000 个页面和 300 个组件,任何组件的改动都会导致全量重建。通过定制 webpack 插件,引入AST 级别的依赖分析,只追踪真正被使用的导出成员,而不是整个文件。结合内容哈希的 Merkle 树计算,把构建图拆成 DAG,并行度拉满。结果?那个十万页面的站,增量构建从 90 分钟干到了 11 分钟,平均一次改动重新生成的页面数从十万降到 400。
动态内容的陷阱:不是所有页面都适合静态

