如何快速实现 markdown 转 HTML 文档?
我想要在 Github 上开一个主题博客,我希望通过 Markdown 语法写作,然后生成 HTML 并附带自定义样式显示在网页上。
我找到了 gulp-markdown 这个库,看起来符合我的需求场景。然而这个库有一个问题,他只能将 Markdown 语法书写的文字转换为 HTML 标签,但并不能自动添加 doctype 文档声明,这就意味着生成的 HTML 文档并不合法。
# 标题
我是正文。
会被编译为
<h1>标题</h1>
<p>我是正文</p>
而不是
<!doctype html>
<html>
<head>
<title>XXX<title>
</head>
<body>
<h1>标题</h1>
<p>我是正文</p>
</body>
</html>
这就很尴尬了,我不知道这个库的作者为什么要这么设计这个库,我觉得它应该有一个配置参数可以自动添加 HTML 文档声明等信息,于是我去查找其文档(注意,它的文档只能翻墙才能看),然而呵呵并没有。
这就很尴尬了,怎么办呢?首先我想到的是,使用其他类似 HTML 模版的库来组合实现我想要的效果,然而搜了一圈发现,并没有合适的。因为这类库都需要首先在 HTML 文档中使用其模版语法标记 HTML 要插入的位置,然后在声明要插入的内容。可是我们并没有 HTML 模版,套路不同。
所以这个思路行不通,接下来我想到的方案是:
- 写一个 Gulp 插件解决这个问题;
- 这个问题肯定不是我第一次遇见,我先查查别人的解决方案;
懒惰是第一生产力,我当然先选择方案二,果不其然,全网看下来,貌似只有一个台湾小哥想到了一个解决方案,大体的思路是使用大陆前端娱乐圈知名人士方方老师写的一个 gulp-html-extend 库,实现一种类模版语言的 HTML 混入。为了实现这一点,你需要在每个 Markdown 文档里写下模版语言语法,类似这样:
<!-- @ @master = ../../layout/master.html-->
<!-- @ @block = content-->
# 我是标题
我是正文
<!-- @ @close-->
额,很显然这个解决方案并不优雅。为什么我要在每次开心书写 Markdown 的时候先写这堆奇怪的注释啊。我拒绝。
那么我们又回到了最初的起点,那个残酷的方案一又萦绕在我心头,要写一个 Gulp 插件吗?不!我的懒惰不允许我就在这里放弃!
当你不知所措的时候,不妨回到最初的起点,思考问题的本质是什么,这通常会激发我的灵感。这次我也这么做了,果不其然有所收获。
让我们一起想想,我实际要做的无非就是把由 gulp-markdown 生成的 HTML 标签插入到一个这样的「壳子」里:
<!doctype html>
<html>
<head>
<title>XXX<title>
</head>
<body>
<!-- 在这里插入 -->
</body>
</html>
所以我只需要在每个生成的 HTML 文件的头尾插入这些字符:
<!doctype html>
<html>
<head>
<title>XXX<title>
</head>
<body>
和这些字符:
</body>
</html>
就行了,所以问题转变为一个文件字符串拼接的问题,我很快就找到了 gulp-header 这个库,它能实现我们在每个文件头部插入字符的需求,而根据「对称就是美」定理,当然会有一个 gulp-footer 库来解决我们后半部分的需求,这样我们的问题就被完美解决了!
但是,老实讲这样的方案还是不够优雅,因为我们给文件前后插入太多字符了,我写代码习惯遵照 make it simple and stupid 的原则,因此对这个方案并不满意,我希望只插入最少的字符解决这个问题,因此接下来的问题就是:最少能插入多少字符保障 HTML 文档的规范性?
进过一番资料的查找,我发现,原来 <html>,<head> 和 <body> 标签都是可以省略的!只要一个 HTML 文档具备 <!doctype html> 文档声明和 <title> 标签,对于现代浏览器而言,就是一个合法合规的 HTML 文档!浏览器会自动生成 <html>,<head> 和 <body> 标签,并且把第一个不能放入 <head> 标签的标签和随后的标签都插入 <body> 标签中。没想到浏览器这么智能吧,我也没想到。
现在真相大白,解决这个问题的方案就很简单了,我们就只用在生成的 HTML 文档中添加最少的字符,这是我的 gulpfile.js 的配置:
const gulp = require('gulp')
const markdown = require('gulp-markdown')
const header = require('gulp-header')
gulp.task('default', () =>
gulp
.src('blog/**/*.md')
.pipe(header('<!doctype html><title>Blog</title>\n\r'))
.pipe(
markdown({
headerIds: false,
}),
)
.pipe(gulp.dest('html')),
)
搞定!
总结
通过这一番调研,我找到了解决 Markdown 生成规范的 HTML 文档的一种比较优雅的解决方案,并在调研过程中学到了关于 HTML 文档必备标签的相关知识,可谓是获益匪浅。希望阅读这篇文章的你也能够有所收获。
最后我再啰嗦两句,可能有人会问,为什么不搞个浏览器同步渲染,所见即所得,同步编辑岂不是更加炫酷,这个其实我有想过,最终决定不搞这个的理由是我觉得既然使用了 Markdown 语法,我的目的就是专心写作,我并不想因为要看到样式而分心,因此我在编辑器中只管我要写什么,当我写好 CSS 后,我就对内容如何呈现已经心中有数了,因此我认为「所见即所得」的功能没什么用。当然,如果你还是想要添加,相信对你而言也不是什么难事,毕竟方法之前的那位台湾小哥已经给出了。
如何快速实现 markdown 转 HTML 文档?的更多相关文章
- 无需编译、快速生成 Vue 风格的文档网站
无需编译.快速生成 Vue 风格的文档网站 https://docsify.js.org/#/#coverpage https://github.com/QingWei-Li/docsify/
- Markdown写接口文档,自动添加TOC
上回说到,用Impress.js代替PPT来做项目展示.这回换Markdown来做接口文档好了.(不敢说代替Word,只能说个人感觉更为方便)当然,还要辅之以Git,来方便版本管理. Markdown ...
- Sublime Text 3安装Package Control快速建立html5和xhtml文档
Sublime Text 3安装Package Control快速建立html5和xhtml文档 先关闭Sublime text 3:第1步:下载sublime_package_control-mas ...
- 使用 flow.ci 快速发布你的项目文档
软件研发的协作过程中,文档是必不可少的一环,有需求文档.接口文档.使用文档等等.当开始写文档时,首先会遇到两个问题: team members 之间如何协作? 文档 OK 后如何分发,去哪里看?如何更 ...
- 基于 Markdown 编写接口文档
最近公司开发项目需要前后端分离,这样话就设计到后端接口设计.复杂功能需要提供各种各样的接口供前端调用,因此编写API文档非常有必要了 网上查了很多资料,发现基于Markdown编写文档是一种比较流行而 ...
- 使用Spec Markdown 编写手册文档
Spec Markdown 是一个基于markdown 的文档编写工具,安装简单,可以让我们编写出专业的文档 参考项目 https://github.com/rongfengliang/spec-md ...
- 使用 VS Code + Markdown 编写 PDF 文档
背景介绍 作为一个技术人员,基本都需要编写技术相关文档,而且大部分技术人员都应该掌握 markdown 这个技能,使用 markdown 来编写并生成 PDF 文档将会是一个不错的体验,以下就介绍下如 ...
- Hi,给他介绍一款markdown的帮助文档生成器
当今大多数的团队都实现了前.后端分支.前端与后端的沟通都是通过接口来实现的(一般情况下都是webapi接口).这种情况你肯定需要一个接口查询的帮助文档,这个当然用swagger都可以实现.但做为前端开 ...
- Solr.NET快速入门(九)【二进制文档上传】【完】
二进制文档上传 SolrNet支持Solr"提取"功能(a.k.a. Solr"Cell")从二进制文档格式(如Word,PDF等)索引数据. 这里有一个简单的 ...
随机推荐
- HTML5在手机端实现视频全屏展示
最近做项目,遇到一个问题,在手机上要实现视频的全屏播放功能.测试了很久,终于找到解决办法. 第一种:将视频放大来控制. 视频在播放的时候,全屏是根据高度来的,如果设置视频 video 标签的宽度是 1 ...
- Python Pandas 时间序列双轴折线图
时间序列pv-gmv双轴折线图 import numpy as np import pandas as pd import matplotlib.pyplot as plt n = 12 date_s ...
- java基础编程
java的类和常用编程模式还是要多练习,多手写java代码 return new String(filecontent, encoding); 看懂这个意思了吗?第一次见这个构造函数吧,而String ...
- c++学习计划
我选择的课程是西北工业大学的<C++程序设计> 理由是:西北工业大学的计算机挺不错的,而且这门课程还有"国家精品"的认证,感觉应该挺不错的. 共48讲...有点多 从2 ...
- Codeforces Round #496 (Div. 3)
一如既往地四题...好久没切了 有点犯困了明显脑子感觉不够灵活. 为了熟练度还是用java写的,,,导致观赏性很差...我好不容易拉了个队友一起切结果过掉a就tm挂机了!!! A题竟然卡了,,,用了十 ...
- 腾讯地图打开地图选取位置 withMap
https://lbs.qq.com/tool/component-picker.html withMap import React, { Component } from "react&q ...
- java.net.UnknownHostException 异常处理
修改hosts文件: 1.把机器名和ip写在下面 2.hosts文件生效 soure /etc/hosts
- windos上安装jenkins部署springboot的jar包(未运行,只是在打包并上传linux成功了)
流程: 从linux上的svn拉取代码,到本地(windos)jenkins的工作区间的workspace,然后通过构建,打包,部署到linux上 环境: windos上安装:maven jdk je ...
- 架构3(基于LVS LB集群解决方案一:piranha)
1.实现调度器的HA 2.对realserver做健康检测 3.动态维护IPVS路由表 pulse 活跃和备用lvs路由器中都会运行pulse守护进程,在备用路由器中,pulse向活跃的服务器的公共接 ...
- 学习 yjango 博士的学习方法后的总结
博士的初期内容主要是机器学习, 基于机器学习的理论来总结人类自身的学习过程和方式, 现总结博士视频中提到的主要方式 -. 学习的原则 例子重塑大脑 明确输入输出 用二阶知识拆分知识 二. 什么是学习 ...