diff --git a/.changeset/solid-symbols-sink.md b/.changeset/solid-symbols-sink.md new file mode 100644 index 0000000000..81200c60ec --- /dev/null +++ b/.changeset/solid-symbols-sink.md @@ -0,0 +1,5 @@ +--- +'@tanstack/router-core': patch +--- + +delete $\_TSR immediately on stream end diff --git a/packages/router-core/src/ssr/tsrScript.ts b/packages/router-core/src/ssr/tsrScript.ts index 0c4b8f703b..69c9abe05d 100644 --- a/packages/router-core/src/ssr/tsrScript.ts +++ b/packages/router-core/src/ssr/tsrScript.ts @@ -9,17 +9,8 @@ self.$_TSR = { }, c() { if (this.hydrated && this.streamEnded) { - const cleanup = () => { - if (self.$_TSR?.hydrated && self.$_TSR?.streamEnded) { - delete self.$_TSR - delete self.$R['tsr'] - } - } - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', cleanup, { once: true }) - } else { - cleanup() - } + delete self.$_TSR + delete self.$R['tsr'] } }, p(script) { diff --git a/packages/router-core/tests/tsr-script-teardown.test.ts b/packages/router-core/tests/tsr-script-teardown.test.ts new file mode 100644 index 0000000000..2355e1c99a --- /dev/null +++ b/packages/router-core/tests/tsr-script-teardown.test.ts @@ -0,0 +1,46 @@ +import { afterEach, beforeEach, describe, expect, test } from 'vitest' +import minifiedTsrBootStrapScript from '../src/ssr/tsrScript?script-string' + +type TsrBootstrap = { + h: () => void + e: () => void + c: () => void +} + +// Assign `self.$_TSR`. +function installBootstrap(): TsrBootstrap { + new Function(minifiedTsrBootStrapScript)() + return (window as any).$_TSR +} + +describe('$_TSR client teardown', () => { + beforeEach(() => { + ;(window as any).$R = { tsr: [] } + delete (window as any).$_TSR + }) + + afterEach(() => { + delete (window as any).$_TSR + delete (window as any).$R + }) + + test('does not tear down until both hydrated and streamEnded', () => { + const tsr = installBootstrap() + + tsr.h() + expect((window as any).$_TSR).toBeDefined() + + tsr.e() + expect((window as any).$_TSR).toBeUndefined() + }) + + test('removes both $_TSR and $R[tsr] on teardown', () => { + const tsr = installBootstrap() + + tsr.h() + tsr.e() + + expect((window as any).$_TSR).toBeUndefined() + expect((window as any).$R.tsr).toBeUndefined() + }) +})