pinia icon indicating copy to clipboard operation
pinia copied to clipboard

Pinia stores imported from npm packages are not reactive or don't share the same context

Open waldemarennsaed opened this issue 1 month ago • 0 comments

Reproduction

Apparently, using exported pinia-stores from npm packages doesn't work as expected. There seems to be an issue with either the context pinia is running in (and conflicts with the one of the consuming application) or the reactivity is somehow broken.

Steps to reproduce the bug

The reproduction contains multiple steps, as creating a local npm package and use it in your vue application as an import. Let's go through it step by step.

Create the local npm package

Using:

Start with the basic steps:

> mkdir pinia-package-test && cd pinia-package-test

Create a package.json that will take care of the module bundling, entry-point, etc. I use the following one:

{
  "name": "pinia-test-package",
  "version": "1.0.0",
  "type": "module",
  "files": [
    "build"
  ],
  "main": "./build/pinia-test-package.umd.cjs",
  "module": "./build/pinia-test-package.js",
  "exports": {
    ".": {
      "import": "./build/pinia-test-package.js",
      "require": "./build/pinia-test-package.umd.cjs"
    }
  },
  "scripts": {
    "build": "vite build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@vue/reactivity": "^3.4.27",
    "pinia": "^2.1.7"
  },
  "devDependencies": {
    "vite": "^5.2.11"
  }
}

I add a simple pinia store called /src/counter.js. Create your /src directory and paste the following inside your /src/counter.js file:

import { ref } from '@vue/reactivity'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counterStore', () => {
    const count = ref(0)

    function increment() {
        count.value++
    }

    function decrement() {
        count.value--
    }

    return {
        count,
        decrement,
        increment
    }
})

For the vite.config.js I use the following configuration:

import { resolve } from 'path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/counter.js'),
      fileName: 'pinia-test-package',
      name: 'pinia-test-package'
    },
    outDir: 'build',
    rollupOptions: {
      external: ['pinia']
    },
    sourcemap: true
  },
  plugins: []
})

Install the package dependencies:

npm install

Now build the package:

npm run build

That will create an output directory, containing all the relevant package files /build.

Since the package.json configuration points at that directory to get the entry file, we can safely continue with the next step: Create the application that will install the created pacakge.

Create the wrapper app

⚠️ For the ease of reproduction, have your npm-package directory pinia-test-package next to your newly created pinia-test-wrapper package, as following:

  • /parent
    • /pinia-test-package
    • /pinia-test-wrapper

For this, I am using a simple vite/vue3 application. Scaffolding it as the documentation points out:

npm create vite@latest pinia-package-wrapper -- --template vue

Then follow the instructions of the CLI:

  • cd pinia-package-wrapper
  • npm install
  • npm run dev

Now a dev-server will be running at port 5173.

🆙 For the ease of testing, I removed the HelloWorld.vue component and removed it's usage from the App.vue component.

Now, install pinia:

npm i -S pinia

Now, install your local npm package (the pinia-test-package that you have created in the first step):

npm i -S ../pinia-test-package

Assuming, that your directories (package & wrapper) are placed side-by-side, as described in the beginning of this section.

Install pinia in your main.js. Your main.js should look like this:

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

In your App.vue now import the package and use it. I implemented a simple counter-headline and two buttons to increment and decrement the counter value. Your App.vue might look like this:

<script setup>
import { useCounterStore } from 'pinia-test-package'

const store = useCounterStore()

function incrementCounter() {
  store.increment()
}

function decrementCounter() {
  store.decrement()
}
</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>

    <h2>Counter: {{ store.count }}</h2>

    <button @click="incrementCounter">+1</button>
    <button @click="decrementCounter">-1</button>
  </div>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

In the end, your app should look like this:

Bildschirmfoto 2024-05-21 um 19 17 33

Explanation:

The goal is to use the counter store-value that we defined in our pinia-package and use it's actions increment & decrement respectively. We want to interact with the pinia-stores count value by using it's defined actions.

Expected behavior

Clicking the buttons should update the pinia-store counter and increment/decrement the count state. Also the UI should update immediately and display the value correctly.

Actual behavior

When clicking the buttons, nothing happens. Here is a short video:

https://github.com/vuejs/pinia/assets/94853611/ac6727ae-fd70-42eb-9369-7d1a183e7033

Notice, while inspecting the pinia store by using the vue-dev-tools (using the ones for chrome), the state does not get updated reactively, but only as soon as I reload the state within my dev-tools:

https://github.com/vuejs/pinia/assets/94853611/78896107-c258-4100-9948-6ca4d053cc10

Additional information

I also tried using the storeToRefs() function that pinia provides, within my App.vue to destructure the count variable but it didn't help at all.

waldemarennsaed avatar May 21 '24 17:05 waldemarennsaed