前言
继之前我开发的一个 markdown 编辑相关项目——md_edit 之后
项目地址。
我其实有一段挺长的使用和反思时间。说实话,最开始做那个项目的时候,我的需求特别简单,就是想要一个能快速敲 markdown 文档的工具,不用太多花里胡哨的功能,能正常渲染、保存本地文件就够了,所以最开始的时候,我自己手敲 markdown 语法,用那个工具打开预览,感觉一切都挺顺畅的,完全能满足我自己的基础需求。
但随着我用得越来越多,尤其是需要编辑一些带大量图片、复杂排版(比如多级列表、表格、代码块)的文档时,单纯手敲语法就显得有点繁琐了,这时候我就想到了用富文本编辑器来辅助编写——毕竟富文本编辑器可以直接点击按钮插入图片、表格,不用记复杂的 markdown 语法,能节省不少时间。可谁知道,这一尝试就遇到了让人头疼的兼容性问题,也让我萌生了优化这个工具的想法。
其实富文本编辑器的兼容性问题,说大不大,说小不小,但真的特别影响使用体验。比如我用某款主流富文本编辑器编辑好内容,导出成 markdown 格式后,再用我的 md_edit 打开,就会出现各种错乱:有的列表会被解析成单个块,层级完全乱掉(后来我才知道,这和底层依赖包的版本有关,就像有些编辑器依赖的 prosemirror-model 包,新版本会出现解析异常,回退到旧版本才能正常显示);有的图片标签会多出一堆多余的属性,导致渲染失败;还有的代码块格式错乱,缩进、高亮全部失效,得手动一个个修改,反而比手敲语法更麻烦。
那段时间我试了好几款富文本编辑器,不管是在线的还是本地的,导出的 markdown 格式或多或少都有兼容性问题,要么是排版错乱,要么是标签冗余,始终没有一个能完美适配我需求的工具。就在我快要放弃,打算重新回到纯手敲语法的模式时,我偶然发现了 Notion——一款我之前用来记笔记、整理思路的工具,它竟然支持导出为 markdown 格式,而且导出的文件特别干净,排版规范,没有多余的冗余标签,图片、表格、列表这些元素都能完美保留,当时我真的觉得“挖到宝了”。
这里先给大家安利一下 Notion。
nition网站链接:
官方网站链接
界面简洁、功能强大,不仅能记笔记、做规划,还能用来编写文档、管理项目,而且导出 markdown 的功能做得真的很出色,大家可以去试试。放一张它的界面截图,大家感受一下(这是我平时用它编写文档的界面,导出 markdown 就是一键操作):


第一个问题就是导出和上传的流程太繁琐。Notion 虽然能导出 markdown,但它只能导出到本地,也就是说,我每次用 Notion 编辑完文档,都要先点击导出,选择 markdown 格式,等待导出完成,然后找到本地的导出文件,再手动上传到我需要的地方(比如我的个人仓库、服务器),整个流程下来,至少要多花3-5分钟,尤其是当我一天需要编辑好几篇文档的时候,重复的导出、上传操作真的很消磨耐心。 第二个问题就是图片路径的问题,这也是最让我头疼的一点。Notion 导出 markdown 时,会默认把图片保存到根目录,并且图片的文件名是随机生成的,没有规律。但我平时整理文档的时候,习惯把图片统一放在 image 文件夹里,这样看起来更整洁,后续查找、替换图片也更方便。这就意味着,我每次导出 markdown 后,不仅要把所有的图片文件手动移动到 image 目录,还要逐一修改 markdown 文档中所有的图片地址,把原来的根目录路径改成 image/文件名 的格式。
实现方式
图片部分
于是我发现我可以不把文章保存在本地,我可以把文章保存在云端。比如说…
…
图床!说干就干。对比与第三方图床,我考虑了一个开源的图床可以部署在cloudfare上
链接地址
样子还是可以的:(详细的部署教程可以看github上的部署链接。)

