Nuxt如何基于Markdown生成内嵌真实内容的SEO友好静态HTML
Nuxt 基于Markdown生成内嵌真实内容的静态HTML实现方案
原实现的问题根因
你当前的实现最终导出的HTML没有内嵌Markdown内容,核心来自两个流程偏差:
- 没有在静态生成阶段完成Markdown到HTML字符串的转换,反而把原始Markdown文本、Markdown解析逻辑全部打包进了客户端JS bundle
- Nuxt 静态生成时的路由参数传递机制里,自定义挂在路由对象上的
content字段不会自动注入到asyncData的上下文里,导致构建运行阶段asyncData拿不到传入的Markdown内容,初始渲染的HTML自然是空的,只能等客户端JS加载完成后临时渲染内容
分步骤正确实现
1. 提前封装仅构建端使用的Markdown渲染工具
这个工具仅在Node构建环境下运行,不会被打入客户端包:
// utils/markdown.js import MarkdownIt from 'markdown-it' const md = new MarkdownIt({ html: true, linkify: true, typographer: true }) export function renderMarkdown(rawMd) { return md.render(rawMd) }
2. 修正构建路由的生成逻辑
在生成路由的阶段就提前读取Markdown文件、完成HTML转换,并把最终渲染好的内容放到Nuxt规定的payload字段里——这个字段的内容会在静态导出时直接序列化内嵌到HTML文件中,不会被打包进客户端JS:
// nuxt.config.js import fs from 'fs' import path from 'path' import { renderMarkdown } from './utils/markdown' const markdownDir = path.resolve(__dirname, 'markdownDir') export default { generate: { routes: () => { const mdFiles = fs.readdirSync(markdownDir).filter(name => name.endsWith('.md')) return mdFiles.map(filename => { const slug = path.basename(filename, '.md') // 构建阶段就读取原始Markdown,提前转换为可直接渲染的HTML字符串 const rawMd = fs.readFileSync(path.join(markdownDir, filename), 'utf-8') const renderedHtml = renderMarkdown(rawMd) return { route: `/articles/${slug}`, // payload内容会直接内嵌到静态HTML的初始状态里 payload: { articleHtml: renderedHtml, slug } } }) } } }
3. 修正详情页的数据取值逻辑
asyncData直接读取构建阶段传入的payload内容,不要在客户端运行时才执行Markdown转换逻辑:
// pages/articles/_slug.vue <template> <div class="markdown-body" v-html="articleHtml"></div> </template> <script> export default { async asyncData({ payload, params }) { // 静态生产环境直接读取已经渲染好的HTML内容 if (payload?.articleHtml) { return { articleHtml: payload.articleHtml, slug: payload.slug } } // dev环境下的兜底逻辑,动态引入Node端依赖,不会被打入生产客户端包 const fs = (await import('fs')).default const path = await import('path') const mdPath = path.resolve(process.cwd(), 'markdownDir', `${params.slug}.md`) const rawMd = fs.readFileSync(mdPath, 'utf-8') const { renderMarkdown } = await import('../../utils/markdown') return { articleHtml: renderMarkdown(rawMd), slug: params.slug } } } </script>
导出效果验证
执行nuxt generate生成静态文件后,直接打开dist目录下对应的文章HTML文件,可以看到:
- 渲染完成的Markdown DOM结构(标题、段落、列表、代码块等内容)直接内嵌在
<div class="markdown-body">标签内部,不需要等待JS加载执行就能被爬虫识别 - 页面渲染所需的初始数据会以JSON格式序列化存在HTML底部的全局状态里, hydration过程会直接复用这份内容,不会重复渲染
常见坑提醒
- 不要把自定义的Markdown内容直接挂在路由对象的非标准字段上,只有Nuxt规定的
payload字段才会在静态导出时被传递到页面上下文中 - Markdown解析的逻辑一定要在构建阶段提前执行,不要放到asyncData里再实时调用,否则解析逻辑、原始Markdown文本会被全部打入客户端JS包,违背静态生成的初衷
- 涉及Node端文件操作的逻辑一定要用动态import引入,避免把fs、path等Node模块打进生产客户端包增加体积
内容的提问来源于stack exchange,提问作者injoker1
相关产品推荐
相关产品推荐

