@rspress/plugin-rss 2.0.0-rc.5 → 2.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -2
- package/dist/index.js +52 -20
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -72,9 +72,10 @@ export declare type FeedOutputType = /** Atom 1.0 Feed */ 'atom' | /** RSS 2.0 F
|
|
|
72
72
|
/**
|
|
73
73
|
* @public
|
|
74
74
|
* @param page Rspress Page Data
|
|
75
|
-
* @param siteUrl
|
|
75
|
+
* @param siteUrl Site URL for generating absolute links
|
|
76
|
+
* @param htmlContent HTML content extracted from SSG output (optional)
|
|
76
77
|
*/
|
|
77
|
-
export declare function generateFeedItem(page: PageIndexInfo, siteUrl: string): {
|
|
78
|
+
export declare function generateFeedItem(page: PageIndexInfo, siteUrl: string, htmlContent?: string | null): {
|
|
78
79
|
id: string;
|
|
79
80
|
title: string;
|
|
80
81
|
author: Author[] | undefined;
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,26 @@ async function writeFile(path, content) {
|
|
|
34
34
|
});
|
|
35
35
|
return promises.writeFile(path, content);
|
|
36
36
|
}
|
|
37
|
-
function
|
|
37
|
+
async function readFile(path) {
|
|
38
|
+
try {
|
|
39
|
+
return await promises.readFile(path, 'utf-8');
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function routePathToHtmlPath(routePath) {
|
|
45
|
+
let fileName = routePath;
|
|
46
|
+
fileName = fileName.endsWith('/') ? `${routePath}index.html` : `${routePath}.html`;
|
|
47
|
+
return fileName.replace(/^\/+/, '');
|
|
48
|
+
}
|
|
49
|
+
function extractHtmlContent(html) {
|
|
50
|
+
const match = html.match(/<div[^>]*class="[^"]*rspress-doc[^"]*"[^>]*>([\s\S]*?)<\/div>(?=<footer|<\/main)/);
|
|
51
|
+
if (match) return match[1].trim();
|
|
52
|
+
const fallbackMatch = html.match(/<div[^>]*class="[^"]*rspress-doc[^"]*"[^>]*>([\s\S]*?)<\/div>/);
|
|
53
|
+
if (fallbackMatch) return fallbackMatch[1].trim();
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function generateFeedItem(page, siteUrl, htmlContent) {
|
|
38
57
|
const { frontmatter: fm } = page;
|
|
39
58
|
return {
|
|
40
59
|
id: selectNonNullishProperty(fm.slug, fm.id, page.routePath) || '',
|
|
@@ -42,7 +61,7 @@ function generateFeedItem(page, siteUrl) {
|
|
|
42
61
|
author: toAuthors(fm.author),
|
|
43
62
|
link: resolve(siteUrl, selectNonNullishProperty(fm.permalink, page.routePath)?.replace(/^\//, '') || ''),
|
|
44
63
|
description: selectNonNullishProperty(fm.description) || '',
|
|
45
|
-
content: selectNonNullishProperty(fm.summary, page.
|
|
64
|
+
content: selectNonNullishProperty(fm.summary, htmlContent, page.content) || '',
|
|
46
65
|
date: toDate(fm.date || fm.published_at),
|
|
47
66
|
category: concatArray(fm.categories, fm.category).map((cat)=>({
|
|
48
67
|
name: cat
|
|
@@ -173,10 +192,10 @@ class FeedsSet {
|
|
|
173
192
|
return this.feeds.slice(0);
|
|
174
193
|
}
|
|
175
194
|
}
|
|
176
|
-
function getRssItems(feeds, page, siteUrl) {
|
|
195
|
+
async function getRssItems(feeds, page, siteUrl, htmlContent) {
|
|
177
196
|
return Promise.all(feeds.filter((options)=>testPage(options.test, page)).map(async (options)=>{
|
|
178
197
|
const after = options.item || ((feed)=>feed);
|
|
179
|
-
const item = await after(generateFeedItem(page, siteUrl), page);
|
|
198
|
+
const item = await after(generateFeedItem(page, siteUrl, htmlContent), page);
|
|
180
199
|
return {
|
|
181
200
|
...item,
|
|
182
201
|
channel: options.id
|
|
@@ -185,48 +204,61 @@ function getRssItems(feeds, page, siteUrl) {
|
|
|
185
204
|
}
|
|
186
205
|
function pluginRss(pluginRssOptions) {
|
|
187
206
|
const feedsSet = new FeedsSet();
|
|
188
|
-
let
|
|
207
|
+
let _pagesForRss = null;
|
|
189
208
|
return {
|
|
190
209
|
name: PluginName,
|
|
191
210
|
globalUIComponents: Object.values(PluginComponents),
|
|
192
211
|
beforeBuild (config, isProd) {
|
|
193
212
|
if (!isProd) {
|
|
194
|
-
|
|
213
|
+
_pagesForRss = null;
|
|
195
214
|
return;
|
|
196
215
|
}
|
|
197
|
-
|
|
216
|
+
const enableSSG = Boolean((config.ssg || config.llms) ?? true);
|
|
217
|
+
if (!enableSSG) throw new Error("[plugin-rss] RSS plugin requires SSG to be enabled. Please set `ssg: true` in your rspress.config.ts or remove the RSS plugin.");
|
|
218
|
+
_pagesForRss = new Map();
|
|
198
219
|
feedsSet.set(pluginRssOptions, config);
|
|
199
220
|
},
|
|
200
221
|
async extendPageData (pageData) {
|
|
201
|
-
if (!
|
|
202
|
-
|
|
203
|
-
|
|
222
|
+
if (!_pagesForRss) return;
|
|
223
|
+
const matchedChannels = feedsSet.get().filter((options)=>testPage(options.test, pageData)).map((options)=>options.id);
|
|
224
|
+
if (matchedChannels.length > 0) _pagesForRss.set(pageData.routePath, {
|
|
225
|
+
page: pageData,
|
|
226
|
+
channels: matchedChannels
|
|
227
|
+
});
|
|
204
228
|
const showRssList = new Set(concatArray(pageData.frontmatter['link-rss']));
|
|
205
|
-
for (const
|
|
229
|
+
for (const channel of matchedChannels)showRssList.add(channel);
|
|
206
230
|
pageData.feeds = Array.from(showRssList, (id)=>{
|
|
207
|
-
const
|
|
231
|
+
const feedChannel = feedsSet.get(id);
|
|
232
|
+
if (!feedChannel) return null;
|
|
233
|
+
const { output, language } = feedChannel;
|
|
208
234
|
return {
|
|
209
235
|
url: output.url,
|
|
210
236
|
mime: output.mime,
|
|
211
237
|
language: language || pageData.lang
|
|
212
238
|
};
|
|
213
|
-
});
|
|
239
|
+
}).filter(Boolean);
|
|
214
240
|
},
|
|
215
241
|
async afterBuild (config) {
|
|
216
|
-
if (!
|
|
217
|
-
const
|
|
242
|
+
if (!_pagesForRss) return;
|
|
243
|
+
const outDir = config.outDir || 'doc_build';
|
|
218
244
|
const feeds = Object.create(null);
|
|
219
|
-
for (const {
|
|
220
|
-
|
|
221
|
-
|
|
245
|
+
for (const [routePath, { page, channels }] of _pagesForRss){
|
|
246
|
+
const htmlPath = node_path.resolve(outDir, routePathToHtmlPath(routePath));
|
|
247
|
+
const htmlFile = await readFile(htmlPath);
|
|
248
|
+
const htmlContent = htmlFile ? extractHtmlContent(htmlFile) : null;
|
|
249
|
+
const items = await getRssItems(channels.map((id)=>feedsSet.get(id)), page, pluginRssOptions.siteUrl, htmlContent);
|
|
250
|
+
for (const { channel, ...item } of items){
|
|
251
|
+
feeds[channel] = feeds[channel] || new Feed(createFeed(feedsSet.get(channel), config));
|
|
252
|
+
feeds[channel].addItem(item);
|
|
253
|
+
}
|
|
222
254
|
}
|
|
223
255
|
for (const [channel, feed] of Object.entries(feeds)){
|
|
224
256
|
const { output } = feedsSet.get(channel);
|
|
225
257
|
feed.items.sort(output.sorting);
|
|
226
|
-
const path = node_path.resolve(
|
|
258
|
+
const path = node_path.resolve(outDir, output.dir, output.filename);
|
|
227
259
|
await writeFile(path, output.getContent(feed));
|
|
228
260
|
}
|
|
229
|
-
|
|
261
|
+
_pagesForRss = null;
|
|
230
262
|
}
|
|
231
263
|
};
|
|
232
264
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rspress/plugin-rss",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.6",
|
|
4
4
|
"description": "A plugin for rss generation for rspress",
|
|
5
5
|
"bugs": "https://github.com/web-infra-dev/rspress/issues",
|
|
6
6
|
"repository": {
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"feed": "^4.2.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@rslib/core": "0.19.
|
|
31
|
+
"@rslib/core": "0.19.2",
|
|
32
32
|
"@types/node": "^22.8.1",
|
|
33
|
-
"@types/react": "^19.2.
|
|
33
|
+
"@types/react": "^19.2.8",
|
|
34
34
|
"react": "^19.2.3",
|
|
35
35
|
"rsbuild-plugin-publint": "^0.3.3",
|
|
36
36
|
"typescript": "^5.8.2"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@rspress/core": "^2.0.0-rc.
|
|
39
|
+
"@rspress/core": "^2.0.0-rc.6"
|
|
40
40
|
},
|
|
41
41
|
"engines": {
|
|
42
42
|
"node": ">=20.9.0"
|