创作背景
身为一个技术人员平时要写大量的技术文档,以前用的是vuepress,最近一段时间切换到了 vitepress
我们的项目文档里一般要包含:
- 需求文档(产品人员写)
- 设计文档(设计师写)
- 技术文档(技术人员写,前端和后端的都要写)
- 部署于维护(运维写)
因为文档要频繁 的不断的完善和更新,尤其是针对用户提出的问题想立马记录下来和将解决方法给出来(比如群里的用户不断的提出问题,然后需要立马记录下这个问题,并给出解决方法),这时遇到了一些问题:
- 每次更新文档要打开项目进行代码同步,每天要频繁的打开多个项目的文档仓库,来回切换和同步比较烦
- 非技术人员无法参与进来,他们根本不知道是么是
vitepress
是么是VSCode
是么是node
等,每个类别的同学都各自写各自的,无法做到一个项目的文档集中到一起 - 每次写完文档要提交代码,编译和部署,即使用ci平台也需要依赖技术人员进行代码推送
- 后端同学不想碰前端这些东西
所以一个想法在脑海浮现:
能否写个在线版本的vitepress
,省去各种node
,VSCode
,编译
等前端这些脚手架的步骤,让技术和非技术,前端和非前端人员等一起来一同完成一个项目的文档,所有人员在线共同写一个项目的文档,技术的非技术的人员只需聚焦文档内容本身即可,而不用去关心背后的技术,大家唯一需要的技能就是写markdown
作为一个执行力比较强的猿,花了一周的时间就把这个想法给实现了,撸了个网站 mdpress-Vitepress Online
Markdown编辑器选型
撸这个在线版本的vitepress
最难的就是找个在线的markdown
编辑器了
markdown的编辑器客户端的找到了好多,但是在线的编辑器好像并不多,自己平时都是在VSCode
里直接撸markdown的,由于自己一直聚焦于图形技术,因此对前端这块不是很熟😭,查找了各种资料最后选择了
Editor.md - 开源在线 Markdown 编辑器 (pandao.github.io)
随着自己不断深入使用和体验以及想扩展功能,发现editor.md已经不能满足我的需求:
- 整个架构还是基于
jquery
那一套的,没有模块化,没有打包 - 不好扩展
- 比如想加个代码格式化功能
- 比如想加个
vitepress
里的container
组件
- 想fork一份自己改的,但是当我看到源码一个文件几千行的代码的我陷入凌乱中了,源码
于是决定自己造轮子了😆
mdpress-editor
大概用了一个月时间就诞生了该篇文章的主角 mdpress-editor


mdpress-editor 是个简单的在线markdown
编辑器
A simple markdown editor base monaco-editor and markdown-it
核心技术选型
markdown编辑器的两大核心选型:
- 编辑器, 选型了 monaco-editor, 因为我对monaco-editor比较熟悉
- markdown解析工具,选型了 markdown-it, 这个我是通过翻
vitepress
的源码发现的
仓库
主要功能
- 代码高亮 ,支持highlight.js or shiki
- 支持代码组 Markdown Extensions | VitePress
- 自定义容器的支持 Markdown Extensions | VitePress
- KateX 支持
- Mermaid 支持
- plantuml 支持
- flowchart 支持
- Swiper 支持
- Qrcode 支持
- github emoji 支持
- toc support
- 嵌入远程的一个markdown文件
- 支持掘金的markdown主题( Multi theme support, theme from juejin-markdown-themes)
- 支持导出 markdown, html, 图片 (export md, html, png files)
- 支持导出markmap (export Markmap support)
- xlsx文件浏览 (XLSX File view by x-spreadsheet and sheetjs)
- 自定义工具栏 (support custom toolbar)
- 代码格式化 (Prettier format support)
特色功能
- Swiper 支持
- Qrcode 支持
- github emoji 支持


