augustkline.com/vite.config.ts

187 lines
5.0 KiB
TypeScript
Raw Normal View History

2024-09-30 19:16:48 -04:00
import { defineConfig } from "vite";
import fs from "fs";
import path from "path";
import { marked, Token, Tokens } from "marked";
import xml from "xml";
import matter from "gray-matter";
import highlight from "highlight.js";
const blogDir = path.resolve(__dirname, "src/blog");
const outputDir = path.resolve(__dirname, "dist/blog");
const rssFeedPath = path.resolve(__dirname, "dist/feed.xml");
const hostname = "https://augustkline.com";
const blogUrl = `${hostname}/blog`;
interface Articles {
title: string;
link: string;
description: string;
pubDate: string;
}
const renderer = new marked.Renderer();
renderer.code = ({ text, lang }: Tokens.Code) => {
const validLang = highlight.getLanguage(lang!) ? lang! : "plaintext";
const highlightedCode = highlight.highlight(text!, { language: validLang });
return `<pre><code class="language-${validLang}">${highlightedCode.value}</code></pre>`;
};
marked.setOptions({
renderer,
gfm: true,
breaks: true,
});
function generateBlogHtml() {
fs.mkdirSync(outputDir, { recursive: true });
const articles: Articles[] = [];
let blurbs: { date: string; content: string }[] = [];
fs.readdirSync(blogDir).forEach((file) => {
if (file.endsWith(".md")) {
const filePath = path.join(blogDir, file);
const str = fs.readFileSync(filePath, "utf-8");
let { data, content } = matter(str);
const slug = `${data.date!}-${data.title!.replace(/ /g, "-")}`;
const html_content = marked.parse(content);
const blogPostsPath = path.join(outputDir, `${slug}.html`);
const postHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${data.title!}</title>
<link rel="stylesheet" type="text/css" href="/style.css">
<link rel="stylesheet" type="text/css" href="/github.css">
</head>
<body>
<main>
${html_content}
<a href="/">Back to Home</a>
</main>
<div id="background">
</div>
</body>
<script type="module" src="/main.js"></script>
</html>
`;
const link = `/blog/${slug}.html`;
const blurbHtml = `
<div>
<a href="${link}">
<h2>${data.title!}</h2>
<p>${new Date(data.date!).toDateString()}</p>
<p>${data.desc!}</p>
</a>
</div>
`;
blurbs.push({ date: data.date!, content: blurbHtml });
fs.writeFileSync(blogPostsPath, postHtml);
// Store article data for RSS
articles.push({
title: data.title!,
link: link,
description: data.desc!,
pubDate: data.date!,
});
}
});
const blogIndexPath = path.join(outputDir, "index.html");
blurbs.sort((a, b) => {
return new Date(b.date).getTime() - new Date(a.date).getTime();
});
let blurbsHtml: string = "";
for (let blurb in blurbs) {
blurbsHtml = blurbsHtml.concat(blurbs[blurb].content);
}
const blogIndexHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>august kline's blog</title>
<link rel="stylesheet" type="text/css" href="/style.css">
<link rel="stylesheet" type="text/css" href="/github.css">
</head>
<body>
<main>
<h1>ʕ··ʔ- august kline's blog </h1>
${blurbsHtml}
</main>
<div id="background">
</div>
</body>
<script type="module" src="/main.js"></script>
</html>
`;
fs.writeFileSync(blogIndexPath, blogIndexHtml);
return articles;
}
// Function to generate RSS feed
function generateRssFeed(articles: Articles[]) {
const feedItems = articles.map((article) => ({
item: [
{ title: article.title },
{ link: article.link },
{ description: article.description },
{ pubDate: article.pubDate },
],
}));
const rss = {
rss: [
{
channel: [
{ title: "ʕ·ᴥ·ʔ-☆ august kline's blog ☆" },
{ link: `${blogUrl}` }, // Update with your domain
{
description:
"whatever's on my mind, short essays, tech stuff, etc :)",
},
...feedItems,
],
},
],
};
const rssXml = xml(rss, { declaration: true });
fs.writeFileSync(rssFeedPath, rssXml);
}
// Export Vite config
export default defineConfig({
build: {
rollupOptions: {
output: {
entryFileNames: `main.js`,
},
plugins: [
{
name: "generate-blog-html-and-rss",
writeBundle() {
// parses blog markdown, writes the blog endpoints and returns array of article data
const articles = generateBlogHtml();
generateRssFeed(articles);
},
},
],
},
},
});