fix: handle non-configurable window.Shopify from browser extensions (#3575)#3850
Open
AndrianBalanescu wants to merge 2 commits into
Open
fix: handle non-configurable window.Shopify from browser extensions (#3575)#3850AndrianBalanescu wants to merge 2 commits into
AndrianBalanescu wants to merge 2 commits into
Conversation
…refs Shopify#3575) Browser extensions like Urban VPN define window.Shopify as non-configurable, causing Object.defineProperty(window, "Shopify", ...) to throw a TypeError and crash the entire Hydrogen app. This wraps the defineProperty call in a try/catch and falls back to polling for window.Shopify.customerPrivacy when the property cannot be redefined. The customerPrivacy override logic is extracted into a shared function that both the defineProperty path and the polling fallback use. Maintainer-suggested approach from issue Shopify#3575.
The setInterval/setTimeout created in the polling fallback path (for when browser extensions make window.Shopify non-configurable) were never cleaned up on component unmount. This caused: - setInterval continuing to fire every 50ms after unmount - Potential state updates on unmounted component - Memory leak until the 30s timeout fired Added cleanupPolling function returned from useEffect that clears both the interval and timeout, matching the cleanup pattern used by other useEffect hooks in the same file.
Author
|
Cycle 520 QA: Fixed polling cleanup leak in the non-configurable window.Shopify fallback path. The setInterval (50ms) and setTimeout (30s) created in the polling fallback were never cleaned up on component unmount, causing memory leaks and potential state updates on unmounted components. Added cleanupPolling function returned from useEffect that clears both timers, matching the cleanup pattern used by other useEffect hooks in the same file. All 10 tests still pass. |
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.
Fix: "Cannot redefine property: Shopify" crash with browser extensions (#3575)
Problem
Browser extensions like Urban VPN define
window.Shopifyas a non-configurable property. When Hydrogen's customer privacy API tries to callObject.defineProperty(window, 'Shopify', ...), it throws aTypeError: Cannot redefine property: Shopify, crashing the entire Hydrogen app for affected users.This has been confirmed by multiple users in #3575 since March 2026.
Solution
As suggested by @frandiox in this comment, the fix avoids relying on
Object.definePropertybeing successful:Wrap
Object.defineProperty(window, 'Shopify', ...)in a try/catch — if the property is non-configurable, the error is caught gracefully instead of crashing the app.Fall back to polling — when
definePropertyfails, a lightweight polling mechanism (every 50ms, cleaned up after 30s) monitorswindow.Shopifyfor thecustomerPrivacyassignment and applies the same override logic.Extracted shared override function — the
customerPrivacygetter/setter logic is extracted intooverrideCustomerPrivacy(), used by both thedefinePropertypath and the polling fallback, ensuring consistent behavior.The previous PR #3576 was closed without merge. This PR takes the maintainer-suggested approach and includes a fallback for maximum resilience.
Testing
window.Shopify(as browser extensions create), verifying the hook does not crash and still processescustomerPrivacyvia the polling fallbackChangeset
@shopify/hydrogen: patchFixes #3575