Skip to content

Perf/scan and font cache#100

Merged
eweren merged 6 commits into
tolgee:mainfrom
eweren:perf/scan-and-font-cache
May 13, 2026
Merged

Perf/scan and font cache#100
eweren merged 6 commits into
tolgee:mainfrom
eweren:perf/scan-and-font-cache

Conversation

@eweren

@eweren eweren commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Preserve empty resolved translations instead of treating them as missing.
  • Performance

    • Cache font availability across a session to avoid redundant lookups.
    • More efficient page-wide retrieval of connected text nodes.
    • Avoid unnecessary full rescans when returning to views by honoring cached freshness.
  • UX / Reliability

    • Faster, more consistent updates to connected-node lists after edits.

Review Change Stack

eweren and others added 3 commits May 12, 2026 16:40
Two hot-path optimisations backported from the v2 rewrite:

1. getConnectedNodes (page-wide): replace manual JS recursion +
   per-node getPluginData() with findAllWithCriteria({ pluginData })
   so the Figma runtime does the filtering natively — O(all nodes)
   → O(connected nodes), zero bridge crossings for unrelated nodes.

2. formatText: hoist the availableFonts cache to module scope so
   listAvailableFontsAsync() is called at most once per plugin
   session rather than once per node during a multi-node pull.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After any setNodesData call (connect, disconnect, pull), the mutation's
onSuccess patched only the stale marker, causing a full-page findAll scan
every time the user returned to Index. On large Figma files this was the
source of the ~20-second connect operation delay.

Fix with three coordinated changes:

- useSetNodesDataMutation: replace invalidateQueries with a direct cache
  patch (setQueryData) that adds, updates, or removes only the affected
  nodes — no bridge round-trip needed.

- useConnectedNodes: set staleTime:30s so the freshly-patched cache is
  still considered valid when the Index route-change effect fires.

- Index: guard allNodes.refetch() behind allNodes.isStale, so it only
  rescans when the cache is genuinely outdated (e.g. after Push/Pull
  which use explicit invalidation, or on first mount).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nent

Updated the translation assignment in the Connect component to use nullish coalescing (??) instead of logical OR (||) for better handling of undefined values. This change ensures that the fallback to node.characters only occurs when resolvedTranslation is null or undefined.
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@eweren has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 42 minutes and 19 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 43574e1f-7462-42d6-94da-7855bb53517e

📥 Commits

Reviewing files that changed from the base of the PR and between 3888c4b and cf8f9c9.

📒 Files selected for processing (1)
  • src/main/utils/settingsTools.ts

Walkthrough

The PR optimizes query caching and data fetching across the Figma plugin. It introduces session-level font caching, refactors connected-nodes queries to handle selection vs. page-wide paths separately, and improves the UI layer's React Query strategy with cache expiration, direct patching, and conditional refetch guards. A minor translation fallback operator fix is included.

Changes

Cache Optimization and Connected Nodes Refactoring

