🍍Automatically Typed, Modular and lightweight Store for Vue using the composition api with DevTools support

Overview

Pinia Build Status npm package coverage thanks

Pronounced like the fruit in Spanish, Piña

Piña is also an invalid package name... that's why it has to be pinia which sounds very similar

🍍 Automatically Typed, Modular and lightweight Store for Vue 3.x based on the composition api with devtools support

👉 Demo on CodeSandbox

Pinia works both for Vue 2.x and Vue 3.x and you are currently on the branch that supports Vue 3.x. Go here for the Vue 2.x compatible version.

What I want is to inspire others to think about ways to improve Vuex and come up with something that works very well with the composition api. Ideally it could also be used without it.

These are the core principles that I try to achieve with this experiment:

  • Autocompletion: even if you write your code in JavaScript!
  • Flat modular structure 🍍 No nesting, only stores, compose them as needed
  • Light layer on top of Vue 💨 keep it very lightweight
  • Only state, getters and actions
  • No more verbose mutations, 👐 patch is the mutation
  • Actions are like methods ⚗️ Group your business logic there
  • Import what you need, let webpack code split 📦 No need for dynamically registered modules
  • SSR support ⚙️
  • DevTools support 💻 Which is crucial to make this enjoyable

Help me keep working on this project 💚

Silver Sponsors

Vue Mastery Vuetify

Bronze Sponsors

Storyblok Storyblok


FAQ

A few notes about the project and possible questions:

Q: Does this replace Vuex, is it its successor?

A: No, or at least that's not the main intention

Q: What about dynamic modules?

A: Dynamic modules are not type safe, so instead we allow creating different stores that can be imported anywhere

Roadmap / Ideas

  • Should the state be merged at the same level as actions and getters?
  • Allow grouping stores together into a similar structure and allow defining new getters (pinia) You can directly call useOtherStore() inside of a getter or action.
  • Getter with params that act like computed properties (@ktsn)

Installation

yarn add [email protected]
# or with npm
npm install [email protected]

Usage

Install the plugin

Create a pinia (the root store) and pass it to app:

import { createPinia } from 'pinia'

app.use(createPinia())

This will also add devtools support. Some features like time traveling and editing are still not supported because vue-devtools doesn't expose the necessary APIs yet.

Creating a Store

You can create as many stores as you want, and they should each exist in different files:

import { defineStore } from 'pinia'

export const useMainStore = defineStore({
  // name of the store
  // it is used in devtools and allows restoring state
  id: 'main',
  // a function that returns a fresh state
  state: () => ({
    counter: 0,
    name: 'Eduardo',
  }),
  // optional getters
  getters: {
    doubleCount() {
      return this.counter * 2
    },
    // use getters in other getters
    doubleCountPlusOne() {
      return this.doubleCount * 2
    },
  },
  // optional actions
  actions: {
    reset() {
      // `this` is the store instance
      this.counter = 0
    },
  },
})

defineStore returns a function that has to be called to get access to the store:

import { useMainStore } from '@/stores/main'

export default defineComponent({
  setup() {
    const main = useMainStore()

    return {
      // gives access to the whole store
      main,
      // gives access only to specific state
      state: computed(() => main.counter),
      // gives access to specific getter; like `computed` properties
      doubleCount: computed(() => main.doubleCount),
    }
  },
})

Note: the SSR implementation on Pinia might change, but if you intend having SSR on your application, you should avoid using useStore functions at the root level of a file to make sure the correct store is retrieved for your currently running application instance. Here is an example:

Avoid doing this:

import { createRouter } from 'vue-router'
const router = createRouter({
  // ...
})

// ❌ Depending on where you do this it will fail
const main = useMainStore()

router.beforeEach((to, from, next) => {
  if (main.isLoggedIn) next()
  else next('/login')
})

Instead, call useMainStore() at the top of setup, like inject and provide in Vue:

export default defineComponent({
  setup() {
    // ✅ This will work
    const main = useMainStore()

    return {}
  },
})

// In a different file...
const pinia = createPinia()
app.use(pinia)

router.beforeEach((to) => {
  // ✅ This will work (requires pinia param when outside of setup on both
  // Client and Server. See the SSR section below for more information)
  const main = useMainStore(pinia)

  if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
})

