在开发 NetUnion 的官网页面时,有这样一个需求:读取本地目录下的新闻和博客文件,并在前端渲染,其中文件均为 Markdown 格式。
与全栈开发直接调用后端数据库不同的是,没有数据表字段来记录文件的不同属性,例如文件的题目、作者、撰写日期等,因此这些属性需要记录在 .md 文件当中。
这样的撰写方式是不是很熟悉?没错,不就是我正在写的 Hexo 博客中 .md 文件的编写格式嘛!
自动导入本地的 .md 文件
当然,首先要读取某个目录下已经撰写好的 .md 文件,才能对内容进行预处理。
但如果每撰写好一个新的新闻或博客文件,就得在代码中 require
出来,太过于麻烦且不现实,因此就需要自动导入的方法。
Webpack 提供了 require.context()
方法可以完美解决导入目录下所有文件的问题,该方法可以导入指定目录(也可以包括子目录)下指定格式的所有文件。关于此方法的更多细节可以在 Webpack 官方文档中了解。
撰写代码自动读取 @/docs/blog/
及其子目录下的所有 .md 文件如下所示,其中 blogFiles(key)
为文件存储的具体内容:
1 | const blogFiles = require.context("@/docs/blog/", true, /\.md$/); |
对 .md 文件进行预处理
参考 Hexo 博客的撰写格式,可以规定 NetUnion 官网的新闻和博客撰写格式如下:
1 | --- |
即用两个 ---
框住属性内容,在第二个 ---
下面为正文内容。
那么首先,可以用 split()
方法根据 ---
及换行符将文章划分为长度不少于 3 (因为在正文中可能出现 ---
)的数组 arr。其中 arr[0] 为空,arr[1] 存储有属性内容,arr[2] 及之后存储正文内容。
1 | // content 为传入的 .md 文件内容 |
对属性内容的处理同样可以先使用 split()
方法按换行符拆分为数组。
1 | const contentInfo = contentArray[1]; |
值得一提的是,在上面两次按换行符分割时,我都使用了 /\r?\n/g
正则表达式。其含义是匹配 0 个或 1 个 \r
及 1 个 \n
,直到结束。因为在 CRLF
行尾序列的文件中,换行符由 \r\n
表示;而在 LF
行尾序列中,换行符由 \n
表示。这样就确保了在 Windows 和 Unix 两种不同的系统上撰写的文件,其解析不会受行尾序列所影响。
接下来就可以提取属性对象了。这里使用 trim()
方法来删除属性名和属性值前后可能出现的多余空格。
1 | const contentInfoItem = {}; |
对正文内容的处理就相当简单了,只需要把 arr[2] 及之后存储的内容用 ---\n
连接起来就可以了。
1 | let contentText = contentArray[2]; |
将属性对象与正文内容合并为一个新的对象,解析就完成了!
1 | const result = { |
如果愿意,还可以在最后对格式进行一定规范,例如可以对 date 属性进行处理:
1 | // 格式为 YYYY-MM-DD |
解析 .md 为 HTML
将结果中的正文内容交给给任意 .md 解析器就可以了,例如 markdown-it。
1 | const md = require("markdown-it")({ |
完整的解析文件在这里。