Skip to content

Pinia 源代码导览

项目结构

pinia-course/
├── 04-core-feature/          # 核心功能实现
│   ├── src/
│   │   ├── pinia.js         # Pinia 实例
│   │   ├── store.js         # Store
│   │   └── reactive.js      # 响应式
│   ├── test/
│   │   ├── pinia.test.js
│   │   ├── store.test.js
│   │   └── reactive.test.js
│   ├── package.json
│   └── README.md
├── 05-lesson-plan.md         # 课程计划
├── 01-intro.md              # 背景研究
├── 02-arch.md              # 架构分析
└── 03-code-walkthrough.md   # 源代码导览

核心文件解析

1. pinia.js - Pinia 实例

文件路径: src/pinia.js

核心功能:

  • 管理 Store
  • 插件系统
  • DevTools 集成

关键代码:

javascript
import { reactive, effectScope } from 'vue'

// Pinia 符号
export const piniaSymbol = Symbol()

// Pinia 实例
export class Pinia {
  constructor() {
    this._s = new Map()  // Store 映射
    this.state = reactive({})  // 全局状态
    this._p = []  // 插件
    this._a = null  // Vue 应用
    this._e = effectScope(true)  // 作用域
  }
  
  // 安装 Pinia
  install(app) {
    this._a = app
    app.provide(piniaSymbol, this)
    app.config.globalProperties.$pinia = this
    
    // 初始化插件
    this._p.forEach(plugin => plugin({ pinia: this, app }))
  }
  
  // 使用插件
  use(plugin) {
    this._p.push(plugin)
    
    if (this._a) {
      plugin({ pinia: this, app: this._a })
    }
    
    return this
  }
  
  // 获取 Store
  get store() {
    return this._s
  }
  
  // 获取状态
  get state() {
    return this.state
  }
}

// 创建 Pinia 实例
export function createPinia() {
  return new Pinia()
}

设计要点:

  • 使用 Map 存储 Store
  • 支持插件系统
  • 与 Vue 集成

2. store.js - Store

文件路径: src/store.js

核心功能:

  • 定义 Store
  • 管理状态
  • 提供方法

关键代码:

javascript
import { reactive, computed, watch } from 'vue'

// 定义 Store
export function defineStore(id, options) {
  const { state, getters, actions } = options
  
  return function useStore(pinia) {
    pinia = pinia || activePinia
    
    if (!pinia._s.has(id)) {
      createStore(id, state, getters, actions, pinia)
    }
    
    return pinia._s.get(id)
  }
}

// 创建 Store
function createStore(id, state, getters, actions, pinia) {
  const initialState = state ? state() : {}
  
  const store = reactive({
    $id: id,
    $state: initialState,
    $patch: (partialStateOrMutator) => {
      if (typeof partialStateOrMutator === 'function') {
        partialStateOrMutator(store.$state)
      } else {
        Object.assign(store.$state, partialStateOrMutator)
      }
    },
    $reset: () => {
      if (state) {
        Object.assign(store.$state, state())
      }
    },
    $dispose: () => {
      pinia._s.delete(id)
    }
  })
  
  // 添加 getters
  if (getters) {
    Object.keys(getters).forEach(key => {
      Object.defineProperty(store, key, {
        get: () => getters[key].call(store, store),
        enumerable: true
      })
    })
  }
  
  // 添加 actions
  if (actions) {
    Object.keys(actions).forEach(key => {
      store[key] = (...args) => actions[key].apply(store, args)
    })
  }
  
  // 添加到 Pinia
  pinia._s.set(id, store)
  pinia.state[id] = store.$state
  
  return store
}

// 活跃的 Pinia 实例
let activePinia = null

// 设置活跃的 Pinia 实例
export function setActivePinia(pinia) {
  activePinia = pinia
}

设计要点:

  • 使用 reactive 创建响应式状态
  • 支持计算属性
  • 支持方法

3. reactive.js - 响应式

文件路径: src/reactive.js

核心功能:

  • 响应式状态
  • 计算属性
  • 监听

关键代码:

javascript
import { reactive, computed, watch } from 'vue'

// 创建响应式状态
export function createState(initialState) {
  return reactive(initialState)
}

// 创建计算属性
export function createGetter(getter) {
  return computed(getter)
}

// 创建监听器
export function createWatcher(source, callback, options = {}) {
  return watch(source, callback, options)
}

// 创建 Store 响应式
export function createStoreReactive(store, pinia) {
  // 监听状态变化
  watch(
    () => store.$state,
    (newState) => {
      pinia.state[store.$id] = newState
    },
    { deep: true }
  )
  
  return store
}

设计要点:

  • 使用 Vue 3 的响应式 API
  • 支持计算属性
  • 支持监听

关键设计决策

1. 使用 Map 存储 Store

原因:

  • 快速查找
  • 自动去重
  • 内存效率高

实现:

javascript
this._s = new Map()

// 添加 Store
this._s.set(id, store)

// 获取 Store
const store = this._s.get(id)

2. 使用 reactive

原因:

  • 响应式状态
  • 自动追踪
  • 高效更新

实现:

javascript
const store = reactive({
  $id: id,
  $state: initialState
})

3. 支持插件系统

原因:

  • 灵活扩展
  • 社区贡献
  • 功能增强

实现:

javascript
pinia.use(plugin)

// 插件结构
function plugin({ pinia, app, store }) {
  // 插件逻辑
}

测试策略

单元测试

javascript
import { describe, it } from 'node:test'
import assert from 'node:assert'
import { createPinia, defineStore } from '../src/pinia.js'

describe('Pinia 测试', () => {
  it('应该创建 Pinia 实例', () => {
    const pinia = createPinia()
    assert.ok(pinia)
  })
  
  it('应该创建 Store', () => {
    const pinia = createPinia()
    const useStore = defineStore('counter', {
      state: () => ({
        count: 0
      })
    })
    
    const store = useStore(pinia)
    assert.ok(store)
    assert.strictEqual(store.count, 0)
  })
})

性能优化

1. 计算属性缓存

javascript
const doubleCount = computed(() => store.count * 2)  // 自动缓存

2. 按需订阅

javascript
watch(
  () => store.count,  // 只订阅 count
  (newVal) => {
    console.log(newVal)
  }
)

3. 懒加载 Store

javascript
const store = useStore()  // 懒加载

总结

Pinia 的源代码体现了以下设计原则:

  1. 简洁:简洁的 API
  2. 响应式:使用 Vue 3 的响应式系统
  3. 插件化:支持插件扩展
  4. 类型安全:完整的 TypeScript 支持

理解源代码有助于更好地使用和优化 Pinia。

参考资源

架构师AI杜公众号二维码

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态