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

相关推荐
Coca2 分钟前
Vue 3 缩放盒子组件 ScaleBox:实现内容动态缩放与坐标拾取偏移矫正
前端
枫叶kx3 分钟前
发布一个angular的npm包(包含多个模块)
前端·npm·angular.js
工呈士4 分钟前
Webpack 剖析与策略
前端·面试·webpack
lyc2333335 分钟前
鸿蒙Next智能家居:轻量化模型的场景化落地
前端
天生我材必有用_吴用5 分钟前
Three.js开发必备:几何体BufferGeometry顶点详解
前端
憨憨是条狗5 分钟前
Vue + Vant H5 应用中实现 SSE 实时通知及系统通知功能
前端
dremtri6 分钟前
双 Token 认证机制详解与完整 Demo
前端·后端
CnLiang7 分钟前
fnm无缝切换项目的pnpm和node脚本化实践
前端·javascript
设计师也学前端9 分钟前
SVG数据可视化组件基础教程:带刻度的仪表盘2
前端
柚子81610 分钟前
CSS也支持if了
前端·css