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

如何在Astro中结合Prism渲染Contentful中的嵌入代码块?

Astro集成Contentful时代码块渲染问题:自定义带主题的Prism组件

我用Astro搭建了一个集成Contentful的Web开发博客,除代码块外所有功能都正常运行。我在Contentful内容模型中为代码块创建了嵌入条目,返回的nodeType结构如下:

{
   nodeType: 'embedded-entry-block',
   data: {
      target: {
      metadata: [Object],
      sys: [Object],
      fields: {
      code:
         '```html\n<!DOCTYPE html>\n<html>\n<head>\n<title>My First Astro App</title>\n</head>\n  <body>\n<h1>Hello, World!</h1>\n</body>\n</html>\n```'
        }
      }
    },
    content: []
}

我不清楚如何通过@contentful/rich-text-html-renderer的documentToHtmlString函数,在博客中用带自定义主题的Prism组件渲染代码块。

目前我已经给嵌入条目传了自定义渲染逻辑到documentToHtmlString的配置里,能提取出代码的语言和内容,并且通过@astrojs/prism的runHighlighterWithAstro实现了无样式的代码块显示,代码如下:

---
import { documentToHtmlString } from "@contentful/rich-text-html-renderer";
import { BLOCKS } from "@contentful/rich-text-types";
import ContentLayout from "@layouts/ContentLayout.astro";
import BlogPostMeta from "@components/BlogPostMeta.astro";
import { BlogPost, contentfulClient } from "@lib/contentful";
import { Prism } from "@astrojs/prism";
import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";

export async function getStaticPaths() {
  const entries = await contentfulClient.getEntries<BlogPost>({
    content_type: "blogPost",
  });

  function extractCode(str: string): { lang: string; code: string } | null {
    const match = str?.match(/```(\w+)\n([\s\S]+)\n```/);
    if (match) {
      return {
        lang: match[1],
        code: match[2],
      };
    }
    return null;
  }

  const renderOptions = {
    renderNode: {
      [BLOCKS.EMBEDDED_ENTRY]: (node: any) => {
        const { code } = node.data.target.fields;
        const extractedCode = extractCode(code);
        if (extractedCode) {
          const { lang, code } = extractedCode;
          const { classLanguage, html } = runHighlighterWithAstro(lang, code);
          return `<pre class=${classLanguage} set:html=${html}></pre>`;
        }
        return "";
      },
    },
  };

  const pages = entries.items.map((item) => ({
    params: { slug: item.fields.slug },
    props: {
      title: item.fields.title,
      description: item.fields.description,
      content: documentToHtmlString(item.fields.content, renderOptions),
      date: new Date(item.fields.date).toLocaleDateString(),
    },
  }));
  return pages;
}

const { slug } = Astro.params;
if (typeof slug !== "string") {
  throw Error(`Slug should be a string. Received: ${slug}`);
}

const { description, content, title, date } = Astro.props;
---

<ContentLayout title={title} date={date}>
  <BlogPostMeta
    title={title}
    description={description}
    publishDate={date}
    pagePath={`/posts/${slug}`}
    slot='meta'
  />
  <body>
    <h1>{title}</h1>
    <time>{date}</time>
    <article slot='content' set:html={content} />
  </body>
</ContentLayout>

我希望使用自己写的CodeBlock组件来渲染带自定义样式的Prism代码块,但因为之前习惯用React,对Astro的机制不太理解,我的CodeBlock组件代码如下:

---
import { Prism } from "@astrojs/prism";

const { language, code } = Astro.props;
---

<Prism lang={language} code={code} />

<style is:global>...
</style>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:21:24