⚠️ : Note that if you are developing an SSR application, you will need to do a bit more.

You can access any property defined in state and getters directly on the store, similar to data and computed properties in a Vue component.

export default defineComponent({
  setup() {
    const main = useMainStore()
    const text = main.name // "eduardo"
    const doubleCount = main.doubleCount // 2

    return {
      text, // will always be "eduardo"
      textDynamic: computed(() => main.name), // reactive value
    }
  },
})

The main store in an object wrapped with reactive, meaning there is no need to write .value after getters but, like props in setup, we cannot destructure it:

export default defineComponent({
  setup() {
    // ❌ This won't work because it breaks reactivity
    // it's the same as destructuring from `props`
    const { name, doubleCount } = useMainStore()
    return { name, doubleCount }
  },
})

Actions are invoked like methods:

export default defineComponent({
  setup() {
    const main = useMainStore()
    // call the action as a method of the store
    main.reset()

    return {}
  },
})

Mutating the state

To mutate the state you can either directly change something:

main.counter++

or call the method $patch that allows you apply multiple changes at the same time with a partial state object:

main.$patch({
  counter: -1,
  name: 'Abalam',
})

The main difference here is that $patch allows you to group multiple changes into one single entry in the devtools.

Replacing the state

Simply set your store $stet property to a new object:

main.$state = { counter: 666, name: 'Paimon' }

SSR

Creating stores with Pinia should work out of the box for SSR as long as you call your useStore() functions at the top of setup functions, getters and actions:

export default defineComponent({
  setup() {
    // this works because pinia knows what application is running
    const main = useMainStore()
    return { main }
  },
})

If you need to use the store somewhere else, you need to pass the pinia instance that was passed to the app to the useStore() function call:

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

app.use(router)
app.use(pinia)

router.beforeEach((to) => {
  // ✅ This will work make sure the correct store is used for the current running app
  const main = useMainStore(pinia)

  if (to.meta.requiresAuth && !main.isLoggedIn) return '/login'
})

To hydrate the initial state, you need to make sure the rootState is included somewhere in the HTML for Pinia to pick it up later on:

import { createPinia } from 'pinia'
// retrieve the rootState server side
const pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)

// after rendering the page, the root state is build and can be read
// serialize, escape (VERY important if the content of the state can be changed
// by the user, which is almost always the case), and place it somewhere on
// the page, for example, as a global variable. Note you need to use your own
// `escapeHTML()` function or use an existing package
escapeHTML(JSON.stringify(pinia.state.value))

On client side, you must hydrate pinia's state before calling any useStore() function. For example, if we serialize the state into a

