init: Vite+React+Tailwind v2 site with HTML content from WP, RSS feed, external feed aggregator, prerender
This commit is contained in:
73
scripts/build-rss.js
Normal file
73
scripts/build-rss.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
const DIST = path.join(ROOT, 'dist');
|
||||
|
||||
const SITE = 'https://pushkinohistory.ru';
|
||||
const TITLE = 'История города Пушкино';
|
||||
const DESC = 'Прошлое, настоящее, будущее города Пушкино.';
|
||||
|
||||
const posts = JSON.parse(fs.readFileSync(path.join(ROOT, 'src/content/posts.json'), 'utf8'));
|
||||
|
||||
const escapeXml = (s) =>
|
||||
String(s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
|
||||
const cdata = (s) => `<![CDATA[${String(s).replace(/]]>/g, ']]]]><![CDATA[>')}]]>`;
|
||||
|
||||
const rfc2822 = (s) => {
|
||||
const d = new Date(s.replace(' ', 'T') + '+03:00');
|
||||
return d.toUTCString();
|
||||
};
|
||||
|
||||
const absoluteImages = (html) =>
|
||||
html.replace(/(src|href)="\/uploads\//g, `$1="${SITE}/uploads/`);
|
||||
|
||||
const items = posts.map((p) => {
|
||||
const html = absoluteImages(p.html);
|
||||
const description = p.excerpt
|
||||
? p.excerpt
|
||||
: html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 500);
|
||||
const url = `${SITE}/${p.slug}/`;
|
||||
return ` <item>
|
||||
<title>${escapeXml(p.title)}</title>
|
||||
<link>${url}</link>
|
||||
<guid isPermaLink="true">${url}</guid>
|
||||
<pubDate>${rfc2822(p.date)}</pubDate>
|
||||
<dc:creator>${cdata('История города Пушкино')}</dc:creator>
|
||||
${(p.categories || []).map((c) => `<category>${escapeXml(c)}</category>`).join('\n ')}
|
||||
<description>${cdata(description)}</description>
|
||||
<content:encoded>${cdata(html)}</content:encoded>
|
||||
</item>`;
|
||||
}).join('\n');
|
||||
|
||||
const lastBuild = new Date().toUTCString();
|
||||
|
||||
const rss = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0"
|
||||
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>${escapeXml(TITLE)}</title>
|
||||
<link>${SITE}/</link>
|
||||
<atom:link href="${SITE}/feed/" rel="self" type="application/rss+xml" />
|
||||
<description>${escapeXml(DESC)}</description>
|
||||
<language>ru-RU</language>
|
||||
<lastBuildDate>${lastBuild}</lastBuildDate>
|
||||
<ttl>60</ttl>
|
||||
${items}
|
||||
</channel>
|
||||
</rss>
|
||||
`;
|
||||
|
||||
fs.mkdirSync(DIST, { recursive: true });
|
||||
fs.writeFileSync(path.join(DIST, 'feed.xml'), rss);
|
||||
console.log(`rss: ${posts.length} items → dist/feed.xml`);
|
||||
Reference in New Issue
Block a user