Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silly-pumas-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/react': patch
---

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.
20 changes: 9 additions & 11 deletions packages/react/src/isomorphicClerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,11 @@ const SDK_METADATA = {
environment: process.env.NODE_ENV,
};

export interface Global {
Clerk?: HeadlessBrowserClerk | BrowserClerk;
__internal_ClerkUICtor?: ClerkUIConstructor;
declare global {
var Clerk: HeadlessBrowserClerk | BrowserClerk | undefined;
var __internal_ClerkUICtor: ClerkUIConstructor | undefined;
}

declare const global: Global;

type GenericFunction<TArgs = never> = (...args: TArgs[]) => unknown;

type MethodName<T> = {
Expand Down Expand Up @@ -548,19 +546,19 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
});
}

// Otherwise, set global.Clerk to the bundled ctor or instance
// Otherwise, set globalThis.Clerk to the bundled ctor or instance
if (this.options.Clerk && !this.options.__internal_clerkJSUrl) {
global.Clerk = isConstructor<BrowserClerkConstructor | HeadlessBrowserClerkConstructor>(this.options.Clerk)
globalThis.Clerk = isConstructor<BrowserClerkConstructor | HeadlessBrowserClerkConstructor>(this.options.Clerk)
? new this.options.Clerk(this.#publishableKey, { proxyUrl: this.proxyUrl, domain: this.domain })
: this.options.Clerk;
}

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

return global.Clerk;
return globalThis.Clerk;
}

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

if (!global.__internal_ClerkUICtor) {
if (!globalThis.__internal_ClerkUICtor) {
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
}

return global.__internal_ClerkUICtor;
return globalThis.__internal_ClerkUICtor;
}

return undefined;
Expand Down
Loading