Newer
Older
express-blog / src / utils / htmlRoutes.js
// src/utils/HtmlRoutes.js
const express = require("express");
const BaseRoute = require("./BaseRoute");
const fs = require("fs/promises");
const path = require("path");
const yaml = require("js-yaml");
const { baseUrl } = require("./baseUrl.js");

class HtmlRoutes extends BaseRoute {
  constructor() {
    super();
    this.shouldCache = process.env.NODE_ENV === "production";
    this.cache = new Map();
  }

  /**
   * @param {string} routePath - The URL path (e.g., '/about')
   * @param {string} htmlFile - Filename in content/pages/ (e.g., 'resume' for resume.html)
   * @param {string} handlebarsFile - The template to wrap the HTML in
   */
  async register(routePath, contentFolder) {
    // Use the 'contentFolder' argument to find the directory
    const folderPath = path.join(
      __dirname,
      `../../content/html/${contentFolder}`,
    );
    const configPath = path.join(folderPath, `config.yaml`);
    // The router's endpoint
    const assetsRouterPath = path.join(routePath, "assets");
    this.router.use(assetsRouterPath, express.static(folderPath));

    const configRaw = await fs.readFile(configPath, "utf8");
    const pageConfig = yaml.load(configRaw);

    this.router.get(routePath, async (req, res, next) => {
      // Renders the web page on each request
      // Moving the logic outside of the function would read contents ahead of time
      // Keeping the logic intact would allow editing files without reloading the server
      try {
        // Return cached version if enabled and exists
        if (this.shouldCache && this.cache.has(routePath)) {
          return res.renderWithBaseContext(
            this.cache.get(routePath).template,
            this.cache.get(routePath).context,
          );
        }
        // Fetch the actual HTML file name from the YAML config
        const filePath = path.join(folderPath, pageConfig.file);
        const htmlContent = await fs.readFile(filePath, "utf8");

        // -- The uri
        const assetsUri = baseUrl + assetsRouterPath;

        const extraStyles = pageConfig.styles.map(
          (stylePath) => assetsUri + "/" + stylePath,
        );
        const extraScripts = pageConfig.scripts.map(
          (scriptsPath) => assetsUri + "/" + scriptsPath,
        );

        const context = {
          title: pageConfig.title || "Default Title",
          slug: routePath,
          content: htmlContent,
          extraStyles: extraStyles || [],
          extraScripts: extraScripts || [],
          meta: pageConfig.meta || {},
        };
        /*
          console.log("Assets Router Path", assetsRouterPath);
          console.log("Assets URI", assetsUri);
          console.log("extraScripts", extraScripts);
          console.log("extraStyles", extraStyles);
          */
        const template = `pages/${pageConfig.page}`;

        // 4. Update Cache
        if (this.shouldCache) {
          this.cache.set(routePath, { template, context });
        }
        res.renderWithBaseContext(template, context);
      } catch (err) {
        err.statusCode = 500;
        next(err);
      }
    });
  }
}

module.exports = HtmlRoutes;