Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 1 addition & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
- 📦 Extremely light
- ⛰️ Nuxt Module

Pinia works with both Vue 2 and Vue 3.
The latest version of pinia works with Vue 3. See the branch [v2](https://github.com/vuejs/pinia/tree/v2) for a version that works with Vue 2.

Pinia is the most similar English pronunciation of the word _pineapple_ in Spanish: _piña_. A pineapple is in reality a group of individual flowers that join together to create a multiple fruit. Similar to stores, each one is born individually, but they are all connected at the end. It's also a delicious tropical fruit indigenous to South America.

Expand Down Expand Up @@ -130,23 +130,6 @@ app.use(pinia)
app.mount('#app')
```

```js
// Vue 2
import { createPinia, PiniaVuePlugin } from 'pinia'

Vue.use(PiniaVuePlugin)
const pinia = createPinia()

new Vue({
el: '#app',
// other options...
// ...
// note the same `pinia` instance can be used across multiple Vue apps on
// the same page
pinia,
})
```

For more detailed instructions, including [Nuxt configuration](https://pinia.vuejs.org/ssr/nuxt.html#nuxt-js), check the [Documentation](https://pinia.vuejs.org).

### Create a Store
Expand Down
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pinia/root",
"packageManager": "pnpm@9.15.3",
"packageManager": "pnpm@10.2.0",
"type": "module",
"private": true,
"workspaces": [
Expand Down Expand Up @@ -36,31 +36,31 @@
"@rollup/plugin-replace": "^6.0.2",
"@rollup/plugin-terser": "^0.4.4",
"@types/lodash.kebabcase": "^4.1.9",
"@types/node": "^22.10.1",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/ui": "^2.1.8",
"@types/node": "^22.13.1",
"@vitest/coverage-v8": "^3.0.5",
"@vitest/ui": "^3.0.5",
"@vue/compiler-sfc": "~3.5.13",
"@vue/server-renderer": "~3.5.13",
"chalk": "^5.4.1",
"conventional-changelog-cli": "^2.2.2",
"execa": "^9.5.2",
"globby": "^14.0.1",
"happy-dom": "^16.5.3",
"lint-staged": "^15.3.0",
"happy-dom": "^16.8.1",
"lint-staged": "^15.4.3",
"lodash.kebabcase": "^4.1.1",
"minimist": "^1.2.8",
"p-series": "^3.0.0",
"pascalcase": "^2.0.0",
"prettier": "^3.4.2",
"rimraf": "^6.0.1",
"rollup": "^4.30.1",
"rollup": "^4.34.2",
"rollup-plugin-typescript2": "^0.36.0",
"semver": "^7.6.3",
"semver": "^7.7.1",
"simple-git-hooks": "^2.11.1",
"typedoc": "^0.26.11",
"typedoc-plugin-markdown": "~4.2.0",
"typescript": "~5.6.3",
"vitest": "^2.1.8",
"typedoc": "^0.27.6",
"typedoc-plugin-markdown": "~4.4.1",
"typescript": "~5.7.3",
"vitest": "^3.0.5",
"vue": "~3.5.13"
},
"simple-git-hooks": {
Expand Down
8 changes: 8 additions & 0 deletions packages/docs/.vitepress/config/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
},
],
},
{
text: 'v3.x',
items: [{ text: 'v2.x', link: 'https://v2.pinia.vuejs.org' }],
},
],

sidebar: {
Expand Down Expand Up @@ -132,6 +136,10 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
text: 'VSCode Snippets',
link: '/cookbook/vscode-snippets.html',
},
{
text: 'Migration from v2 to v3',
link: '/cookbook/migration-v2-v3.html',
},
{
text: 'Migration from v0/v1 to v2',
link: '/cookbook/migration-v1-v2.html',
Expand Down
4 changes: 4 additions & 0 deletions packages/docs/.vitepress/config/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
},
],
},
{
text: 'v3.x',
items: [{ text: 'v2.x', link: 'https://v2.pinia.vuejs.org' }],
},
],
sidebar: {
'/zh/api/': [
Expand Down
33 changes: 33 additions & 0 deletions packages/docs/cookbook/migration-v2-v3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Migrating from v2 to v3

Pinia v3 is a _boring_ major release with no new features. It drops deprecated APIs and updates major dependencies. It only supports Vue 3. If you are using Vue 2, you can keep using v2. If you need help, [book help with Pinia's author](https://cal.com/posva/consultancy).

For most users, the migration should require **no change**. This guide is here to help you in case you encounter any issues.

## Deprecations

### `defineStore({ id })`

The `defineStore()` signature that accepts an object with an `id` property is deprecated. You should use the `id` parameter instead:

```ts
defineStore({ // [!code --]
id: 'storeName', // [!code --]
defineStore('storeName', { // [!code ++]
// ...
})
```

### `PiniaStorePlugin`

This deprecated type alias has been removed in favor of `PiniaPlugin`.

## New versions

- Only Vue 3 is supported.
- TypeScript 5 or newer is required.
- The devtools API has been upgraded to [v7](https://devtools.vuejs.org).

## Nuxt

The Nuxt module has been updated to support Nuxt 3. If you are using Nuxt 2 or Nuxt bridge, you can keep using the old version of Pinia.
22 changes: 0 additions & 22 deletions packages/docs/cookbook/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@ expect(store.someAction).toHaveBeenCalledTimes(1)
expect(store.someAction).toHaveBeenLastCalledWith()
```

Please note that if you are using Vue 2, `@vue/test-utils` requires a [slightly different configuration](#Unit-test-components-Vue-2-).

### Initial State

You can set the initial state of **all of your stores** when creating a testing pinia by passing an `initialState` object. This object will be used by the testing pinia to _patch_ stores when they are created. Let's say you want to initialize the state of this store:
Expand Down Expand Up @@ -291,23 +289,3 @@ const wrapper = mount(Counter, {
## E2E tests

When it comes to Pinia, you don't need to change anything for E2E tests, that's the whole point of these tests! You could maybe test HTTP requests, but that's way beyond the scope of this guide 😄.

## Unit test components (Vue 2)

When using [Vue Test Utils 1](https://v1.test-utils.vuejs.org/), install Pinia on a `localVue`:

```js
import { PiniaVuePlugin } from 'pinia'
import { createLocalVue, mount } from '@vue/test-utils'
import { createTestingPinia } from '@pinia/testing'

const localVue = createLocalVue()
localVue.use(PiniaVuePlugin)

const wrapper = mount(Counter, {
localVue,
pinia: createTestingPinia(),
})

const store = useSomeStore() // uses the testing pinia!
```
4 changes: 2 additions & 2 deletions packages/docs/core-concepts/outside-component-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const router = createRouter({
})

// ❌ Depending on the order of imports this will fail
const store = useStore()
const store = useUserStore()

router.beforeEach((to, from, next) => {
// we wanted to use the store here
Expand All @@ -53,7 +53,7 @@ router.beforeEach((to, from, next) => {
router.beforeEach((to) => {
// ✅ This will work because the router starts its navigation after
// the router is installed and pinia will be installed too
const store = useStore()
const store = useUserStore()

if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})
Expand Down
54 changes: 4 additions & 50 deletions packages/docs/core-concepts/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ A Pinia plugin is a function that optionally returns properties to be added to a
```js
export function myPiniaPlugin(context) {
context.pinia // the pinia created with `createPinia()`
context.app // the current app created with `createApp()` (Vue 3 only)
context.app // the current app created with `createApp()`
context.store // the store the plugin is augmenting
context.options // the options object defining the store passed to `defineStore()`
// ...
Expand Down Expand Up @@ -143,28 +143,6 @@ pinia.use(({ store }) => {

Note that state changes or additions that occur within a plugin (that includes calling `store.$patch()`) happen before the store is active and therefore **do not trigger any subscriptions**.

:::warning
If you are using **Vue 2**, Pinia is subject to the [same reactivity caveats](https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats) as Vue. You will need to use `Vue.set()` (Vue 2.7) or `set()` (from `@vue/composition-api` for Vue <2.7) for when creating new state properties like `secret` and `hasError`:

```js
import { set, toRef } from '@vue/composition-api'
pinia.use(({ store }) => {
if (!store.$state.hasOwnProperty('secret')) {
const secretRef = ref('secret')
// If the data is meant to be used during SSR, you should
// set it on the `$state` property so it is serialized and
// picked up during hydration
set(store.$state, 'secret', secretRef)
}
// set it directly on the store too so you can access it
// both ways: `store.$state.secret` / `store.secret`
set(store, 'secret', toRef(store.$state, 'secret'))
store.secret // 'secret'
})
```

:::

#### Resetting state added in plugins

By default, `$reset()` will not reset state added by plugins but you can override it to also reset the state you add:
Expand Down Expand Up @@ -395,10 +373,12 @@ declare module 'pinia' {
```

:::tip

There is also a `StoreGetters` type to extract the _getters_ from a Store type. You can also extend the options of _setup stores_ or _option stores_ **only** by extending the types `DefineStoreOptions` and `DefineSetupStoreOptions` respectively.

:::

## Nuxt.js
## Nuxt

When [using pinia alongside Nuxt](../ssr/nuxt.md), you will have to create a [Nuxt plugin](https://nuxt.com/docs/guide/directory-structure/plugins) first. This will give you access to the `pinia` instance:

Expand Down Expand Up @@ -427,32 +407,6 @@ The above example is using TypeScript, you have to remove the type annotations `

:::

### Nuxt.js 2

If you are using Nuxt.js 2, the types are slightly different:

```ts{3,15-17}
// plugins/myPiniaPlugin.ts
import { PiniaPluginContext } from 'pinia'
import { Plugin } from '@nuxt/types'

function MyPiniaPlugin({ store }: PiniaPluginContext) {
store.$subscribe((mutation) => {
// react to store changes
console.log(`[🍍 ${mutation.storeId}]: ${mutation.type}.`)
})

// Note this has to be typed if you are using TS
return { creationTime: new Date() }
}

const myPlugin: Plugin = ({ $pinia }) => {
$pinia.use(MyPiniaPlugin)
}

export default myPlugin
```

## Existing plugins

You can check existing [Pinia plugins on GitHub](https://github.com/topics/pinia-plugin) with the topic _pinia-plugin_.
6 changes: 4 additions & 2 deletions packages/docs/core-concepts/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export const useStore = defineStore('storeId', {
```

:::tip
If you are using Vue 2, the data you create in `state` follows the same rules as the `data` in a Vue instance, i.e. the state object must be plain and you need to call `Vue.set()` when **adding new** properties to it. **See also: [Vue#data](https://v2.vuejs.org/v2/api/#data)**.

In order for Vue to properly detect state, you must declare every state piece in `data`, even if its initial value is `undefined`.

:::

## TypeScript
Expand Down Expand Up @@ -215,7 +217,7 @@ store.$patch((state) => {

<!-- TODO: disable this with `strictMode`, `{ noDirectPatch: true }` -->

The main difference here is that `$patch()` allows you to group multiple changes into one single entry in the devtools. Note that **both direct changes to `state` and `$patch()` appear in the devtools** and can be time traveled (not yet in Vue 3).
The main difference here is that `$patch()` allows you to group multiple changes into one single entry in the devtools. Note that **both direct changes to `state` and `$patch()` are tracked in devtools** and can be time traveled.

## Replacing the `state`

Expand Down
20 changes: 0 additions & 20 deletions packages/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,6 @@ app.use(pinia)
app.mount('#app')
```

If you are using Vue 2, you also need to install a plugin and inject the created `pinia` at the root of the app:

```js {1,3-4,12}
import { createPinia, PiniaVuePlugin } from 'pinia'

Vue.use(PiniaVuePlugin)
const pinia = createPinia()

new Vue({
el: '#app',
// other options...
// ...
// note the same `pinia` instance can be used across multiple Vue apps on
// the same page
pinia,
})
```

This will also add devtools support. In Vue 3, some features like time traveling and editing are still not supported because vue-devtools doesn't expose the necessary APIs yet but the devtools have way more features and the developer experience as a whole is far superior.

## What is a Store?

A Store (like Pinia) is an entity holding state and business logic that isn't bound to your Component tree. In other words, **it hosts global state**. It's a bit like a component that is always there and that everybody can read off and write to. It has **three concepts**, the [state](./core-concepts/state.md), [getters](./core-concepts/getters.md) and [actions](./core-concepts/actions.md) and it's safe to assume these concepts are the equivalent of `data`, `computed` and `methods` in components.
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ features:
- title: 🔑 Type Safe
details: Types are inferred, which means stores provide you with autocompletion even in JavaScript!
- title: ⚙️ Devtools support
details: Pinia hooks into Vue devtools to give you an enhanced development experience in both Vue 2 and Vue 3.
details: Pinia hooks into Vue devtools to give you an enhanced development experience.
- title: 🔌 Extensible
details: React to store changes and actions to extend Pinia with transactions, local storage synchronization, etc.
- title: 🏗 Modular by design
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
title="Create your own Pinia from scratch"
/>

Pinia [started](https://github.com/vuejs/pinia/commit/06aeef54e2cad66696063c62829dac74e15fd19e) as an experiment to redesign what a Store for Vue could look like with the [Composition API](https://github.com/vuejs/composition-api) around November 2019. Since then, the initial principles have remained the same, but Pinia works for both Vue 2 and Vue 3 **and doesn't require you to use the composition API**. The API is the same for both except for _installation_ and _SSR_, and these docs are targeted to Vue 3 **with notes about Vue 2** whenever necessary so it can be read by Vue 2 and Vue 3 users!
Pinia [started](https://github.com/vuejs/pinia/commit/06aeef54e2cad66696063c62829dac74e15fd19e) as an experiment to redesign what a Store for Vue could look like with the [Composition API](https://github.com/vuejs/composition-api) around November 2019. Since then, the initial principles have remained the same and Vue 2 support has been dropped in 2025, but Pinia **doesn't require you to use the composition API**.

## Why should I use Pinia?

Expand Down
6 changes: 3 additions & 3 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
},
"dependencies": {
"@chenfengyuan/vue-countdown": "^2.1.2",
"@vueuse/core": "^12.4.0",
"@vueuse/core": "^12.5.0",
"pinia": "workspace:*",
"typedoc-vitepress-theme": "^1.1.1",
"vitepress": "1.5.0",
"typedoc-vitepress-theme": "^1.1.2",
"vitepress": "1.6.3",
"vitepress-translation-helper": "^0.2.2",
"vue-use-spring": "^0.3.3"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/typedoc-markdown.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export async function createTypeDocApp(config = {}) {
if (project) {
// Rendered docs
try {
await app.generateDocs(project, options.out)
await app.generateOutputs(project)
app.logger.info(`generated at ${options.out}.`)
} catch (error) {
app.logger.error(error)
Expand Down
4 changes: 2 additions & 2 deletions packages/docs/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineConfig, Plugin } from 'vite'
import { defineConfig, type Plugin } from 'vite'
import _fs from 'fs'
import path from 'path'
// import TypeDocPlugin from './vite-typedoc-plugin'
Expand All @@ -24,7 +24,7 @@ export default defineConfig({
__BROWSER__: 'true',
},
optimizeDeps: {
exclude: ['vue-demi', '@vueuse/shared', '@vueuse/core', 'pinia'],
exclude: ['@vueuse/shared', '@vueuse/core', 'pinia'],
},
})

Expand Down
Loading
Loading