Skip to content
Advertisement

Read all .md files, convert them to html and send them

I use fs to read the file which is in .md format and I want to transform it into html file.

This is my code so far:

fs = require('fs');
fs.readFile(__dirname + '/posts/react-v16.13.0.md', 'utf8', function (err, data) {
  if (err) {
    return console.log(err);
  }
  console.log(data);
});

the file is situated in that folder and has that name.

This function puts in console the content of the .md file.

For converting it to html I added this:

const showdown = require('showdown');
converter = new showdown.Converter();
...
fs = require('fs');
fs.readFile(__dirname + '/posts/react-v16.13.0.md', 'utf8', function (
  err,
  data
) {
  if (err) {
    return console.log(err);
  }
  text = data;
  html = converter.makeHtml(text);
  console.log(html);
});

It puts the file as html in the log which is fine.

My problem is how to do this if there are multiple files in /posts/ folder, how to read and send those files?

I would like to send them to front-end using a POST method.

Is it possible to read all the files from the folder, transform them and send them?

Advertisement

Answer

It seems from the comment thread below the question that you want something that does the following:

  • Converts all markdown files from a given directory to HTML
  • Sends them all in a single request
  • Is usable in a single-page app

Here’s an approach that fulfils all of these requirements. The HTML of each post is inserted into a template element, the content of which can be cloned and manipulated within the SPA script.

server.js

// with `.promises`, we can use `async/await`
const fs = require("fs").promises;

// ...

const getHtmlByFilename = async filename => {
  const md = await fs.readFile(
    path.join(__dirname, "posts", filename),
    "utf-8"
  );

  return converter.makeHtml(md);
};

app.get("/", async (request, response) => {
  const filenames = await fs.readdir(path.join(__dirname, "posts"));

  // we can also use Promise.all
  // to map over the filenames in parallel
  const htmls = await Promise.all(
    filenames.map(async filename => {
      const html = await getHtmlByFilename(filename);

      return { filename, html };
    })
  );

  response.send(
    htmlBoilerplate(
      htmls
        .map(
          ({ filename, html }) =>
            `<template id="${filename}">${html}</template>`
        )
        .join("n"),
      "<h1>SPA</h1>",
      '<script src="/public/spa.js"></script>'
    )
  );
});

public/spa.js

[...document.querySelectorAll("template")].forEach(template => {
  const clone = template.content.cloneNode(true);

  const filename = template.id;

  const details = document.createElement("details");
  const summary = document.createElement("summary");

  summary.textContent = filename;

  details.appendChild(summary);
  details.appendChild(clone);

  document.querySelector(".markdown-body").appendChild(details);
});

glitch.me demo

Source | Live

Limitations

  • The conversion is done on-the-fly. If you have heavy traffic, you’ll want to implement some caching, or perhaps simply save the HTML versions separately, and trigger updates to them whenever the corresponding Markdown is edited.
  • The current code is probably not XSS safe — this assumes that either the content/filenames of posts are trusted, or that you carry out proper sanitation where required.
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement