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
8 changes: 7 additions & 1 deletion packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,20 @@
"types": "./dist/types/experimental.d.ts",
"import": "./dist/esm/experimental.js",
"require": "./dist/cjs/experimental.js"
},
"./static": {
"types": "./dist/types/static.d.ts",
"import": "./dist/esm/static.js",
"require": "./dist/cjs/static.js"
}
},
"types": "./dist/types/index.d.ts",
"files": [
"dist",
"server",
"errors",
"webhooks"
"webhooks",
"static"
],
"scripts": {
"build": "pnpm clean && tsup",
Expand Down
43 changes: 43 additions & 0 deletions packages/nextjs/src/static.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client';

import type { ClerkProviderProps } from '@clerk/clerk-react';
import { ClerkProvider as ReactClerkProvider } from '@clerk/clerk-react';
import type { Without } from '@clerk/types';
import React from 'react';

import { useAwaitablePush } from './app-router/client/useAwaitablePush';
import { useAwaitableReplace } from './app-router/client/useAwaitableReplace';
import { mergeNextClerkPropsWithEnv } from './utils/mergeNextClerkPropsWithEnv';

type NextStaticClerkProviderProps = Without<ClerkProviderProps, 'publishableKey'> & {
/**
* Used to override the default NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY env variable if needed.
* This is optional for NextJS as the ClerkProvider will automatically use the NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY env variable if it exists.
*/
publishableKey?: string;
};

// StaticClerkProvider is a light wrapper around the `<ClerkProvider/>` exported from `@clerk/clerk-react`
// It is meant to be used only for developers that want to static export their Next.js app (https://nextjs.org/docs/app/guides/static-exports).
// This opts out of keyless, the `dynamic` prop (aka SSR) and route revalidation on auth state updates (since RSCs and middleware do not exist in the context of static export).

/**
* The ClerkProvider exported from `/static` should only be used for static exports only.
* Using this provider means that you opt out of authorization checks on the server.
* @param props
* @returns
*/
const StaticClerkProvider = (props: NextStaticClerkProviderProps) => {
const push = useAwaitablePush();
const replace = useAwaitableReplace();
const mergedProps = mergeNextClerkPropsWithEnv({
...props,
// @ts-expect-error Error because of the stricter types of internal `push`
routerPush: push,
// @ts-expect-error Error because of the stricter types of internal `replace`
routerReplace: replace,
});
return <ReactClerkProvider {...mergedProps}>{props.children}</ReactClerkProvider>;
};
Comment on lines +30 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove ts-expect-error by adapting router functions; add explicit return type and a dev-time guard

Avoid suppressing type errors and add an explicit return type for this public component. Also surface a clear dev warning when publishableKey is missing.

-const StaticClerkProvider = (props: NextStaticClerkProviderProps) => {
-  const push = useAwaitablePush();
-  const replace = useAwaitableReplace();
-  const mergedProps = mergeNextClerkPropsWithEnv({
-    ...props,
-    // @ts-expect-error Error because of the stricter types of internal `push`
-    routerPush: push,
-    // @ts-expect-error Error because of the stricter types of internal `replace`
-    routerReplace: replace,
-  });
-  return <ReactClerkProvider {...mergedProps}>{props.children}</ReactClerkProvider>;
-};
+const StaticClerkProvider = (props: NextStaticClerkProviderProps): React.JSX.Element => {
+  const push = useAwaitablePush();
+  const replace = useAwaitableReplace();
+  // Adapt to the looser router function shape expected by the provider (fire-and-forget).
+  const routerPush = (to: string) => { void push(to); };
+  const routerReplace = (to: string) => { void replace(to); };
+
+  const mergedProps = mergeNextClerkPropsWithEnv({
+    ...props,
+    routerPush,
+    routerReplace,
+  });
+
+  if (!mergedProps.publishableKey && process.env.NODE_ENV !== 'production') {
+    // Visible, actionable feedback in dev builds.
+    // eslint-disable-next-line no-console
+    console.error(
+      'Clerk: Missing publishableKey. Set NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY or pass publishableKey to <ClerkProvider /> from @clerk/nextjs/static.'
+    );
+  }
+
+  return <ReactClerkProvider {...mergedProps}>{props.children}</ReactClerkProvider>;
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const StaticClerkProvider = (props: NextStaticClerkProviderProps) => {
const push = useAwaitablePush();
const replace = useAwaitableReplace();
const mergedProps = mergeNextClerkPropsWithEnv({
...props,
// @ts-expect-error Error because of the stricter types of internal `push`
routerPush: push,
// @ts-expect-error Error because of the stricter types of internal `replace`
routerReplace: replace,
});
return <ReactClerkProvider {...mergedProps}>{props.children}</ReactClerkProvider>;
};
const StaticClerkProvider = (props: NextStaticClerkProviderProps): React.JSX.Element => {
const push = useAwaitablePush();
const replace = useAwaitableReplace();
// Adapt to the looser router function shape expected by the provider (fire-and-forget).
const routerPush = (to: string) => { void push(to); };
const routerReplace = (to: string) => { void replace(to); };
const mergedProps = mergeNextClerkPropsWithEnv({
...props,
routerPush,
routerReplace,
});
if (!mergedProps.publishableKey && process.env.NODE_ENV !== 'production') {
// Visible, actionable feedback in dev builds.
// eslint-disable-next-line no-console
console.error(
'Clerk: Missing publishableKey. Set NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY or pass publishableKey to <ClerkProvider /> from @clerk/nextjs/static.'
);
}
return <ReactClerkProvider {...mergedProps}>{props.children}</ReactClerkProvider>;
};
🤖 Prompt for AI Agents
packages/nextjs/src/static.tsx lines 30-41: The component currently suppresses
type errors with ts-expect-error, lacks an explicit return type, and doesn’t
warn when publishableKey is missing; fix by giving StaticClerkProvider an
explicit React.FC<NextStaticClerkProviderProps> (or appropriate ReactElement)
return type, adapt useAwaitablePush/useAwaitableReplace wrappers so their
signatures match the expected routerPush/routerReplace types (e.g., accept same
args and return Promise<boolean> or void as required) and remove the
ts-expect-error comments, and add a dev-only guard (process.env.NODE_ENV !==
'production') that logs a clear console.warn if mergedProps.publishableKey is
falsy before rendering. Ensure changes preserve behavior and types without using
any ts-expect-error.


export { StaticClerkProvider as ClerkProvider };
Loading