Skip to content
全新发布

PDF SDK 与 AI 文档处理

在 GitHub 获取完整的私有化部署SDK 包及 AI 智能文档处理能力,一键部署,快速构建您的文档处理工作流。

架构

ComPDFKit Web SDK 采用严格的三层架构。理解各层之间的边界对于定制 UI 和扩展 SDK 至关重要。

三个层次

集成方页面
  └─ webviewer.js(iframe 嵌入 — packages/core/webviewer.js)
       └─ Webview Vue 应用(packages/webview — 开源)
            └─ Core 桥接层(packages/webview/src/core/)
                 └─ ComPDFKitViewer(packages/core — 闭源)
                      └─ Web Worker(compdfkit_worker.js)
                           └─ WASM(ComPDFKit.wasm / pdfium.wasm)
位置状态是否开源
嵌入入口packages/core/webviewer.js创建 iframe是(薄层)
UI 层packages/webviewPinia stores
Core 桥接层packages/webview/src/core/无状态(仅一个注册表)
引擎packages/core基于 WASM

1. 嵌入入口 — webviewer.js

集成方调用 ComPDFKitViewer.init(options, element)。它创建一个指向已构建 webview 应用的 <iframe>,与 iframe 进行配置握手,并从 iframe.contentWindow.instance 捕获 instance 对象({ UI, Core, docViewer })后解析返回。详见 快速开始

2. UI 层 — packages/webview

一个 Vue 3 + Pinia 单页应用。它持有所有 UI 状态(哪些面板打开、当前工具、主题、工具栏定义)并渲染整个界面。它从不直接导入 packages/core——仅通过 core 桥接层与引擎通信。

子系统:

  • src/apis/ — 组装到 window.instance.UI(引擎接口组装到 window.instance.Core)的公共 API 接口。
  • src/core/ — 无状态桥接层。
  • src/components/ — 200+ 个 Vue 组件。
  • src/stores/ — Pinia stores(viewerdocument)。
  • src/helpers/src/hooks/src/constants/

3. Core 桥接层 — src/core/

一个由约 120 个单函数模块组成的扁平门面,将调用转发到 ComPDFKitViewer 引擎实例。它不持有业务状态,也不进行 DOM 操作——其唯一的可变结构是 documentViewers Map(多实例注册表)。详见 Core 桥接层

4. 引擎 — packages/core

ComPDFKitViewer 类(src/index.js,约 5400 行)是 SDK 单体式核心。它管理 PDF 渲染、批注、表单、内容编辑和测量,并通过 MessageHandler 与 WASM worker 通信。它通过 Rollup 构建为 packages/webview/lib/webview.min.js(主库)和 lib/PDFWorker.js(worker),webview 在构建时导入。

启动流程

端到端加载序列:

1. 集成方:ComPDFKitViewer.init(options, el)
2. webviewer.js:创建 iframe → webviewer/index.html?version=...#d=...&docId=...
3. iframe 启动:main.js → createApp(App= Suspenser.vue) → setupStore + i18n → mount('#app')
4. Suspenser.vue 在 <Suspense> 中渲染 <App/>(fallback:加载 logo)
5. App/index.vue setup():
     await i18nextPromise            // 翻译就绪
     initDocument({ $t })            // 从 lib/webview.min.js 构造 new ComPDFKitViewer(options)
                                    //   → core.setDocumentViewer(1, documentViewer)
     defineWebViewerInstanceUIAPIs() // window.instance = { docViewer, Core, UI }
     await loadConfig(initOptions)   // iframe↔父窗口握手,应用集成方 options
     读取 hash 参数:css / theme / header
6. App onMounted:postMessage({ type: 'viewerLoaded', docId }) → window.parent
7. webviewer.js:捕获 iframe.contentWindow.instance,触发 'ready',解析 init Promise

main.js 将两个插件应用于同一个 app: setupStore(app)(Pinia)和 i18n(app)(i18next-vue)应用于同一个 createApp(App) 实例,再挂载。(早期版本为 i18n 创建了第二个 createApp(App) 并挂载它,导致启用了 Pinia 的 app 未被挂载——此问题已修复。)

instance 对象

定义于 packages/webview/src/apis/index.js

javascript
window.instance = {
  docViewer,                  // = core.getDocumentViewer()(实例 1)
  Core: objForWebViewerCore,  // 整个 core 桥接层的展开
  UI:   objForWebViewerUI,    // 所有 apis/*.js 工厂,已注入 store
};

objForWebViewerUIapis/ 模块构建。每个模块是一个工厂 (stores...) => (...args) => resultindex.js 在注册时注入 Pinia store,因此公共接口是内部函数。两种 store 访问模式并存:

  • 直接 Pinia storeuseVieweruseDocument):API 直接调用 store 的 action/getter。大多数 API 使用此模式。
  • 封装 storeviewerStoredocumentStore,由 api_helpers/createEncapsulatedStore.js 构建):仅暴露 dispatch(action)(args)getState(key)(返回深拷贝)。弹窗 API、getPasswordgetPanels 使用此模式。

多实例模型

桥接层通过 src/core/documentViewers.js 中的单个 Map 支持多个并存的 PDF 查看器:

javascript
const documentViewerMap = new Map();
export const getDocumentViewer = (number = 1) => documentViewerMap.get(number);
export const setDocumentViewer = (number, documentViewer, options) => { /* … */ };
export const deleteDocumentViewer = (number) => { documentViewerMap.delete(number); };
  • 默认实例为 1——主文档。无参数的 getDocumentViewer() 解析到实例 1。
  • 实例 23 用于文档对比功能("旧文件"和"新文件"查看器),由 CompareDocumentContainer.vue 注册。
  • 约 120 个桥接文件中仅约 13 个显式传递 docNum 参数;其余硬编码到实例 1。因此多实例是按方法可选的,并非整个 API 接口统一支持。

关键设计模式

  • 单向依赖规则: apis/ → core/ → engine。API 从不直接导入 packages/core,而是通过 src/core/。桥接层从不触碰 Pinia store 或 DOM。
  • 无状态桥接层: src/core/ 文件不含业务逻辑——它们是纯委托函数。每个文件一个函数;文件名 === 函数名;docNum 始终是最后一个参数。
  • 每个文件一个函数(apis): 每个 apis/ 模块导出一个工厂,动词前缀(set/get/open/disable),含 JSDoc。
  • EventBus: 引擎使用自定义 EventBus(core.eventBus())进行跨模块通信——annotationChangetoolChangedscalechangingpagerendered 等。详见 事件
  • 消息队列: ComPDFKitViewer.enqueue() 序列化异步操作,防止 WASM worker 上的竞态条件。
  • store 镜像引擎: Pinia document store 是引擎工具/样式状态的 UI 侧镜像——setActiveToolColorsetToolState 等 setter 既写入 store,也推送到 core
  • 封装 store 接缝: 两个 store 上的 dispatch/getState 明确作为 API 访问通道,使公共接口与 Pinia 内部解耦。

批注类型别名

引擎中部分批注类型共享实现:

  • 测量的 circle 映射到 square
  • 测量的 ink 映射到 curve
  • 带弧点的 ink 映射到 arc

在使用工具和批注样式时这些别名很重要。

下一步