核心架构总览

src/
├── store.ts        # Store 核心实现
├── rootStore.ts    # 根 Store 管理
├── pinia.ts        # 主入口和核心 API
├── hmr.ts          # 热模块替换支持
├── types.ts        # 类型定义
├── deprecations.ts # 废弃 API
└── devtools.ts     # Devtools 集成

核心源码解析

创建 Pinia 实例

// src/pinia.ts
export function createPinia(): Pinia {
  // 创建一个 effect 作用域,用于管理所有 store 的响应式效果
  const scope = effectScope(true);

  // 在作用域内创建全局状态树
  const state = scope.run(() => ref<Record<string, StateTree>>({}))!;

  // 创建 pinia 实例,markRaw 标记避免被响应式处理
  const pinia: Pinia = markRaw({
    // Vue 插件安装方法
    install(app: App) {
      // 设置当前活跃的 pinia 实例
      setActivePinia(pinia);
      // 提供依赖注入
      app.provide(piniaSymbol, pinia);
      // 全局挂载
      app.config.globalProperties.$pinia = pinia;
    },

    // 内部属性:
    _p: [], // 插件列表
    _a: null, // 当前 app 实例
    _e: scope, // effect 作用域
    _s: new Map(), // store 的映射表
    state, // 全局状态树
  });

  return pinia;
}

定义 Store 的核心函数

// src/store.ts
export function defineStore(idOrOptions: string | DefineStoreOptions, setup?: () => {}, setupOptions?: DefineSetupStoreOptions): StoreDefinition {
  let id: string;
  let options: DefineStoreOptions | DefineSetupStoreOptions;

  // 参数重载处理
  if (typeof idOrOptions === "string") {
    id = idOrOptions;
    options = setupOptions || {};
    if (typeof setup !== "function") {
      options = setup || {};
    }
  } else {
    options = idOrOptions;
    id = idOrOptions.id;
  }

  function useStore(pinia?: Pinia | null, hot?: StoreGeneric): StoreGeneric {
    // 获取当前 Vue 实例(如果在组件内调用)
    const currentInstance = getCurrentInstance();
    // 获取 pinia 实例(优先使用参数传入的,其次从组件注入获取)
    pinia = pinia || (currentInstance && inject(piniaSymbol));

    if (pinia) setActivePinia(pinia);

    // 确保有活跃的 pinia 实例
    pinia = activePinia!;

    // 如果该 store 尚未创建
    if (!pinia._s.has(id)) {
      // 区分 options 和 setup 两种定义方式
      if (typeof setup === "function") {
        createSetupStore(id, setup, options, pinia);
      } else {
        createOptionsStore(id, options as DefineStoreOptions, pinia);
      }
    }

    // 获取 store 实例
    const store: Store = pinia._s.get(id)!;

    // 处理热更新
    if (hot) {
      // ...热更新逻辑
    }

    // SSR 处理
    if (__SSR__ && currentInstance && currentInstance.proxy) {
      // ...SSR 逻辑
    }

    return store as any;
  }

  useStore.$id = id;

  return useStore;
}

创建 Composition API 风格的 Store

// src/store.ts
function createSetupStore(id: string, setup: () => {}, options: DefineSetupStoreOptions, pinia: Pinia): Store {
  let scope!: EffectScope;

  // 创建部分 store 定义
  const partialStore = {
    _p: pinia, // 所属的 pinia 实例
    $id: id, // store 的唯一 ID
    $onAction: addSubscription.bind(null, actionSubscriptions),
    $patch,
    $reset,
    $subscribe(callback, options = {}) {
      // ...订阅逻辑
    },
    $dispose,
  } as unknown as Store;

  // 创建响应式 store
  const store: Store = reactive(partialStore) as Store;

  // 将 store 注册到 pinia 中
  pinia._s.set(id, store);

  // 在 effect 作用域中运行 setup 函数
  const setupStore = pinia._e.run(() => {
    scope = effectScope();
    return scope.run(() => setup());
  })!;

  // 遍历 setup 返回的结果
  for (const key in setupStore) {
    const prop = setupStore[key];

    // 处理 ref 和 reactive
    if (isRef(prop) && !isComputed(prop)) {
      // 如果是 ref(非 computed),将其加入 state
      if (!pinia.state.value[id]) {
        pinia.state.value[id] = {};
      }
      pinia.state.value[id][key] = prop;
    } else if (typeof prop === "function") {
      // 处理 action 方法
      const actionValue = wrapAction(key, prop);
      setupStore[key] = actionValue;
    }
  }

  // 合并 setup 返回的结果到 store
  Object.assign(store, setupStore);

  // 允许插件扩展 store
  pinia._p.forEach((extender) => {
    Object.assign(store, extender({ store, app: pinia._a, pinia }));
  });

  return store;
}

