基于 Tiptap + Yjs + Hocuspocus 的富文本协同项目,期待你的参与 😍😍😍

在线预览地址

Github 地址

如果你对这个项目感兴趣,或者想参与贡献的,可以看 issue 认领需求,如果想加入交流群可以添加我微信 yunmz777 拉你进群。

技术选型

框架

技术 用途 官网链接
Next.js React 全栈框架,支持 SSR、App Router 等特性 nextjs.org
React 19 UI 框架,构建组件化用户界面 react.dev
TypeScript 静态类型系统,提升开发可靠性 www.typescriptlang.org

富文本编辑器体系(Tiptap)

技术 用途 官网链接
Tiptap 基于 ProseMirror 的无头富文本编辑器框架 tiptap.dev
Tiptap Pro 扩展 表格、占位符、数学公式、拖拽、节点 ID、Emoji 等增强功能 Pro 扩展说明
Yjs 数据同步框架,实现多人协同编辑 yjs.dev
@hocuspocus 基于 Yjs 的 WebSocket 协同服务端 hocuspocus.dev

⚙️ 工程化工具链

技术 用途 官网链接
ESLint 代码质量与规范检查工具 eslint.org
Prettier 代码自动格式化 prettier.io
Husky Git 提交钩子,配合 Lint 检查 typicode.github.io/husky
Commitizen + cz-git 规范化 Git 提交信息 commitizen-tools.github.io/commitizen/
Vitest 单元测试框架,Vite 原生支持 vitest.dev
Playwright 端对端浏览器测试 playwright.dev

样式

技术 用途 官网链接
shadcn/ui 基于 Radix UI 封装的现代 React 组件库,支持主题切换、无锁样式、自定义 Tailwind 风格 ui.shadcn.com
Tailwind CSS 原子化 CSS 样式库,与 shadcn 深度集成 tailwindcss.com
Radix UI 无样式的可访问性基础组件,shadcn 的核心依赖 www.radix-ui.com
tailwindcss-animate Tailwind 的动画插件,配合 @keyframes 使用 github.com/jamiebuilds...

其他精选依赖

技术 用途 官网链接
Zustand 轻量级状态管理库,支持持久化、异步逻辑 zustand.pmnd.rs
Framer Motion 高性能动画库,适用于组件过渡、交互反馈等 www.framer.com/motion
Lucide 现代图标库,支持 React 组件直接引入 lucide.dev
Date-fns 常用日期处理函数库,API 简洁,体积小 date-fns.org

目录结构

txt 复制代码
src/
├── app/                # Next.js 应用目录,包含页面路由、布局配置等
├── components/         # 可复用的 UI 组件库
├── extensions/         # Tiptap 编辑器的自定义扩展功能
├── hooks/              # 自定义 React Hooks
├── services/           # 业务逻辑服务层(如 API 调用、请求封装等)
├── stores/             # 状态管理(如使用 Zustand、Jotai 等)
├── styles/             # 全局样式和样式模块
├── types/              # 全局 TypeScript 类型定义
├── utils/              # 工具函数、辅助方法
├── worker/             # Web Worker 实现,用于异步或性能密集型任务
└── middleware.ts       # Next.js 中间件,用于请求拦截、认证控制等

其中 styles 里面包含了大量的 tiptap 的 css 样式,这些 CSS 文件用于为 Tiptap 提供完整的富文本样式支持。由于 Tiptap 是无头组件,所有样式(如段落、代码块、表格、列表、协同编辑等)都需自行定义。每个 CSS 文件针对一个功能模块进行样式分离,便于维护与扩展。这种拆分方式能保持样式结构清晰、职责明确。

每个不同的文件都代表不同的插件的样式,例如 code.css 代表代码块 <pre><code> 的样式定义,包括背景色、字体、行号样式,适配 CodeBlock 插件(如支持语法高亮的效果)。

对于 components 又分为两个不同的分类,src 目录下的是全局公共组件或者业务性质可共用的,在 app 目录下的是每个页面或者一个 layout 路由组下的业务组件,为了避免渲染成路由,可用 _components 命名的方式命名。

核心模块

Service 封装和调用

service 目录下的 request.ts 为全局的 fetch 封装:

这段代码封装了一个基于 fetch 的请求工具类,支持统一拦截、超时控制、错误处理与自动重试等高级功能。同时,它提供了 get/post/put/delete/patch 等方法,返回统一格式的响应结果,便于在项目中稳定复用。

对于不同模块的,可以再 service 目录下再新建一个新的目录作为特定模块的封装,例如我有一个 user 模块,index.ts 作为函数的封装,type.ts 作为接口的出参和入参的类型。

具体调用时可以不用添加 try...catch 语法捕捉,可以在具体调用时传入不同的错误结果不同的处理,由统一的 fetch 实例来处理。

tiptap 扩展

借助 tiptap 的强大的扩展功能,我们可以在原来的基础上扩展任务我们想要的功能,甚至你可以在 tiptap 上扩展一个页面。

如果要创建一个扩展,一般遵循以下原则:

ts 复制代码
import { Node, NodeViewRendererProps } from "@tiptap/core";
// - Node: 创建扩展的核心 API
// - NodeViewRendererProps: 自定义组件的 props 类型(含 editor、node 等)

import {
  NodeViewWrapper, // 将 React 组件包装为 NodeView
  ReactNodeViewRenderer, // 用于包裹 React 节点,Tiptap 会识别它作为 NodeView 的容器
  useEditorState, // 用于订阅 editor 的状态(如目录、选中状态等)
} from "@tiptap/react";

