不到 100 行代码,使用 Node 写一个静态博客生成器
现在有很多流行的静态博客生成工具,比如 hexo
、hugo
等,其实手动实现一个静态博客生成工具也是一个简单的过程,本文就带大家使用 node 实现一个简单的静态博客生成工具。我们的目标是将 markdown 文件生成一个静态的站点。只需 5 步,不到 100 行代码量。
1. 建立项目
先新建一个项目目录
mkdir node-site-generator && cd node-site-generator
初始化项目
npm init -y
安装一些依赖包, 这些依赖包具体作用后面会解释到
npm i del markdown-it parse-md walkdir --save
然后在项目目录下新建一个main.js
,因为代码比较少,我们的所有代码就写到这里。
2. 收集 markdown 文件
在项目根目录下新建 src
目录,该目录用于存放我们所有的 markdown 源文件,我们首先将该目录下的所有 markdown 文件的路径收集起来,编写一个 walk
函数,并使用 walkdir
对src
目录进行遍历。
const walkdir = require('walkdir');
async function walk (srcPath){let result = await walkdir.async(srcPath,{return_object:true});
const mdPaths = [];
Object.entries(result).forEach(([path, fileStatus]) => {
// walkdir 会遍历所有目录和文件,我只将遍历结果中的 md 文件路径收集起来
if(!fileStatus.isDirectory() && path.match(/\.md$/ig)){mdPaths.push(path);
}
});
return mdPaths;
}
3. 将 markdown 文件渲染成 html
在根目录下新建 public
文件夹,再在 public
目录下新建 articles
目录,用于存放生成好的静态 HTML 文件。
按照上一步收集到文件路径读取 markdown 文件,并将其生成 HTML 静态文件。
这里我们用到了 parse-md
包和 markdown-it
两个包,作用如下:
-
parse-md
用于读取 makrdown 的元信息,如标题、创建时间等,元信息类似下面的格式--- title: SQL 学习笔记 date: 2018-06-11 ---
-
markdown-it
用于将 markdown 文件渲染成 HTML
继续在mian.js
编写如下内容
const fs = require('fs'); // node 原生的文件模块
const {default: parseMD} = require('parse-md');
const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();
// htmlTemplate 函数将生内容字符串填充到 HTML 模板中,方便复用
function htmlTemplate(content, title = '站点标题', isArticle = false){
return `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title> 站点标题 </title>
<link rel="stylesheet" href="${isArticle ?'../styles.css':'./styles.css'}">
</head>
<body>
<header>${title}</header>
<ul>
${content}
</ul>
<footer> Simple Blog 2019-2020 </footer>
</body>
</html>
`;}
// 将 markdown 文件渲染为 HTML 静态文件
function parseMDtoHTML(paths = []){
// paths 是一个数组,存放了我们上一步中收集到所有的 md 文件路径
let indexData = [];
for (let i = 0; i < paths.length; i++) {const str = fs.readFileSync(paths[i], 'utf8');
// 读取 markdown 文件的源信息和内容,得到标题、日期等,之后生成首页也要用到这些元信息
const {metadata, content} = parseMD(str);
const {title, date} = metadata;
// indexData 之后用于生成首页
const mdHtml = md.render(content);
const articleHtml = `<article>
<h2>${title}</h2>
<p>${date.toLocaleDateString()}</p>
${mdHtml}
</article>`;
const fileTitle = title.replace('/\s/g', '-');
const writePath = `./public/articles/${fileTitle}.html`;
fs.writeFileSync(writePath, htmlTemplate(articleHtml, '文章页', true));
indexData.push({...metadata, fileTitle});
}
return indexData;
}
4. 生成首页
只将 markdown 生成 HTML 还是不够的,我们还需要一个首页,这一步我们就给静态博客生成一个首页 index.html
,并将其生成在public
目录下,首页要包含导航到所有文章区域的链接:
function generateIndex(indexData = []){
// indexData 所用的是第三部中收集的文章元信息数组,用于生成文章的链接
const listHTML = indexData.map(i => {
return `
<li>
<a href="./articles/${i.fileTitle}.html">${i.title}</a>
<time>${i.date.toLocaleDateString()}</time>
</li>
`
}).join('');
// htmlTemplate 函数具体见第三步
const indexHTML = htmlTemplate(listHTML);
fs.writeFile('./public/index.html', indexHTML, function () {console.log(` 写入 index.html 成功 `);
});
}
5. 编写入口函数
接下来我们在 main.js
的最底部编写一个 start
函数,将上面的过程串联起来:
const del = require('del');
async function start() {
// 1. del 用于删除上一次生成的静态文件
del(['./public/articles/**.html', './public/index.html']);
// 2. 收集 src 目录下的所有 markdown 文件的路径
const paths = await walk('./src');
// 3. 读取所有 markdown 文件并生成 html
const indexData = await parseMDtoHTML(paths);
// 4. 生成首页 index.html
await generateIndex(indexData);
}
// 执行 start 函数
start();
最后在项目目录下执行 node main.js
启动,就可以看到 public
目录下生成的结果。额外地,为了避免生成的 html 静态文件太过朴素,建议在生成静态 HTML 的过程中加一点样式。
到此就实现了一个非常简单的静态博客生成器,其中很多过程都简化处理了,主要是为了阐述生成静态博客的思路,如果要完成一个功能丰富的静态博客生成工具,还有很多可以完善的地方。
源代码地址:https://github.com/JohnSnow93/node-site-generator