Skip to content

Remove beforeunload event listener from SafeLock#7775

Open
bsingerftm wants to merge 2 commits intoclerk:mainfrom
bsingerftm:claude/assess-beforeunload-event-gC7zx
Open

Remove beforeunload event listener from SafeLock#7775
bsingerftm wants to merge 2 commits intoclerk:mainfrom
bsingerftm:claude/assess-beforeunload-event-gC7zx

Conversation

@bsingerftm
Copy link

@bsingerftm bsingerftm commented Feb 5, 2026

Removes the beforeunload event listener from the SafeLock function. This listener was attempting to release locks when the page unloads, but it is both redundant and harmful to user experience.

Why this listener is harmful

The beforeunload event listener disables the browser's back-forward cache (bfcache), which degrades navigation performance. As noted in the codebase itself (beforeUnloadTracker.ts:6-7):

"Ideally we should not be always listening for the beforeUnload event as it effectively disables the browser's BF cache."

This is the root cause of the UX issues reported in #7714.

Why this listener is redundant

The SafeLock function uses a dual-locking strategy:

  1. Web Locks API (primary path for modern browsers)
  • When navigator.locks is available in a secure context, the native Web Locks API is used
  • Locks acquired via Web Locks API are automatically released when the page unloads or the async callback completes
  • The beforeunload handler was calling lock.releaseLock() on the browser-tabs-lock instance, which isn't even used in this code path
  1. browser-tabs-lock fallback (older browsers/non-secure contexts)
  • The library has its own automatic cleanup via timeout mechanism:
  • Locks are refreshed every 1000ms via refreshLockWhileAcquired()
  • A lockCorrector() removes stale locks where timeRefreshed is older than 5 seconds
  • The library itself does not use beforeunload internally
  • When a tab closes without releasing, the lock automatically expires within ~5 seconds

Trade-off analysis

In the fallback case, other tabs may need to wait up to 5 seconds to acquire an orphaned lock. This is acceptable because:

  • The lock timeout is already 5000ms (safeLock.ts:15,27)
  • The poller interval is 5000ms (SessionCookiePoller.ts)
  • The token cache already accounts for "SafeLock contention (~5s)" in its background refresh threshold (tokenCache.ts:111)
  • This only affects the rare case of a tab closing while holding a lock

Additional benefit

This also removes a TypeScript linting issue (@typescript-eslint/no-misused-promises) where an async function was used as an event handler without proper promise handling.

🐛 Bug fix (fixes #7714)

Summary by CodeRabbit

  • Bug Fixes
    • Improved lock management during page navigation by adjusting how locks are released on page unload.

The beforeunload listener was redundant and degraded UX by disabling
the browser's back-forward cache (bfcache). Lock cleanup is handled
automatically:
- Web Locks API releases locks natively on page unload
- browser-tabs-lock has a built-in timeout mechanism that expires
  orphaned locks after ~5 seconds

Fixes clerk#7714

https://claude.ai/code/session_01S2A4oTbEm3huTsR26xkU1E
@changeset-bot
Copy link

changeset-bot bot commented Feb 5, 2026

⚠️ No Changeset found

Latest commit: 78d955b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Feb 5, 2026

@claude is attempting to deploy a commit to the Clerk Production Team on Vercel.

A member of the Team first needs to authorize it.

@bsingerftm bsingerftm marked this pull request as ready for review February 5, 2026 17:02
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

The change removes the beforeunload event listener from the safe lock mechanism in the authentication module. Previously, this listener was registered to call lock.releaseLock(key) when pages unloaded. The removal eliminates this automatic cleanup behavior on page unload. The core lock acquisition functionality remains unchanged, continuing to use the navigator.locks API when available or falling back to the browser-tabs-lock mechanism. The public API signature of the SafeLock function is unchanged.

🚥 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 'Remove beforeunload event listener from SafeLock' directly and accurately summarizes the main change in the pull request.
Linked Issues check ✅ Passed The PR directly addresses issue #7714 by removing the beforeunload event listener that was causing poor UX and disabling browser bfcache, matching the issue's primary objective.
Out of Scope Changes check ✅ Passed The changes are narrowly focused on removing the beforeunload listener from SafeLock, with no unrelated modifications beyond this stated objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove need for beforeunload listener

2 participants