Skip to content

RSS / Atom / JSON フィード#

View Markdown

feeds を有効にし、ssg.siteUrl を設定すると、SSG ビルドは名前付きコレクションから機械可読のフィードを書き出します。

  • feed.xml — RSS 2.0
  • atom.xml — Atom 1.0
  • feed.json — JSON Feed 1.1

機能は自分でオンにするまでオフです。既存サイトはそのままです。

import { oxContent } from "@ox-content/vite-plugin";

export default {
  plugins: [
    oxContent({
      feeds: true,
      ssg: {
        siteUrl: "https://example.com",
      },
    }),
  ],
};

false または省略はファイルを出しません。true は既定でオンです。3 形式すべて、content コレクション(なければ設定された最初のコレクション)、20 件制限です。単一オブジェクトは 1 本の既定フィードで、設定したフィールドだけ上書きします。

oxContent({
  feeds: {
    formats: ["rss", "json"],
    collection: "blog",
    limit: 10,
    path: "/feeds",
  },
  ssg: {
    siteUrl: "https://example.com",
  },
});

名前付きレコードまたは配列を渡すと、複数フィードを書き出します。チャンネルごとにコレクション、パス、形式、メタデータを設定できます。

oxContent({
  feeds: {
    blog: {
      formats: ["rss"],
      collection: "blog",
      path: "/",
      title: "blog | example.com",
      description: "Technical articles",
      language: "en",
      image: "https://example.com/icon.png",
      favicon: "https://example.com/icon.png",
      copyright: "© 2026 example.com",
    },
    media: {
      formats: ["rss"],
      collection: "media",
      path: "/works/media",
      title: "Media | example.com",
      language: "ja",
    },
  },
  ssg: {
    siteUrl: "https://example.com",
  },
});

Programmatic items#

フィードの元データが JSON ファイル、database の結果、ビルド時に集めた curated データのときは、チャンネルに collection ではなく items を設定できます。resolver は SSG 中に実行され、promise を返せます。

import media from "./src/contents/external-rss/media.json";

oxContent({
  feeds: {
    media: {
      formats: ["rss"],
      path: "/works/media",
      title: "Media | ryoppippi.com",
      items: async () =>
        media
          .filter((item) => !item.playlist)
          .map((item) => ({
            title: item.title,
            url: item.link,
            id: `media:${item.link}`,
            date: item.pubDate,
            description: `${item.kind === "podcast" ? "Podcast" : "YouTube"} | ${item.title}`,
            author: { name: "ryoppippi", url: "https://ryoppippi.com" },
            language: item.lang,
          })),
    },
  },
  ssg: {
    siteUrl: "https://ryoppippi.com",
  },
});

1 つのチャンネルに collectionitems を同時に書くことはできません。 同時に指定すると reject されます。programmatic item は titleurl または loc、任意の iddatedescriptioncontentauthor / authorsimageattachmentslanguage を受け取ります。RSS、Atom、 JSON Feed の各 renderer は、その形式が対応する field を出力します。

独自 dev server#

独自 Vite middleware や dev server で、一時ファイルを書かずに同じフィードの bytes を返したいときは renderFeedFiles() を使います。writeFeedFiles() と 同じ解決済み feed options、collection data、publish-state filtering、base、 SSG site metadata を受け取ります。結果には安全なサイト相対 pathcontentType、直列化済み content が入ります。

import type { Plugin } from "vite";
import { renderFeedFiles, resolveFeedsOptions } from "@ox-content/vite-plugin";

const feeds = resolveFeedsOptions({
  media: {
    formats: ["rss", "atom", "json"],
    path: "/works/media",
    title: "Media | ryoppippi.com",
    items: async () => [
      {
        title: "Guest appearance",
        url: "https://media.example.com/episode",
        date: "2026-08-01",
        author: { name: "ryoppippi", url: "https://ryoppippi.com" },
      },
    ],
  },
});

export function feedMiddleware(): Plugin {
  return {
    name: "site-feeds",
    configureServer(server) {
      server.middlewares.use(async (req, res, next) => {
        const rendered = await renderFeedFiles({
          options: feeds,
          siteUrl: "https://ryoppippi.com",
          siteName: "ryoppippi.com",
          base: "/",
        });
        if (rendered.warning) {
          server.config.logger.warn(rendered.warning);
          return next();
        }

        const requestPath = new URL(req.url ?? "/", "http://localhost").pathname.replace(
          /^\/+/,
          "",
        );
        const file = rendered.files.find((candidate) => candidate.path === requestPath);
        if (!file) {
          return next();
        }

        res.statusCode = 200;
        res.setHeader("Content-Type", file.contentType);
        res.end(file.content);
      });
    },
  };
}

危険な path、不正な site URL、重複した出力 path は writeFeedFiles() と同じ warning で失敗します。

オプション 既定
feeds boolean / 単一フィード / 名前付き / 配列 false
formats ("rss" | "atom" | "json")[] ["rss", "atom", "json"]
collection string content、なければ最初のコレクション
items FeedItemInput[] / async resolver 省略
limit number 20
path string /(サイトルート)
title string SSG のサイト名
description string SSG のサイト説明
language string 省略
image string 省略
favicon string 省略
copyright string 省略

path は生成ファイルのサイト相対ディレクトリです。/feeds なら feeds/feed.xmlfeeds/atom.xmlfeeds/feed.json を書き出します。チャンネルの titledescriptionlanguageimagefaviconcopyright は、各形式に対応するフィールドがあるときサイト既定を上書きします(JSON Feed に copyright はありません)。

項目は新しい順です。ソートキーは frontmatter の date、なければ lastUpdated です。draft: true のエントリは外れます。

feeds をオンにしても ssg.siteUrl がなければ、ファイルは書き出しません。ビルドは続き、警告を出します。

タイトルと説明はエスケープされるので、XML や JSON の外へは出られません。

ブログ索引の項目#

ブログblog.feeds で集めた外部投稿は索引にだけ載ります。 生成ファイルには入りません。このリリースに取り込みスイッチはありません。

関連#

Last updated: