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

Next.js 13 App Router开发MDX博客遇fs模块无法解析错误

解决Next.js 13 App Router中「Module not found: Can't resolve 'fs'」错误

问题根源

你把Next.js 12 Pages Router的代码直接搬到App Router环境里,但两者的运行规则完全不同:

  • 加了"use client"的组件会在浏览器端运行,而fs是Node.js专属模块,浏览器环境不存在这个模块,所以触发报错。
  • App Router已经废弃了getStaticProps这类Pages Router的 data fetching方法,默认的page组件是服务器组件,支持直接在组件内写异步逻辑读取文件系统。

具体修复步骤

  1. 移除"use client"指令:让page组件保持默认的服务器组件身份,这样就能在服务器端正常使用fs模块。
  2. 迁移getStaticProps逻辑到组件内部:服务器组件允许异步函数,直接把文件读取、处理的逻辑放到page组件里执行。
  3. 替换客户端API(如果需要交互):App Router里不再使用next/router的useRouter,要改用next/navigation的同名钩子,且必须把用到它的部分拆成单独的客户端组件(这类API只能在客户端组件中调用)。
  4. 调整Head使用(可选):App Router推荐用metadata API替代next/head,如果要继续使用Head也可以,但注意它在App Router中的用法差异。

修改后的代码示例

import Head from 'next/head';
import BlogSidebar from '../../components/blog/sidebar';
import Pagination from '../../components/blog/pagination';
import fs from 'fs';
import matter from 'gray-matter';
import { join } from 'path';

// 封装异步获取文章数据的逻辑
async function getPosts() {
  const blogsDirectory = join(process.cwd(), '_blog');
  const files = fs.readdirSync(blogsDirectory);

  let posts = files.map((fileName) => {
    const slug = fileName.replace(/\.md$/, '');
    const fullPath = join(blogsDirectory, `${slug}.md`);
    const readFile = fs.readFileSync(fullPath, 'utf8');
    const { data: frontmatter } = matter(readFile);
    return {
      slug,
      frontmatter,
    };
  });

  posts = posts.sort((job1, job2) => (job1.frontmatter.date > job2.frontmatter.date ? -1 : 1));
  return posts;
}

// 异步page组件(App Router支持异步服务器组件)
export default async function Page() {
  const posts = await getPosts();
  console.log(posts, "posts");

  return (
    <div>
      <Head>
        <title>博客列表页</title>
      </Head>
      <BlogSidebar />
      <Pagination posts={posts} />
      {/* 其他页面内容 */}
    </div>
  );
}

若需客户端交互(如路由跳转)

如果页面需要用到useRouter这类客户端API,不要把整个page设为客户端组件,而是拆出独立的客户端组件:

// components/blog/ClientNavigation.js
"use client";
import { useRouter } from 'next/navigation';

export default function ClientNavigation() {
  const router = useRouter();
  // 这里编写需要客户端路由的逻辑
  return <button onClick={() => router.back()}>返回上页</button>;
}

之后在服务器组件的page中直接导入并使用这个组件即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:45:23