如何将其他GitHub仓库的Markdown/MDX文件作为Next.js静态站点内容源
Next.js 拉取外部GitHub仓库MD/MDX内容实现方案
方案1:构建时拉取(对标Gatsby gatsby-source-git)
这个方案和Gatsby的实现逻辑完全一致,在站点构建前先把内容仓库的文件拉到本地,后续流程和处理本地MDX文件没有区别。
实现步骤:
- 安装依赖
simple-git用于操作git命令:npm install simple-git --save-dev - 在项目根目录新建
scripts/fetch-content.js脚本,用于拉取内容仓库:
// scripts/fetch-content.js const { simpleGit } = require('simple-git'); const fs = require('fs/promises'); const path = require('path'); // 替换为你的内容仓库地址 const CONTENT_REPO_URL = 'https://github.com/示例/内容仓库.git'; const LOCAL_SAVE_PATH = path.join(process.cwd(), '.external-content'); async function run() { // 清空历史内容 await fs.rm(LOCAL_SAVE_PATH, { recursive: true, force: true }); // 浅克隆仅拉最新版本,提升构建速度 await simpleGit().clone(CONTENT_REPO_URL, LOCAL_SAVE_PATH, ['--depth', '1']); } run();
- 修改
package.json的构建命令,在执行next build前先运行拉取脚本:
{ "scripts": { "dev": "node scripts/fetch-content.js && next dev", "build": "node scripts/fetch-content.js && next build" } }
- 拉取完成后就可以直接用
fs模块读取本地.external-content目录下的MDX文件,把文件内容传给next-mdx-remote即可,示例如下:
// App Router 服务端组件示例 import { MDXRemote } from 'next-mdx-remote/rsc'; import fs from 'fs/promises'; import path from 'path'; // 生成静态路径 export async function generateStaticParams() { const contentDir = path.join(process.cwd(), '.external-content'); const files = await fs.readdir(contentDir); return files .filter(file => file.endsWith('.mdx')) .map(file => ({ slug: file.replace('.mdx', '') })); } export default async function BlogPost({ params }) { const filePath = path.join(process.cwd(), '.external-content', `${params.slug}.mdx`); const mdxSource = await fs.readFile(filePath, 'utf8'); return <MDXRemote source={mdxSource} />; }
方案2:运行时拉取(适合内容高频更新场景)
如果不需要每次内容更新都重新构建站点,可以在服务端请求时直接拉取GitHub仓库的MDX内容,配合Next.js的增量缓存能力兼顾性能和更新时效性。
实现示例:
// App Router 服务端组件示例 import { MDXRemote } from 'next-mdx-remote/rsc'; import { cache } from 'react'; // 缓存请求避免重复拉取 const getMdxContent = cache(async (slug) => { // 替换为你的仓库raw文件地址 const res = await fetch(`https://raw.githubusercontent.com/示例/内容仓库/main/${slug}.mdx`, { // 每1小时自动更新缓存内容 next: { revalidate: 3600 } }); if (!res.ok) throw new Error('内容不存在'); return res.text(); }); export default async function BlogPost({ params }) { const mdxSource = await getMdxContent(params.slug); return <MDXRemote source={mdxSource} />; }
提示:如果是私有仓库,请求时需要在header中携带GitHub个人访问Token做认证,所有拉取逻辑必须放在服务端运行,避免Token泄露。
内容的提问来源于stack exchange,提问作者Ruben Vinke
相关产品推荐
相关产品推荐

