Skip to content
Open
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
2 changes: 0 additions & 2 deletions .changeset/jolly-bushes-kick.md

This file was deleted.

15 changes: 15 additions & 0 deletions .changeset/light-eagles-stay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@clerk/clerk-js': major
'@clerk/shared': major
'@clerk/react': minor
'@clerk/nextjs': minor
'@clerk/astro': minor
'@clerk/nuxt': minor
'@clerk/vue': minor
'@clerk/react-router': minor
'@clerk/tanstack-react-start': minor
'@clerk/expo': minor
'@clerk/chrome-extension': minor
---

Remove `clerkJSVariant` option and headless bundle. Use `prefetchUI={false}` instead.
33 changes: 5 additions & 28 deletions .github/workflows/nightly-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,35 +70,10 @@ jobs:
E2E_CLERK_UI_VERSION: "latest"
E2E_NEXTJS_VERSION: "canary"
E2E_NPM_FORCE: "true"
E2E_REACT_DOM_VERSION: "19.2.3"
E2E_REACT_VERSION: "19.2.3"
E2E_REACT_DOM_VERSION: "19.2.1"
E2E_REACT_VERSION: "19.2.1"
INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }}

# Print error logs for immediate visibility in CI
- name: Print App Error Logs
if: steps.integration_tests.outputs.exit_code != '0'
run: |
echo "=== Integration Test Failed ==="
echo ""
# Integration tests use os.tmpdir() which is /tmp on Linux
if [ -d /tmp/.temp_integration ]; then
echo "=== App Error Logs (.err.log files) ==="
find /tmp/.temp_integration -name "*.err.log" -type f 2>/dev/null | while read f; do
echo ""
echo "--- $f ---"
tail -100 "$f" 2>/dev/null || echo "(empty or not readable)"
done
echo ""
echo "=== App Stdout Logs (last 50 lines each) ==="
find /tmp/.temp_integration -name "e2e.*.log" -type f 2>/dev/null | while read f; do
echo ""
echo "--- $f ---"
tail -50 "$f" 2>/dev/null || echo "(empty or not readable)"
done
else
echo "=== No app logs found (directory /tmp/.temp_integration does not exist) ==="
fi

# Upload test artifacts if tests failed
- name: Upload Test Artifacts
if: steps.integration_tests.outputs.exit_code != '0'
Expand All @@ -107,8 +82,10 @@ jobs:
name: test-artifacts-${{ matrix.test-name }}
path: |
${{runner.temp}}/test-output.log
/tmp/.temp_integration/
integration/test-results/
integration/.next/
${{runner.temp}}/clerk-js/node_modules/
${{runner.temp}}/clerk-ui/node_modules/
retention-days: 7