Layer / File(s) Summary
Font Availability Caching
src/main/endpoints/formatText.ts
Module-level availableFontsCache and an in-flight availableFontsPromise are added; getAvailableFonts returns cached fonts or shares a single in-flight figma.listAvailableFontsAsync() call.
Connected Nodes Endpoint Refactoring
src/main/endpoints/getConnectedNodes.ts
Endpoint now short-circuits selection-based fetch using findTextNodesInfo on the current selection; page-wide path loads the page and uses findAllWithCriteria for TEXT nodes with TOLGEE_NODE_INFO, mapping via getNodeInfo.
Connected Nodes Query Cache Optimization
src/ui/hooks/useConnectedNodes.ts, src/ui/hooks/useSetNodesDataMutation.ts, src/ui/views/Index/Index.tsx
Adds staleTime: 30_000 to connected-nodes query; mutations patch the connected-nodes cache by merging updates, filtering disconnected entries, and appending new nodes; Index route only refetches all nodes when cache is stale.
Translation Fallback Operator Fix
src/ui/views/Connect/Connect.tsx
Uses resolvedTranslation ?? node.characters instead of `

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tolgee/figma-plugin#69: Modifies font-style discovery and loaders that interact with available-fonts logic, related to the font caching change.
  • tolgee/figma-plugin#98: Overlaps in cache/refetch logic for useSetNodesDataMutation and Index.tsx.
  • tolgee/figma-plugin#91: Related node-connection logic and UI handling of connected nodes.

Suggested reviewers

  • JanCizmar
  • dkrizan
  • ZuzanaOdstrcilova

Poem

🐰 A rabbit hums in code and cheer,
Fonts cached once — no more repeat, my dear.
Nodes connect with careful care,
Cache patched gently, refetch spared,
Empty strings kept — hooray, cache cleared! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Perf/scan and font cache' accurately reflects the main changes: performance optimizations for font caching and node scanning/connected nodes retrieval.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/endpoints/formatText.ts`:
- Around line 73-76: formatText's font-loading logic races because multiple
concurrent callers can see availableFontsCache null and each call
figma.listAvailableFontsAsync(); introduce an in-flight promise (e.g.,
availableFontsPromise) alongside availableFontsCache, set availableFontsPromise
= figma.listAvailableFontsAsync() before awaiting, await that promise to
populate availableFontsCache, return cached value for subsequent callers, and on
rejection clear availableFontsPromise (and leave availableFontsCache null) so
future attempts retry; update any references in formatText to use the promise
cache to dedupe concurrent requests.

In `@src/ui/hooks/useSetNodesDataMutation.ts`:
- Around line 27-31: The multiline ternary inside the Array.prototype.map
callback (the block that checks patch.has(item.id) and uses patch.get(item.id))
violates Prettier; replace it with a single-line ternary or an explicit block
return to satisfy formatting—for example, change the map callback to either:
map((item) => patch.has(item.id) ? { ...item, ...patch.get(item.id)! } : item)
or convert to a block: map((item) => { if (patch.has(item.id)) return { ...item,
...patch.get(item.id)! }; return item; }) so that the expressions using
patch.has and patch.get in useSetNodesDataMutation are flattened and
Prettier-friendly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3da73715-6335-453d-a8bb-8e564a2c4312

📥 Commits

Reviewing files that changed from the base of the PR and between 52c604e and 1e28075.

📒 Files selected for processing (6)
  • src/main/endpoints/formatText.ts
  • src/main/endpoints/getConnectedNodes.ts
  • src/ui/hooks/useConnectedNodes.ts
  • src/ui/hooks/useSetNodesDataMutation.ts
  • src/ui/views/Connect/Connect.tsx
  • src/ui/views/Index/Index.tsx

Comment thread src/main/endpoints/formatText.ts Outdated
Comment thread src/ui/hooks/useSetNodesDataMutation.ts
eweren and others added 3 commits May 12, 2026 17:04
Enhanced the font retrieval logic in formatText by introducing an in-flight promise to prevent concurrent requests for available fonts. This change ensures that the listAvailableFontsAsync function is called only once while the promise is pending, improving performance and reducing unnecessary API calls.
… characters

When Index remounts after navigating back from Pull, mountedRef resets to
false and the route-change effect treats the mount as the first render,
skipping selectionLoadable.refetch(). Marking the selectedNodes query stale
in onSuccess ensures useQuery triggers a background refetch on remount so
the updated node characters are visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updated the getGlobalSettings function to return a Promise with a Partial<GlobalSettings> type. Improved error handling for clientStorage data retrieval by checking for both string and already-parsed object formats, ensuring robust data parsing and reducing potential errors.
@eweren eweren enabled auto-merge May 12, 2026 16:19
@eweren eweren merged commit f1b742d into tolgee:main May 13, 2026
4 checks passed
@eweren eweren deleted the perf/scan-and-font-cache branch May 13, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants