fix(website): remove Wistia players on unmount - #20056
Draft
posthog[bot] wants to merge 1 commit into
Draft
Conversation
The three hand-rolled Wistia wrappers detached the player's DOM without telling the player to stop. The vendor script kept the player registered and its timers running against nodes that no longer existed, so its event relay threw. Each wrapper now calls the player's own remove() before it clears the container. WistiaCustomPlayer loses its no-op cleanup. A shared removeWistiaPlayer() helper holds the teardown and swallows a vendor error so unmount always finishes. The onReady callbacks also check that the ready player belongs to their own embed. A _wq entry stays registered against its media id, so an entry from an earlier mount also receives a later mount's player. Generated-By: PostHog Desktop Task-Id: c6cd30ed-97b5-4688-ae54-0b60191c98b0
Contributor
Deploy preview
|
Contributor
Bundle reportTotal JS (gzip)8.86 MiB (+0.3 KiB / +0.0%) Eager graph (modules shipped in each entrypoint's initial chunks)
Largest modules in the
|
| Module | Size |
|---|---|
./src/data/mcp-tools.json |
1119.4 KiB |
css ./node_modules/.pnpm/css-loader@5.2.7_webpack@5.101.3/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[1]!./node_modules/.pnpm/postcss-loader@4.3.0_postcss@8.5.6_webpack@5.101.3/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[2]!./src/styles/global.css |
761.0 KiB |
./src/components/Stickers/Stickers.tsx |
696.4 KiB |
./node_modules/.pnpm/@radix-ui+react-icons@1.3.2_react@18.3.1/node_modules/@radix-ui/react-icons/dist/react-icons.esm.js |
481.4 KiB |
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/x-ray.mjs |
480.8 KiB |
./node_modules/.pnpm/rehype-raw@7.0.0/node_modules/rehype-raw/lib/index.js + 29 modules |
395.1 KiB |
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/im-the-driver.mjs |
385.7 KiB |
./src/hooks/useCustomers.tsx + 55 modules |
370.0 KiB |
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
354.8 KiB |
./node_modules/.pnpm/react-markdown@8.0.7_@types+react@16.14.66_react@18.3.1/node_modules/react-markdown/lib/react-markdown.js + 88 modules |
351.4 KiB |
./src/components/ProductComparisonTable/index.tsx + 126 modules |
302.5 KiB |
./node_modules/.pnpm/cloudinary-core@2.14.0_lodash@4.17.21/node_modules/cloudinary-core/cloudinary-core.js |
281.9 KiB |
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/doll-house.mjs |
281.7 KiB |
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/director.mjs |
275.6 KiB |
./src/components/SearchUI/index.tsx + 87 modules |
273.7 KiB |
Eager-graph budgets are report-only until a baseline is established. Sizes are gzip of public/**/*.js; eager size is webpack module source bytes for the modules actually shipped in the entrypoint's initial chunks (post-tree-shake).
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.
Changes
Our three hand-rolled Wistia wrappers tore the player's DOM out on unmount, but never told the player to stop. Wistia keeps a player registered and its timers running until you call
remove()on it. The result is a player that keeps firing events at nodes that no longer exist, and a vendor event relay that throws when it dereferences internals that are gone.TypeErrors from the vendor script. Every visit that leaves such a page also leaks a live player that keeps running for the rest of the session.containerRef.current.innerHTML = ''(WistiaVideo,MediaPlayer) or did nothing at all.WistiaCustomPlayerhad a cleanup that only wrote to the console and let the player persist on purpose.remove()before it clears its container.innerHTML = ''is no longer used as a lifecycle tool._wqentry stays registered against its media id, so an entry from an earlier mount also receives a later mount's player. EachonReadynow checks that the player belongs to its own embed. Without this check, an unmounted player's callback destroys a live video.src/lib/wistia.tsholds the teardown and swallows a vendor error, so unmount always finishes.Mechanical: an import line per component, and a
test:wistiascript that follows the existingtest:navsandtest:sdk-referencespattern.Not a visual change. Nothing renders differently. The change only affects what happens after React unmounts a player, so there are no screenshots.
🗺️ PR tour
1. The shared teardown —
src/lib/wistia.ts(new)Start here. One function. It calls the player's
remove()and swallows an error, because a teardown that throws is as bad as no teardown. The comment records why detaching the container is not enough.posthog.com/src/lib/wistia.ts
Lines 1 to 13 in 09c6e42
2.
WistiaVideo— the wrapper in the signalThis is the component the homepage demo uses. Cleanup unbinds the
endhandler as before, then removes the player, then empties the container.replaceChildren()replacesinnerHTML = ''. It covers an embed that never became a player. The container is already held incontainerRef, so no new ref is needed.posthog.com/src/components/WistiaVideo/index.tsx
Lines 57 to 72 in 09c6e42
3.
WistiaCustomPlayer— the persist-forever no-opThe old cleanup logged a message and kept the player alive on purpose. The comment said this stopped re-initialization on tab focus changes, but the effect only depends on
mediaId, and React does not re-run effects on focus. The guard above it already skips an existing player.The new cleanup removes the player, clears the ref, resets
isReady, and drops an embed that never initialized.posthog.com/src/components/WistiaCustomPlayer/index.tsx
Lines 531 to 541 in 09c6e42
4. The
onReadyidentity guard — both_wqwrappersSame three lines in
WistiaCustomPlayerandMediaPlayer. A stale entry must not touch a player it does not own. See the reviewer's guide for the measurement that made this necessary.posthog.com/src/components/WistiaCustomPlayer/index.tsx
Lines 135 to 145 in 09c6e42
5.
MediaPlayer— the Wistia branch had no cleanup at allThe Wistia branch returned nothing, so a player survived both unmount and every change of
videoId,source,startTime, orborderRadius.Two things here beyond the common pattern. The cleanup sets the player in state to
null, because a 250 ms interval pollsplayer.time()and must stop. It also drops the localplayerreference, because Wistia retains the pushed_wqentry and itsonReadyclosure shares this scope.embedDivstays, since the callback still needs it to recognize its own embed.posthog.com/src/components/MediaPlayer/index.tsx
Lines 216 to 230 in 09c6e42
6. Tests and script —
src/lib/wistia.test.ts,package.jsonThree cases on the helper: it delegates, it stays quiet with no player, and it swallows a vendor error. Run with
pnpm test:wistia.🔍 Reviewer's guide
Testing done
npx prettier --checkon the 5 changed filesnpx tsc --noEmitsrc/. The 267 reported errors are all pre-existingnode_modulestype-parse noisenpx eslinton the 4 changed componentsanyand unused-var warningspnpm test:wistiapnpm start, loaded/and/ai/ai, client-side navigation away (a real React unmount), before the fixWistia.api.all().lengthstays at 2 while.wistia_embedcount drops to 0 — players alive, DOM goneremove()E-v1.js, video playing, then teardowninnerHTML = ''leaves atimechangetick firing after teardown.remove()leaves none_wqreuseonReadyreceives the new player (video.containeris not its own embed). This is what the identity guard preventsNot tested: the production build (
pnpm build) and the Vercel preview. Both need a full build, which exceeds this environment. iOS Safari, the browser in the original signal, was not available — the fix targets the mechanism, which was measured on Chromium.Where the risk is
_wqentry'sonReadywould callremove()on a newly mounted player and leave a dead video. This is measured, not theoretical.remove()on one nulls state the other still uses, and the vendor throws. This shows up on/aiin dev, which mountsDemostwice. With one player — what the homepage renders — teardown is silent. Detaching the DOM withoutremove()throws in the same place, so this is a vendor constraint rather than something this change introduces.WistiaCustomPlayerreverses a deliberate decision. If the player was kept alive for a reason not written in the comment, this is the hunk that would show it.Deliberately left out
MediaPlayerhas the same missing teardown: itsYT.Playeris never captured and never destroyed. It is a different vendor and not part of the reported errors, so it stays out of this diff.!window.Wistiascript loader is still copy-pasted in three places and does not dedupe an in-flight load, so two wrappers mounting together can each append the script.WistiaCustomPlayer'sonReady(captions polling) still outlive unmount. Their bodies swallow errors, so they leak quietly rather than throw.@wistia/wistia-player-react, whichWistiaEmbedalready uses, would delete this whole class of bug.WistiaVideois the natural first candidate. That is a rewrite per component, not this PR.Checklist
vercel.json— no pages movedCreated with PostHog Desktop from this inbox report.