- name: Report Status
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/custom-flows-react-vite/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ createRoot(document.getElementById('root')!).render(
<div className='flex w-full max-w-sm flex-col gap-6'>
<ClerkProvider
clerkJSUrl={import.meta.env.VITE_CLERK_JS_URL as string}
clerkUiUrl={import.meta.env.VITE_CLERK_UI_URL as string}
clerkUIUrl={import.meta.env.VITE_CLERK_UI_URL as string}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/expo-web/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function RootLayout() {
routerPush={(to: string) => router.push(to)}
routerReplace={to => router.replace(to)}
clerkJSUrl={process.env.EXPO_PUBLIC_CLERK_JS_URL}
clerkUiUrl={process.env.EXPO_PUBLIC_CLERK_UI_URL}
clerkUIUrl={process.env.EXPO_PUBLIC_CLERK_UI_URL}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/express-vite/src/client/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ document.addEventListener('DOMContentLoaded', async function () {
const clerk = new Clerk(publishableKey);

await clerk.load({
clerkUiCtor: ClerkUi,
clerkUICtor: ClerkUi,
});

if (clerk.isSignedIn) {
Expand Down
1 change: 1 addition & 0 deletions integration/templates/next-app-router/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const metadata = {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider
prefetchUI={process.env.NEXT_PUBLIC_CLERK_PREFETCH_UI === 'false' ? false : undefined}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/react-cra/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ root.render(
<ClerkProvider
publishableKey={process.env.REACT_APP_CLERK_PUBLISHABLE_KEY as string}
clerkJSUrl={process.env.REACT_APP_CLERK_JS as string}
clerkUiUrl={process.env.REACT_APP_CLERK_UI as string}
clerkUIUrl={process.env.REACT_APP_CLERK_UI as string}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/react-router-library/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ createRoot(document.getElementById('root')!).render(
<ClerkProvider
publishableKey={PUBLISHABLE_KEY}
clerkJSUrl={CLERK_JS_URL}
clerkUiUrl={CLERK_UI_URL}
clerkUIUrl={CLERK_UI_URL}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/react-router-node/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function App({ loaderData }: Route.ComponentProps) {
<ClerkProvider
loaderData={loaderData}
clerkJSUrl={import.meta.env.VITE_CLERK_JS_URL}
clerkUiUrl={import.meta.env.VITE_CLERK_UI_URL}
clerkUIUrl={import.meta.env.VITE_CLERK_UI_URL}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/react-vite/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const Root = () => {
return (
<ClerkProvider
clerkJSUrl={import.meta.env.VITE_CLERK_JS_URL as string}
clerkUiUrl={import.meta.env.VITE_CLERK_UI_URL as string}
clerkUIUrl={import.meta.env.VITE_CLERK_UI_URL as string}
routerPush={(to: string) => navigate(to)}
routerReplace={(to: string) => navigate(to, { replace: true })}
appearance={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function RootDocument({ children }: { children: React.ReactNode }) {
<body>
<ClerkProvider
clerkJSUrl={import.meta.env.VITE_CLERK_JS_URL}
clerkUiUrl={import.meta.env.VITE_CLERK_UI_URL}
clerkUIUrl={import.meta.env.VITE_CLERK_UI_URL}
appearance={{
options: {
showOptionalFields: true,
Expand Down
2 changes: 1 addition & 1 deletion integration/templates/vue-vite/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const app = createApp(App);
app.use(clerkPlugin, {
publishableKey: import.meta.env.VITE_CLERK_PUBLISHABLE_KEY,
clerkJSUrl: import.meta.env.VITE_CLERK_JS_URL,
clerkUiUrl: import.meta.env.VITE_CLERK_UI_URL,
clerkUIUrl: import.meta.env.VITE_CLERK_UI_URL,
clerkJSVersion: import.meta.env.VITE_CLERK_JS_VERSION,
appearance: {
options: {
Expand Down
1 change: 1 addition & 0 deletions integration/tests/components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('component

const signOut = async ({ app, page, context }) => {
const u = createTestUtils({ app, page, context });
await u.page.waitForClerkJsLoaded();
await u.page.evaluate(async () => {
await window.Clerk.signOut();
});
Expand Down
32 changes: 32 additions & 0 deletions integration/tests/prefetch-ui.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { expect, test } from '@playwright/test';

import type { Application } from '../models/application';
import { appConfigs } from '../presets';

test.describe('prefetchUI disabled @nextjs', () => {
test.describe.configure({ mode: 'serial' });
let app: Application;

test.beforeAll(async () => {
app = await appConfigs.next.appRouter.clone().commit();
await app.setup();
// Use withEmailCodes but disable the UI prefetching
const env = appConfigs.envs.withEmailCodes.clone().setEnvVariable('public', 'CLERK_PREFETCH_UI_DISABLED', 'true');
await app.withEnv(env);
await app.dev();
});

test.afterAll(async () => {
await app.teardown();
});

test('does not inject clerk-ui script when prefetchUI is disabled', async ({ page }) => {
await page.goto(app.serverUrl);

// Wait for clerk-js script to be present (ensures page has loaded)
await expect(page.locator('script[data-clerk-js-script]')).toBeAttached();

// clerk-ui script should NOT be present
await expect(page.locator('script[data-clerk-ui-script]')).not.toBeAttached();
});
});
5 changes: 3 additions & 2 deletions packages/astro/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ interface InternalEnv {
readonly PUBLIC_CLERK_FRONTEND_API?: string;
readonly PUBLIC_CLERK_PUBLISHABLE_KEY?: string;
readonly PUBLIC_CLERK_JS_URL?: string;
readonly PUBLIC_CLERK_UI_URL?: string;
readonly PUBLIC_CLERK_JS_VARIANT?: 'headless' | '';
readonly PUBLIC_CLERK_JS_VERSION?: string;
readonly PUBLIC_CLERK_UI_URL?: string;
readonly PUBLIC_CLERK_UI_VERSION?: string;
readonly PUBLIC_CLERK_PREFETCH_UI?: string;
readonly CLERK_API_KEY?: string;
readonly CLERK_API_URL?: string;
readonly CLERK_API_VERSION?: string;
Expand Down
20 changes: 5 additions & 15 deletions packages/astro/src/integration/create-integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ function createIntegration<Params extends HotloadAstroClerkIntegrationParams>()

// These are not provided when the "bundled" integration is used
const clerkJSUrl = (params as any)?.clerkJSUrl as string | undefined;
const clerkUiUrl = (params as any)?.clerkUiUrl as string | undefined;
const clerkJSVariant = (params as any)?.clerkJSVariant as string | undefined;
const clerkJSVersion = (params as any)?.clerkJSVersion as string | undefined;
const prefetchUI = (params as any)?.prefetchUI as boolean | undefined;

return {
name: '@clerk/astro/integration',
Expand All @@ -32,10 +31,6 @@ function createIntegration<Params extends HotloadAstroClerkIntegrationParams>()
logger.error('Missing adapter, please update your Astro config to use one.');
}

if (typeof clerkJSVariant !== 'undefined' && clerkJSVariant !== 'headless' && clerkJSVariant !== '') {
logger.error('Invalid value for clerkJSVariant. Acceptable values are `"headless"`, `""`, and `undefined`');
}

const internalParams: ClerkOptions = {
...params,
sdkMetadata: {
Expand All @@ -61,9 +56,8 @@ function createIntegration<Params extends HotloadAstroClerkIntegrationParams>()
...buildEnvVarFromOption(proxyUrl, 'PUBLIC_CLERK_PROXY_URL'),
...buildEnvVarFromOption(domain, 'PUBLIC_CLERK_DOMAIN'),
...buildEnvVarFromOption(clerkJSUrl, 'PUBLIC_CLERK_JS_URL'),
...buildEnvVarFromOption(clerkUiUrl, 'PUBLIC_CLERK_UI_URL'),
...buildEnvVarFromOption(clerkJSVariant, 'PUBLIC_CLERK_JS_VARIANT'),
...buildEnvVarFromOption(clerkJSVersion, 'PUBLIC_CLERK_JS_VERSION'),
...buildEnvVarFromOption(prefetchUI === false ? 'false' : undefined, 'PUBLIC_CLERK_PREFETCH_UI'),
},

ssr: {
Expand Down Expand Up @@ -170,14 +164,10 @@ function createClerkEnvSchema() {
PUBLIC_CLERK_PROXY_URL: envField.string({ context: 'client', access: 'public', optional: true, url: true }),
PUBLIC_CLERK_DOMAIN: envField.string({ context: 'client', access: 'public', optional: true, url: true }),
PUBLIC_CLERK_JS_URL: envField.string({ context: 'client', access: 'public', optional: true, url: true }),
PUBLIC_CLERK_UI_URL: envField.string({ context: 'client', access: 'public', optional: true, url: true }),
PUBLIC_CLERK_JS_VARIANT: envField.enum({
context: 'client',
access: 'public',
optional: true,
values: ['headless'],
}),
PUBLIC_CLERK_JS_VERSION: envField.string({ context: 'client', access: 'public', optional: true }),
PUBLIC_CLERK_PREFETCH_UI: envField.string({ context: 'client', access: 'public', optional: true }),
PUBLIC_CLERK_UI_URL: envField.string({ context: 'client', access: 'public', optional: true, url: true }),
PUBLIC_CLERK_UI_VERSION: envField.string({ context: 'client', access: 'public', optional: true }),
PUBLIC_CLERK_TELEMETRY_DISABLED: envField.boolean({ context: 'client', access: 'public', optional: true }),
PUBLIC_CLERK_TELEMETRY_DEBUG: envField.boolean({ context: 'client', access: 'public', optional: true }),
CLERK_SECRET_KEY: envField.string({ context: 'server', access: 'secret' }),
Expand Down
30 changes: 18 additions & 12 deletions packages/astro/src/internal/create-clerk-instance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
loadClerkJsScript,
loadClerkUiScript,
setClerkJsLoadingErrorPackageName,
loadClerkJSScript,
loadClerkUIScript,
setClerkJSLoadingErrorPackageName,
shouldPrefetchClerkUI,
} from '@clerk/shared/loadClerkJsScript';
import type { ClerkOptions } from '@clerk/shared/types';
import type { ClerkUiConstructor } from '@clerk/shared/ui';
Expand All @@ -16,7 +17,7 @@ import { runOnce } from './run-once';

let initOptions: ClerkOptions | undefined;

setClerkJsLoadingErrorPackageName(PACKAGE_NAME);
setClerkJSLoadingErrorPackageName(PACKAGE_NAME);

function createNavigationHandler(
windowNav: typeof window.history.pushState | typeof window.history.replaceState,
Expand All @@ -40,7 +41,7 @@ async function createClerkInstanceInternal<TUi extends Ui = Ui>(options?: AstroC
// Both functions return early if the scripts are already loaded
// (e.g., via middleware-injected script tags in the HTML head).
const clerkJsChunk = getClerkJsEntryChunk(options);
const clerkUiCtor = getClerkUiEntryChunk(options);
const clerkUICtor = getClerkUIEntryChunk(options);

await clerkJsChunk;

Expand All @@ -59,7 +60,7 @@ async function createClerkInstanceInternal<TUi extends Ui = Ui>(options?: AstroC
routerReplace: createNavigationHandler(window.history.replaceState.bind(window.history)),
...options,
// Pass the clerk-ui constructor promise to clerk.load()
clerkUiCtor,
clerkUICtor,
} as unknown as ClerkOptions;

initOptions = clerkOptions;
Expand Down Expand Up @@ -105,21 +106,26 @@ function updateClerkOptions<TUi extends Ui = Ui>(options: AstroClerkUpdateOption
* Returns early if window.Clerk already exists.
*/
async function getClerkJsEntryChunk<TUi extends Ui = Ui>(options?: AstroClerkCreateInstanceParams<TUi>): Promise<void> {
await loadClerkJsScript(options);
await loadClerkJSScript(options);
}

/**
* Gets the ClerkUI constructor, either from options or by loading the script.
* Returns early if window.__internal_ClerkUiCtor already exists.
* Returns undefined when prefetchUI={false} (no UI needed).
*/
async function getClerkUiEntryChunk<TUi extends Ui = Ui>(
async function getClerkUIEntryChunk<TUi extends Ui = Ui>(
options?: AstroClerkCreateInstanceParams<TUi>,
): Promise<ClerkUiConstructor> {
if (options?.clerkUiCtor) {
return options.clerkUiCtor;
): Promise<ClerkUiConstructor | undefined> {
if (!shouldPrefetchClerkUI(options?.prefetchUI)) {
return undefined;
}

await loadClerkUiScript(options);
if (options?.clerkUICtor) {
return options.clerkUICtor;
}

await loadClerkUIScript(options as any);

if (!window.__internal_ClerkUiCtor) {
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
Expand Down
28 changes: 24 additions & 4 deletions packages/astro/src/internal/merge-env-vars-with-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ import { isTruthy } from '@clerk/shared/underscore';

import type { AstroClerkIntegrationParams } from '../types';

/**
* Merges `prefetchUI` param with env vars.
* - If param `prefetchUI` is explicitly `false`, return `false`
* - If env `PUBLIC_CLERK_PREFETCH_UI` is "false", return `false`
* - Otherwise return `undefined` (default behavior: prefetch UI)
*/
function mergePrefetchUIConfig(paramPrefetchUI: AstroClerkIntegrationParams['prefetchUI']): boolean | undefined {
// Explicit false from param takes precedence
if (paramPrefetchUI === false) {
return false;
}

// Check env var
if (import.meta.env.PUBLIC_CLERK_PREFETCH_UI === 'false') {
return false;
}

return undefined;
}

/**
* @internal
*/
Expand All @@ -15,9 +35,9 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish
publishableKey: paramPublishableKey,
telemetry: paramTelemetry,
clerkJSUrl: paramClerkJSUrl,
clerkUiUrl: paramClerkUiUrl,
clerkJSVariant: paramClerkJSVariant,
clerkJSVersion: paramClerkJSVersion,
clerkUIUrl: paramClerkUiUrl,
prefetchUI: paramPrefetchUI,
...rest
} = params || {};

Expand All @@ -28,10 +48,10 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & { publish
proxyUrl: paramProxy || import.meta.env.PUBLIC_CLERK_PROXY_URL,
domain: paramDomain || import.meta.env.PUBLIC_CLERK_DOMAIN,
publishableKey: paramPublishableKey || import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY || '',
clerkUiUrl: paramClerkUiUrl || import.meta.env.PUBLIC_CLERK_UI_URL,
clerkJSUrl: paramClerkJSUrl || import.meta.env.PUBLIC_CLERK_JS_URL,
clerkJSVariant: paramClerkJSVariant || import.meta.env.PUBLIC_CLERK_JS_VARIANT,
clerkJSVersion: paramClerkJSVersion || import.meta.env.PUBLIC_CLERK_JS_VERSION,
clerkUIUrl: paramClerkUiUrl || import.meta.env.PUBLIC_CLERK_UI_URL,
prefetchUI: mergePrefetchUIConfig(paramPrefetchUI),
telemetry: paramTelemetry || {
disabled: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DISABLED),
debug: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DEBUG),
Expand Down
Loading
Loading