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

如何分批导出大型Next.js静态站点?

问题描述

我正在为我的站点使用Next.js的Static HTML Export功能,该站点包含1000万个静态页面,但构建应用时遇到了内存问题。

是否可以分批导出?比如第一次构建导出10万个页面,第二次再导出10万个,以此类推?

为了控制成本,我不想使用Incremental Static Regeneration或getServerSideProps。

该站点使用MongoDB,仅包含两个页面:

index.js
[postPage].js

首页代码如下:

export async function getStaticProps() {
  const { db } = await connectToDatabase();

  const postsFeed = await db
    .collection("myCollection")
    .aggregate([{ $sample: { size: 100 } }])
    .toArray();

  return {
    props: {
      postsFeed: JSON.parse(JSON.stringify(postsFeed)),
    },
  };
}

文章页代码如下:

export async function getStaticPaths() {

  const { db } = await connectToDatabase();
  const posts = await db
    .collection("myCollection")
    .find({})
    .toArray();

  const paths = posts.map((data) => {
    return {
      params: {
        postPage: data.slug.toString(),
      }
    }
  })

  return {
    paths,
    fallback: 'blocking'
  }
}

export async function getStaticProps(context) {

  const postSlug = context.params.postPage;

  const { db } = await connectToDatabase();

  const posts = await db
    .collection("myCollection")
    .find({ slug: { $eq: postSlug } })
    .toArray();

  const postsFeed = await db
    .collection("myCollection")
    .aggregate([{ $sample: { size: 100 } }])
    .toArray();

  return {
    props: {
      posts: JSON.parse(JSON.stringify(posts)),
      postsFeed: JSON.parse(JSON.stringify(postsFeed)),
    },
  };
}
解决方案

1. 改造getStaticPaths实现分批拉取路径

当前getStaticPaths一次性拉取1000万条数据,是内存溢出的核心原因。通过MongoDB分页查询+环境变量控制,实现批次导出:

  • 新增环境变量EXPORT_BATCH_START(起始偏移量)和EXPORT_BATCH_SIZE(单批次数量),指定当前导出的范围。
  • 修改文章页的getStaticPaths代码:
export async function getStaticPaths() {
  const { db } = await connectToDatabase();
  // 读取环境变量,默认值可按需调整
  const start = parseInt(process.env.EXPORT_BATCH_START || 0);
  const size = parseInt(process.env.EXPORT_BATCH_SIZE || 100000);

  const posts = await db
    .collection("myCollection")
    .find({})
    .skip(start)
    .limit(size)
    .toArray();

  const paths = posts.map((data) => ({
    params: {
      postPage: data.slug.toString(),
    }
  }));

  return {
    paths,
    fallback: false, // 仅导出当前批次页面,避免触发动态生成
  };
}

2. 分批执行导出命令

每次导出前设置对应环境变量,执行Next.js构建导出命令,完成后合并静态文件:

# 第一批次:导出前10万条页面
EXPORT_BATCH_START=0 EXPORT_BATCH_SIZE=100000 next build && next export

# 第二批次:导出第10万-20万条页面
EXPORT_BATCH_START=100000 EXPORT_BATCH_SIZE=100000 next build && next export

# 后续批次以此类推,直到所有页面导出完成

注意:每次导出后,需将out目录下的文章页面(如out/[postPage]相关文件)复制到统一的静态文件存储目录,避免被下一次导出覆盖。

3. 处理首页重复生成问题

首页每次构建都会重新生成,可按以下方式处理:

  • 第一次导出时备份首页文件,后续批次导出后,将备份的首页文件替换回out目录,再合并到存储目录。
  • 或者通过环境变量控制首页的getStaticProps,仅在第一次构建时生成首页(需额外添加判断逻辑)。

4. 额外优化点

  • 避免文章页重复执行$sample查询:提前将首页的postsFeed生成静态JSON文件,文章页直接读取该文件,减少数据库查询和内存占用。
  • 提升Node.js内存限制:构建前加上NODE_OPTIONS="--max-old-space-size=8192"(数值根据服务器内存调整),临时缓解内存压力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 19:35:21