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 つのチャンネルに collection と items を同時に書くことはできません。 同時に指定すると reject されます。programmatic item は title、url または loc、任意の id、date、description、content、author / authors、image、attachments、language を受け取ります。RSS、Atom、 JSON Feed の各 renderer は、その形式が対応する field を出力します。

独自ホストが route planning の時点で feed data をすでに読み込んでいる場合は、 feeds.items でもう一度読み込む代わりに、通常は build 専用の outputs(ctx) lifecycle から返せます。default items、名前付き collections、任意の collectionNames を返してください。Ox Content は同じ writeFeedFiles() path と publish-state filtering を使います。独自ホスト lifecycle も見てください。 oxContentCustomHost() に dev.feedOutputs: true を設定すると、重複した feed route を足さずに、Vite 開発中もその coordinated feed file を配信できます。

独自 dev server#

独自 Vite middleware や dev server で、一時ファイルを書かずに同じフィードの bytes を返したいときは renderFeedFiles() を使います。writeFeedFiles() と 同じ解決済み feed options、collection data、publish-state filtering、base、 SSG site metadata を受け取ります。結果には安全なサイト相対 path、 contentType、直列化済み 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.xml、feeds/atom.xml、feeds/feed.json を書き出します。チャンネルの title、description、language、image、favicon、copyright は、各形式に対応するフィールドがあるときサイト既定を上書きします(JSON Feed に copyright はありません)。

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

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

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

ブログ索引の項目#

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

関連#

Last updated: