-
-
Notifications
You must be signed in to change notification settings - Fork 5
feat/zero-0.23 #137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat/zero-0.23 #137
Conversation
src/create-zero.ts
Outdated
| S extends Schema, | ||
| MD extends CustomMutatorDefs | undefined = undefined, | ||
| >(options: () => ZeroOptions<S, MD>) { | ||
| let zero: Zero<S, MD> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reasoning behind not making zero a shallowRef here? Wouldn't that mean that reactivity of your existing queries breaks when a new zero instance is created?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With Nuxt you cannot define reactive state outside of script setup because the value will be shared by all users during SSR. But I'm not so sure now how this would work here because zero is still a global value... This is an SSR problem for sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point I really need to opinion of @danielroe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I think the changes I made in 57a7b81 should prevent leaks of the zero instance between Nuxt requests while maintaining reactivity, as long as useZero is called inside a setup context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say we just do it like that for now. One thing to change is how zero is initialised. The way I did it before (and you later implemented in your PR) doesn't allow for async things like fetching a token. What I have now works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the options are passed to useZero, it'll muddle the responsibility of the function IMO, as you technically only have to call useZero with options once (to create the instance), after which it can be used without options (to just provide the already created instance). Keeping that responsibility separated between createZero (for creating) and useZero (for providing the instance) is clearer for consumers (they don't need to know/care that we actually create the instance lazily in useZero).
To deal with async fetching, you can already pass an async getter to the auth option, and to fetch for example the userID async you can use a reactive variable or store and do the fetching somewhere in the background. To give you an idea, this is what our internal usage would look like with these changes. When the user in the userStore changes, a new zero instance is created:
let lastClaims: AuthData;
export const { useZero, useQuery } = createZero(() => {
const userStore = useUserStore();
return {
schema,
userID: userStore.firebaseUser?.uid ?? "anon",
server: import.meta.env.VITE_ZERO_CACHE_URL,
mutators: createMutators(() => lastClaims),
auth: async () => {
if (!userStore.firebaseUser) {
return;
}
const { token, claims } = await userStore.firebaseUser.getIdTokenResult();
if (!isEqual(lastClaims, claims) && claims.sub) {
lastClaims = claims as AuthData;
}
return token;
},
}
});My proposal is that we move on with #119 (pending approval from @danielroe), which should be good to merge by now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But here the options aren't reactive. I really don't want to hold up this release either but it also gotta work 😅
A small example:
export function useBasketSession(shopId: MaybeRefOrGetter<ID<'order'>>) {
const headers = useRequestHeaders(['cookie']);
const session = ref(null);
async function fetch() {
const res = await $fetch(`/api/shop/${toValue(shopId)}/basket`, {
method: 'GET',
headers,
});
session.value = res;
}
async function clear() {
await $fetch(`/api/shop/${toValue(shopId)}/basket`, {
method: 'DELETE',
headers,
});
session.value = null;
}
return {
session,
fetch,
clear,
}
}
export const { useZero: useBasket, useQuery: useBasketQuery } = createZero<Schema, ClientMutators>(() => {
const { session } = useBasketSession();
const config = useRuntimeConfig().public.zero;
return {
userID: session.value?.orderId ?? 'anon',
auth: session.value?.token,
schema: zeroSchema,
mutators: clientMutators(session.value?.decoded),
server: import.meta.client ? config.server : undefined,
kvStore: 'mem', // No need to persist the basket
}
});This will start the zero client in the page:
<script setup lang="ts">
const route = useRoute();
const { fetch } = useBasketSession(route.shopId);
await fetch();
const basket = useBasket();
const { data: items } = useBasketQuery(basket.query...);
// etc..
</script>But clearing the value and refetching a new session will not recreate the zero client
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
implemented in #119 |
createZerois not a composable because it works outside of the vue context. The function passed in does run with the Vue context.The idea is that you can call
useZeroanywhere and the same client will be provided down the component tree whenever you calluseZeroagain. It's only initialised once