diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index 8af04cf9ae22..b207a23623b9 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -220,6 +220,134 @@ exports[`atom has feed item for each post 1`] = ` ] `; +exports[`atom has feed item for each post - with trailing slash 1`] = ` +[ + " + + https://docusaurus.io/myBaseUrl/blog/ + Hello Blog + 2023-07-23T00:00:00.000Z + https://github.com/jpmonette/feed + + Hello Blog + https://docusaurus.io/myBaseUrl/image/favicon.ico + Copyright + + <![CDATA[test links]]> + https://docusaurus.io/myBaseUrl/blog/blog-with-links/ + + 2023-07-23T00:00:00.000Z + + absolute full url

+

absolute pathname

+

relative pathname

+

md link

+

anchor

+

relative pathname + anchor

+

+

+ +]]>
+
+ + <![CDATA[MDX Blog Sample with require calls]]> + https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post/ + + 2021-03-06T00:00:00.000Z + + Test MDX with require calls

+ + + + +]]>
+
+ + <![CDATA[Full Blog Sample]]> + https://docusaurus.io/myBaseUrl/blog/mdx-blog-post/ + + 2021-03-05T00:00:00.000Z + + HTML Heading 1 +

HTML Heading 2

+

HTML Paragraph

+ + +

Import DOM

+

Heading 1

+

Heading 2

+

Heading 3

+

Heading 4

+
Heading 5
+
    +
  • list1
  • +
  • list2
  • +
  • list3
  • +
+
    +
  • list1
  • +
  • list2
  • +
  • list3
  • +
+

Normal Text Italics Text Bold Text

+

link image

]]>
+
+ + <![CDATA[Complex Slug]]> + https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô/ + + 2020-08-16T00:00:00.000Z + + complex url slug

]]>
+ + +
+ + <![CDATA[Simple Slug]]> + https://docusaurus.io/myBaseUrl/blog/simple/slug/ + + 2020-08-15T00:00:00.000Z + + simple url slug

]]>
+ + Sébastien Lorber + https://sebastienlorber.com + +
+ + <![CDATA[some heading]]> + https://docusaurus.io/myBaseUrl/blog/heading-as-title/ + + 2019-01-02T00:00:00.000Z + + + <![CDATA[date-matter]]> + https://docusaurus.io/myBaseUrl/blog/date-matter/ + + 2019-01-01T00:00:00.000Z + + date inside front matter

]]>
+ +
+ + <![CDATA[Happy 1st Birthday Slash! (translated)]]> + https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash/ + + 2018-12-14T00:00:00.000Z + + Happy birthday! (translated)

]]>
+ + Yangshun Tay (translated) + + + Sébastien Lorber (translated) + lorber.sebastien@gmail.com + +
+
", +] +`; + exports[`json filters to the first two entries 1`] = ` [ "{ @@ -378,6 +506,102 @@ exports[`json has feed item for each post 1`] = ` ] `; +exports[`json has feed item for each post - with trailing slash 1`] = ` +[ + "{ + "version": "https://jsonfeed.org/version/1", + "title": "Hello Blog", + "home_page_url": "https://docusaurus.io/myBaseUrl/blog/", + "description": "Hello Blog", + "items": [ + { + "id": "https://docusaurus.io/myBaseUrl/blog/blog-with-links/", + "content_html": "

absolute full url

/n

absolute pathname

/n

relative pathname

/n

md link

/n

anchor

/n

relative pathname + anchor

/n

/n

\\"\\"

/n/n", + "url": "https://docusaurus.io/myBaseUrl/blog/blog-with-links/", + "title": "test links", + "summary": "absolute full url", + "date_modified": "2023-07-23T00:00:00.000Z", + "tags": [] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post/", + "content_html": "

Test MDX with require calls

/n/n/n/n/n", + "url": "https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post/", + "title": "MDX Blog Sample with require calls", + "summary": "Test MDX with require calls", + "date_modified": "2021-03-06T00:00:00.000Z", + "tags": [] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/mdx-blog-post/", + "content_html": "

HTML Heading 1

/n

HTML Heading 2

/n

HTML Paragraph

/n/n/n

Import DOM

/n

Heading 1

/n

Heading 2

/n

Heading 3

/n

Heading 4

/n
Heading 5
/n/n/n

Normal Text Italics Text Bold Text

/n

link \\"image\\"

", + "url": "https://docusaurus.io/myBaseUrl/blog/mdx-blog-post/", + "title": "Full Blog Sample", + "summary": "HTML Heading 1", + "date_modified": "2021-03-05T00:00:00.000Z", + "tags": [] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô/", + "content_html": "

complex url slug

", + "url": "https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô/", + "title": "Complex Slug", + "summary": "complex url slug", + "date_modified": "2020-08-16T00:00:00.000Z", + "tags": [ + "date", + "complex" + ] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/simple/slug/", + "content_html": "

simple url slug

", + "url": "https://docusaurus.io/myBaseUrl/blog/simple/slug/", + "title": "Simple Slug", + "summary": "simple url slug", + "date_modified": "2020-08-15T00:00:00.000Z", + "author": { + "name": "Sébastien Lorber", + "url": "https://sebastienlorber.com" + }, + "tags": [] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/heading-as-title/", + "content_html": "", + "url": "https://docusaurus.io/myBaseUrl/blog/heading-as-title/", + "title": "some heading", + "date_modified": "2019-01-02T00:00:00.000Z", + "tags": [] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/date-matter/", + "content_html": "

date inside front matter

", + "url": "https://docusaurus.io/myBaseUrl/blog/date-matter/", + "title": "date-matter", + "summary": "date inside front matter", + "date_modified": "2019-01-01T00:00:00.000Z", + "tags": [ + "date" + ] + }, + { + "id": "https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash/", + "content_html": "

Happy birthday! (translated)

", + "url": "https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash/", + "title": "Happy 1st Birthday Slash! (translated)", + "summary": "Happy birthday! (translated)", + "date_modified": "2018-12-14T00:00:00.000Z", + "author": { + "name": "Yangshun Tay (translated)" + }, + "tags": [] + } + ] +}", +] +`; + exports[`rss filters to the first two entries 1`] = ` [ " @@ -593,3 +817,123 @@ exports[`rss has feed item for each post 1`] = ` ", ] `; + +exports[`rss has feed item for each post - with trailing slash 1`] = ` +[ + " + + + Hello Blog + https://docusaurus.io/myBaseUrl/blog/ + Hello Blog + Sun, 23 Jul 2023 00:00:00 GMT + https://validator.w3.org/feed/docs/rss2.html + https://github.com/jpmonette/feed + en + Copyright + + <![CDATA[test links]]> + https://docusaurus.io/myBaseUrl/blog/blog-with-links/ + https://docusaurus.io/myBaseUrl/blog/blog-with-links/ + Sun, 23 Jul 2023 00:00:00 GMT + + absolute full url

+

absolute pathname

+

relative pathname

+

md link

+

anchor

+

relative pathname + anchor

+

+

+ +]]>
+
+ + <![CDATA[MDX Blog Sample with require calls]]> + https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post/ + https://docusaurus.io/myBaseUrl/blog/mdx-require-blog-post/ + Sat, 06 Mar 2021 00:00:00 GMT + + Test MDX with require calls