// 👉 你的自定义组件(实际渲染逻辑)
import MyReactComponent from "./MyReactComponent";

// 👉 正式定义扩展
export const MyNode = Node.create({
  name: "myNode", // 节点名称,必须唯一
  group: "block", // 节点分组,可选 block / inline / list
  atom: true, // 原子节点,不可编辑内部内容
  draggable: true, // 是否允许拖拽移动
  inline: false, // 是否是 inline 类型,默认为 block

  // HTML -> Node 映射(反序列化)
  parseHTML() {
    return [
      {
        tag: 'div[data-type="my-node"]',
      },
    ];
  },

  // Node -> HTML 映射(序列化)
  renderHTML({ HTMLAttributes }) {
    return ["div", { ...HTMLAttributes, "data-type": "my-node" }, ""]; // SSR 输出结构
  },

  // 客户端渲染视图(NodeView)------ 仅在浏览器中执行
  addNodeView() {
    if (typeof window !== "undefined") {
      return ReactNodeViewRenderer(MyReactComponent);
    }
    return null; // SSR 时跳过 NodeView
  },

  // 自定义命令:插入该节点
  addCommands() {
    return {
      insertMyNode:
        () =>
        ({ commands }) => {
          return commands.insertContent({
            type: this.name,
          });
        },
    };
  },
});

创建完成之后可以在这里添加并导出:

这两个文件都要。

协同

贡献指南

1. Fork 仓库

首先,fork 仓库到你的 GitHub 账户中。这会创建一个你自己的仓库副本。

2. 克隆仓库

在你的本地机器上克隆你刚刚 fork 的仓库:

bash 复制代码
git clone https://github.com/你的用户名/项目名.git
cd 项目名

3. 添加上游远程仓库

为了保持你的仓库与原始仓库同步,请添加上游远程仓库:

bash 复制代码
git remote add upstream https://github.com/xun082/DocFlow.git

4. 创建新分支

在开始工作之前,请确保你创建了一个新的分支:

bash 复制代码
git checkout -b feat/你的分支名

其中 feat/ 是表示"功能开发分支"的前缀,后者为你具体的功能点描述,例如:

bash 复制代码
feat/login-page             # 开发登录页面功能
feat/user-permission        # 实现用户权限控制
feat/invite-code-refactor   # 重构邀请码功能模块

对于不同的功能有不同的前缀:

前缀 说明
feature/ 新功能开发
fix/ 缺陷修复
hotfix/ 线上紧急修复
refactor/ 重构代码,不涉及功能变更
test/ 添加或修改测试相关内容
chore/ 构建、依赖等杂项维护
docs/ 文档更新

开发流程

在开启之前,请确保你的 NodeJs 版本大于或者等于 20,PNPM 版本大于或者等于 9

1. 安装依赖

在你开始开发之前,请安装所有的依赖:

bash 复制代码
pnpm install

2. 运行项目

为了确保你在一个正常运行的环境下进行开发,启动项目:

bash 复制代码
pnpm dev

3. 提交更改

在提交你的更改之前,请确保你进行了适当的代码格式化和 lint:

bash 复制代码
pnpm lint
pnpm format

然后提交你的更改:

bash 复制代码
git add .
pnpm commit

5. 同步你的分支

在你准备好提交你的更改之前,请确保你的分支是最新的:

bash 复制代码
git fetch upstream
git rebase upstream/main

6. 推送分支

将你的分支推送到你自己的仓库:

bash 复制代码
git push origin feature/你的分支名

7. 创建 Pull Request

在 GitHub 上,导航到你 fork 的仓库,点击 "Compare & pull request" 按钮。请确保你详细描述了你所做的更改。

代码审查

所有的 Pull Request 都会被审查。请注意以下几点:

  • 你的代码是否清晰且易于理解。
  • 你是否遵循了项目的代码风格和规范。
  • 你是否添加了适当的测试。
  • 你的更改是否与现有的代码兼容。

常见问题

如何报告 Bug?

如果你发现了 Bug,请在 GitHub 上创建一个 Issue,并尽可能详细地描述 Bug 及其复现步骤。

如何请求新功能?

如果你有新功能的建议,请在 GitHub 上创建一个 Issue,详细描述你的建议及其潜在的用途。

相关推荐
fcm1918 小时前
(6) tauri之前端框架性能对比
前端·javascript·rust·前端框架·vue·react
今晚务必早点睡18 小时前
前端缓存好还是后端缓存好?缓存方案实例直接用
前端·后端·缓存
双普拉斯18 小时前
微信小程序通用弹窗组件封装与动画实现
javascript·html5
IT_陈寒18 小时前
Vue3性能优化:5个被低估的Composition API技巧让我打包体积减少了40% 🚀
前端·人工智能·后端
x007xyz18 小时前
🚀🚀🚀前端的无限可能-纯Web实现的字幕视频工具 FlyCut Caption
前端·openai·音视频开发
前端Hardy18 小时前
HTML&CSS: 在线电子签名工具
前端·javascript·canvas
biomooc18 小时前
D3.js 与数据可视化
开发语言·javascript·信息可视化
前端Hardy18 小时前
告别抽象!可视化动画带你学习算法——选择排序
前端·javascript·css
毕设十刻19 小时前
基于vue的考研信息系统6kv17(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
望获linux19 小时前
论文解读:利用中断隔离技术的 Linux 亚微秒响应性能优化
java·linux·运维·前端·arm开发·数据库·性能优化