close
  • English
  • @rspress/plugin-rss

    Generates RSS files for specific document pages with feed.

    Installation

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

    Update Rspress config

    rspress.config.ts
    import { defineConfig } from '@rspress/core';
    import { pluginRss } from '@rspress/plugin-rss';
    
    export default defineConfig({
      plugins: [
        pluginRss({
          // The URL of your document site
          siteUrl: 'https://example.com',
          // ...more configurations below
        }),
      ],
    });

    By default, this plugin generates a blog.xml file in the doc_build/rss/ folder for all pages starting with /blog/.

    The RSS file can be accessed via /rss/blog.xml.

    Tip

    This plugin only works with rspress build and does not generate RSS files on rspress dev.

    Usage

    Selecting pages to be included in RSS

    Use the feed.test option to select which pages to be included in the RSS file.

    pluginRss({
      // ...
      feed: { test: '/zh/blog' },
    });

    Requirements

    All documents included in the RSS must have either date or published_at in their frontmatter to ensure that the RSS updates are stable on the user side.

    ---
    published_at: 2024-01-10 08:00:00
    ---
    
    Or frontmatter `date`.

    Generating multiple RSS files

    Sometimes, you may need to generate multiple RSS files for, e.g., different languages or categories.

    You can provide a list of RSS options to the feed option. For instance:

    pluginRss({
      feed: [
        { id: 'blog', test: '/blog/', title: 'Rspress Blog', language: 'en-US' },
        {
          id: 'blog-zh',
          test: '/zh/blog/',
          title: 'Rspress 博客',
          language: 'zh-CN',
        },
        {
          id: 'rspack',
          test: ({ frontmatter }) => frontmatter.categories.includes('rspack'),
          title: 'Rspack Releases',
          language: 'en-US',
        },
        {
          id: 'rsbuild',
          test: ({ frontmatter }) => frontmatter.categories.includes('rsbuild'),
          title: 'Rsbuild Releases',
          language: 'en-US',
        },
      ],
    });

    The options above will generate four RSS files: blog.xml, blog-zh.xml, rspack.xml, rsbuild.xml, all located in the rss folder.

    Modifying the output path

    You can customize the output path using the output and feed.output parameters.

    Please refer to the FeedOutputOptions below.

    Linking RSS to document pages

    By default, this plugin will insert a <link rel="alternate"> tag in the selected pages that are included in the RSS, linking to the URL of the RSS file. RSS readers can automatically detect the RSS URL.

    If you want to insert this tag in pages that are not included in the RSS (such as the homepage), you can add the link-rss frontmatter to the document, with the value being the feed id. For example:

    ---
    link-rss: blog
    ---
    
    This frontmatter will insert a `<link rel="alternate">` tag in the page of this document, pointing to the RSS URL of the `blog` feed.
    
    However, this page itself will not be included in that RSS.

    link-rss also supports inserting multiple <link> tags associated with feed ids on a single page:

    ---
    link-rss:
      - blog
      - releases
    ---

    Cook the RSS content

    The RSS file consists of two parts: the RSS basic information, known as the channel in the RSS format, and the list of articles, known as the item in the RSS format.

    Here's how you can cook each part:

    • The channel can be fully modified through the feed parameter. Please refer to the Other Options below.
    • The item can be fully modified through the feed.item parameter. Please refer to the item section below.

    Options

    PluginRssOptions

    Options of the plugin.

    export interface PluginRssOptions {
      siteUrl: string;
      feed?: Partial<FeedChannel> | FeedChannel[];
      output?: Omit<FeedOutputOptions, 'filename'>;
    }

    siteUrl

    • Type: string
    • Required

    The site URL of the current document site. It will be used in the RSS file.

    When there is a base configuration, siteUrl needs to include the base path. For example:

    // rspress.config.ts
    import path from 'path';
    import { defineConfig } from '@rspress/core';
    import { pluginRss } from '@rspress/plugin-rss';
    
    export default defineConfig({
      base: '/base/',
      plugins: [
        pluginRss({
          siteUrl: 'https://example.com/base/',
        }),
      ],
    });

    feed

    • Type: FeedChannel | FeedChannel[]
    • Default: { id: 'blog', test: '/blog/' }

    RSS configuration, multiple value array can generate multiple RSS files.

    See FeedChannel for more information.

    output

    • Type: Omit<FeedOutputOptions, "filename">
    • Default: { dir: 'rss', type: 'atom' }

    Options for document output. Please refer to FeedOutputOptions below.

    FeedChannel

    Options for RSS file.

    export interface FeedChannel extends Partial<FeedOptions> {
      id: string;
      test:
        | RegExp
        | string
        | (RegExp | string)[]
        | ((item: PageIndexInfo) => boolean);
      item?: (
        item: FeedItem,
        page: PageIndexInfo,
        siteUrl: string,
      ) => FeedItem | PromiseLike<FeedItem>;
      output?: FeedOutputOptions;
    }

    id

    • Type: string
    • Required

    The ID of an RSS, unique among multiple RSS options. It is also the default file basename for the RSS file.

    test

    • Type: RegExp | string | (RegExp | string)[] | ((item: PageIndexInfo) => boolean)
    • Required

    Used to select documents to be included in the RSS. The types are as follows:

    • RegExp: Regular expression to match the document's route.
    • string: Prefix-based matching to the document's route.
    • (item: PageIndexInfo) => boolean: Match pages based on page data and frontmatter. This is also the recommended way to include a route prefix while excluding specific pages such as /blog/.
    Tip

    item.routePath does not include the base path.

    For example, if you only want to include article pages under /blog/ but exclude the blog index page itself:

    feed: {
      id: 'blog',
      test: (item) => {
        return (
          item.routePath.startsWith('/blog/') && item.routePath !== '/blog/'
        );
      },
    }

    item

    • Type: (item: FeedItem, page: PageIndexInfo, siteUrl: string) => FeedItem | PromiseLike<FeedItem>
    • Default:

    Generates structured data for each article in the RSS file.

    Refer to the type of structured data:

    The plugin has a built-in generator that utilizes the document's frontmatter and page data.

    For example, the content in the RSS will prioritize the summary from frontmatter, and then try the document content.

    You can provide the item function to modify the generated data which will be passed as the first parameter to the function you provided.

    For example, the following configuration truncates the content of articles in the RSS:

    const item: FeedChannel['item'] = item => ({
      ...item,
      content: item.content.slice(0, 1000),
    });

    output

    • Type: FeedOutputOptions
    • Default: Uses the plugin's output option by default

    In addition to the plugin's output option, there is an additional filename to modify the output filename.

    Please refer to FeedOutputOptions below.

    Other options

    FeedChannel also inherits the FeedOptions from the feed package. Please refer to

    for parameters that are not listed.

    FeedOutputOptions

    Output options for RSS files, available at both the top level of the plugin options and the feed level. Using the following type:

    interface FeedOutputOptions {
      dir?: string;
      type?: 'atom' | 'rss' | 'json';
      filename?: string;
      publicPath?: string;
      sorting?: (left: FeedItem, right: FeedItem) => number;
      transform?: (
        content: string,
        context: {
          type: 'atom' | 'rss' | 'json';
          feed: Feed;
          channel: FeedChannel;
        },
      ) => string | PromiseLike<string>;
    }

    Example:

    pluginRss({
      // Applied to all RSS outputs
      output: {
        // Change the output folder for RSS files to 'feeds', relative to `doc_build`
        dir: 'feeds',
        // Output in RSS 2.0 format, use `.rss` extension by default.
        type: 'rss',
      },
      feed: [
        {
          id: 'blog',
          test: '/blog/',
          title: 'My Blog',
          output: {
            type: 'atom' /* default to using `id` as the base file name */,
          },
        },
        {
          id: 'releases',
          test: '/releases/',
          title: 'Releases',
          output: { dir: 'releases', filename: 'feed.rss' },
        },
      ],
    });

    Building with the options above will output two files: feeds/blog.xml and releases/feed.rss.

    dir

    • Type: string
    • Default: rss

    Output folder for RSS files, relative to doc_build.

    type

    • Type: "atom" | "rss" | "json"
    • Default: atom

    Output format of the RSS file, atom by default. Details of these types:

    ValueFormatDefault ExtensionMIME Type
    atomAtom 1.0.xmlapplication/atom+xml
    rssRSS 2.0.rssapplication/rss+xml
    jsonJSON Feed 1.1.jsonapplication/json

    filename

    • Type: string
    • Default: ID as the file basename; extension by RSS output format

    Modify the full filename of the RSS file.

    publicPath

    • Type: string
    • Default: the value of siteUrl

    URL Prefix for the RSS file. An RSS URL is composed of publicPath, dir, and filename.

    sorting

    • Typesorting?: (left: FeedItem, right: FeedItem) => number;

    Used for sorting the articles. By default, the newest articles go first, followed by the older ones.

    transform

    • Type: (content: string, context: { type: 'atom' | 'rss' | 'json'; feed: Feed; channel: FeedChannel }) => string | PromiseLike<string>

    Transform the final generated feed content before it is written to disk. This hook is available in both the plugin-level output option and the per-feed output option, so the same customization pattern can be used for Atom, RSS, and JSON Feed outputs.

    For example, the following configuration injects a custom folo:id into XML feeds and adds the same identifier to JSON Feed:

    pluginRss({
      siteUrl: 'https://example.com/',
      output: {
        transform(content, { type, channel }) {
          if (type === 'json') {
            return JSON.stringify({
              ...JSON.parse(content),
              foloId: channel.id,
            });
          }
    
          const closingTag = type === 'rss' ? '</channel>' : '</feed>';
          return content.replace(
            closingTag,
            `<folo:id>${channel.id}</folo:id>${closingTag}`,
          );
        },
      },
    });