+ + + + +]]>
+
+ + <![CDATA[Full Blog Sample]]> + https://docusaurus.io/myBaseUrl/blog/mdx-blog-post/ + https://docusaurus.io/myBaseUrl/blog/mdx-blog-post/ + Fri, 05 Mar 2021 00:00:00 GMT + + HTML Heading 1 +

HTML Heading 2

+

HTML Paragraph

+ + +

Import DOM

+

Heading 1

+

Heading 2

+

Heading 3

+

Heading 4

+
Heading 5
+
    +
  • list1
  • +
  • list2
  • +
  • list3
  • +
+
    +
  • list1
  • +
  • list2
  • +
  • list3
  • +
+

Normal Text Italics Text Bold Text

+

link image

]]>
+
+ + <![CDATA[Complex Slug]]> + https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô/ + https://docusaurus.io/myBaseUrl/blog/hey/my super path/héllô/ + Sun, 16 Aug 2020 00:00:00 GMT + + complex url slug

]]>
+ date + complex +
+ + <![CDATA[Simple Slug]]> + https://docusaurus.io/myBaseUrl/blog/simple/slug/ + https://docusaurus.io/myBaseUrl/blog/simple/slug/ + Sat, 15 Aug 2020 00:00:00 GMT + + simple url slug

]]>
+
+ + <![CDATA[some heading]]> + https://docusaurus.io/myBaseUrl/blog/heading-as-title/ + https://docusaurus.io/myBaseUrl/blog/heading-as-title/ + Wed, 02 Jan 2019 00:00:00 GMT + + + <![CDATA[date-matter]]> + https://docusaurus.io/myBaseUrl/blog/date-matter/ + https://docusaurus.io/myBaseUrl/blog/date-matter/ + Tue, 01 Jan 2019 00:00:00 GMT + + date inside front matter

]]>
+ date +
+ + <![CDATA[Happy 1st Birthday Slash! (translated)]]> + https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash/ + https://docusaurus.io/myBaseUrl/blog/2018/12/14/Happy-First-Birthday-Slash/ + Fri, 14 Dec 2018 00:00:00 GMT + + Happy birthday! (translated)

]]>
+ lorber.sebastien@gmail.com (Sébastien Lorber (translated)) +
+
+
", +] +`; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index 022d4ce749a9..b900129c9bdc 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -9,6 +9,7 @@ import {jest} from '@jest/globals'; import path from 'path'; import fs from 'fs-extra'; import {DEFAULT_PARSE_FRONT_MATTER} from '@docusaurus/utils'; +import {fromPartial} from '@total-typescript/shoehorn'; import {DEFAULT_OPTIONS} from '../options'; import {generateBlogPosts} from '../blogUtils'; import {createBlogFeedFiles} from '../feed'; @@ -80,12 +81,12 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { const outDir = path.join(siteDir, 'build-snap'); await testGenerateFeeds( - { + fromPartial({ siteDir, siteConfig, i18n: DefaultI18N, outDir, - } as LoadContext, + }), { path: 'invalid-blog-path', routeBasePath: 'blog', @@ -120,12 +121,12 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { // Build is quite difficult to mock, so we built the blog beforehand and // copied the output to the fixture... await testGenerateFeeds( - { + fromPartial({ siteDir, siteConfig, i18n: DefaultI18N, outDir, - } as LoadContext, + }), { path: 'blog', routeBasePath: 'blog', @@ -163,12 +164,12 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { // Build is quite difficult to mock, so we built the blog beforehand and // copied the output to the fixture... await testGenerateFeeds( - { + fromPartial({ siteDir, siteConfig, i18n: DefaultI18N, outDir, - } as LoadContext, + }), { path: 'blog', routeBasePath: 'blog', @@ -216,12 +217,12 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { // Build is quite difficult to mock, so we built the blog beforehand and // copied the output to the fixture... await testGenerateFeeds( - { + fromPartial({ siteDir, siteConfig, i18n: DefaultI18N, outDir, - } as LoadContext, + }), { path: 'blog', routeBasePath: 'blog', @@ -245,4 +246,48 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => { ).toMatchSnapshot(); fsMock.mockClear(); }); + + it('has feed item for each post - with trailing slash', async () => { + const siteDir = path.join(__dirname, '__fixtures__', 'website'); + const outDir = path.join(siteDir, 'build-snap'); + const siteConfig = { + title: 'Hello', + baseUrl: '/myBaseUrl/', + url: 'https://docusaurus.io', + favicon: 'image/favicon.ico', + trailingSlash: true, + markdown, + }; + + // Build is quite difficult to mock, so we built the blog beforehand and + // copied the output to the fixture... + await testGenerateFeeds( + fromPartial({ + siteDir, + siteConfig, + i18n: DefaultI18N, + outDir, + }), + { + path: 'blog', + routeBasePath: 'blog', + tagsBasePath: 'tags', + authorsMapPath: 'authors.yml', + include: DEFAULT_OPTIONS.include, + exclude: DEFAULT_OPTIONS.exclude, + feedOptions: { + type: [feedType], + copyright: 'Copyright', + }, + readingTime: ({content, defaultReadingTime}) => + defaultReadingTime({content}), + truncateMarker: //, + } as PluginOptions, + ); + + expect( + fsMock.mock.calls.map((call) => call[1] as string), + ).toMatchSnapshot(); + fsMock.mockClear(); + }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/feed.ts b/packages/docusaurus-plugin-content-blog/src/feed.ts index 22b7f53cbb80..95e63ac5af69 100644 --- a/packages/docusaurus-plugin-content-blog/src/feed.ts +++ b/packages/docusaurus-plugin-content-blog/src/feed.ts @@ -11,7 +11,10 @@ import logger from '@docusaurus/logger'; import {Feed, type Author as FeedAuthor} from 'feed'; import * as srcset from 'srcset'; import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils'; -import {blogPostContainerID} from '@docusaurus/utils-common'; +import { + blogPostContainerID, + applyTrailingSlash, +} from '@docusaurus/utils-common'; import {load as cheerioLoad} from 'cheerio'; import type {DocusaurusConfig} from '@docusaurus/types'; import type { @@ -40,8 +43,14 @@ async function generateBlogFeed({ } const {feedOptions, routeBasePath} = options; - const {url: siteUrl, baseUrl, title, favicon} = siteConfig; - const blogBaseUrl = normalizeUrl([siteUrl, baseUrl, routeBasePath]); + const {url: siteUrl, baseUrl, title, favicon, trailingSlash} = siteConfig; + const blogBaseUrl = applyTrailingSlash( + normalizeUrl([siteUrl, baseUrl, routeBasePath]), + { + trailingSlash, + baseUrl, + }, + ); const blogPostsForFeed = feedOptions.limit === false || feedOptions.limit === null @@ -85,7 +94,7 @@ async function defaultCreateFeedItems({ siteConfig: DocusaurusConfig; outDir: string; }): Promise { - const {url: siteUrl} = siteConfig; + const {url: siteUrl, baseUrl, trailingSlash} = siteConfig; function toFeedAuthor(author: Author): FeedAuthor { return {name: author.name, link: author.url, email: author.email}; @@ -105,13 +114,19 @@ async function defaultCreateFeedItems({ } = post; const content = await readOutputHTMLFile( - permalink.replace(siteConfig.baseUrl, ''), + permalink.replace(baseUrl, ''), outDir, - siteConfig.trailingSlash, + trailingSlash, ); const $ = cheerioLoad(content); - const blogPostAbsoluteUrl = normalizeUrl([siteUrl, permalink]); + const blogPostAbsoluteUrl = applyTrailingSlash( + normalizeUrl([siteUrl, permalink]), + { + trailingSlash, + baseUrl, + }, + ); const toAbsoluteUrl = (src: string) => String(new URL(src, blogPostAbsoluteUrl));