效果展示:https://md.hubly.top/editor.html

项目初衷
作为一个经常使用Markdown写作,并需要多平台发布的内容创作者,我经常面临两个痛点:一是需要将.md文件快速转换为Word、PDF等格式;二是为不同平台调整排版耗时耗力。上周末,我决定用一天时间,尝试构建一个轻量工具来解决这些问题。
技术栈选择
-
后端:Node.js + Express
-
前端:原生JavaScript (Vanilla JS)
-
构建工具:无(追求极简)
-
部署:准备托管在静态CDN平台
-
开发时间:1天
选择这个技术栈主要基于:
-
快速启动:Node.js环境搭建简单,Express框架轻量且熟悉
-
零依赖:前端坚持用原生JS,避免框架学习成本和打包复杂度
-
功能聚焦:核心是格式转换和排版,不需要复杂SPA
系统架构
后端设计(Express应用)
// 核心路由结构
app.post('/convert', handleConversion); // 处理格式转换
app.get('/themes', getThemes); // 获取主题列表
app.post('/preview', generatePreview); // 生成排版预览
关键技术点:
-
文件处理 :使用
multer中间件处理.md文件上传 -
格式转换管道:
-
HTML转换:
marked.js库解析Markdown -
PDF生成:
puppeteer无头浏览器渲染HTML后截图 -
Word文档:基于HTML生成.docx文件结构
-
PNG导出:Canvas渲染+html2canvas库
-
-
主题系统:CSS样式表预置,通过API动态切换
前端实现(原生JS)
// 核心模块组织
class MDtoEditor {
constructor() {
this.editor = document.getElementById('editor');
this.themeManager = new ThemeManager();
this.converter = new FormatConverter();
}
// 主题切换
switchTheme(themeName) {
// 动态加载CSS,修改内联样式
}
// 内容导出
exportFormat(format) {
// 调用后端API,处理返回结果
}
}
DOM操作优化:
-
使用事件委托减少监听器数量
-
防抖处理实时预览更新
-
虚拟滚动处理长文档
开发时间线(一天实战)
上午 9:00-12:00:搭建基础框架
-
初始化Express项目
-
配置基本路由和中间件
-
实现Markdown到HTML的基础转换
-
创建前端基础界面(编辑器区域+控制面板)
下午 13:00-17:00:核心功能开发
-
实现四种格式导出功能(HTML/Word/PDF/PNG)
-
开发主题系统:5套公众号主题+5套知乎主题
-
实现实时预览功能
-
添加深色/浅色模式切换
晚上 18:00-21:00:优化与测试
-
移动端适配响应式布局
-
数据本地存储(localStorage)
-
错误处理和用户反馈
-
基础样式美化
关键技术决策与解决方案
1. 纯前端VS服务端渲染
决策:混合模式
-
格式转换需要服务端(特别是PDF生成)
-
主题切换和实时预览完全在前端
-
减少服务端压力,提升响应速度
2. 主题系统实现
/* 主题CSS变量系统 */
:root[data-theme="geek"] {
--primary-color: #2d3748;
--code-bg: #1a202c;
--font-family: 'SF Mono', monospace;
}
通过修改data-theme属性,一键切换所有样式变量。
3. 文件导出优化
-
PDF导出使用缓存,避免重复生成
-
PNG导出支持分辨率选择
-
批量导出时使用队列处理
4. 数据安全策略
-
所有转换在内存中完成,不存储用户文件
-
支持离线使用(基础编辑功能)
-
可选加密传输(未来版本)
遇到的挑战与解决
挑战1:PDF中文支持
问题 :默认配置下中文显示乱码 解决方案:
-
嵌入中文字体到PDF生成环境
-
配置puppeteer字体参数
-
提供字体回退机制
挑战2:移动端体验
问题 :编辑器在手机上操作不便 解决方案:
-
定制移动端虚拟键盘处理
-
底部固定操作栏
-
手势支持(滑动切换主题)
挑战3:一天内完成
策略:
-
功能优先级排序(核心转换 > 高级排版)
-
使用现成库解决复杂问题(不重复造轮子)
-
最小可行产品思维,先完成再完善
性能优化
-
懒加载:主题CSS按需加载
-
缓存策略:转换结果临时缓存
-
Worker支持:大文件处理放在Web Worker
-
代码分割:按功能模块动态加载
部署配置
// Express静态文件服务
app.use(express.static('public', {
maxAge: '1d',
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
res.setHeader('Cache-Control', 'no-cache');
}
}
}));
计划部署到CDN平台,利用边缘计算加速访问。
未来可能的扩展
-
插件系统:允许自定义转换器和主题
-
协作编辑:实时多人编辑支持
-
API开放:提供RESTful API供其他系统集成
-
桌面应用:基于Electron打包
开发心得
一天内完成这个项目,验证了"小步快跑"的开发理念。关键技术选择上,Node.js + Express提供了足够的后端能力,原生JavaScript避免了框架复杂度,让注意力集中在核心功能上。
最大的收获是:在时间约束下,必须做出明确的技术取舍。例如,放弃实时协同编辑、简化用户系统、优先保证核心转换的稳定性。这些决策让项目在一天内从想法变为可用产品。
项目开源地址:欢迎访问GitHub仓库查看完整代码和技术实现细节。
技术栈:Node.js 20.x, Express 5.x, Vanilla JS
开发时长:约12小时
如果你对某个技术实现细节感兴趣,欢迎在评论区讨论。代码已开源,适合作为学习Express和原生JS的参考项目。