diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 41c428dc52..6371d3a1a9 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -17,6 +17,7 @@ import { BlogItemsToModules, TagsModule, BlogPaginated, + FeedType, } from './types'; import { LoadContext, @@ -24,6 +25,7 @@ import { ConfigureWebpackUtils, Props, Plugin, + HtmlTags, } from '@docusaurus/types'; import {Configuration, Loader} from 'webpack'; import {generateBlogFeed, generateBlogPosts} from './blogUtils'; @@ -42,6 +44,26 @@ const DEFAULT_OPTIONS: PluginOptions = { truncateMarker: //, // string or regex }; +function assertFeedTypes(val: any): asserts val is FeedType { + if (typeof val !== 'string' && !['rss', 'atom', 'all'].includes(val)) { + throw new Error( + `Invalid feedOptions type: ${val}. It must be either 'rss', 'atom', or 'all'`, + ); + } +} + +const getFeedTypes = (type?: FeedType) => { + assertFeedTypes(type); + let feedTypes: ('rss' | 'atom')[] = []; + + if (type === 'all') { + feedTypes = ['rss', 'atom']; + } else { + feedTypes.push(type); + } + return feedTypes; +}; + export default function pluginContentBlog( context: LoadContext, opts: Partial, @@ -389,19 +411,13 @@ export default function pluginContentBlog( return; } - const { - feedOptions: {type: feedType}, - } = options; const feed = await generateBlogFeed(context, options); + if (!feed) { return; } - let feedTypes = []; - if (feedType === 'all') { - feedTypes = ['rss', 'atom']; - } else { - feedTypes.push(feedType); - } + + const feedTypes = getFeedTypes(options.feedOptions?.type); await Promise.all( feedTypes.map(feedType => { @@ -419,5 +435,54 @@ export default function pluginContentBlog( }), ); }, + + injectHtmlTags() { + if (!options.feedOptions) { + return {}; + } + + const feedTypes = getFeedTypes(options.feedOptions?.type); + const { + siteConfig: {title}, + baseUrl, + } = context; + const feedsConfig = { + rss: { + type: 'application/rss+xml', + path: 'blog/rss.xml', + title: `${title} Blog RSS Feed`, + }, + atom: { + type: 'application/atom+xml', + path: 'blog/atom.xml', + title: `${title} Blog Atom Feed`, + }, + }; + const headTags: HtmlTags = []; + + feedTypes.map(feedType => { + const feedConfig = feedsConfig[feedType] || {}; + + if (!feedsConfig) { + return; + } + + const {type, path, title} = feedConfig; + + headTags.push({ + tagName: 'link', + attributes: { + rel: 'alternate', + type, + href: normalizeUrl([baseUrl, path]), + title, + }, + }); + }); + + return { + headTags, + }; + }, }; } diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index d6cb5c8de2..2c5350b5fa 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -17,6 +17,8 @@ export interface DateLink { link: string; } +export type FeedType = 'rss' | 'atom' | 'all'; + export interface PluginOptions { path: string; routeBasePath: string; @@ -30,7 +32,7 @@ export interface PluginOptions { rehypePlugins: string[]; truncateMarker: RegExp | string; feedOptions?: { - type: 'rss' | 'atom' | 'all'; + type: FeedType; title?: string; description?: string; copyright: string;