Skip to content

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
    • Removed an unload handler that could trigger "Leave site?" prompts and interfere with browser back/forward cache, improving navigation and page restoration while preserving existing lock behavior.

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

🦋 Changeset detected

Latest commit: 17726af

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@clerk/clerk-js Patch
@clerk/chrome-extension Patch
@clerk/expo Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another 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

Removed the beforeunload event listener from the SafeLock implementation in the authentication module; the listener that previously called lock.releaseLock(key) on page unload is no longer registered. The lock acquisition and release logic otherwise remains unchanged: it still prefers the navigator.locks API when available and falls back to the browser-tabs-lock mechanism. The public signature SafeLock(key: string) 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.
Linked Issues check ✅ Passed The PR fully addresses #7714's requirement to remove the beforeunload listener that was degrading browser navigation performance and disabling bfcache.
Out of Scope Changes check ✅ Passed All changes are directly scoped to removing the beforeunload listener from SafeLock and updating the changelog; no unrelated modifications present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately and concisely summarizes the main change: removing the beforeunload event listener from SafeLock, which is the primary focus of the changeset and directly addresses the performance issue described in the PR objectives.

✏️ 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.

Copy link
Member

@nikosdouvlis nikosdouvlis left a comment

Choose a reason for hiding this comment

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

Makes sense, I verified the claims against the library source, thank you

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.changeset/remove-beforeunload-safelock.md:
- Line 5: Update the changelog entry to remove the unsupported claim about
triggering "Leave site?" prompts and instead state that the removed window
"beforeunload" listener in SafeLock caused bfcache disablement; reference the
SafeLock component and the removed beforeunload handler (which called
lock.releaseLock(key)) so the description clearly attributes the change to
bfcache impact and not to prompt behavior, and optionally mention issue `#7714`
for context.

bsingerftm and others added 2 commits February 9, 2026 11:46
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@wobsoriano wobsoriano changed the title Remove beforeunload event listener from SafeLock fix(clerk-js): Remove beforeunload event listener from SafeLock Feb 9, 2026
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

3 participants