于是本期的项目就利用了这个项目的图床以及api,当我粘贴图片的时候网页就会调用api来上传我剪切板上的图片,然后上传完成就会返回图片的地址并且进行自动填充。
把最难的一部分也就图片上传也做好了。
自动同步到仓库
不过说起来简单,实际实现的时候,却遇到了不少麻烦,尤其是在 GitHub 的同步上,真的让我头疼了很久,现在回想起来,还是有点惭愧,因为目前这个功能还不够完善,没有实现 GitHub 的完美同步,只能支持 CNB 和 GitLab 的同步,下面我就详细说说实现过程和遇到的问题。
首先,我研究了不同代码仓库的同步方式,发现大部分代码仓库都支持通过 API 进行文件的上传和提交,也就是所谓的 git push 操作,只不过不同仓库的 API 接口和认证方式有所不同。其中,CNB 和 GitLab 比较简单,支持通过用户名 + token 的方式进行认证,然后调用 API 就能实现文件的上传和同步,而 GitHub 则比较特殊,它的认证方式更加严格,几乎只能通过网页端登录认证,或者通过 SSH 密钥认证,直接用用户名 + token 的方式很难实现 git push 操作。
先说说 CNB 和 GitLab 的同步实现吧,这部分相对简单。对于 GitLab,要实现自动同步,首先需要获取个人访问令牌(Personal Access Token),获取方式也很简单:登录 GitLab 账号,点击右上角的头像,进入“Edit profile”,然后在左侧菜单选择“Access Tokens”,填写令牌名称,勾选所需的权限(比如 api、read_repository、write_repository 等),然后点击“Create personal access token”,生成令牌后,一定要立即复制保存,因为它只会显示一次,后续无法再次查看。

获取到 GitLab 的 token 之后,用户只需要在我的项目中填写自己的 GitLab 用户名、token,以及仓库地址,我的项目就会通过 GitLab 的 API,将编辑好的 markdown 文档上传到指定的仓库中。具体的实现逻辑是:先通过 API 获取仓库的相关信息,然后构造提交数据(包括文档内容、提交信息等),再调用 API 进行提交,提交成功后,用户就能在自己的 GitLab 仓库中看到同步后的文档了。
CNB 的同步实现和 GitLab 类似,也是通过用户名 + token 的方式进行认证,调用它的 API 实现文件上传和同步,操作起来也比较简单,这里就不详细说明了。总的来说,CNB 和 GitLab 的同步功能,实现起来比较顺利,没有遇到太大的问题,测试了几次,都能正常同步,满足了大部分用户的需求。
接下来就是 GitHub 的同步问题,这也是我遇到的最大的麻烦。我最开始的想法是,和 GitLab 一样,通过用户名 + token 的方式进行认证,然后调用 GitHub 的 API 实现 git push 操作。但我查了很多资料,也尝试了很多次,发现 GitHub 对 API 的权限控制非常严格,直接用用户名 + token 的方式,很难实现文件的提交和推送,大部分情况下都会被拒绝访问,提示认证失败。
后来我了解到,GitHub 其实也支持通过 API 进行文件的上传和提交,只不过需要更复杂的认证流程,比如使用 OAuth 2.0 认证,或者通过 SSH 密钥认证。OAuth 2.0 认证的流程比较复杂,需要用户授权我的应用访问他们的 GitHub
然后我就尝试了 SSH 密钥认证的方式。这种方式的原理是,用户在自己的服务器上生成 SSH 密钥,然后将公钥添加到 GitHub 账号中,这样服务器就能通过 SSH 密钥认证,直接访问 GitHub 仓库,实现 git push 操作。对于我的项目来说,如果用户是在服务器上部署我的项目,那么只需要在服务器上生成 SSH 密钥,添加到 GitHub 账号,然后在我的项目中,将用户名和 token 设置为空,就可以通过 SSH 方式实现同步了。
这里我简单给大家介绍一下 GitHub SSH 密钥的配置步骤,方便大家参考。首先,在服务器上打开终端,执行命令 ls -al ~/.ssh,查看是否已经存在 SSH 密钥对(id_rsa 私钥和 id_rsa.pub 公钥)。如果没有,就执行命令 ssh-keygen -t rsa -b 4096 -C “你的 GitHub 关联邮箱”,生成密钥对,生成过程中可以直接回车,使用默认路径,也可以设置密钥密码(增加安全性)。
生成密钥对之后,需要将公钥添加到 GitHub 账号中。执行命令 cat ~/.ssh/id_rsa.pub,复制输出的公钥内容,然后登录 GitHub 账号,点击右上角的头像,进入“Settings”,在左侧边栏中点击“SSH and GPG keys”,然后点击“New SSH key”,粘贴公钥内容,填写一个描述性的标题,点击“Add SSH key”即可。
配置完成后,可以执行命令 ssh -T git@github.com,测试 SSH 连接是否成功,如果显示“Hi 用户名! You’ve successfully authenticated, but GitHub does not provide shell access.”,就说明配置成功了。这时候,在我的项目中,将用户名和 token 设置为空,就可以通过 SSH 方式同步文档到 GitHub 仓库了。