Action 包装器

// src/store.ts
function wrapAction(name: string, action: Function) {
  return function (this: any) {
    // 设置当前活跃的 pinia 实例
    setActivePinia(pinia);
    const args = Array.from(arguments);

    // 回调队列
    const afterCallbackList: Array<Function> = [];
    const onErrorCallbackList: Array<Function> = [];

    // 定义 after 和 onError 钩子
    function after(callback: Function) {
      afterCallbackList.push(callback);
    }

    function onError(callback: Function) {
      onErrorCallbackList.push(callback);
    }

    try {
      // 执行 action,确保正确的 this 上下文
      const ret = action.apply(this && this.$id === id ? this : store, args);

      // 处理异步 action
      if (ret instanceof Promise) {
        return ret
          .then((value) => {
            // 执行成功回调
            afterCallbackList.forEach((callback) => callback(value));
            return value;
          })
          .catch((error) => {
            // 执行错误回调
            onErrorCallbackList.forEach((callback) => callback(error));
            return Promise.reject(error);
          });
      }

      // 同步 action 的成功回调
      afterCallbackList.forEach((callback) => callback(ret));
      return ret;
    } catch (error) {
      // 同步 action 的错误处理
      onErrorCallbackList.forEach((callback) => callback(error));
      throw error;
    }
  };
}

关键设计解析

响应式状态管理

Pinia 使用 Vuereactive 系统管理状态:

// 在 createSetupStore 中
if (isRef(prop) && !isComputed(prop)) {
  if (!pinia.state.value[id]) {
    pinia.state.value[id] = reactive({});
  }
  pinia.state.value[id][key] = prop;
}

依赖注入系统

通过 Vueprovide/inject 实现 store 的共享:

// 安装时提供 pinia 实例
app.provide(piniaSymbol, pinia);

// 使用时注入
pinia = inject(piniaSymbol);

类型系统实现

Pinia 的类型系统是其一大亮点,通过复杂的泛型实现完善的类型推断:

// src/types.ts
export interface StoreDefinition<
  Id extends string = string,
  S extends StateTree = StateTree,
  G extends _GettersTree<S> = _GettersTree<S>,
  A = _ActionsTree
> {
  (pinia?: Pinia | null, hot?: StoreGeneric): Store<Id, S, G, A>
  $id: Id
}

性能优化策略

  1. 惰性初始化:Store 只有在第一次使用时才会被创建;

  2. Effect Scope:使用 Vue 3effectScope 管理响应式效果,便于统一清理;

  3. 标记非响应式:对 pinia 实例使用 markRaw 避免不必要的响应式转换;

  4. 缓存策略:Store 实例会被缓存,避免重复创建;

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 核心架构总览
  2. 2. 核心源码解析
    1. 2.1. 创建 Pinia 实例
    2. 2.2. 定义 Store 的核心函数
    3. 2.3. 创建 Composition API 风格的 Store
    4. 2.4. Action 包装器
  3. 3. 关键设计解析
    1. 3.1. 响应式状态管理
    2. 3.2. 依赖注入系统
    3. 3.3. 类型系统实现
  4. 4. 性能优化策略