我们都知道,一些使用markdown语法的博客系统喜欢用YAML front matter
表达文章信息。
---
title: "Markdown Preview Enhanced 将掘金MD主题搬过来"
author: "Bambi"
date: 2023-06-11
theme: fancy
---
就像上面这样,其中
theme
字段定义了markdown文档的主题样式。掘金的编辑器就有这个功能,而且掘金的主题集众多优秀掘友的创意于一身,让我十分爱不释手。
把掘金MD主题搬到我的编辑器
不过相较于五花八门的博客系统,平时写笔记我用的更多的还是vscode编辑器
。而且除了写技术笔记之外,我还会用markdown语法去写一些需要对外展示的内容,比如简历
。这时掘金的主题更能显示出优势。毕竟如果只是写笔记,普通的黑色主题足矣。
于是,我就想能不能把掘金里面这些好看的主题
和方便的front matter
搬到我的编辑器里面随时取用。通过比对我选择了Markdown Preview Enhanced这款预览插件,因为他有比较丰富的自定义功能。不过想要享用掘金的主题效果,还要稍微动手自定义一番。
目标效果
这就是在vscode
中的最终效果,可以像在掘金编辑器里面一样,通过front matter
配置theme
实时享用鲜美的掘金主题。
Markdown Preview Enhanced
目前MPE
(简称)是可以支持通过Settings
切换多套MD主题的,可是这些主题我认为都没有掘金的主题香。于是咱们继续看他的自定义功能:
显然这个功能可以满足我们配置多套css的需求,只需要将喜欢的掘金主题
从GitHub上整理到自己的电脑即可。
但是找遍MPE
的文档,也没有看见更加配置化的介入方法了。也就是说我们没办法像掘金编辑器
一样,用front matter
的theme
字段优雅的配置这个样式。而必须要像写代码一样@import
来实现,这是违背markdown易读易写的宗旨的。
在自己的编辑器中,实现用front matter一键切换掘金主题
我需要像下面这样,输入主题名即可配置主题
---
title: "Markdown Preview Enhanced 将掘金MD主题搬过来"
author: "Bambi"
date: 2023-06-11
theme: fancy
---
目前,MPE
本身是不能识别theme字段的,但是他预留了定制化markdown效果的Extend Parser
!使用其中的onWillParseMarkdown
接口,就可以在parser.js
自定义markdown的写法了!
下面就是我基于onWillParseMarkdown
接口的实现,只需要识别出theme
配置,再插入插件看得懂的@import
语法即可。
parser.js
module.exports = {
onWillParseMarkdown: function(markdown) {
return new Promise((resolve, reject)=> {
// YAMLCfgList 整个YAML的配置的数组
const YAMLCfgList = markdown?.match(/---\n([\s\S]*?)\n---/)?.[1]?.split('\n');
// ThemeYAMLCfg theme字段在YAML中的配置字符串
const ThemeYAMLCfg = YAMLCfgList?.find(one => /^[^:]*theme\:[\s\S]*/.test(one));
// theme 主题名
const theme = ThemeYAMLCfg?.split(':')[1]?.trim();
// 如果配置了theme,就在YAML配置后面换行插入@import语句,URL是less文件所在的相对路径
if (theme) {
const relativePath = `../_style/${theme}.less`;
const md = markdown.replace(/(---\n([\s\S]*?)\n---)/, `$1\n@import \"${relativePath}\" \n`)
return resolve(md)
}
// 如果没有配置theme,正常输出原文
return resolve(markdown)
})
},
...
}
这里要注意几个小问题:
-
目前
MPE
的@import
语法是不支持绝对路径
的,只支持相对路径。所以主题最好是和.md文件同目录。我这里因为需要实现一个日常配置,不可能每次都把.less丢进去。我这里的解决办法是建一个指定的目录来存放md文档
,主题文件也固定放在这里:- 在用户目录下面新建一个doc目录,作为日常写文档的指定路径。
- 在doc目录下建一个_style文件,把
喜欢的掘金主题
丢进去即可。 - 在doc目录下建一个你需要的分类目录,存放相应的.md文件,所以代码中固定的路径是这样的:
../_style/${theme}.less
。如果以后想给文档更灵活分类,层级变多的话,需要需要再优化一下,我这里是初版就不拓展了。
用户目录/
└── doc/
├── _style/
│ └── fancy.less
│ └── ...
└── example/
└── demo.md
└── ...
2. @import
语句一定要插入到front matter
后面,front matter
不在头部会导致md预览不能识别。所以我这里:$1\n@import \"${relativePath}\" \n
,代表在$1选中的语句后面换行插入@import。
const md = markdown.replace(/(---\n(\[\s\S]\*?)\n---)/, `$1\n@import \"${relativePath}\" \n`)
解决报错
嗯,到此为止,这个输入掘金主题名可以在vscode使用掘金主题的插件效果就实现了。不过还有个别扭的地方,就是主题名输入的不正确
的时候,预览顶部会出现一行获取不到文件
的报错信息。
这个加入一个文件是否存在的判断即可解决。
const absolutePath = `/Users/你的用户目录/doc/_style/${theme}.less`;
const fs = require('fs');
// 判断这个主题在_style目录是否存在,如果存在就做转换处理
if (fs.existsSync(absolutePath)) {
const md = markdown.replace...
return resolve(md)
}
- 这里要注意的是,
MPE
的这个parser.js
文件,并不在我们的doc目录下,他在MPE
自己的目录里面,所以我们在这里使用fs
模块,一定要使用绝对路径哈。
局限
此方法暂不支持dark模式下的预览,MPE
的Settings
最好不要动,即使动了也不要选dark主题。目前两种主题是有互相影响的,并没有实现完全实现解耦。后续我有时间会再优化这个问题。
妙用
MPE
导出到PDF
格式是非常方便的,可以配好主题之后,直接在预览页上右键导出PDF。如果样式需要微调,去_style里面调整也很方便。
最终parser.js完整代码
module.exports = {
onWillParseMarkdown: function(markdown) {
return new Promise((resolve, reject)=> {
const YAMLCfgList = markdown?.match(/---\n([\s\S]*?)\n---/)?.[1]?.split('\n');
const ThemeYAMLCfg = YAMLCfgList?.find(one => /^[^:]*theme\:[\s\S]*/.test(one));
const theme = ThemeYAMLCfg?.split(':')[1]?.trim();
if (theme) {
const absolutePath = `/Users/你的用户目录/doc/_style/${theme}.less`;
const relativePath = `../_style/${theme}.less`;
const fs = require('fs');
if (fs.existsSync(absolutePath)) {
const md = markdown.replace(/(---\n([\s\S]*?)\n---)/, `$1\n@import \"${relativePath}\" \n`)
return resolve(md)
}
}
return resolve(markdown)
})
},
...
}