Replies: 2 comments 5 replies
-
You can use standard cookies. Here's an example that uses import Cookies from "js-cookie";
import cookie from "cookie";
export function loader({ request }: LoaderFunctionArgs) {
// read server cookies
const cookies = cookie.parse(request.headers.get("cookie") ?? "");
return json({ cookies });
}
export default function Index() {
const data = useLoaderData<typeof loader>();
const { revalidate } = useRevalidator();
const setTheme = (theme: string) => {
// set client cookie
Cookies.set("theme", theme);
console.log("setting theme", document.cookie);
revalidate();
};
//...
} |
Beta Was this translation helpful? Give feedback.
5 replies
-
So I was also trying to solve this problem and this discussion was very helpful. I inlined some of the the @remix-run/cloudflare code to create a // creatClientCookie.ts
import {
createCookieFactory,
type SignFunction,
type UnsignFunction,
} from '@remix-run/server-runtime'
const encoder = new TextEncoder()
export const sign: SignFunction = async (value, secret) => {
let key = await createKey(secret, ['sign'])
let data = encoder.encode(value)
let signature = await crypto.subtle.sign('HMAC', key, data)
let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(
/=+$/,
'',
)
return value + '.' + hash
}
export const unsign: UnsignFunction = async (signed, secret) => {
let index = signed.lastIndexOf('.')
let value = signed.slice(0, index)
let hash = signed.slice(index + 1)
let key = await createKey(secret, ['verify'])
let data = encoder.encode(value)
let signature = byteStringToUint8Array(atob(hash))
let valid = await crypto.subtle.verify('HMAC', key, signature, data)
return valid ? value : false
}
async function createKey(
secret: string,
usages: CryptoKey['usages'],
): Promise<CryptoKey> {
let key = await crypto.subtle.importKey(
'raw',
encoder.encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
usages,
)
return key
}
function byteStringToUint8Array(byteString: string): Uint8Array {
let array = new Uint8Array(byteString.length)
for (let i = 0; i < byteString.length; i++) {
array[i] = byteString.charCodeAt(i)
}
return array
}
export const createClientCookie = createCookieFactory({ sign, unsign }) Usage with react-resizable-panel: async function handleLayout(sizes: number[]) {
const cookie = await layoutCookie.serialize(sizes)
document.cookie = cookie
}
...
return (
<PanelGroup
onLayout={handleLayout}
>
... |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Currently, the only way to set a cookie in a Remix app is using the
Set-Cookie
header, because the cookie library cannot run on the client. However, Remix has made specific decisions about the encoding of its cookies, which has to be manually replicated if you want to set the cookie on client-side (usingdocument.cookie
).An example of this might be a cookie related to app layout – you can update this dynamically (i.e, resizing a sidebar) on the client, and on refresh you need to render server side using this information if you want to avoid content jump on client side render. This is typically done using a cookie (see https://github.com/bvaughn/react-resizable-panels?tab=readme-ov-file#how-can-i-use-persistent-layouts-with-ssr ), but to do this you have to manually copy how Remix encodes cookies.
This is obviously not ideal and is brittle if remix were to ever change this encoding for whatever reason.
The code encoding/decoding cookies is not exported and is within the
remix-server-runtime
https://github.com/remix-run/remix/blob/main/packages/remix-server-runtime/cookies.tsBeta Was this translation helpful? Give feedback.
All reactions