DSH / Atlas
2026-09-16implementedfeature

Browser Excel preview with saved formula results

显示已保存公式结果的浏览器 Excel 预览

PDF conversion loses spreadsheet navigation and the relationship between a formula and its saved value. Spreadsheet preview also needlessly depends on the Host Office engine when the browser can read the workbook. Unsupported drawing content can also prevent cell preview. ExcelJS 4.4.0 expects prefixed DrawingML element names and fails on valid default-namespace drawings emitted by Openpyxl. A chart that the viewer c

English

Problem

PDF conversion loses spreadsheet navigation and the relationship between a formula and its saved value. Spreadsheet preview also needlessly depends on the Host Office engine when the browser can read the workbook.

Unsupported drawing content can also prevent cell preview. ExcelJS 4.4.0 expects prefixed DrawingML element names and fails on valid default-namespace drawings emitted by Openpyxl. A chart that the viewer cannot display must not make otherwise readable worksheets unavailable.

Decision

The document preview opens XLSX, XLS, CSV, and TSV with FortuneSheet and package-local adapters for ExcelJS, SheetJS CE, and PapaParse. The adapter accepts bytes, format, and limits and returns worksheet data; it has no React state setters, timers, or component references. Dependencies own file parsing, while the adapters share display formatting and initial selection without introducing another workbook model. CSV/TSV retain literal strings and a plain-text option; implicit type inference could otherwise discard leading zeros or interpret source text as formulas. The shared document reader calls remote.workspaceFiles.readBytes(sessionId, path, {}, signal) and receives native bytes through the binary Remote, retaining Session authorization, file versions, reload, and transient bytes without base64 decoding. Workspace Files owns bounded file reads; format parsing stays in the Client. The registration marks only XLSX/XLS as binaryExtensions, so the shared document container offers Plain text for CSV/TSV. Each renderer registers its body under its own id.

Preview is read-only and retains formula text alongside saved results. It does not recalculate, so unsupported functions cannot replace a valid saved result with an error. A formula without a saved result remains blank. Workbooks containing formulas show a compact warning beside the formula icon instead of consuming worksheet height with a notice row. The spreadsheet is neither an authoring tool nor a full Excel rendering engine.

The package-local XlsxPreviewArchive inspects XLSX content inside the parser Worker and removes DrawingML parts and their relationship parts from a temporary ZIP. ExcelJS also ignores worksheet drawing references; ignoring those references alone still leaves its archive-level drawing parser exposed to the failure. The source bytes and retained worksheet XML remain unchanged. A separate notice lists detected charts, images, shapes, and conditional formatting that the preview does not display and recommends a system application. Formula warnings remain independent, and files without detected unsupported content have no notice. Other formats return no unsupported-content categories.

A disposable browser Worker contains parser CPU work. A source-byte limit precedes parsing, a combined rectangular-area limit precedes FortuneSheet matrix allocation, and a timeout terminates stalled parsing. These limits do not claim a hard memory sandbox. Styles are scoped to the renderer; external hyperlinks are text only.

The pinned FortuneSheet React dependency carries a patch that skips the input box's read-only layout state update unless formula-reference highlighting is enabled. The unconditional update otherwise causes a maximum-update-depth failure when switching worksheets under the shipped React 18.3.1 runtime. Sheet activation also retains the adapter's complete initial selection instead of clearing it and leaving an empty or invalid address. The browser scenario covers these failures through the bundled ESM entry.

The read-only formula bar takes formulas from raw cell.f and writes formulas and cell text through textContent. FortuneSheet's formula formatter emits HTML spans containing document text, and its HTML helper passes formulas and strings starting with <span through unchanged. Neither read-only mode nor the parser Worker isolates this DOM. The core patch HTML-escapes copied cell contents, including literal strings and saved formula results, while preserving the clipboard table and formatting.

The core patch also skips drawing freeze dividers when allowEdit === false, retaining the frozen-pane calculations and editable-mode dividers. These dividers are Canvas strokes, so scoped CSS cannot change them. Preview-scoped CSS hides the row and column freeze drag handles. The ESM and CommonJS entries receive the same patches. Recheck worksheet switching, complete initial selections, literal formula-bar text, escaped table copying, and frozen-pane rendering and scrolling when upgrading FortuneSheet.

Alternatives considered