Comments
  • How to split store in different files? And the limits of object type inference

    How to split store in different files? And the limits of object type inference

    Hello,

    I would simply like to split a store in different files and especially to make my different store parts (state, getter, actions) able to inherit from interface, abstract classes, etc.. Furthermore, splitting parts of a Pinia store seems to break the this usage. As Pinia seems to not really be typed (cause it is only based on object type inference), we just can't split the different parts of a store.

    I really wonder why Pinia didn't do like vuex-smart-module allowing to have strong typing through classes usage and to use directly the type of each parts of a store without creating redundant Interface types. People easily say, "oh classes usage like in vuex-smart-module is more verbose cause you have to specify generics", but when you have to use State, Getter or Action TYPE, you clearly don't want to write/specify n interfaces with k methods for each part a store.

    It is common for a lot of projects with strong architecture to have for requirement the need of an abstraction between different parts of different stores. Example two instances of store like: ProjectResourceStore and HomeResourceStore having each one Action inheriting from the same abstract class AResourceActions. What is really useful is that AResourceActions allows having default implementations and specifying a "contract". ProjectResourceAction and HomeResourceAction will be obligated to implement all non-implemented AResourceActions methods.

    What I say above seems to be clearly impossible with Pinia as it has only object type inference.

    It's also important to understand that with classes if I want to have a Type of a store part (State, Getter, Action), I don't have to manually specify all the properties/methods in a redundant Interface that will be used as a way to have non-infered type. Indeed, with classes, I can directly use the class as a Type.

    This problem has already been mentioned here: #343, but my issue just try to expose the problem with other related issues and limitations of Pinia type system. Also, no satisfying code example in the original issue has been provided.

    contribution welcome 📚 docs 
    opened by nicolidin 46
  • @pinia/nuxt latest version gives error

    @pinia/nuxt latest version gives error

    Reproduction

    https://github.com/Rigo-m/pinia-issue-repro

    Steps to reproduce the behavior

    1. yarn
    2. yarn dev

    Expected behavior

    Should work

    Actual behavior

    Throws error because vue composition api is being imported twice

    Additional information

    Latest node LTS

    help wanted external 
    opened by Rigo-m 24
  • Mocking stores in component unit tests

    Mocking stores in component unit tests

    Hi there! I had the need to mock an imported useStore function in my unit tests, and was having some trouble with setting up the mocks in the test properly. I came up with the following solution:

    component.vue

    <template>
        <button @click="addOne">Add 1</button>
    </template>
    
    <script lang="ts">
    import { defineComponent } from '@vue/composition-api';
    import { useCounterStore } from '../stores/counter';
    
    export default defineComponent({
        setup() {
            const counterStore = useCounterStore();
    
            return { addOne };
    
            function addOne() {
                counterStore.add(1);
            }
        }
    });
    </script>
    

    component.test.js

    import { shallowMount } from '@vue/test-utils';
    import CounterComponent from './component.vue';
    import { useCounterStore } from '../stores/counter';
    
    describe('Component', () => {
        it('Calls the add method on the counter store', () => {
            const counterStore = useCounterStore({});
            jest.spyOn(counterStore, 'add');
    
            const component = shallowMount(CounterComponent);
            component.find('button').trigger('click');
    
            expect(counterStore.add).toHaveBeenCalledWith(1);
        });
    });
    
    discussion 
    opened by rijkvanzanten 17
  • Feature request: subscribeAction()

    Feature request: subscribeAction()

    VueX has an option to subscribeAction. I think it would be even more relevant here. Pinia currently has subscribe() but it's just a simple wrapper over watch() and it often might not be precise enough.

    Subscribing to actions would be more explicit.

    https://vuex.vuejs.org/api/#subscribeaction

    store.subscribeAction((action, state) => {
      console.log(action.type)
      console.log(action.payload)
    })
    

    Usecase:

    In many places in the code you might want to react to userStore.state.isLoggedIn. Current store.subscribe() may fire multiple times, you'd need to check for truthy value of loggedIn, check if it's different from previous value and so on.

    discussion plugin-api 
    opened by MartinMalinda 16
  • docs page flickering

    docs page flickering

    Reproduction

    Using latest chrome on a mac, open 2 tabs to https://pinia.esm.dev/ and the page starts flickering weirdly.

    I can see it's caused by the dark mode flipping on and off rapidly. I assume it has something to do with how dark mode selection is being saved in localstorage.

    contribution welcome 📚 docs 
    opened by theoephraim 15
  • Can't import the named export from non EcmaScript module (only default export is available)

    Can't import the named export from non EcmaScript module (only default export is available)

    Steps to reproduce the behavior

    1. Use Vue-cli to create a Vue 3 app with Typescript.
    2. Run yarn add [email protected].
    3. Edit the main.ts:
    import { createApp } from "vue";
    import App from "./App.vue";
    import { createPinia } from "pinia";
    
    const app = createApp(App);
    app.use(createPinia());
    app.mount("#app");
    
    1. Run yarn serve.

    Expected behavior

    The compilation goes without an error

    Actual behavior

    Throws error:

    ERROR  Failed to compile with 18 errors                                                                                                           
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'computed' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'del' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'effectScope' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'getCurrentInstance' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'inject' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'isReactive' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'isRef' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'isVue2' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'markRaw' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'onUnmounted' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'reactive' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'ref' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'set' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'toRaw' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'toRef' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'toRefs' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'unref' from non EcmaScript module (only default export is available)
    
     error  in ./node_modules/pinia/dist/pinia.mjs
    
    Can't import the named export 'watch' from non EcmaScript module (only default export is available)
    

    Additional Information:

    "dependencies": {
       "core-js": "^3.6.5",
       "pinia": "^2.0.0-rc.9",
       "primeflex": "^3.0.1",
       "primeicons": "^4.1.0",
       "primevue": "^3.7.1",
       "vue": "^3.0.0",
       "vue-router": "^4.0.0-0"
     },
     "devDependencies": {
       "@typescript-eslint/eslint-plugin": "^4.18.0",
       "@typescript-eslint/parser": "^4.18.0",
       "@vue/cli-plugin-babel": "~4.5.0",
       "@vue/cli-plugin-eslint": "~4.5.0",
       "@vue/cli-plugin-router": "~4.5.0",
       "@vue/cli-plugin-typescript": "~4.5.0",
       "@vue/cli-service": "~4.5.0",
       "@vue/compiler-sfc": "^3.0.0",
       "@vue/eslint-config-prettier": "^6.0.0",
       "@vue/eslint-config-typescript": "^7.0.0",
       "eslint": "^6.7.2",
       "eslint-plugin-prettier": "^3.3.1",
       "eslint-plugin-vue": "^7.0.0",
       "lint-staged": "^9.5.0",
       "node-sass": "^4.12.0",
       "prettier": "^2.2.1",
       "sass-loader": "^8.0.2",
       "typescript": "~4.1.5"
     },
    
    bug has workaround 
    opened by MycroftHolmes1989 14
  • Should the state be merged at the same level as actions and getters?

    Should the state be merged at the same level as actions and getters?

    In the readme, you mention

    Should the state be merged at the same level as actions and getters?

    I figured we should open a discussion around this 🙂


    My 2 cents:

    I think we should either scope all things into relevant properties, eg:

    store.state.counter
    store.getters.doubleCount
    store.actions.reset()
    

    or scope none

    store.counter     // state
    store.doubleCount // getter
    store.reset       // action
    

    Having them all merged in the "root" store might cause naming conflicts between getters and state. However, you could make the argument that having a getter with the exact same name as a property in the state is a fairly bad design decision to begin with. In the case of a naming conflict, the state one should probably overwrite the getter, as getters will often rely on the state value to produce their own value.

    A big pro for having them all in the root is that you would be able to do things like

    import { useStore } from '@/stores/my-store';
    
    export default createComponent({
      setup() {
        const { counter, doubleCount, reset } = useStore();
      }
    });
    

    where you can destructure any of the 'items' in the store.

    Is there any specific reason why you decided on putting actions / getters in the root currently @posva?

    discussion 
    opened by rijkvanzanten 14
  • Pinia v2 doesn't work with vue@2 & @vue/composition-api@1.2.4

    Pinia v2 doesn't work with [email protected] & @vue/[email protected]

    Reproduction

    Not sure what went wrong, attached are screenshots of my package.json and the terminal output after upgrading to piniav2. It was working find prior.

    Add any other context about the problem here. Screen Shot 2021-10-27 at 11 32 44 PM Screen Shot 2021-10-27 at 11 33 06 PM

    opened by floydjones1 13
  • error when building with vite-ssg

    error when building with vite-ssg

    Attempting to run npm build on my vitesse-based project and I'm seeing the following error:

    ...
    [vite-ssg] Build for server...
    vite v2.5.6 building SSR bundle for production...
    ✓ 78 modules transformed.
    .vite-ssg-temp/manifest.webmanifest        0.38 KiB
    .vite-ssg-temp/main.js                     137.98 KiB
    .vite-ssg-temp/assets/style.1bff94d7.css   22.56 KiB
    TypeError: Cannot read property '_s' of undefined
        at useStore (/home/weiner/Sites/hc_project/handcrafted/vue/node_modules/pinia/dist/pinia.cjs.js:1544:20)
        at Module.<anonymous> (/home/weiner/Sites/hc_project/handcrafted/vue/.vite-ssg-temp/main.js:2673:19)
        at Module.o._compile (/home/weiner/Sites/hc_project/handcrafted/vue/node_modules/jiti/dist/v8cache.js:2:2778)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
        at Module.load (internal/modules/cjs/loader.js:937:32)
        at Function.Module._load (internal/modules/cjs/loader.js:778:12)
        at Module.require (internal/modules/cjs/loader.js:961:19)
        at require (internal/modules/cjs/helpers.js:92:18)
        at __require (/home/weiner/Sites/hc_project/handcrafted/vue/node_modules/vite-ssg/dist/chunk-3FHQZVYO.js:22:12)
        at build (/home/weiner/Sites/hc_project/handcrafted/vue/node_modules/vite-ssg/dist/node/cli.js:140:52)
    
    

    Any idea if the issue is with pinia or with vite-ssg? The only ticket I can find that references both is https://github.com/antfu/vite-ssg/issues/72. Here's the app init in my main.ts

    // https://github.com/antfu/vite-ssg
    // https://github.com/antfu/vite-ssg/issues/72
    export const createApp = ViteSSG(
      App,
      {routes},
      (ctx) => {
        // install all modules under `modules/`
        Object.values(import.meta.globEager('./modules/*.ts')).map(i => i.install?.(ctx));
        const pinia = createPinia()
        pinia.use(({store}) => {
          store.router = markRaw(ctx.router)
        })
    
        ctx.app.use(pinia)
      },
    )
    
    bug 
    opened by mrweiner 13
  • interested in redux devtools support?

    interested in redux devtools support?

    Screen Recording 2021-02-17 at 02 37 54 PM

    I wrote a plugin that allows you to manage the Pinia store/state using the redux devtools. Is there any interest in this? Is it worth making a plugin for?

    feature request 
    opened by james2doyle 13
  • Is it possible to access Nuxt context from a pinia sotre?

    Is it possible to access Nuxt context from a pinia sotre?

    First of all thanks for this awesome library.

    When I'm using nuxt to build my apps, I normally tend to use Nuxt axios and auth modules for instance and have my API methods wrapped around vuex accessing this.$axios to perform HTTP requests without being worried about authentication and other configuration stuff.

    I want to know if it is possible to have nuxt context injected inside my pinia store so i can keep using this pattern? If so how can I achieve this?

    Thanks.

    feature request 
    opened by isneezy 13
  • Production Build + Vue Devtool Plugin Error

    Production Build + Vue Devtool Plugin Error

    Reproduction

    https://codesandbox.io/s/cedarexamplesandbox-forked-idhgg3?file=/vite.config.js

    Steps to reproduce the bug

    When attempting to use Vue Devtools in a production build by setting __VUE_PROD_DEVTOOLS__: true, there is an error when using Pinia

    1. Go to https://codesandbox.io/s/cedarexamplesandbox-forked-idhgg3?file=/vite.config.js
    2. Click on Terminal under preview pane
    3. Click + to add another terminal instance
    4. Execute a production build and start the server with npm run build && npm run serve (you should be prompted to open the new port in another browser pane) image
    5. Open the production build instance in a new window image
    6. open the console and Vue devtools

    Expected behavior

    Vue devtools should work as expected with no errors

    Actual behavior

    Console error:

        at index.b5e1fa3c.js:7:1055
        at addPlugin (VM240 backend.js:3068:7)
        at async Object.<anonymous> (VM240 backend.js:2229:5)
    

    Looking through the stack trace, there is a property that Pinia is adding in non-prod environments, and is being referenced by the devtools plugin code image

    Additional information

    No response

    bug contribution welcome 🧑‍💻 pkg:devtools 
    opened by zcrumbo 1
  • docs: add initial state value/reactivity section

    docs: add initial state value/reactivity section

    Hey, sorry, i had quite a few things to solve out before coming back to this. I've added a section under the core-concepts/state about the importance of setting all the properties to benefit reactivity.

    This refers to this issue

    Let me know what you think of it, i think it could be great to explain a bit why it is better (is it?) to access the property with the myStore.myProperty instead of myStore.$state.myProperty on line 125.

    Cheers !

    opened by DarioRega 1
  • Possible edge case in devtools integration: Cannot read properties of null (reading '__VUE_DEVTOOLS_APP_RECORD_ID__')

    Possible edge case in devtools integration: Cannot read properties of null (reading '__VUE_DEVTOOLS_APP_RECORD_ID__')

    Reproduction

    https://github.com/basuneko/pinia-devtools-issue

    Steps to reproduce the bug

    1. Checkout the reproduction repo and run npm run serve
    2. Open a new tab and devtools
    3. Open the reproduction app - you should see the default vue cli homepage
    4. Wait ~60 seconds for the devtools timeout

    Expected behavior

    • 'bacon' and 'yolo' stores are listed in the pinia devtools tab and can be inspected
    • the console shows pinia initialisation messages
        🍍 bacon store added
        🍍 yolo store added
      
    • No errors are raised in the console;

    Actual behavior

    ✅ Both 'bacon' and 'yolo' stores are indeed listed in the pinia devtools tab

    ❌ However, instead of the 🍍 messages, after a timeout, devtools spits out a bunch of errors

    Screen Shot 2022-09-06 at 5 31 46 PM
    * Error: Timed out getting app record for app at backend.js:1160:14
    * [Hook] Error in async event handler for devtools-plugin:setup with args:
    * TypeError: Cannot read properties of null (reading '__VUE_DEVTOOLS_APP_RECORD_ID__') at getAppRecordId (backend.js:1103:11)
    

    Additional information

    Hi. I'm migrating a Vue 2, Vuex 3, vuex-module-decorators project to Pinia. For some historic reasons, our store module files export the actual store instance and, while that seems to work with Pinia as well, it seems to break something in the devtools integration. Here's an example:

    // @/store/pinia.ts
    
    import { Vue } from 'vue'
    import { PiniaVuePlugin } from 'pinia'
    
    Vue.use(PiniaVuePlugin) // it doesn't matter whether it's called here or in main.ts
    
    export const pinia = createPinia()
    
    // @/store/useUserStore.ts
    import { defineStore } from 'pinia'
    import { pinia } from '@/store/pinia'
    
    const useUserStore = defineStore('user', { ... })
    
    export const userStore = useUserStore(pinia) 
    

    I'm following the Stores outside of components guide, and passing an instance of Pinia into useUserStore. Functionality-wise, this seems to work fine. I have plenty of cypress tests and they're all passing after the migration. But the devtools errors are mildly concerning.

    Vue 2.7.5 -> 2.7.10 Pinia 2.0.21 Devtools extension 6.2.1 Chrome 105.0.5195.52

    contribution welcome vue 2.x 🧑‍💻 pkg:devtools 
    opened by basuneko 1
  • Cannot bypass getters with TypeScript

    Cannot bypass getters with TypeScript

    Reproduction

    https://stackblitz.com/edit/github-xe2cxw?file=src%2Fstores%2Fcounter.test.ts

    Steps to reproduce the bug

    Given the following code:

    import { defineStore } from 'pinia';
    import { createTestingPinia } from '@pinia/testing';
    
    const useStore = defineStore('lol', {
      state: () => ({ n: 0 }),
      getters: {
        double: (state) => state.n * 2,
      },
    });
    const pinia = createTestingPinia();
    const store = useStore(pinia);
    
    store.n++;
    store.double = 3;
    

    Expected behavior

    TypeScript should not complain.

    Actual behavior

    TypeScript raises the following error:

    TS2540: Cannot assign to 'double' because it is a read-only property.
    

    Additional information

    This is to be able to mock getters in tests https://pinia.vuejs.org/cookbook/testing.html#mocking-getters

    :sparkles: enhancement has workaround 🧪 pkg:testing 
    opened by nterray 4
  • Added autoImportDir for stores/ dir if it exists and is specified

    Added autoImportDir for stores/ dir if it exists and is specified

    Scope: Pinia's Nuxt module

    This change adds the autoImportDir to the Nuxt module, to automatically import a user's "/stores" directory if it exists. This is a feature to help people who may wish to organize their stores into a separate directory, just like they did with Nuxt 2.x, but using the name "stores" to not conflict with the Nuxt 2.x directory "store".

    I didn't have time tonight to provide an accompanying test, but if it this is a feature you think you'd like, please let me know and I can take a stab at writing the test. (fwiw, I tested manually in a test app that the feature works)

    • [x] Auto importing of "stores" works
    • [ ] Hot module reloading when stores changes...not quite there. Almost.
    discussion ⛰ pkg:nuxt 
    opened by richardeschloss 4
