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

Posted

技术标签:

【中文标题】读取所有 .md 文件,将它们转换为 html 并发送它们【英文标题】:Read all .md files, convert them to html and send them 【发布时间】:2021-01-07 22:40:16 【问题描述】:

我使用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 方法将它们发送到前端。

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

【问题讨论】:

可以使用fs.readdir()获取文件列表。 nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback @AKX 我尝试了类似fs.readdir(__dirname + '/posts', 'utf8', function (err, data) ... 但我得到他的错误:/.../Projects/md/server/node_modules/showdown/dist/showdown.js:2459 text = text.replace(/¨/g, '¨T'); 这可能会对您有所帮助。 ***.com/a/10049704/1524756 “所有文件......发送它们”是什么意思。将它们全部连接到一个 html blob 并将其作为响应/请求正文发送? 你弄丢了我,对不起,:脸红: 【参考方案1】:

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

将所有 Markdown 文件从给定目录转换为 HTML 在一个请求中全部发送 可在单页应用中使用

这是一种满足所有这些要求的方法。每篇文章的 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

限制

转换是即时完成的。如果您的流量很大,您可能需要实现一些缓存,或者可能只是单独保存 HTML 版本,并在相应的 Markdown 被编辑时触发更新。 当前代码可能不是 XSS 安全的 - 这假定帖子的内容/文件名是可信的,或者您在需要时进行了适当的清理。

【讨论】:

【参考方案2】:
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);
);

【讨论】:

【参考方案3】:

我建议使用 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/ ....

【讨论】:

为什么?这将成为瓶颈。 我以为他想通过一个帖子请求发送所有文件,这意味着他没有那么多文件......也许我误解了【参考方案4】:

试试这个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"));
)

【讨论】:

以上是关于读取所有 .md 文件,将它们转换为 html 并发送它们的主要内容,如果未能解决你的问题,请参考以下文章

go 读取文件夹所有文件并生成md5 字符串

读取目录中的所有文件,将它们存储在对象中,并发送对象

C程序:从文件中读取矩阵数据,并显示出来,利用链式存储结构。

读取 xls,将所有日期转换为正确格式,-> 写入 csv

读取二进制文件碎片并转换为具有内存效率的整数

使用承诺重构代码以读取文件并将它们转换为 json