Adopt FortuneExcel's React-oriented conversion helper. Its component setters and post-render sizing couple file conversion to one UI lifecycle. The local adapter can be tested without mounting a workbook and needs no second intermediate workbook model.

Write an OOXML parser or create a new public package. ExcelJS already owns the container and file semantics. One preview consumer does not justify another public API, Cordis service, or generic workbook abstraction; a second independent consumer can motivate extraction.

Patch ExcelJS's drawing namespace handling. Correct parsing would still leave drawings undisplayed. Filtering the unsupported parts prevents them from blocking the supported cell preview without maintaining drawing behavior that the viewer cannot use.

Replace ExcelJS or require users to rewrite their files. A parser replacement puts retained fonts, borders, merges, and frozen panes at risk. Rewriting a source file makes a viewer defect the user's responsibility. A temporary preview copy preserves both the existing adapter and the user's file.

Keep PDF as an Excel fallback or calculate every formula on import. PDF retains neither spreadsheet interaction nor formula inspection, while recalculation can change saved results. The Office engine reference remains applicable to Word/PowerPoint previews and independent conversion consumers; its conversion capability still supports spreadsheets.

Consequences

The renderer trades complete Excel fidelity for browser-local navigation and reusable conversion code. The package README owns supported formats, resource defaults, and unsupported features. Real XLSX/XLS fixtures and delimited-text cases cover conversion, Worker tests cover cancellation and cleanup, and the shipped-profile browser scenario opens a workbook with Office conversion disabled and copies a saved XLOOKUP result under read-only settings. It also exercises XLS sheet switching and CSV/TSV literal copying, text-view switching, and reload. SheetJS CE is pinned to its official release tarball because the public npm registry is stale; its Apache-2.0 license follows the existing permissive-license and bundled-notice policy.

Drawing filtering adds ZIP inspection and, when parts are omitted, temporary uncompressed ZIP allocation. Existing Worker lifetime and source/matrix limits still apply; they do not bound decompressed memory. Drawing fixtures cover default and alternate prefixes, exact retained XML and input bytes, images, shapes, and comment VML. The browser scenario checks the notice, saved-value copying, and notice removal on file replacement. Adding drawing rendering requires revisiting both filtering and notice classification; a namespace fix alone does not restore that capability.

中文

问题

PDF 转换会丢失工作表导航以及公式与已保存值之间的关系。浏览器能够读取工作簿时,表格预览也没有必要依赖 Host Office 引擎。

不支持的绘图内容也可能阻断单元格预览。ExcelJS 4.4.0 要求 DrawingML 元素名带前缀,遇到 Openpyxl 生成的合法默认命名空间绘图时会失败。查看器无法展示的图表不应使原本可读的工作表无法打开。

决策

文档预览使用 FortuneSheet 与包内 ExcelJS、SheetJS CE 和 PapaParse 适配层打开 XLSX、XLS、CSV 和 TSV。适配层接收字节、格式和限制并返回工作表数据,不包含 React 状态设置器、计时器或组件引用。依赖库负责文件解析,适配层复用显示格式化和初始选区,不引入另一种工作簿模型。CSV/TSV 保留字面字符串和纯文本选项;隐式类型推断可能丢失前导零或把源文本解释为公式。共享文档读取器调用 remote.workspaceFiles.readBytes(sessionId, path, {}, signal),并通过二进制 Remote 直接接收原生字节,保留 Session 授权、文件版本、重新载入和临时字节,无需 base64 解码。Workspace Files 负责有界文件读取,格式解析留在 Client。注册仅将 XLSX/XLS 标为 binaryExtensions,共享文档容器因此为 CSV/TSV 提供纯文本选项。每个渲染器以自己的 id 注册正文。

预览为只读,同时保留公式文本与已保存结果。它不重新计算,因此不受支持的函数不会用错误覆盖有效的已保存结果。没有已保存结果的公式保持为空。包含公式的工作簿会在公式图标旁显示紧凑提示,不再用整行提示占用工作表高度。该表格既不是编写工具,也不是完整的 Excel 渲染引擎。

包内 XlsxPreviewArchive 在解析 Worker 中检查 XLSX 内容,从临时 ZIP 中移除 DrawingML 部件及其关系部件。ExcelJS 同时忽略工作表绘图引用;仅忽略这些引用仍会让其归档级绘图解析器触发该故障。源字节和保留的工作表 XML 均不改变。独立提示列出实际检测到但预览未展示的图表、图片、形状和条件格式,并建议使用系统应用。公式提示保持独立,未检测到不支持内容的文件不显示此提示。其他格式不返回不支持内容分类。

