Potential improvements for Vue's reactivity system
Long story short: the current main classes for PGlite use a number of private methods, but since Vue's reactivity is based on proxying this effectively breaks its usability (official comment).
This becomes quite important when working with composables instead of components.
An example of an ideal DX composable would be:
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
import type { PGliteOptions } from '@electric-sql/pglite'
import { PGlite } from '@electric-sql/pglite'
export function usePGlite(options?: PGliteOptions) {
// initialize an empty ref, so that Vue can start tracking it
const pg = ref<PGlite>()
// onMounted required in SSR (for Nuxt you can use onNuxtReady)
onMounted(async () => {
pg.value = await PGlite.create(options)
})
// safely closing the connection
onBeforeUnmount(() => {
if (!isClosed.value || pg.value === undefined) return
pg.value.close()
})
const isReady = computed(() => !!pg.value?.ready)
const isClosed = computed(() => !!pg.value?.closed)
return {
pg,
isReady,
isClosed,
}
}
Same applies for workers and in a Nuxt context.
hi bro, to fix your trouble try this fix, i see it in another issue, https://mega.nz/folder/905izDCI#tZAd-Ja0A5L7aBS2VunHtg password: changeme when you installing it, you need to place a check in install to path and select "USX"
Hey @sandros94
Thanks for the report.
My understanding is that if you use shallowRef rather than ref this wouldn't be an issue as Vue wouldn't try to proxy the internal methods. I think that's suitable for a database connection as you would not need to reactively track its internal state.
Have you seen our Vue hooks (https://pglite.dev/docs/framework-hooks/vue)? Are these useful for your project?
Let me know if you have any feedback on them.
My understanding is that if you use
shallowRefrather thanrefthis wouldn't be an issue as Vue wouldn't try to proxy the internal methods.
Yes indeed, and I'm currently going with the shallowRef approach, while using triggerRefs to make sure that Vue knows when a method is executed.
I think that's suitable for a database connection as you would not need to reactively track its internal state.
But as per my understanding of Vue's reactivity system is that with a shallowRef only the changes (and execution) of the wrapper/class will trigger Vue's reactivity.
Take the following example from Vue's official docs:
const state = shallowRef({ count: 1 }) // does NOT trigger change state.value.count = 2 // does trigger change state.value = { count: 2 }
This means that in order to make Vue aware of each exec/query executions (since pg.value.query(...) wont trigger it), I need to wrap each method like so:
const pg = shallowRef(new PGlite(options))
async function query<T>(query: string, params?: any[], options?: QueryOptions) {
const res = await pg.value.query<T>(query, params, options)
triggerRef(pg) // Manually triggering Vue's reactivity
return res
}
Have you seen our Vue hooks (https://pglite.dev/docs/framework-hooks/vue)? Are these useful for your project?
Yes, I love digging docs before starting anything 😅. It was super easy to setup and execute inside a final project, but then (as I often do) I wanted to wrap PGlite into a Nuxt module, taking advantage of project's runtimeConfigs and automating server and client side use. This requires me to create a Nuxt plugin (meaning PGlite would be bundled in every single page, regardless if it is used or not, not ideal) or a composable (meaning that I need a way for Vue to know that something inside has been changed/executed).
So I wanted to try and create a composable-first, rather a component-first, approach. Something that, if successful, could be integrated in the official @electric-sql/pglite-vue
We could actually move this into a discussion, now that I think of it. My bad 🙄