Skip to content

fix(pro): downgrade @clerk/clerk-js to v5 — actual fix for sign-in modal#3232

Merged
koala73 merged 1 commit into
mainfrom
fix/pro-clerk-v5-downgrade
Apr 20, 2026
Merged

fix(pro): downgrade @clerk/clerk-js to v5 — actual fix for sign-in modal#3232
koala73 merged 1 commit into
mainfrom
fix/pro-clerk-v5-downgrade

Conversation

@koala73

@koala73 koala73 commented Apr 20, 2026

Copy link
Copy Markdown
Owner

TL;DR

PRs #3227 and #3228 did NOT fix the production sign-in bug. The deployed `clerk.no-rhc-UeQvd9Xf.js` chunk still throws "Clerk was not loaded with Ui components" because the entire v6 line of `@clerk/clerk-js` (whether the default headless export or the `/no-rhc` bundled variant) requires the caller to wire up a UI controller — neither variant auto-mounts UI on `clerk.load()`.

This PR pins pro-test to `@clerk/clerk-js@^5.125.7`, the same major version the working main app at `worldmonitor.app/` uses. v5 still auto-mounts UI on `clerk.load()`, so the plain `import { Clerk } from '@clerk/clerk-js'` pattern (which the main app uses verbatim and which pro-test had before #3227) just works.

Why my earlier diagnosis was wrong

I claimed `@clerk/clerk-js/no-rhc` was a "drop-in bundled-UI variant". That's false on v6. `no-rhc` ("no Remote Hosted Code") just removes the runtime CDN chunk loader — it does NOT auto-register the UI controller. Per Clerk's docs, even with no-rhc you still need:

```js
const script = document.createElement('script');
script.src = `https://${clerkDomain}/npm/@clerk/ui@1/dist/ui.browser.js`;
// ... wait for load ...
await clerk.load({ ui: { ClerkUI: window.__internal_ClerkUICtor } });
```

Both the headless and no-rhc v6 builds throw the same `assertComponentsReady` error if you skip that wiring. The user's screenshot from production confirmed it: stack trace points at `clerk.no-rhc-UeQvd9Xf.js:22:203968`, exactly the same assertion that fired on the original headless bundle.

Why I missed it during diagnosis

The main app uses `@clerk/clerk-js` v5.125.7 — installed in the repo root `node_modules`. I only inspected pro-test's `node_modules/@clerk/clerk-js` (v6.4.0) and didn't compare versions. The two `Clerk` named exports look identical to TypeScript and at the source level, but their runtime contracts diverge sharply at the v5→v6 boundary.

Verification

Build output of the rebuilt chunk vs main app's working chunk:

Marker This PR (`clerk-PNSFEZs8.js`) Main app (`clerk-DC7Q2aDh.js`)
Size 3,052,870 B 3,053,136 B
`mountComponent` 44 44
`SignInComponent` 3 3
`openSignIn` 2 2
`Clerk was not loaded with Ui` 0 0

The rebuilt /pro chunk now matches the production main-app chunk byte-for-byte in structure. The assertion error string is absent because v5 unconditionally mounts UI inside `clerk.load()`.

Compare the broken v6/no-rhc chunk that's currently live:

  • Size: 810,612 B (3.5x smaller — UI controller registration code missing)
  • `Clerk was not loaded with Ui`: 1 (assertion always fires when no UI ctor passed)

Diff

  • `pro-test/package.json` — `@clerk/clerk-js` ^6.4.0 → ^5.125.7
  • `pro-test/package-lock.json` — regenerated
  • `pro-test/src/services/checkout.ts` — revert `/no-rhc` import to plain `@clerk/clerk-js`
  • `public/pro/assets/clerk-PNSFEZs8.js` (NEW) — v5 build, 3MB, UI auto-mounted
  • `public/pro/assets/index-zHF6-nOX.js` (NEW) — app bundle pointing at it
  • `public/pro/assets/clerk.no-rhc-UeQvd9Xf.js` (DEL) — broken v6 chunk
  • `public/pro/assets/index-CFLOgmG-.js` (DEL) — old app bundle

Test plan

  • Merge + Vercel deploy.
  • Visit `/pro` as anonymous user, click SIGN IN → modal opens, no console error.
  • Click pricing GET STARTED on Pro tier → modal opens.
  • Sign in → checkout flow auto-resumes via the existing `pendingProductId` listener.
  • Bonus: PR chore(ci): enforce pro-test bundle freshness — local hook + CI backstop #3229's CI freshness check should now succeed because `public/pro/` reflects the rebuild.

Follow-up

Worth a separate spike to either (a) figure out the correct v6 wiring (load `@clerk/ui` from CDN per the docs, with appropriate CSP allowance and error handling) and re-upgrade, or (b) wait until `@clerk/ui` is published as an npm-importable package so we can stop depending on the CDN script tag. Until then, v5 is fine — that's what the main app runs in production.

The actual root cause behind the "Clerk was not loaded with Ui
components" sign-in failure on /pro is NOT the import path — it's
that pro-test was on @clerk/clerk-js v6.4.0 while the main app
(which works fine) is on v5.125.7.

Clerk v6 fundamentally changed `clerk.load()`: the UI controller
is no longer auto-mounted by default. Both `@clerk/clerk-js` (the
default v6 entry) and `@clerk/clerk-js/no-rhc` (the bundled-UI
variant) expect the caller to either:
  - load Clerk's UI bundle from CDN and pass `window.__internal_ClerkUICtor`
    to `clerk.load({ ui: { ClerkUI } })`, or
  - manually wire up `clerkUICtor`.

That's why my earlier "switch to no-rhc" fix (PR #3227 + #3228)
didn't actually unbreak production — both v6 variants throw the same
assertion. The error stack on the deployed bundle confirmed it:
`assertComponentsReady` from `clerk.no-rhc-UeQvd9Xf.js`.

Fix: pin pro-test to `@clerk/clerk-js@^5.125.7` to match the main
app's working version. v5 still auto-mounts UI on `clerk.load()` —
no extra wiring needed. The plain `import { Clerk } from '@clerk/clerk-js'`
pattern (which the main app uses verbatim and which pro-test had
before #3227) just works under v5.

Verification of the rebuilt bundle (chunk: clerk-PNSFEZs8.js):
  - 3.05 MB (matches main app's clerk-DC7Q2aDh.js: 3.05 MB)
  - 44 occurrences of mountComponent (matches main: 44)
  - 3 occurrences of SignInComponent (matches main: 3)
  - 0 occurrences of "Clerk was not loaded with Ui" (the assertion
    error string is absent; UI is unconditionally mounted)

Includes the rebuilt public/pro/ artifacts so this fix is actually
deployed (PR #3229's CI check will catch any future PR that touches
pro-test/src without rebuilding).
@vercel

vercel Bot commented Apr 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
worldmonitor Ignored Ignored Apr 20, 2026 11:16am

Request Review

@greptile-apps

greptile-apps Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR downgrades @clerk/clerk-js from v6.4.0 to v5.125.7 in the pro-test sub-package and reverts the service import from @clerk/clerk-js/no-rhc back to plain @clerk/clerk-js. The root cause (assertComponentsReady error) is correctly identified: v6 requires explicit UI controller wiring that v5 does automatically inside clerk.load(), and v5 matches what the main app already ships successfully.

Confidence Score: 5/5

Safe to merge — the fix is a targeted, well-justified version pin with no logic changes and matching production evidence.

All changes are P2 or lower. The version downgrade is the minimal correct fix, the import revert is accurate, rebuilt assets are verified against the main-app chunk, and the PR description provides thorough root-cause analysis with size/marker verification.

No files require special attention. The committed 3 MB Clerk bundle is intentional per the project's existing convention for pre-built /pro assets.

Important Files Changed

Filename Overview
pro-test/package.json Downgrades @clerk/clerk-js from ^6.4.0 to ^5.125.7 — the core fix, aligning with the main app's working dependency.
pro-test/src/services/checkout.ts Reverts dynamic import from @clerk/clerk-js/no-rhc back to @clerk/clerk-js; rest of the logic (load guard, listener, checkout flow) is unchanged and correct.
public/pro/index.html References updated bundle index-zHF6-nOX.js and drops stale index-CFLOgmG-.js; no logic changes.
public/pro/assets/clerk-PNSFEZs8.js New v5 Clerk bundle (~3 MB), replacing the broken v6/no-rhc chunk; committed as a pre-built static asset per existing project convention.
public/pro/assets/clerk.no-rhc-UeQvd9Xf.js Deleted — was the broken v6/no-rhc chunk that always triggered the assertComponentsReady error.
pro-test/package-lock.json Regenerated lockfile reflecting the v5 Clerk dependency tree; expected change.

Sequence Diagram

sequenceDiagram
    participant User
    participant Pro Page
    participant checkout.ts
    participant ClerkJS v5
    participant API

    User->>Pro Page: clicks SIGN IN / GET STARTED
    Pro Page->>checkout.ts: startCheckout(productId)
    checkout.ts->>checkout.ts: ensureClerk()
    checkout.ts->>ClerkJS v5: import('@clerk/clerk-js')
    checkout.ts->>ClerkJS v5: new Clerk(key)
    checkout.ts->>ClerkJS v5: instance.load({ appearance })
    Note over ClerkJS v5: v5 auto-mounts UI controller inside load()
    ClerkJS v5-->>checkout.ts: ready (UI mounted)
    checkout.ts->>checkout.ts: addListener (pending checkout)
    checkout.ts->>ClerkJS v5: openSignIn()
    ClerkJS v5-->>User: Sign-in modal opens
    User->>ClerkJS v5: signs in
    ClerkJS v5->>checkout.ts: listener fires (user set)
    checkout.ts->>API: POST /create-checkout (Bearer token)
    API-->>checkout.ts: { checkout_url }
    checkout.ts->>User: DodoPayments overlay opens
Loading

Reviews (1): Last reviewed commit: "fix(pro): downgrade @clerk/clerk-js to v..." | Re-trigger Greptile

@koala73
koala73 merged commit d7393d8 into main Apr 20, 2026
11 checks passed
@koala73
koala73 deleted the fix/pro-clerk-v5-downgrade branch April 20, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant