Skip to content

Commit fb11e32

Browse files
authored
fix(react): Use globalThis instead of bare global in the browser Clerk loader (#8909)
1 parent f4488f5 commit fb11e32

2 files changed

Lines changed: 14 additions & 11 deletions

File tree

.changeset/silly-pumas-cheer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/react': patch
3+
---
4+
5+
Fix `ReferenceError: global is not defined` thrown from the browser Clerk loader during `<ClerkProvider>` startup in production builds (seen in TanStack Start and React Router apps). The loader now reads the Clerk global via `globalThis` instead of relying on a `window.global` polyfill side-effect, whose load order across bundler chunks was not guaranteed.

packages/react/src/isomorphicClerk.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,11 @@ const SDK_METADATA = {
9191
environment: process.env.NODE_ENV,
9292
};
9393

94-
export interface Global {
95-
Clerk?: HeadlessBrowserClerk | BrowserClerk;
96-
__internal_ClerkUICtor?: ClerkUIConstructor;
94+
declare global {
95+
var Clerk: HeadlessBrowserClerk | BrowserClerk | undefined;
96+
var __internal_ClerkUICtor: ClerkUIConstructor | undefined;
9797
}
9898

99-
declare const global: Global;
100-
10199
type GenericFunction<TArgs = never> = (...args: TArgs[]) => unknown;
102100

103101
type MethodName<T> = {
@@ -548,19 +546,19 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
548546
});
549547
}
550548

551-
// Otherwise, set global.Clerk to the bundled ctor or instance
549+
// Otherwise, set globalThis.Clerk to the bundled ctor or instance
552550
if (this.options.Clerk && !this.options.__internal_clerkJSUrl) {
553-
global.Clerk = isConstructor<BrowserClerkConstructor | HeadlessBrowserClerkConstructor>(this.options.Clerk)
551+
globalThis.Clerk = isConstructor<BrowserClerkConstructor | HeadlessBrowserClerkConstructor>(this.options.Clerk)
554552
? new this.options.Clerk(this.#publishableKey, { proxyUrl: this.proxyUrl, domain: this.domain })
555553
: this.options.Clerk;
556554
}
557555

558-
if (!global.Clerk) {
556+
if (!globalThis.Clerk) {
559557
// TODO @nikos: somehow throw if clerk ui failed to load but it was not headless
560558
throw new Error('Failed to download latest ClerkJS. Contact support@clerk.com.');
561559
}
562560

563-
return global.Clerk;
561+
return globalThis.Clerk;
564562
}
565563

566564
private async getClerkUIEntryChunk(): Promise<ClerkUIConstructor | undefined> {
@@ -587,11 +585,11 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
587585
nonce: this.options.nonce,
588586
});
589587

590-
if (!global.__internal_ClerkUICtor) {
588+
if (!globalThis.__internal_ClerkUICtor) {
591589
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
592590
}
593591

594-
return global.__internal_ClerkUICtor;
592+
return globalThis.__internal_ClerkUICtor;
595593
}
596594

597595
return undefined;

0 commit comments

Comments
 (0)