Skip to content
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

Potential improvements for Vue's reactivity system #277

Open
sandros94 opened this issue Aug 29, 2024 · 3 comments
Open

Potential improvements for Vue's reactivity system #277

sandros94 opened this issue Aug 29, 2024 · 3 comments

Comments

@sandros94
Copy link
Contributor

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.

@samwillis
Copy link
Collaborator

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.

@sandros94
Copy link
Contributor Author

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.

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

@sandros94 sandros94 changed the title Incompatibility with Vue's reactivity Potential improvements for Vue's reactivity system Sep 2, 2024
@sandros94
Copy link
Contributor Author

We could actually move this into a discussion, now that I think of it. My bad 🙄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@samwillis @sandros94 and others