Owner
Eduardo San Martin Morote
Member of the @vuejs core team Speaker, trainer. From 🇪🇸, lives in 🇫🇷
Eduardo San Martin Morote
Transforms Vue.js 2.0 SFCs to Vue.js 3.0 Composition API syntax.

vue2-migration-helper Transforms Vue.js SFCs to composition api syntax. Install npm i vue2-migration-helper CLI # convert all .vue files in source dir

Muhammad Ubaid Raza 25 Sep 23, 2022
🛠️Vue kit of useful Vue Composition API functions

??️ Vue kit of useful Vue Composition API functions.

Salvatore Tedde 43 Feb 28, 2022
Vue composition-api composable components. i18n, validation, pagination, fetch, etc. +50 different composables

vue-composable Out-of-the-box ready to use composables ?? TreeShakable ??‍♂️ Fully Typescript ?? Vue 3 and 2 support ?? Vue Devtools support Introduct

Carlos Rodrigues 1k Sep 26, 2022
🕶 Vue Composition API for automatic fetch data when condition has been changed

vue-condition-watcher ?? Introduction Vue Composition API for automatic fetch data when condition has been changed Features ✔ Auto fetch data when con

Willy Hong 41 Aug 21, 2022
Use Vue Composition API Right Now (WIP)

Vue Use Use Vue Composition API Right Now. Note: Currently only Vue.js 2.x is supported. Since Vue.js has released a beta version of 3.0, this library

