fix(pro): regenerate /pro bundle so deployed assets reflect #3227 Clerk fix#3228
Conversation
…3227 PR #3227 fixed pro-test/src/services/checkout.ts to import @clerk/clerk-js/no-rhc instead of the headless main export, but the deployed bundle in public/pro/assets/ was never regenerated. The Vercel deploy ships whatever is committed under public/pro/ — the root build script does not run pro-test's vite build — so production /pro continued serving the old broken clerk-C6kUTNKl.js even after #3227 merged. Sign-in still threw "Clerk was not loaded with Ui components". Rebuild: cd pro-test && npm run build, which writes the new chunks to ../public/pro/assets/. Deletes the stale clerk-C6kUTNKl.js + index-J1JYVlDk.js, adds clerk.no-rhc-UeQvd9Xf.js + index-CFLOgmG-.js, and updates pro/index.html to reference them.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Greptile SummaryThis PR commits the regenerated Confidence Score: 5/5Safe to merge — build artifacts are internally consistent and directly address the production Clerk modal failure. All four changed files are Vite build outputs. The new index bundle verifiably references clerk.no-rhc-UeQvd9Xf.js, the HTML entry point is updated to the new hash, and the stale headless chunks are deleted. No source logic changes are present and no P0/P1 issues were identified. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["index.html\n(entry point)"] -->|"script src\nindex-CFLOgmG-.js"| B["index-CFLOgmG-.js\n(app bundle)"]
B -->|"dynamic import\nclerk.no-rhc-UeQvd9Xf.js"| C["clerk.no-rhc-UeQvd9Xf.js\n(Clerk UI bundle, ~810 KB)"]
C --> D["✅ Sign-in modal\nmounts correctly"]
E["index.html (old)"] -->|"script src\nindex-J1JYVlDk.js"| F["index-J1JYVlDk.js\n(old app bundle)"]
F -->|"dynamic import\nclerk-C6kUTNKl.js"| G["clerk-C6kUTNKl.js\n(headless Clerk, no UI)"]
G --> H["❌ 'Clerk was not loaded\nwith UI components'"]
style D fill:#22c55e,color:#fff
style H fill:#ef4444,color:#fff
style C fill:#3b82f6,color:#fff
style G fill:#f97316,color:#fff
Reviews (1): Last reviewed commit: "fix(pro): regenerate /pro bundle with no..." | Re-trigger Greptile |
…taleness public/pro/ is committed to the repo and served verbatim by Vercel. The root build script only runs the main app's vite build — it does NOT run pro-test's build. So any PR that changes pro-test/src/** without manually running `cd pro-test && npm run build` and committing the regenerated chunks ships to production with a stale bundle. This footgun just cost us: PR #3227 fixed the Clerk "not loaded with Ui components" sign-in bug in source, merged, deployed — and the live site still threw the error because the committed chunk under public/pro/assets/ was the pre-fix build. PR #3228 fix-forwarded by rebuilding. Two-layer enforcement so it doesn't happen again: 1. .husky/pre-push — mirrors the existing proto freshness block. If pro-test/ changed vs origin/main, rebuild and `git diff --exit-code public/pro/`. Blocks the push with a clear message if the bundle is stale or untracked files appear. 2. .github/workflows/pro-bundle-freshness.yml — CI backstop on any PR touching pro-test/** or public/pro/**. Runs `npm ci + npm run build` in pro-test and fails the check if the working tree shows any diff or untracked files under public/pro/. Required before merge, so bypassing the local hook still can't land a stale bundle. Note: the hook's diff-against-origin/main check means it skips the build when pushing a branch that already matches main on pro-test/ (e.g. fix-forward branches that only touch public/pro/). CI covers that case via its public/pro/** path filter.
The first scoping fix used `^pro-test/` only, but the CI workflow keys off both `pro-test/**` AND `public/pro/**`. That left a gap: a bundle-only PR (e.g. a fix-forward rebuild like #3228, or a hand-edit to a committed asset) skipped the local check entirely while CI would still validate it. The hook and CI are now consistent. Trigger condition: `^(pro-test|public/pro)/` — the rebuild + diff check now fires whenever the branch delta touches either side of the source/artifact pair, matching the CI workflow's path filter.
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).
…op (#3229) * chore(ci): enforce pro-test bundle freshness, prevent silent deploy staleness public/pro/ is committed to the repo and served verbatim by Vercel. The root build script only runs the main app's vite build — it does NOT run pro-test's build. So any PR that changes pro-test/src/** without manually running `cd pro-test && npm run build` and committing the regenerated chunks ships to production with a stale bundle. This footgun just cost us: PR #3227 fixed the Clerk "not loaded with Ui components" sign-in bug in source, merged, deployed — and the live site still threw the error because the committed chunk under public/pro/assets/ was the pre-fix build. PR #3228 fix-forwarded by rebuilding. Two-layer enforcement so it doesn't happen again: 1. .husky/pre-push — mirrors the existing proto freshness block. If pro-test/ changed vs origin/main, rebuild and `git diff --exit-code public/pro/`. Blocks the push with a clear message if the bundle is stale or untracked files appear. 2. .github/workflows/pro-bundle-freshness.yml — CI backstop on any PR touching pro-test/** or public/pro/**. Runs `npm ci + npm run build` in pro-test and fails the check if the working tree shows any diff or untracked files under public/pro/. Required before merge, so bypassing the local hook still can't land a stale bundle. Note: the hook's diff-against-origin/main check means it skips the build when pushing a branch that already matches main on pro-test/ (e.g. fix-forward branches that only touch public/pro/). CI covers that case via its public/pro/** path filter. * fix(hooks): scope pro-test freshness check to branch delta, not worktree The first version of this hook used `git diff --name-only origin/main -- pro-test/`, which compares the WORKING TREE to origin/main. That fires on unstaged local pro-test/ scratch edits and blocks pushing unrelated branches purely because of dirty checkout state. Switch to `$CHANGED_FILES` (computed earlier at line 77 from `git diff origin/main...HEAD`), which scopes the check to commits on the branch being pushed. This matches the convention the test-runner gates already use (lines 93-97). Also honor `$RUN_ALL` as the safety fallback when the branch delta can't be computed. * fix(hooks): trigger pro freshness check on public/pro/ too, match CI The first scoping fix used `^pro-test/` only, but the CI workflow keys off both `pro-test/**` AND `public/pro/**`. That left a gap: a bundle-only PR (e.g. a fix-forward rebuild like #3228, or a hand-edit to a committed asset) skipped the local check entirely while CI would still validate it. The hook and CI are now consistent. Trigger condition: `^(pro-test|public/pro)/` — the rebuild + diff check now fires whenever the branch delta touches either side of the source/artifact pair, matching the CI workflow's path filter.
…3232) 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).
Reviewer flagged that the first iteration's `window.top !== window`
check was too broad. The repo explicitly markets "Embeddable iframe
panels" as an Enterprise feature
(pro-test/src/locales/en.json: whiteLabelDesc), so legitimate
customer embeds must keep firing premium RPCs normally. Only the /pro
marketing preview — which is known-anonymous and generates expected
401 noise — should short-circuit.
Fix: replace the blanket iframe check with a unique marker that only
/pro's preview iframe carries.
- pro-test/src/App.tsx: iframe src switched from
`?alert=false` (dead param, unused in main app) to
`?embed=pro-preview`. Rebuilt public/pro/ to ship the change.
- src/utils/embedded-preview.ts: two-gate check now. Gate 1 still
requires `window.top !== window` so the marker leaking into a
top-level URL doesn't disable premium RPCs for the top-level app.
Gate 2 requires `?embed=pro-preview` in location.search so only
the known embedder matches. Enterprise white-label embeds without
this marker behave exactly like a top-level visit.
Same three premium fetchers + the one country-intel path still gate
on IS_EMBEDDED_PREVIEW; the semantic change is purely in how the
flag is computed.
Per PR #3229 / #3228 lesson, the pro-test rebuild ships in the same
PR as the source change — public/pro/assets/index-*.js and index.html
reflect the new iframe src.
…review iframe (#3235) * fix(preview): skip premium RPCs when main app runs inside /pro preview iframe pro-test/src/App.tsx embeds the full main app as a "live preview" via <iframe src="https://worldmonitor.app?alert=false" sandbox="...">. The iframe boots an anonymous main-app session, which fires premium RPCs (get-regional-snapshot, get-tariff-trends, list-comtrade-flows, and on country-click the fetchProSections batch) with no Clerk bearer available. Every call 401s, the circuit breakers catch and fall through to empty fallbacks (so the preview renders fine), but the 401s surface on the PARENT /pro page's DevTools console and Sentry because `sandbox` includes `allow-same-origin`. Net effect: /pro pricing page shows a flood of fake-looking errors that cost us a session of debugging to trace back to the iframe. PR #3233's premiumFetch swap didn't help here (there's simply no token to inject for an anonymous iframe). Introduce `src/utils/embedded-preview.ts::IS_EMBEDDED_PREVIEW`, a module-level boolean evaluated once at load from `window.top !== window` (with try/catch for cross-origin sandboxes), and short-circuit three init-time premium entry points when true: - RegionalIntelligenceBoard.loadCurrent → renderEmpty() - fetchTariffTrends → return emptyTariffs - fetchComtradeFlows → return emptyComtrade Plus one defensive gate in country-intel.fetchProSections for the case a user clicks a country inside the iframe preview. Each gate returns the exact same empty fallback the breaker would have produced after a 401, so visual behavior is unchanged — the preview iframe still shows the dashboard layout with empty premium panels, just without the network request and its console/Sentry trail. Live-tab /pro page should now see zero 401s from regional-snapshot / tariff-trends / comtrade-flows on load. * fix(preview): narrow iframe gate to ?embed=pro-preview marker only Reviewer flagged that the first iteration's `window.top !== window` check was too broad. The repo explicitly markets "Embeddable iframe panels" as an Enterprise feature (pro-test/src/locales/en.json: whiteLabelDesc), so legitimate customer embeds must keep firing premium RPCs normally. Only the /pro marketing preview — which is known-anonymous and generates expected 401 noise — should short-circuit. Fix: replace the blanket iframe check with a unique marker that only /pro's preview iframe carries. - pro-test/src/App.tsx: iframe src switched from `?alert=false` (dead param, unused in main app) to `?embed=pro-preview`. Rebuilt public/pro/ to ship the change. - src/utils/embedded-preview.ts: two-gate check now. Gate 1 still requires `window.top !== window` so the marker leaking into a top-level URL doesn't disable premium RPCs for the top-level app. Gate 2 requires `?embed=pro-preview` in location.search so only the known embedder matches. Enterprise white-label embeds without this marker behave exactly like a top-level visit. Same three premium fetchers + the one country-intel path still gate on IS_EMBEDDED_PREVIEW; the semantic change is purely in how the flag is computed. Per PR #3229 / #3228 lesson, the pro-test rebuild ships in the same PR as the source change — public/pro/assets/index-*.js and index.html reflect the new iframe src.
Why this PR exists
PR #3227 fixed `pro-test/src/services/checkout.ts` to import `@clerk/clerk-js/no-rhc` instead of the headless main export. It merged at 09:45 UTC and deployed, but production /pro still throws "Clerk was not loaded with Ui components" because:
This PR rebuilds pro-test against the post-#3227 source and commits the regenerated bundle.
Diff
```
M public/pro/index.html (script src updated to new chunk hashes)
```
No source changes — just the build output that #3227 should have included.
Test plan
Follow-up: prevent recurrence
A separate PR will add (a) a pre-push hook that detects `pro-test/src/**` changes and refuses to push if `public/pro/` is out of date, and (b) a CI check that runs `cd pro-test && npm run build` and fails if the working tree has uncommitted diffs in `public/pro/`. Without these, this footgun will fire again every time someone touches the pricing page or checkout flow.