@clerk/remix does not work with the root layout export
AdiRishi opened this issue · 10 comments
Preliminary Checks
- I have reviewed the documentation: https://clerk.com/docs
- I have searched for existing issues: https://github.com/clerk/javascript/issues
- I have not already reached out to Clerk support via email or Discord (if you have, no need to open an issue here)
- This issue is not a question, general help request, or anything other than a bug report directly related to Clerk. Please ask questions in our Discord community: https://clerk.com/discord.
Reproduction / Replay Link
https://github.com/AdiRishi/repro-remix-cf-with-layout
Publishable key
pk_live_Y2xlcmsubmFhbWRlby5vcmck
Description
Remix has recently released a way to have a stable app shell, preventing various issues. See https://remix.run/docs/en/main/file-conventions/root#layout-export
However, using this stable layout function seems to break the Clerk Remix integration.
Steps to reproduce:
The reproduction repository I've made uses a Remix Cloudflare setup. There is a commit in that repository (commit 104af3f17bf6c375e8b970c4d8f77a51ffb43698
) that has a working version just before the layout function change if you want to see a working version of the app.
I've made the reproduction repository by effectively following the quickstart guide.
- Go to the reproduction repository and run
pnpm install
- Update the
.dev.vars
file with your ownCLERK_PUBLISHABLE_KEY
andCLERK_SECRET_KEY
- Run
pnpm dev
and go tohttp://localhost:8788
Expected behavior:
This should behave the exact same way as if we were not using the layout export. Aka things should work.
Actual behavior:
In other projects I've seen this behave differently, but in the reproduction repository I've made we can see an infinite 401 loop.
Environment
System:
OS: macOS 14.3.1
CPU: (8) arm64 Apple M1 Pro
Memory: 1.06 GB / 32.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
Yarn: 1.22.19 - ~/.nvm/versions/node/v20.11.0/bin/yarn
npm: 10.5.0 - ~/.nvm/versions/node/v20.11.0/bin/npm
pnpm: 8.15.4 - ~/.nvm/versions/node/v20.11.0/bin/pnpm
bun: 1.0.25 - /opt/homebrew/bin/bun
Browsers:
Chrome: 122.0.6261.69
Safari: 17.3.1
npmPackages:
@clerk/remix: ^3.1.19 => 3.1.19
@cloudflare/workers-types: ^4.20240222.0 => 4.20240222.0
@remix-run/cloudflare: ^2.8.0 => 2.8.0
@remix-run/cloudflare-pages: ^2.8.0 => 2.8.0
@remix-run/css-bundle: ^2.8.0 => 2.8.0
@remix-run/dev: ^2.8.0 => 2.8.0
@remix-run/react: ^2.8.0 => 2.8.0
@types/react: ^18.2.60 => 18.2.60
@types/react-dom: ^18.2.19 => 18.2.19
@typescript-eslint/eslint-plugin: ^7.1.0 => 7.1.0
eslint: ^8.57.0 => 8.57.0
eslint-import-resolver-typescript: ^3.6.1 => 3.6.1
eslint-plugin-import: ^2.29.1 => 2.29.1
eslint-plugin-jsx-a11y: ^6.8.0 => 6.8.0
eslint-plugin-react: ^7.33.2 => 7.33.2
eslint-plugin-react-hooks: ^4.6.0 => 4.6.0
isbot: ^5.1.1 => 5.1.1
react: ^18.2.0 => 18.2.0
react-dom: ^18.2.0 => 18.2.0
typescript: ^5.3.3 => 5.3.3
wrangler: ^3.30.0 => 3.30.0
I confirm the issue.
The Clerk integration appears to be totally broken in the latest version of Remix (currently v2.8.0).
I'm facing the exact same issue with the infinite 401 loop.
The official docs (even the beta ones) don't mention a word about it.
After looking around a bit I found the following issue which might be somehow related:
#965
Looks like it was addressed by #1444 but unfortunately in reality the issue wasn't fixed.
Any help would be much appreciated 🙏
Hey @kstratis , just as an FYI you can use Clerk with remix 2.8.0 (I'm doing it right now), you just have to avoid the root layout export, and use the classic way of exporting the entire app shell from App
, ErrorBoundary
and HydrateFallback
@AdiRishi When you say use the classic way can you give example. Were using Remix/Vite an no matter what I do it won't work
@AdiRishi Yes, looks like you are correct. By removing the layout export everything works as expected.
@AlexanderKaran Here's what's working in latest Remix (v2.8.0) using vite with express js:
root.tsx
import type { MetaFunction, LoaderFunction } from "@remix-run/node";
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import { ClerkApp, ClerkErrorBoundary } from "@clerk/remix";
import { rootAuthLoader } from "@clerk/remix/ssr.server";
export const loader: LoaderFunction = args => {
return rootAuthLoader(args, ({ request }) => {
const { sessionId, userId, getToken } = request.auth;
console.log(sessionId);
console.log(userId);
// fetch data
return { yourData: 'here' };
});
};
export const meta: MetaFunction = () => ([{
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
}]);
export const ErrorBoundary = ClerkErrorBoundary();
function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default ClerkApp(App);
Regardless though, this needs to be fixed cause exporting layout
is now the default.
Hello everyone and thanks for the report :) I just wanted to let you know that we're going to investigate this one this week so please expect an update from me or @desiprisg within the next few days.
Hello everyone and thanks for reporting that!
This issue is already fixed in our latest release, Clerk Core 2, which is currently in beta and is expected to be shipped as a GA release within the next two weeks.
Unfortunately, fixing this in v4 requires a breaking change - even though we suggest giving the beta version a try, here's a workaround you can use in the meantime:
import { cssBundleHref } from "@remix-run/css-bundle";
import type { LinksFunction, LoaderFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
isRouteErrorResponse,
useLoaderData,
useRouteError,
useRouteLoaderData,
} from "@remix-run/react";
import { rootAuthLoader } from "@clerk/remix/ssr.server";
import { ClerkProvider } from "@clerk/remix";
import { ClerkApp } from "@clerk/remix";
import { ClerkErrorBoundary } from "@clerk/remix";
export const links: LinksFunction = () => [
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
];
export const loader: LoaderFunction = (args) => rootAuthLoader(args);
export function Layout({ children }: { children: React.ReactNode }) {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
const { __clerk_ssr_interstitial_html } =
error?.data?.clerkState?.__internal_clerk_state || {};
if (__clerk_ssr_interstitial_html) return ClerkErrorBoundary();
}
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
function App() {
return <Outlet />;
}
export default ClerkApp(App);
If you have any questions please reply here and I will take a look!
So we can upgrade to the beta and it will work without the workaround?
Thank you for your input @octoper!
I've had the chance to test your solution, and it indeed resolves the issue.
Looks like the root of the confusion lies in the documentation: The beta documentation mirrors the content found in the latest stable version almost exactly; Your recommendation is absolutely essential for the current version to function correctly. However, it appears the Clerk core 2 installation guidelines, which should be present in the beta documentation, are missing. By chance, I discovered the necessary instructions here. Integrating these steps with the original examples from the latest documentation —with minor adjustments for layout— leads to a seamless setup as expected. Here's my working root.tsx
using Clerk core 2:
import type { LoaderFunction } from "@remix-run/node";
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import { ClerkApp } from "@clerk/remix";
import { rootAuthLoader } from "@clerk/remix/ssr.server";
export const loader: LoaderFunction = (args) => rootAuthLoader(args);
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
function App() {
return <Outlet />;
}
export default ClerkApp(App);
I hope this clarification helps, and I suggest you consider updating the beta documentation to include the Clerk core 2 installation instructions explicitly.
P.S
So we can upgrade to the beta and it will work without the workaround?
@AlexanderKaran That is correct. Use my example above.
I can confirm updating to the beta version fixes the issue.
btw your upgrader is so clutch congratulations, what an incredible piece of software!!