FE Next 26 Jul 7, 2022
Collection of essential Vue Composition Utilities for Vue 2 and 3

Collection of essential Vue Composition Utilities ?? Features ?? Interactive docs & demos ?? Seamless migration: Works for both Vue 3 and 2 ⚡ Fully tr

VueUse 92 Oct 3, 2022
A Vue composition function that makes infinite scroll a breeze.

vue-use-infinite-scroll Installation npm i -S vue-use-infinite-scroll Usage template <div> <span>{{ errorMessageRef }}</span> <ul> <li

Andrea Simone Costa 108 Aug 2, 2022
Collection of utility composition functions for Vue

Extensive collection of composition functions for Vue

Justin Brooks 86 Aug 24, 2022
A vue code diff display plugin, support Vue2 / Vue3

A code diff display plugin, available for Vue2 / Vue3. It is the vue3 version of vue-code-diff, refer to a lot of code, thanks here.

Shimada666 106 Oct 3, 2022
Vue 3 jsx runtime support.

vue-jsx-runtime Vue 3 jsx runtime support. The background https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html . With new jsx ru

doly mood 7 May 17, 2022
A simple Vue 3 plugin for handling browser cookies with typescript support

A vue 3 plugin for handling browser cookies with typescript support. Load and save cookies within your Vue 3 application