- 嵌入远程的一个markdown文件
- 支持掘金的markdown主题
- 导出 Markmap
- xlsx文件浏览
- Prettier 代码格式化
- 暗黑模式🕶️
总体设计
因为对markdown语法进行了扩展,涉及到许多的扩展插件,如果将这些插件全部打包进来会导致包的体积非常大, 故采用动态注入插件的机制
在全局设计上提供了插件注入机制的
- 减少默认打包的体积
- 用户不是需要所有的功能,可以做到让用户按需使用
- 当用户用到了某个插件时,但是用户没有注入改插件给予对应的提示
js
require(['vs/editor/editor.main'], function() {
registerMonaco(monaco);
});
prettier.prettierPlugins = prettierPlugins;
registerPrettier(prettier);
shiki
.getHighlighter({
theme: 'material-theme-palenight',
langs: languages
})
.then(highlighter => {
registerShikiHighlighter(highlighter);
});
registerSwiper(Swiper);
//注入其他插件等
功能介绍
暗黑模式

代码高亮


默认的代码高亮用的是 highlight.js,也支持 shiki 如果你喜欢shiki的风格需要你注入 shiki
js
shiki.getHighlighter({
theme: 'material-theme-palenight',
langs: languages
})
.then(highlighter => {
mdpress.registerShikiHighlighter(highlighter);
});
Prettier代码格式化
目前绝大数在线的markdown编辑器都没有提供这个功能,使用该功能需要你注入Prettier
html
<script src="./lib/prettier/standalone.js"></script>
<script src="./lib/prettier/plugins/acorn.js"></script>
<!-- <script src="./lib/prettier/plugins/angular.js"></script> -->
<script src="./lib/prettier/plugins/babel.js"></script>
<script src="./lib/prettier/plugins/estree.js"></script>
<!-- <script src="./lib/prettier/plugins/flow.js"></script> -->
<!-- <script src="./lib/prettier/plugins/glimmer.js"></script> -->
<!-- <script src="./lib/prettier/plugins/graphql.js"></script> -->
<script src="./lib/prettier/plugins/html.js"></script>
<script src="./lib/prettier/plugins/markdown.js"></script>
<!-- <script src="./lib/prettier/plugins/meriyah.js"></script> -->
<script src="./lib/prettier/plugins/postcss.js"></script>
<script src="./lib/prettier/plugins/typescript.js"></script>
<!-- <script src="./lib/prettier/plugins/yaml.js"></script> -->
js
prettier.prettierPlugins = prettierPlugins;
mdpress.registerPrettier(prettier);
代码组


这个功能是我从vitepress
里抄的😆
Markdown Extensions | VitePress
消息提示容器

这个功能是我从vitepress
里抄的😆
Markdown Extensions | VitePress
katex

- 行内代码
ruby
$\sqrt{3x-1}+(1+x)^2$
- 块级公式
perl
$$\begin{array}{c}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} &
= \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{array}$$
Mermaid

less
::: mermaid
flowchart LR
A[Hard] -->|Text| B(Round)
B --> C{Decision}
C -->|One| D[Result 1]
C -->|Two| E[Result 2]
:::
plantuml

less
@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response
Alice -> Bob: Another authentication Request
Alice <-- Bob: Another authentication Response
@enduml
flowchart

ini
::: flowchart
st=>start: Start:>http://www.google.com[blank]
e=>end:>http://www.google.com
op1=>operation: My Operation
sub1=>subroutine: My Subroutine
cond=>condition: Yes
or No?:>http://www.google.com
io=>inputoutput: catch something...
para=>parallel: parallel tasks
st->op1->cond
cond(yes)->io->e
cond(no)->para
para(path1, bottom)->sub1(right)->op1
para(path2, top)->op1
:::
swiper

