mdpress-editor:一个简单的Web Markdown编辑器

创作背景

身为一个技术人员平时要写大量的技术文档,以前用的是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的源码发现的

仓库

主要功能

特色功能

  • 嵌入远程的一个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]

注意:

  • 因为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

相关推荐
wearegogog1231 小时前
基于 MATLAB 的卡尔曼滤波器实现,用于消除噪声并估算信号
前端·算法·matlab
Drawing stars1 小时前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
品克缤1 小时前
Element UI MessageBox 增加第三个按钮(DOM Hack 方案)
前端·javascript·vue.js
小二·1 小时前
Python Web 开发进阶实战:性能压测与调优 —— Locust + Prometheus + Grafana 构建高并发可观测系统
前端·python·prometheus
小沐°1 小时前
vue-设置不同环境的打包和运行
前端·javascript·vue.js
qq_419854052 小时前
CSS动效
前端·javascript·css
烛阴2 小时前
3D字体TextGeometry
前端·webgl·three.js
桜吹雪3 小时前
markstream-vue实战踩坑笔记
前端
C_心欲无痕3 小时前
nginx - 实现域名跳转的几种方式
运维·前端·nginx
花哥码天下3 小时前
恢复网站console.log的脚本
前端·javascript·vue.js