Anish George 43 Aug 26, 2022
Support for TypeScript's path mapping in Vite

vite-tsconfig-paths Give vite the ability to resolve imports using TypeScript's path mapping. Usage Install as dev dependency Inject vite-tsconfig-pat

Alec Larson 548 Sep 30, 2022
Lightweight dependency injection library for Vue.js

STFALCON-VUE-DI STFALCON-VUE-DI is a missed piece of vue apps. This library allows you to simplify an injection of the vue components into your app. I

Stfalcon LLC 9 Jul 30, 2020
Vue Use Utilities build on top of vue-demi & @vue/compostion-api

Vue Use Utilities Vue Use Utilities build on top of vue-demi & @vue/compostion-api. It works both for Vue 2 & 3. ✨ Features ?? Composable Utilities ??

Vue Blocks 25 Sep 12, 2022
A plugin that provides a composable API for giving elements a fixed aspect ratio.

@tailwindcss/aspect-ratio A plugin that provides a composable API for giving elements a fixed aspect ratio. Installation Install the plugin from npm:

Tailwind Labs 729 Sep 26, 2022
CSS Maximum Reversi best practices for Reversi UI/UX using CSS3 and Vue3

CSS Maximum Reversi is for exploring the best of Reversi UI/UX with CSS3 and Vue3. Play Game hinastory.github.io/css-maximum-reversi/ QR Code  Screens

null 2 Feb 22, 2022
DOM helpers plugin for Vue.js using gaspard

Vue-gaspard DOM helpers plugin for Vue.js using gaspard Getting started Installing npm yarn bower unpkg npm install vue-gaspard yarn add vue-gaspard b

Luca 7 Jul 30, 2020
Calculates and displays the downloads and distribution of your GitHub releases

Calculates and displays the downloads and distribution of your GitHub releases

Musthaq Ahamad 9 Jan 12, 2022
The word highlighter library for Vue 2 and Vue 3.

The word highlighter library for Vue 2 and Vue 3.

ryo 96 Sep 27, 2022