读取所有 .md 文件,将它们转换为 html 并发送

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

我使用fs读取.md格式的文件,我想将其转换为html文件。

到目前为止,这是我的代码:

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);
});

该文件位于该文件夹中并具有该名称。

此函数将 .md 文件的内容放入控制台。

为了将其转换为 html,我添加了这个:

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);
});

它将文件作为 html 放入日志中,这很好。

我的问题是,如果 /posts/ 文件夹中有多个文件,如何读取和发送这些文件?

我想使用 POST 方法将它们发送到前端。

是否可以从文件夹中读取所有文件,转换它们并发送它们?

我推荐使用 readdir 和 readFile 的同步变体

const basePath = __dirname + '/posts/';
const htmls = [];

fs.readdirSync(basePath).forEach(file => {
  const text = fs.readFileSync(basePath + file, 'utf8');
  htmls.push({
    file,
    html: converter.makeHtml(text)
  });
});

// upload htmls with axios/fetch/ ....
const {readdir, readFile} = require('fs');
const showdown  = require('showdown');
const axios = require('axios');

let fileHtmlList = [];

const converter = new showdown.Converter();

readdir(`${__dirname}/posts`, 'utf8', (fsDirError, fileNameList) => {
    if(!fsDirError) {
        fileNameList.forEach((fileName) => {
            readFile(`${__dirname}/posts/${fileName}`, 'utf8', (fsReadError, fileContent) => {
                if(!fsReadError) {
                    fileHtmlList.push({
                        fileName: `${__dirname}/posts/${fileName}`,
                        htmlContent: converter.makeHtml(fileContent)
                    }); 
                } else {
                    return console.error(fsReadError);
                }  
            });    
        });
    } else {
        return console.error(fsDirError);
    }
});

/* I'm guessing this part from your description, if the content needs to be rendered then the code needs change */

let sendFrontEnd = async (data) => {
    try {
        const response = await axios.post(`urlToSend`, data);
        console.log(response);
    } catch (error) {
        console.error(error);
    }
};

fileHtmlList.forEach((item) => {
    sendFrontEnd(item.htmlContent);
});

从问题下方的评论线程看来,您想要执行以下操作的内容:

  • 将给定目录中的所有降价文件转换为 HTML
  • 将它们全部发送到一个请求中
  • 可用于 single-page 应用程序

这是一种满足所有这些要求的方法。每个 post 的 HTML 被插入到一个 template 元素中,其内容可以在 SPA 脚本中被克隆和操作。

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 演示

Source | Live

限制

  • 转换完成 on-the-fly。如果你的流量很大,你会想要实现一些缓存,或者可能只是单独保存 HTML 版本,并在编辑相应的 Markdown 时触发对它们的更新。
  • 当前代码可能不是 XSS 安全的 — 这假设 post 中的 content/filenames 是可信的,或者您在需要时进行了适当的清理。

试试这个 js 库

<!-- Lightweight client-side loader that feature-detects and load polyfills only when necessary -->
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>
<!-- Load the element definition -->
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>

    <div class="markdown-body">
        <zero-md src="README.md"> </zero-md>
    </div>

我强烈建议在 html 文件中使用零降价,因为

  • 从您的 readme.md 文件自动更新。
  • 如果您使用将自述文件转换为 html,您必须在每次更新自述文件(或更多代码)时手动转换。

完整 html 在我的来源

<!DOCTYPE html>
<html>
  <head>
    <title>API Get link Zing Mp3</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <style>
      .markdown-body {
        box-sizing: border-box;
        min-width: 200px;
        max-width: 980px;
        margin: 0 auto;
        padding: 45px;
      }
    
      @media (max-width: 767px) {
        .markdown-body {
          padding: 15px;
        }
      }
    </style>
    <!-- Lightweight client-side loader that feature-detects and load polyfills only when necessary -->
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs@2/webcomponents-loader.min.js"></script>

<!-- Load the element definition -->
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@1/src/zero-md.min.js"></script>

<!-- Simply set the `src` attribute to your MD file and win -->

  </head>
  <body>
    <div class="markdown-body">
      <zero-md src="README.md">
      </zero-md>
    </div>
    </body>
</html>

如果您使用的是 nodejs,则可以将路由器添加到 readme.md 文件

app.get('/README.md', function (req, res) {
    res.sendFile(path.join(__dirname, "README.md"));
})