docs(guide): how to load many sheets without paying for it (HF-360) - #1759
Open
marcin-kordas-hoc wants to merge 5 commits into
Open
marcin-kordas-hoc wants to merge 5 commits into
marcin-kordas-hoc wants to merge 5 commits into
Conversation
…-15559) Loading sheets one by one is the slowest way to get data into the engine, and the guide never said so. Every setSheetContent call recalculates the loaded cells that depend on the sheet it just filled, so with cross-sheet references the cost of a per-sheet loop grows with every step; a customer case measured it at over a hundred times the cost of a single buildFromSheets call for 500 cross-referencing sheets. The section states the rule, explains the mechanism, notes that pre-registering sheet names only removes the extra recalculation addSheet triggers and not the growth itself, and points to batch operations for the case where the data is not known upfront. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…OT-15559) Three more findings from the same customer case, all of them things the guide never said: - A formula that references a sheet added later is repaired when that sheet arrives, without re-parsing, so load order is free. It also means ordering the inserts by dependency is not a fix for the cost of incremental loading: it holds only while every reference points one way. - Reads throw while the evaluation is suspended, which is what turns a batch around a load loop into a crash in a host application that renders from the engine. - Integrations that accept the HyperFormula class build an empty engine and add sheets one at a time; hand them an instance instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4dd93e4. Configure here.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
hyperformula-docs | f9326a9 | Commit Preview URL Branch Preview URL |
Sep 11 2026, 03:27 AM |
- Drop the `loading` tag: every other guide page stops at ten tags and this page was the only one at eleven. The word is already in the heading it would index. - Don't restate what "Suspending automatic recalculations" further down the same page already says; link to it instead. - Attribute the doubling to the measurement it comes from rather than stating it as a property of addSheet. - "Order of loading" as a noun phrase, matching every other heading on the page, and it no longer reads as an absolute the next paragraph walks back. - Say that the placeholder-repair behaviour arrived in 3.1.1; without it the advice is false on earlier releases. - One cell-value convention across both samples. - Don't assert what third-party integrations do in general; state the condition and what to do about it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Performance comparison of head (f9326a9) vs base (c920375) |
"it has to call buildEmpty" asserts a necessity the API does not impose — a library handed the class could collect the data and call buildFromSheets itself. What is true is narrower: the engine gets built on the library's terms, and one that receives sheets one at a time adds them one at a time. Passing a prepared instance is what removes the choice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
The HOT-15559 investigation this section comes from ruled that route out, and the guide left it out. Anyone optimising a slow multi-sheet load will reach for sharding into several instances, so the guide should say what it costs: a formula can only reference a sheet in its own instance, and pointing at one held elsewhere is #REF!. Measured, not carried over from the investigation's own citation: instance A holding Sheet1!A1 = 10, instance B evaluating =Sheet1!A1 against it = #REF!, and the same reference inside one instance = 10. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1759 +/- ##
========================================
Coverage 97.32% 97.32%
========================================
Files 195 195
Lines 15739 15739
Branches 3390 3461 +71
========================================
Hits 15318 15318
+ Misses 421 413 -8
- Partials 0 8 +8 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Context
docs/guide/performance.mdsays nothing about loading. The page coversuseColumnIndex, address-mapping policies, lazy-transformation cleanup and suspending recalculation, and stops there — so the one decision an integrator makes before any of that advice applies, how to get the data in, is undocumented.It matters more than it looks. With a dense cross-sheet dependency graph, loading sheets one at a time is quadratic: as an example, on the released 3.4.0 with 500 cross-referencing sheets the per-sheet loop takes over a hundred times as long as a single
buildFromSheetscall.This adds a "Loading multiple sheets" section and two subsections for the findings that came out of the same investigation:
buildFromSheetsagainst a per-sheetaddSheet+setSheetContentloop, with the mechanism: everysetSheetContentrecalculates the loaded cells that depend on the sheet it just filled, so the work grows with each step.addSheetadds to this whenever the loaded formulas already point at the sheet being added, which is why pre-registering the sheet names removes about half the cost and not the growth.#REF!and is repaired when that sheet arrives, with no re-parse. This shipped in 3.1.1 and is documented nowhere. It also means ordering the inserts by dependency is not a fix for the cost above — it holds only while every reference points one way.HyperFormulaclass callsbuildEmptyand then adds sheets one at a time, which is the slow path by construction.The section also states that reads throw while the evaluation is suspended, and links to batch operations — that is what turns a batch wrapped around a load loop into a crash in a host application that renders from the engine.
How did you test your changes?
Documentation only, no production code touched.
developsource rather than written from memory. ReadingSheet1!B1after the first sample gives10; readingHub!A1through the second gives#REF!, then1afteraddSheet('Later'), then42aftersetSheetContent— the values the sample's comments claim. The samples themselves print nothing; the reads were added to run them.#REF!-repair claim was checked twice: the behaviour on the released 3.4.0, and the mechanism still present ondevelop(SheetMappingplaceholder handling,isPlaceholder).buildFromSheets.grepoverdocs/guide/confirmed the placeholder-sheet behaviour appears in no other page, so this does not contradict or duplicate an existing statement.buildFromSheetsandaddSheetas search tags. The page keeps ten tags, which is the maximum every other guide page observes.Bugbot's findings and a self-review pass are applied in 5f4513b: the tag count, the duplication with the page's own suspension section, the
3.1.1version note on the placeholder behaviour, a noun-phrase heading, one cell-value convention across the samples, and dropping a general claim about third-party integrations in favour of the condition that actually matters.Types of changes
Related issues:
Checklist:
🤖 Generated with Claude Code
Note
Low Risk
Documentation-only change with no runtime or API behavior modifications.
Overview
Adds a Loading multiple sheets section to the performance guide so integrators know how to initialize multi-sheet workbooks without quadratic recalculation cost.
It recommends
buildFromSheetsover per-sheetaddSheet+setSheetContent, explains why incremental loads get slower as cross-sheet dependencies grow (includingaddSheetdirtying when formulas already point at the new sheet), and points runtime loaders at batch operations plus avoiding reads while evaluation is suspended. Subsections cover that load order is flexible since 3.1.1 (#REF!with live repair when a missing sheet arrives), that dependency-ordered inserts do not fix the incremental cost, that one engine instance is required for cross-sheet formulas, and that integrations should receive a pre-built instance rather than the class so they do not rebuild via the slow path.Frontmatter search tags
buildFromSheetsandaddSheetare added.Reviewed by Cursor Bugbot for commit f9326a9. Bugbot is set up for automated code reviews on this repo. Configure here.