close
  • 中文
  • @rspress/plugin-llms new

    为 Rspress 站点生成 llms.txt 相关文件,使大模型可以更好地理解你的文档站。

    Warning

    @rspress/plugin-llms 的实现原理是使用 remark 处理 MDX 源文件,因此不支持 React Hooks、自定义组件等动态内容的渲染。

    本插件仅作为由于代码不兼容 SSR,无法开启 SSG 和 SSG-MD 功能时的备选方案,建议优先使用 SSG-MD 功能。

    安装

    npm
    yarn
    pnpm
    bun
    deno
    npm add @rspress/plugin-llms -D

    使用

    1. 安装插件

    在配置文件中写入以下的配置:

    // rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import { pluginLlms } from '@rspress/plugin-llms';
    
    export default defineConfig({
      plugins: [pluginLlms()],
    });

    之后执行 rspress build 命令,在生成产物的同时,会在产物目录下根据导航栏、侧边栏生成 llms.txt llms-full.txt 和对应路由的 markdown 文件。

    2. UI 展示

    如果你希望阅读文档站的用户可以更多地调用大模型来阅读文档,可以在页面顶部增加一个复制 Markdown 按钮,效果与本网站相同。

    使用 themeConfig(推荐)

    最简单的方式是在 themeConfig 中启用 llmsUI。这将自动在所有 H1 标题下方(或大纲面板中)添加 LlmsCopyButtonLlmsViewOptions 组件,无需自定义主题代码:

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import { pluginLlms } from '@rspress/plugin-llms';
    
    export default defineConfig({
      plugins: [pluginLlms()],
      themeConfig: {
        llmsUI: true,
        // 或者使用自定义选项:
        // llmsUI: {
        //   viewOptions: ['markdownLink', 'chatgpt', 'claude'],
        //   placement: 'outline', // 在大纲面板中显示而非 H1 下方
        // },
      },
    });

    使用自定义主题

    如果你需要更多控制,可以通过 自定义主题 来添加复制 Markdown 按钮。

    为所有页面增加顶部复制按钮,示例:

    theme/index.tsx
    import { getCustomMDXComponent as basicGetCustomMDXComponent } from '@rspress/core/theme-original';
    import {
      LlmsContainer,
      LlmsCopyButton,
      LlmsViewOptions,
    } from '@rspress/plugin-llms/runtime';
    
    function getCustomMDXComponent() {
      const { h1: H1, ...mdxComponents } = basicGetCustomMDXComponent();
    
      const MyH1 = ({ ...props }) => {
        return (
          <>
            <H1 {...props} />
            <LlmsContainer>
              <LlmsCopyButton />
              {/* LlmsViewOptions 组件可根据需要添加  */}
              <LlmsViewOptions />
            </LlmsContainer>
          </>
        );
      };
      return {
        ...mdxComponents,
        h1: MyH1,
      };
    }
    
    export { getCustomMDXComponent };
    export * from '@rspress/core/theme-original';

    为指定页面增加复制按钮,示例:

    docs/hello-world.mdx
    # Hello world
    
    <LlmsContainer>
      <LlmsCopyButton />
      <LlmsViewOptions /> {/* LlmsViewOptions 组件可根据需要添加  */}
    </LlmsContainer>
    
    这是一个示例文档。

    选项

    这个插件接受一个对象参数,类型如下:

    • 类型:
    interface LlmsTxt {
      name: string;
      onTitleGenerate?: (context: {
        title: string | undefined;
        description: string | undefined;
      }) => string;
      onLineGenerate?: (page: PageIndexInfo) => string;
      onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
    }
    
    interface MdFiles {
      mdxToMd?: boolean;
      remarkPlugins?: PluggableList;
    }
    
    interface LlmsFullTxt {
      name: string;
    }
    export interface Options {
      llmsTxt?: false | LlmsTxt;
      mdFiles?: false | MdFiles;;
      llmsFullTxt?: false | LlmsFullTxt;
      include?: (context: { page: PageIndexInfo }) => boolean;
      exclude?: (context: { page: PageIndexInfo }) => boolean;
    }
    • 默认值:

    当未开启 国际化 时,默认值为:

    {
      llmsTxt: { name: 'llms.txt' },
      llmsFullTxt: { name: 'llms-full.txt' },
      mdFiles: true
    }

    当开启 国际化 时,会使用多组配置,默认值为:

    [
      {
        llmsTxt: { name: 'llms.txt' },
        llmsFullTxt: { name: 'llms-full.txt' },
        mdFiles: true,
        include: ({ page }) => page.lang === config.lang,
      },
      // 根据 locales 配置自动生成其他语言
      {
        llmsTxt: { name: `${lang}/llms.txt` },
        llmsFullTxt: { name: `${lang}/llms-full.txt` },
        mdFiles: true,
        include: ({ page }) => page.lang === lang,
      },
      // ...
    ];

    llmsTxt

    • 类型: false | LlmsTxt
    import type { PageIndexInfo } from '@rspress/core';
    
    export interface LlmsTxt {
      name: string;
      onTitleGenerate?: (context: {
        title: string | undefined;
        description: string | undefined;
      }) => string;
      onLineGenerate?: (page: PageIndexInfo) => string;
      onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
    }
    • 默认值: { name: 'llms.txt' }

    是否生成 llms.txt 文件,或者通过 hooks 自定义生成 llms.txt 文件。

    一个 llms.txt 文件的默认格式如下:

    # {title}
    
    > {description}
    
    ## {nav1.title}
    
    - [{page.title}]({ page.routePath }): {page.frontmatter.description}
    
    ## {nav2.title}
    
    - [{page.title}]({ page.routePath }): {page.frontmatter.description}

    你可以通过 hook 对指定部分进行修改。

    • onTitleGenerate: 自定义生成 title 和 description 部分。
    • onLineGenerate: 自定义生成 md 文件的每一行。
    • onAfterLlmsTxtGenerate: 最后修改 llms.txt 文件的内容。

    例如:

    pluginLlms({
      llmsTxt: {
        onTitleGenerate: ({ title, description }) => {
          return `# ${title} - llms.txt
    
    > ${description}
    
    Rspress is a static site generator based on Rsbuild and it can generate llms.txt with @rspress/plugin-llms.
    `;
        },
      },
    });

    对应的生成结果为:

    # Rspress - llms.txt
    
    > Rsbuild based static site generator
    
    Rspress is a static site generator based on Rsbuild and it can generate llms.txt with @rspress/plugin-llms.
    
    ## guide
    
    - [foo](/foo.md)

    mdFiles

    • 类型: false | MdFiles
    export interface MdFiles {
      mdxToMd?: boolean;
      remarkPlugins?: PluggableList;
    }
    • 默认值: { mdxToMd: false, remarkPlugins: [] }

    是否生成对应路由的 markdown 文件,当设置为 false 时,不会生成对应路由的 markdown 文件。

    mdxToMd

    • 类型: boolean
    • 默认值: false

    是否将 mdx 内容转换为 md 内容,如果启用,会将 mdx 文件通过一组默认策略转换为 md 文件,但可能会有一定的信息丢失。

    remarkPlugins

    • 类型: PluggableList
    • 默认值: []

    用户可以传入自定义的 remark plugins 来对 Markdown 的内容做一些修改。

    llmsFullTxt

    • 类型: false | LlmsFullTxt
    export interface LlmsFullTxt {
      name: string;
    }
    • 默认值: { name: 'llms-full.txt' }

    是否生成 llms-full.txt 文件,当设置为 false 时,不会生成 llms-full.txt 文件。

    include

    • 类型: (context: { page: PageIndexInfo }) => boolean

    是否生成时包含某些页面,一般用于精简 llms.txt。

    • 示例:

    只为语言为英文的页面生成 llms.txt 等相关文件:

    pluginLlms({
      llmsTxt: {
        name: 'llms.txt',
      },
      llmsFullTxt: {
        name: 'llms-full.txt',
      },
      include: ({ page }) => {
        return page.lang === 'en';
      },
    });

    exclude

    • 类型: (context: { page: PageIndexInfo }) => boolean

    是否生成时排除某些页面,会在 include 之后执行。

    • 示例:

    排除 /foo 路由下的单个页面:

    pluginLlms({
      llmsTxt: {
        name: 'llms.txt',
      },
      llmsFullTxt: {
        name: 'llms-full.txt',
      },
      exclude: ({ page }) => {
        return page.routePath === '/foo';
      },
    });

    UI 组件选项

    LlmsCopyButtonProps

    • 类型LlmsCopyButtonProps
    interface LlmsCopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}

    LlmsViewOptionsProps

    • 类型LlmsViewOptionsProps
    type Option =
      | {
          title: string;
          icon?: React.ReactNode;
          onClick?: () => void;
        }
      | {
          title: string;
          href: string;
          icon?: React.ReactNode;
        }
      | 'markdownLink'
      | 'chatgpt'
      | 'claude';
    
    interface LlmsViewOptionsProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
      options?: Option[];
    }

    options

    • 类型Option[]
    type Option =
      | {
          title: string;
          icon?: React.ReactNode;
          onClick?: () => void;
        }
      | {
          title: string;
          href: string;
          icon?: React.ReactNode;
        }
      | 'markdownLink'
      | 'chatgpt'
      | 'claude';
    • 默认值['markdownLink', 'chatgpt', 'claude']

    自定义下拉菜单中的选项,默认支持 "复制 Markdown 链接"、ChatgptClaude

    同时生成多组 llms.txt

    某些情况下,你可能生成多组 llms.txt,例如多语言站点。此时,你可以通过传入一个数组来实现。

    • 示例:
    // rspress.config.ts
    import { defineConfig } from '@rspress/core';
    defineConfig({
      lang: 'en',
      plugins: [
        pluginLlms([
          {
            llmsTxt: {
              name: 'llms.txt',
            },
            llmsFullTxt: {
              name: 'llms-full.txt',
            },
            include: ({ page }) => page.lang === 'en',
          },
          {
            llmsTxt: {
              name: 'zh/llms.txt',
            },
            llmsFullTxt: {
              name: 'zh/llms-full.txt',
            },
            include: ({ page }) => page.lang === 'zh',
          },
        ]),
      ],
    });