@@ -18,6 +18,90 @@ const resolveOutDir = (app) => {
1818 return app . options ?. dest || app . dir ?. dest || process . cwd ( )
1919}
2020
21+ const generateRSS = ( app , options ) => {
22+ const { filter, hostname, count, selector, language, username } = options
23+ const { pages } = app
24+ const outDir = resolveOutDir ( app )
25+ const siteData = resolveSiteData ( app )
26+
27+ const feed = new RSS ( {
28+ title : siteData . title ,
29+ description : siteData . description ,
30+ feed_url : `${ hostname } /rss.xml` ,
31+ site_url : hostname ,
32+ copyright : `${ username } ${ new Date ( ) . getFullYear ( ) } ` ,
33+ language
34+ } )
35+
36+ pages
37+ . filter ( filter )
38+ . map ( ( page ) => ( {
39+ ...page ,
40+ date : new Date ( page . frontmatter . date || '' )
41+ } ) )
42+ . sort ( ( a , b ) => b . date - a . date )
43+ . slice ( 0 , count )
44+ . map ( ( page ) => ( {
45+ title : page . frontmatter . title ,
46+ description : page . frontmatter . description ,
47+ url : `${ hostname } ${ page . path } ` ,
48+ date : new Date ( page . frontmatter . date ) ,
49+ custom_elements : [
50+ {
51+ 'content:encoded' : {
52+ _cdata : ( ( ) => {
53+ let htmlContent ;
54+ if ( app . env ?. isBuild ) {
55+ const outFilePath = path . join (
56+ outDir ,
57+ page . path . replace ( / \/ $ / , '/index.html' ) . replace ( / [ ^ \. h t m l ] $ / , '.html' )
58+ )
59+ if ( fs . existsSync ( decodeURIComponent ( outFilePath ) ) ) {
60+ htmlContent = fs . readFileSync ( decodeURIComponent ( outFilePath ) , 'utf8' )
61+ const $ = load ( htmlContent , { decodeEntities : false } )
62+ $ ( '.header-anchor' ) . remove ( )
63+ $ ( 'h1' ) . eq ( 0 ) . remove ( )
64+ $ ( '.sr-only' ) . remove ( )
65+ $ ( 'a svg' ) . remove ( )
66+ $ ( selector )
67+ . find ( 'img' )
68+ . each ( function ( ) {
69+ const src = $ ( this ) . attr ( 'src' )
70+ if ( ! / ^ ( h t t p s ? : ) ? \/ \/ / . test ( src ) ) {
71+ $ ( this ) . attr ( 'src' , hostname + src )
72+ }
73+ } )
74+ return $ ( selector ) . html ( ) || ''
75+ }
76+ }
77+
78+ htmlContent = page . contentRendered || page . content || ''
79+ if ( ! htmlContent ) return ''
80+
81+ const $ = load ( `<div id="rss-wrapper">${ htmlContent } </div>` , { decodeEntities : false } )
82+ $ ( '.header-anchor' ) . remove ( )
83+ $ ( 'h1' ) . eq ( 0 ) . remove ( )
84+ $ ( '.sr-only' ) . remove ( )
85+ $ ( 'a svg' ) . remove ( )
86+ $ ( '#rss-wrapper' )
87+ . find ( 'img' )
88+ . each ( function ( ) {
89+ const src = $ ( this ) . attr ( 'src' )
90+ if ( ! / ^ ( h t t p s ? : ) ? \/ \/ / . test ( src ) ) {
91+ $ ( this ) . attr ( 'src' , hostname + src )
92+ }
93+ } )
94+ return $ ( '#rss-wrapper' ) . html ( ) || ''
95+ } ) ( )
96+ }
97+ }
98+ ]
99+ } ) )
100+ . forEach ( ( page ) => feed . item ( page ) )
101+
102+ return feed . xml ( { indent : true } )
103+ }
104+
21105const rssFeedPlugin = (
22106 {
23107 filter = ( ) => true ,
@@ -27,77 +111,46 @@ const rssFeedPlugin = (
27111 language = 'zh-CN' ,
28112 username = ''
29113 } = { }
30- ) => ( {
31- name : 'rss-feed' ,
32- async onGenerated ( app ) {
33- if ( ! app . env ?. isProd ) {
34- return
35- }
114+ ) => {
115+ const options = { filter, hostname, count, selector, language, username } ;
36116
37- logger . wait ( 'Generate rss.xml...' )
38-
39- const { pages } = app
40- const outDir = resolveOutDir ( app )
41- const siteData = resolveSiteData ( app )
42-
43- const feed = new RSS ( {
44- title : siteData . title ,
45- description : siteData . description ,
46- feed_url : `${ hostname } /rss.xml` ,
47- site_url : hostname ,
48- copyright : `${ username } ${ new Date ( ) . getFullYear ( ) } ` ,
49- language
50- } )
51-
52- pages
53- . filter ( filter )
54- . map ( ( page ) => ( {
55- ...page ,
56- date : new Date ( page . frontmatter . date || '' )
57- } ) )
58- . sort ( ( a , b ) => b . date - a . date )
59- . slice ( 0 , count )
60- . map ( ( page ) => ( {
61- title : page . frontmatter . title ,
62- description : page . frontmatter . description ,
63- url : `${ hostname } ${ page . path } ` ,
64- date : new Date ( page . frontmatter . date ) ,
65- custom_elements : [
66- {
67- 'content:encoded' : {
68- _cdata : ( ( ) => {
69- const outFilePath = path . join (
70- outDir ,
71- page . path . replace ( / \/ $ / , '/index.html' ) . replace ( / [ ^ \. h t m l ] $ / , '.html' )
72- )
73- const htmlContent = fs . readFileSync ( decodeURIComponent ( outFilePath ) , 'utf8' )
74- const $ = load ( htmlContent , { decodeEntities : false } )
75- $ ( '.header-anchor' ) . remove ( )
76- $ ( 'h1' ) . eq ( 0 ) . remove ( )
77- $ ( '.sr-only' ) . remove ( )
78- $ ( 'a svg' ) . remove ( )
79- $ ( selector )
80- . find ( 'img' )
81- . each ( function ( ) {
82- const src = $ ( this ) . attr ( 'src' )
83- if ( ! / ^ ( h t t p s ? : ) ? \/ \/ / . test ( src ) ) {
84- $ ( this ) . attr ( 'src' , hostname + src )
85- }
86- } )
87- return $ ( selector ) . html ( )
88- } ) ( )
89- }
117+ return {
118+ name : 'rss-feed' ,
119+ extendsBundlerOptions : ( bundlerOptions , app ) => {
120+ if ( app . options . bundler . name === '@vuepress/bundler-vite' ) {
121+ bundlerOptions . viteOptions = bundlerOptions . viteOptions || { }
122+ bundlerOptions . viteOptions . plugins = bundlerOptions . viteOptions . plugins || [ ]
123+ bundlerOptions . viteOptions . plugins . push ( {
124+ name : 'vite-plugin-rss-feed' ,
125+ configureServer ( server ) {
126+ server . middlewares . use ( ( req , res , next ) => {
127+ if ( req . url === '/rss.xml' ) {
128+ res . setHeader ( 'Content-Type' , 'application/rss+xml; charset=utf-8' )
129+ res . end ( generateRSS ( app , options ) )
130+ return
131+ }
132+ next ( )
133+ } )
90134 }
91- ]
92- } ) )
93- . forEach ( ( page ) => feed . item ( page ) )
94-
95- fs . writeFile ( path . join ( outDir , 'rss.xml' ) , feed . xml ( { indent : true } ) , ( error ) => {
96- if ( error ) {
97- console . error ( error )
135+ } )
136+ }
137+ } ,
138+ async onGenerated ( app ) {
139+ if ( ! app . env ?. isBuild ) {
140+ return
98141 }
99- } )
142+
143+ logger . info ( 'Generate rss.xml...' )
144+ const xml = generateRSS ( app , options )
145+ const outDir = resolveOutDir ( app )
146+
147+ fs . writeFile ( path . join ( outDir , 'rss.xml' ) , xml , ( error ) => {
148+ if ( error ) {
149+ console . error ( error )
150+ }
151+ } )
152+ }
100153 }
101- } )
154+ }
102155
103156export default rssFeedPlugin
0 commit comments