diff --git a/.gitignore b/.gitignore index 1437c53..03b2792 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ yarn-error.log* # vercel .vercel + +rss.xml \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 178b563..e82e99d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "dependencies": { "@tabler/icons": "^1.100.0", "@vercel/analytics": "^1.1.0", + "feed": "^4.2.2", "gray-matter": "^4.0.3", "marked": "^4.3.0", "postcss": "^8.4.16", @@ -2599,6 +2600,17 @@ "reusify": "^1.0.4" } }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4561,6 +4573,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -5418,6 +5435,17 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -7321,6 +7349,14 @@ "reusify": "^1.0.4" } }, + "feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "requires": { + "xml-js": "^1.6.11" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -8706,6 +8742,11 @@ "is-regex": "^1.1.4" } }, + "sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -9337,6 +9378,14 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 3a57a27..fddc39d 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,14 @@ "scripts": { "dev": "next dev", "build": "next build", + "prebuild": "node scripts/generate-rss.js", "start": "next start", "lint": "next lint" }, "dependencies": { "@tabler/icons": "^1.100.0", "@vercel/analytics": "^1.1.0", + "feed": "^4.2.2", "gray-matter": "^4.0.3", "marked": "^4.3.0", "postcss": "^8.4.16", diff --git a/scripts/generate-rss.js b/scripts/generate-rss.js new file mode 100644 index 0000000..b18aa34 --- /dev/null +++ b/scripts/generate-rss.js @@ -0,0 +1,60 @@ +const fs = require("fs"); +const path = require("path"); +const { Feed } = require("feed"); +const matter = require("gray-matter"); +const { loadEnvConfig } = require("@next/env"); + +loadEnvConfig(process.cwd()); + +const getPostsSortByDate = () => { + const files = fs.readdirSync(path.join("posts")); + let posts = files.map((filename) => { + const markdownWithMeta = fs.readFileSync( + path.join("posts", filename), + "utf-8" + ); + + const { data } = matter(markdownWithMeta); + data.slug = filename.replace(".md", ""); + return data; + }); + + return sortPostsInDesc(posts); +}; + +const sortPostsInDesc = (posts) => { + return posts?.sort( + (first, next) => new Date(next.date) - new Date(first.date) + ); +}; + +const generateRSSFeed = () => { + const siteUrl = process.env.NEXT_PUBLIC_VERCEL_URL; + const posts = getPostsSortByDate(); + const feed = new Feed({ + title: "Bruno Blog | RSS Feed", + description: "RSS Feed for Bruno Blog", + id: siteUrl, + link: siteUrl, + image: `${siteUrl}/favicon-32x32.png`, + favicon: `${siteUrl}/favicon.ico`, + copyright: "Anoop M D and Contributors", + feedLinks: { + rss2: `${siteUrl}/feed.xml`, + }, + }); + + posts.forEach((post) => { + feed.addItem({ + title: post.title, + id: `${siteUrl}/blog/${post.slug}`, + link: `${siteUrl}/blog/${post.slug}`, + description: post.description, + date: new Date(post.date), + }); + fs.writeFileSync("./public/rss.xml", feed.rss2()); + }); + console.log("RSS Feed generated!"); +}; + +generateRSSFeed();