Newer
Older
express-blog / src / services / sitemapService.js
@Jason Jason on 26 Jun 2 KB modified: .gitignore
// src/services/sitemapService.js
const path = require("path");
const fs = require("fs").promises;
const getPostsMenu = require("./postsMenuService");

class SitemapService {
  constructor() {
    this.staticSitemapPath = path.resolve(
      __dirname,
      "../../content/sitemap.json"
    );
    this.postsPath = path.join(__dirname, "../../content/posts");
  }

  async getStaticPages() {
    try {
      const data = await fs.readFile(this.staticSitemapPath, "utf-8");
      return JSON.parse(data);
    } catch (error) {
      console.warn("Could not load static sitemap.json, using empty array");
      return [];
    }
  }

  async getBlogPostUrls() {
    const menu = await getPostsMenu(this.postsPath);
    const urls = [];

    for (const yearData of menu) {
      for (const monthData of yearData.months) {
        for (const post of monthData.posts) {
          urls.push({
            loc: `/blog/${post.year}/${post.month}/${post.slug}`,
            lastmod: post.date
              ? new Date(post.date).toISOString().split("T")[0]
              : null,
            changefreq: "monthly",
            priority: "0.7",
          });
        }
      }
    }

    return urls;
  }

  async getCompleteSitemap() {
    const [staticPages, blogUrls] = await Promise.all([
      this.getStaticPages(),
      this.getBlogPostUrls(),
    ]);

    // Add blog posts as a section in the sitemap
    const blogSection = {
      title: "Blog Posts",
      children: blogUrls.map((url) => ({
        loc: url.loc,
        title: url.loc.split("/").pop().replace(/-/g, " "), // Convert slug to title
        lastmod: url.lastmod,
        changefreq: url.changefreq,
        priority: url.priority,
      })),
    };

    return [...staticPages, blogSection];
  }

  async getAllUrls() {
    const sitemap = await this.getCompleteSitemap();
    return this.flatten(sitemap);
  }

  flatten(entries, out = []) {
    for (const entry of entries) {
      if (entry.loc) {
        out.push({
          loc: entry.loc,
          lastmod: entry.lastmod,
          changefreq: entry.changefreq || "monthly",
          priority: entry.priority || "0.5",
        });
      }
      if (Array.isArray(entry.children)) {
        this.flatten(entry.children, out);
      }
    }
    return out;
  }
}

module.exports = new SitemapService();