不过这种方式也有一个缺点,就是只适合在服务器上部署我的项目,如果用户是在本地使用网页端版本,或者本地的 python 版本,就很难实现 SSH 密钥认证,因为本地环境的 SSH 密钥很难和 GitHub 进行关联,尤其是对于不熟悉 SSH 配置的用户来说,操作起来非常麻烦。
另外,我也了解到,GitHub 其实有专门的 API 可以实现 git push 操作,只不过需要更复杂的参数配置和认证流程,我目前还在研究中,后续会继续优化这个功能,争取实现 GitHub 的完美同步,让用户不管是在服务器上还是本地,都能轻松将文档同步到 GitHub 仓库。说来也惭愧,目前在 GitHub 同步这一块,确实做得不够好,还需要继续努力,也希望有懂这方面的朋友能给我一些建议和帮助。
关于Cloudfare Page
具体来说,Cloudflare Page 是一个静态网站托管服务,它主要用于部署静态网页,不支持运行服务器端的代码,也不允许调用 git push 这样的命令,因为这些命令需要服务器端的环境支持,而 Cloudflare Page 只提供静态资源的托管,不提供服务器端的运行环境。我当时也尝试了各种方法,想通过 API 来调用上传文件的功能,实现同步到仓库,但由于我学艺不精,研究了很久,也没有找到合适的方法,最终只能放弃,所以目前 Cloudflare Page 上的部署版本,无法实现自动同步到仓库的功能。
不过大家也不用太失望,虽然是残血版,但核心的功能还是可以正常使用的。比如图片自动上传功能,因为图床也是部署在 Cloudflare 上的,所以调用图床 API 没有任何问题,用户可以正常粘贴图片,实现自动上传和路径填充;导出 markdown 文件的功能也可以正常使用,用户编辑完文档后,可以一键导出 markdown 文件,保存到本地;markdown 编辑和预览功能也完全正常,和本地部署、服务器部署的版本没有区别。
步骤:
先fork

然后打开cloudfare

选择page
选择导入现有库,选择你的git仓库即可。

这就是cloudfare部署方法
后言
话说还是老传统,本篇博客就是这个编辑器写的。

最后最后,这个项目是开源的,所有的代码都放在 GitHub 上,大家可以自由下载、使用、修改,如果大家在使用过程中遇到问题,或者有好的建议和想法,欢迎在 GitHub 上提交 issue 或者 pull request,和我一起完善这个项目。我也希望这个项目能帮助到和我有一样需求的人,让大家在编辑 markdown 文档的时候,能节省更多时间,享受更流畅的使用体验。
再次放上两个版本的项目地址,方便大家获取:
网页端版本:https://github.com/mumuhaha487/09md_edit
Python 本地版本:https://github.com/mumuhaha487/09md_edit_python
如果大家觉得这个项目有用,欢迎给我点个 star,这对我来说是最大的鼓励和支持,谢谢大家!