如何快速实现 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等)索引数据. 这里有一个简单的 ...
随机推荐
- Spark FPGrowth (Frequent Pattern Mining)
给定交易数据集,FP增长的第一步是计算项目频率并识别频繁项目.与为同样目的设计的类似Apriori的算法不同,FP增长的第二步使用后缀树(FP-tree)结构来编码事务,而不会显式生成候选集,生成的代 ...
- mysql批量更新的两种方式效率试验<二>
Mysql两种批量更新的对比 简介: mysql搭载mybits框架批量更新有两种方式,一种是在xml中循环整个update语句,中间以‘:’隔开,还有一种是使用case when 变相实现批量更新, ...
- java中的静态代理和动态代理
1.动态代理的定义:为其他对象提供一个代理以控制对这个对象的访问 代理类主要负责委托类的预处理消息,过滤消息,把消息传给委托类以及消息事后处理 按照代理类的创建时期,代理类可以分为2种:静态代理类(在 ...
- day15 十五、模块、from导入、起别名
一.模块的概念 1.什么是模块:一系列功能的集合体 2.定义模块:创建一个py文件就是一个模块,该py文件名就是模块名 模块的四种存在方式 使用python编写的.py文件 包:一堆py文件的集合体 ...
- spark streaming集成flume
1. 安装flume flume安装,解压后修改flume_env.sh配置文件,指定java_home即可. cp hdfs jar包到flume lib目录下(否则无法抽取数据到hdfs上): $ ...
- 将lits集合转化为树状结构
一,bean的类型: public class DeptListRES { /** * 子节点 */ private List<DeptListRES> children; private ...
- scrollview嵌套tableview
之前写过一次,忘记了, 用的通知 FS
- Cesium 实践
详细内容请参考教程:https://www.jianshu.com/p/31c3b55a21eb 该教程翻译自官方英文教程,对入门cesium 帮助很大. 2,Cesium项目实例 实践: 问题 ...
- python-颜色显示
格式:\033[显示方式;字体色;背景色m......[\033[0m] ------------------------------------------- 字体色 | 背景色 | 颜色描述 -- ...
- Spring Boot 自动配置原理(精髓)
一.自动配置原理(掌握) SpringBoot启动项目会加载主配置类@SpringBootApplication,开启@EnableAutoConfiguration自动配置功能 @EnableAut ...