不到100行代码,使用Node写一个静态博客生成器

比特追光者
• 阅读 4029

不到100行代码,使用Node写一个静态博客生成器

现在有很多流行的静态博客生成工具,比如hexohugo等,其实手动实现一个静态博客生成工具也是一个简单的过程,本文就带大家使用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函数,并使用walkdirsrc目录进行遍历。

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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
11个最流行的静态(博客)网站生成工具
11个最流行的静态(博客)网站生成工具最近特别流行使用静态网站搭建博客,本博客就是host在GitHubPages的静态网站。静态网站非常适合专注于内容的网站,例如,博客。那你可能会问,为什么不用大名顶顶的wordpress(动态网站)呢。静态网站和动态网站相比有如下好处:省钱。静态网站占用的系统
Stella981 Stella981
3年前
Hexo 简明入门教程(一)
导言对于个人独立博客的搭建,或者一些产品网站的介绍我个人比较推崇直接用静态网站生成器来完成这个事情,对于,静态网页部署方便,浏览速度快。以下为部分静态网站生成器简要列表Ruby1.Jekyll(github默认pages引擎)2.Octopress(兼容jekyll)Python1.
Stella981 Stella981
3年前
Hexo建站过程总结
Hexo是一个基于Node.js快速、简洁且高效的博客框架,可以将Markdown文件快速的生成静态网页,托管在GitHubPages上。由于原来博客的主机费用问题,我没有办法再在那个主机上面再进行博客的更新,实在是太贵了,对于我来说。所以就在GitHub上面开始建站,使用Hexo来搭载我的博客。Hexo和WordPress有很大的不
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(