Node.js+Express+marked+mermaid.js:搭建Markdown在线编辑器支持流程图渲染
在技术文档和开发笔记中,Markdown因其简洁语法成为首选,但若能在线实时预览并嵌入流程图(如mermaid),将极大提升写作效率。本文基于Node.js 18.20,使用Express 4、marked 12、mermaid.js和EJS模板引擎,构建一个可直接运行的在线Markdown编辑器,支持实时解析、保存/加载文档,并原生支持mermaid流程图渲染。## 实现思路
1. 用Express搭建Web服务,提供静态资源与API接口;
2. 使用marked解析Markdown,自定义渲染器识别mermaid代码块,由前端mermaid.js客户端渲染;
3. 提供左侧编辑、右侧预览的双面板界面,点击按钮触发解析或保存/加载;
4. 基于本地文件系统(docs目录)实现简单的文档持久化。
## 1. 项目初始化与依赖安装
创建项目目录并初始化:
mkdir md-edit-app
cd md-edit-app
npm init -y
安装核心依赖(指定版本以保证兼容性,当前Node.js推荐18.20):
npm install express@4.18.3 marked@12.0.2
npm install cors@2.8.5 body-parser@1.20.2 fs-extra@11.2.0 ejs@3.1.9
## 2. 服务器主程序(app.js)
创建app.js,实现以下功能:
- 配置marked解析器,自定义code渲染器:遇到语言为mermaid的代码块时输出<div class="mermaid">内容</div>,由前端mermaid.js接管渲染;其它代码块保留常规<pre><code>结构。
- 提供API:
- POST /api/parse:接收markdown原文,返回解析后的HTML;
- POST /api/save:保存文档(.md文件到docs目录);
- GET /api/load/:filename:加载已保存文档;
- GET /api/docs:列出所有.md文件。
- 设置模板引擎为EJS,视图目录为views。
- 启动服务监听8000端口。
完整代码如下(已修正原文中模板字符串错误):
const express = require('express');
const marked = require('marked');
const cors = require('cors');
const bodyParser = require('body-parser');
const fs = require('fs-extra');
const path = require('path');
const app = express();
const renderer = new marked.Renderer();
renderer.code = (code, language) => {
if (language === 'mermaid') {
return `<div class="mermaid">${code}</div>`;// 原文笔误已修正
}
return `<pre><code class="language-${language}">${code}</code></pre>`;
};
marked.setOptions({
renderer: renderer,
highlight: true,
breaks: true,
gfm: true
});
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
const DOCS_DIR = path.join(__dirname, 'docs');
fs.ensureDirSync(DOCS_DIR);
app.get('/', (req, res) => {
res.render('editor', { title: 'Markdown 在线编辑器 (支持Mermaid)' });
});
app.post('/api/parse', (req, res) => {
try {
const { markdown } = req.body;
if (!markdown) return res.status(400).json({ error: 'Markdown 内容不能为空' });
const html = marked.parse(markdown);
res.json({ html });
} catch (error) {
res.status(500).json({ error: '解析失败: ' + error.message });
}
});
app.post('/api/save', (req, res) => {
try {
const { filename, content } = req.body;
if (!filename || !content) return res.status(400).json({ error: '文件名和内容不能为空' });
fs.writeFileSync(path.join(DOCS_DIR, `${filename}.md`), content, 'utf8');
res.json({ success: true, message: '保存成功' });
} catch (error) {
res.status(500).json({ error: '保存失败: ' + error.message });
}
});
app.get('/api/load/:filename', (req, res) => {
try {
const filePath = path.join(DOCS_DIR, `${req.params.filename}.md`);
if (!fs.existsSync(filePath)) return res.status(404).json({ error: '文件不存在' });
const content = fs.readFileSync(filePath, 'utf8');
res.json({ success: true, content });
} catch (error) {
res.status(500).json({ error: '加载失败: ' + error.message });
}
});
app.get('/api/docs', (req, res) => {
try {
const files = fs.readdirSync(DOCS_DIR)
.filter(file => path.extname(file) === '.md')
.map(file => ({ name: path.basename(file, '.md'), path: file }));
res.json({ success: true, docs: files });
} catch (error) {
res.status(500).json({ error: '获取列表失败: ' + error.message });
}
});
const PORT = 8000;
app.listen(PORT, () => {
console.log(`服务器运行在: http://localhost:${PORT}`);
});
## 3. 前端编辑器页面(views/editor.ejs)
前端集成mermaid.js进行客户端渲染。页面包含:
- 控制栏:文件名输入框、保存/加载/刷新预览按钮;
- 左侧textarea编辑区(预填充示例内容);
- 右侧预览容器(id="preview")。
点击“刷新预览”时,通过fetch POST /api/parse获取HTML,然后调用mermaid.run渲染所有mermaid图表。注意mermaid初始化需在DOM解析后执行。
核心模板内容:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<style>
/* 略,完整样式可参考原文 */
</style>
</head>
<body>
<div class="header">
<h1>Markdown 在线编辑器 (支持 Mermaid 流程图)</h1>
</div>
<div class="controls">
<input type="text" id="filename" placeholder="输入文件名(无需.md)" value="demo">
<button id="saveBtn">保存文档</button>
<button id="loadBtn">加载文档</button>
<button id="refreshBtn">刷新预览</button>
</div>
<div class="container">
<div class="editor-container">
<textarea id="editor" placeholder="请输入 Markdown 内容...">
## Markdown 编辑器 (支持 Mermaid)
### 功能说明
- 支持标准 Markdown 语法
- 支持 Mermaid 流程图渲染
- 支持文档保存/加载
### Mermaid 示例
graph TD
A[开始] --> B{选择操作}
B -->|编辑| C
B -->|预览| D[实时预览]
C --> E[保存文档]
D --> E
E --> F[结束]
普通代码示例
console.log('Hello, Markdown!');
</textarea>
</div>
<div class="preview-container">
<div id="preview" class="preview"></div>
</div>
</div>
<script>
// mermaid初始化
mermaid.initialize({ startOnLoad: false, theme: 'default', securityLevel: 'loose' });
function refreshPreview() {
fetch('/api/parse', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ markdown: document.getElementById('editor').value })
})
.then(res => res.json())
.then(data => {
document.getElementById('preview').innerHTML = data.html;
mermaid.run({ querySelector: '.mermaid' });
})
.catch(err => alert('解析失败: ' + err));
}
document.getElementById('refreshBtn').addEventListener('click', refreshPreview);
// 保存/加载文档逻辑类似,通过fetch调用/api/save和/api/load/:filename
// 完整脚本可参考原文,此处略
</script>
</body>
</html>
## 运行与使用
1. 创建目录结构:
md-edit-app/
├── app.js
├── views/
│ └── editor.ejs
├── public/ (空文件夹)
└── docs/ (自动创建)
2. 启动服务器:
node app.js
3. 打开浏览器访问 http://localhost:8000
4. 在左侧编辑Markdown,点击“刷新预览”查看渲染结果;输入文件名后点击“保存文档”可持久化到服务器;输入已保存文件名点击“加载文档”可恢复内容。
## 技术要点总结
- 服务端使用marked解析Markdown,通过自定义renderer.code将mermaid代码块原样输出为div,避免服务端渲染mermaid,减少Node端依赖。
- 前端引入mermaid.js CDN,在获得HTML后调用mermaid.run()动态渲染图表,支持graph TD、flowchart等主流图表类型。
- 文件操作使用fs-extra的ensureDirSync确保docs目录存在,同步读写适合轻量场景。
- API设计遵循RESTful风格,支持跨域(cors中间件),便于后续扩展或分离前后端。
## 扩展建议
- 添加用户认证、版本管理。
- 集成Markdown扩展如表格、数学公式(Katex)。
- 将文件存储切换为数据库,支持多人协作。
- 优化前端UI,增加自动保存和分屏拖拽等功能。
本方案开箱即用,代码可直接复制运行。通过自定义marked渲染器结合前端mermaid.js,在没有复杂构建工具的情况下实现了客户端流程图渲染,适合快速搭建个人笔记或团队文档工具。
Re: Node.js+Express+marked+mermaid.js:搭建Markdown在线编辑器支持流程图渲染
这个实现很实用,Markdown + Mermaid 正好解决了技术文档里写流程图还得切换到其他工具的痛点。用 marked 自定义渲染器来分离处理,思路清晰。提个小细节:代码里 `highlight: true` 可能不会直接生效,因为 marked 本身没有高亮能力,通常需要配合 highlight.js 或 prism,不过对于 mermaid 渲染不影响。另外如果后续要支持更复杂的 mermaid 主题或动态更新,可以考虑用 `mermaid.run` 取代全局 `mermaid.init`,这样能更好控制渲染时机。整体框架搭得很完整,收藏备用。Re: Node.js+Express+marked+mermaid.js:搭建Markdown在线编辑器支持流程图渲染
感谢楼主分享这么详细的教程!从项目结构到代码实现,每一步都写得很清楚,特别是对 marked 自定义渲染器的处理,以及后端 API 的设计,对想自己搭建 markdown 编辑器的朋友来说非常实用。 另外注意到你的 `app.js` 代码在最后部分似乎被截断了(`if (!fs.existsSync(fileP` 后面没有了),可能是粘贴时漏掉了一部分,比如文件读取或者错误处理之类的逻辑。如果能补充完整就更好啦,方便大家直接复制运行验收。 再次感谢你的分享,这套方案结合 mermaid 实时渲染确实能提升写作和文档制作的体验,收藏了!Re: Node.js+Express+marked+mermaid.js:搭建Markdown在线编辑器支持流程图渲染
感谢分享这么详细的教程!从项目初始化到自定义marked渲染器、双面板编辑预览、文件保存/加载,整个流程非常完整,适合快速上手搭建一个实用的在线 Markdown 编辑器。特别是 marked 的 renderer 自定义处理 mermaid 代码块,让流程图渲染无缝集成到 Markdown 解析中,这个思路很巧妙。如果后续能加入语法高亮(比如 highlight.js)和自动保存功能,体验会更棒。另外,生产环境中建议对文件名做一下路径安全检查,防止 directory traversal。辛苦了!
页:
[1]