xml
::: swiper
<div class="swiper">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div class="swiper-slide">
<img src="https://mdpress.glicon.design/p/files/2023-09-19/_97Umejwi3DfuOlGYg7iE.jpg"/>
</div>
<div class="swiper-slide">
<img src="https://mdpress.glicon.design/p/files/2023-09-19/Viaaga99bu_9v4OGJ-Idk.jpg"/>
</div>
<div class="swiper-slide">
<img src="https://mdpress.glicon.design/p/files/2023-09-19/ttkWmxXd0mjrhQp1k195D.jpg"/>
</div>
<div class="swiper-slide">
<img src="https://mdpress.glicon.design/p/files/2023-09-19/GmZdx5wpsgF-wcl1AO2ec.jpg"/>
</div>
<div class="swiper-slide">
<img src="https://mdpress.glicon.design/p/files/2023-09-19/87hQUHXwwa77rhPaWQORV.jpg"/>
</div>
</div>
<!-- If we need pagination -->
<div class="swiper-pagination"></div>
</div>
:::
Qrcode二维码

makefile
qrcode:http://www.baidu.com
qrcode:[url]
有些需要在文档里贴一些公众号链接等这时就需要这个功能了
github emoji

这里直接使用了missive/emoji-mart: 🏪 One component to pick them all (github.com)组件
使用时你需要指定emoji的data地址emojiURL
,默认是从jsDelivr - A free, fast, and reliable CDN for JS and open source拉取的数据
js
const mdEditor = new MDEditor(dom, {
preview: true, //open preview model
theme: 'vitepress',
dark: false,
themeURL: './../theme/', //theme files path
themeCache: true, //open theme cache
tocOpen: false, //open toc
emojiURL: 'https://cdn.jsdelivr.net/npm/@emoji-mart/data',
//monaco config
monacoOptions: {
language: 'markdown',
value: '',
automaticLayout: true
},
prettierOptions: {
tabWidth: 4
}
})
TOC

lua
[[toc]]
引用远程的markdown文件

makefile
include:./snip.md
include:[url]
掘金主题的支持


导出markmap


excel文件显示

makefile
excel:https://sheetjs.com/pres.numbers
excel:[url]
- 数据解析依赖 sheetjs
- 数据显示依赖 x-spreadsheet
注意:
- 因为x-spreadsheet默认会选中第一个单元格,当你的页面存在滚动条时 x-spreadsheet默认选中第一个单元格会导致页面自动滚动x-spreadsheet的位置
- 这个问题我还在解决中
添加自定义的工具栏图标
图标使用的是iconfont-阿里巴巴矢量图标库

这里演示添加一个自定义图标用来导入一个markdown文件
js
function customIcons() {
const data = {
icon: 'icon-file-markdown1',
title: '我是自定义按钮-导入markdown',
className: 'red'
}
const icon = new mdpress.ToolIcon(data);
icon.addTo(mEditor);
icon.on('click', () => {
const parseMd = (file) => {
const fileRender = new FileReader();
fileRender.onload = () => {
if (mEditor && fileRender.result) {
mEditor.setValue(fileRender.result);
}
};
fileRender.readAsText(file);
};
const inputFile = document.createElement('input');
inputFile.type = 'file';
inputFile.accept = '.md';
inputFile.addEventListener('change', () => {
if (inputFile.files.length) {
parseMd(inputFile.files[0]);
} else {
alert('没有发现上传文件');
}
});
inputFile.click();
})
}
API
请参阅仓库deyihu/mdpress-editor: simple markdown editor (github.com)
注意事项
整个项目还在快速的迭代中,所以可能会存在一些问题:
- 版本发布不是标准的流程,没有release
- 有些功能细节可能没有做好,但是核心功能是没有是么问题了
- 文档可能会延迟点
总结
-
mdpress-editor的本质就是把
VSCode
的markdown编辑功能搬到线上来 -
mdpress-editor是整个在线
vitepress
里一部分,但是却扮演者重要角色,在线vitepress
里面还包含着:- 菜单组织
- 文档组织
- 项目管理
- 人员协作
- 主题管理
- 在线编译和发布
-
在这里分享下,希望可以帮到有类似需求的同学
彩蛋
作为 maptalks/maptalks.js的开发者,maptalks缺少个教程,因而正好就基于mdpress
写了个maptalks的教程 介绍 | maptalks study