独立可释放的浏览器 Worker 承担解析 CPU 工作。解析前检查源文件字节限制,FortuneSheet 分配矩阵前检查矩形区域合计限制,并通过超时终止停滞的解析。这些限制不代表严格的内存沙箱。样式限定在渲染器区域内,外部超链接仅显示为文本。

固定版本的 FortuneSheet React 依赖带有一个补丁:只读输入框仅在启用公式引用高亮时才提交布局状态更新。无条件更新会在仓库交付的 React 18.3.1 运行时下切换工作表时触发最大更新深度错误。激活工作表时还会保留适配层提供的完整初始选区,避免清空后留下空白或无效地址。浏览器场景通过打包后的 ESM 入口覆盖这些故障。

只读公式栏直接读取原始 cell.f,通过 textContent 写入公式和单元格文本。FortuneSheet 的公式格式化器会生成含有文档文本的 HTML span,其 HTML 辅助函数会原样放行公式和以 <span 开头的字符串。只读模式和解析 Worker 都不能隔离这部分 DOM。core 补丁会对复制的单元格内容进行 HTML 转义,包括字面字符串和已保存的公式结果,同时保留剪贴板表格及其格式。

core 补丁还在 allowEdit === false 时跳过冻结分隔线的绘制,保留冻结窗格计算和编辑模式下的分隔线。这些分隔线由 Canvas 绘制,因此局部 CSS 无法修改。预览区域内的 CSS 隐藏行列冻结拖拽条。ESM 和 CommonJS 入口应用相同补丁。升级 FortuneSheet 时需要重新检查工作表切换、完整初始选区、公式栏字面文本、经过转义的表格复制,以及冻结窗格的绘制和滚动。

考虑过的替代方案

采用 FortuneExcel 面向 React 的转换辅助函数。 其组件状态设置器和渲染后尺寸调整把文件转换耦合到一种 UI 生命周期。本地适配层无需挂载工作簿即可测试,也不需要第二种中间工作簿模型。

自行编写 OOXML 解析器或创建新的公共包。 ExcelJS 已经负责容器和文件语义。单个预览使用方不足以支持另一套公共 API、Cordis 服务或通用工作簿抽象;出现第二个独立使用方时再考虑提取。

修补 ExcelJS 的绘图命名空间处理。 正确解析仍不能使查看器展示绘图。过滤不支持的部件可防止其阻断已支持的单元格预览,无需维护查看器无法使用的绘图行为。

替换 ExcelJS 或要求用户重写文件。 更换解析器会使现有字体、边框、合并及冻结窗格的保留面临风险。重写源文件则把查看器缺陷交给用户处理。临时预览副本同时保留现有适配器和用户文件。

保留 PDF 作为 Excel 兜底,或在导入时计算所有公式。 PDF 无法保留表格交互与公式查看,而重新计算可能改变已保存结果。Office 引擎参考仍适用于 Word/PowerPoint 预览与独立转换使用方;转换能力仍支持表格。

影响

渲染器用部分 Excel 保真度换取浏览器内导航和可复用的转换代码。包 README 负责说明支持的格式、资源默认值和不支持的功能。真实 XLSX/XLS fixture 和分隔文本用例覆盖转换,Worker 测试覆盖取消和清理,发布 profile 的浏览器场景在禁用 Office 转换后打开工作簿,并在只读设置下复制已保存的 XLOOKUP 结果。该场景还验证 XLS 工作表切换,以及 CSV/TSV 字面值复制、纯文本切换和重新载入。由于公共 npm 仓库版本过旧,SheetJS CE 固定使用官方发布的 tarball;其 Apache-2.0 许可证沿用现有宽松许可证及打包声明规则。

绘图过滤增加 ZIP 检查,并在移除部件时分配临时未压缩 ZIP。现有 Worker 生命周期和源文件/矩阵限制仍然适用,但不约束解压后的内存。绘图 fixture 覆盖默认及替代前缀、保留 XML 和输入字节的逐字节一致性、图片、形状及批注 VML。浏览器场景检查提示、已保存值的复制,以及文件替换后的提示移除。增加绘图渲染时,必须同时重新审视过滤和提示分类;仅修复命名空间不能恢复该能力。