uni-app x 专属 Pinia 库正式发布

v0.1.0 为首个公开版本:以 uni-app x 内建响应式原语(ref / computed / reactive / watch)为唯一底层依赖、不重造响应式栈,把 store 组织、跨页面单例、实例 API 这些标准 Pinia 在 vdom 模式 App 原生端给不了的能力收进一套 Pinia 心智的 API。Web 与 Android 真机全用例通过,云打包 release 编译零错误。

一、为什么做这个库

uni-app x 的 vdom 模式 App 原生端,标准 Pinia 因 UTS 强类型约束(Proxy、动态属性、Partial<T> 缺失)无法编译;官方仅推荐"导出模块级 reactive 变量"的裸方案。直接用它写业务,四件事反复发生:

  • 无统一范式:state、派生值、修改逻辑混在一个 reactive 对象里,命名与组织全靠自觉,项目一大就失控
  • 无单例保证:跨页面共享同一份可变全局,"谁在什么时候创建了什么"全靠约定,同 id 冲突静默覆盖
  • 无实例 API:批量更新、清理重建、反查归属都要业务手写,每个项目重复一遍
  • 迁移成本:将来项目切到蒸汽模式(标准 Pinia 全平台可用),调用方代码要全部重写

unix-pinia 把这些收敛成一套库:写过 Pinia 的开发者看一眼 API 就能上手(defineStore / storeToRefs / createPinia);单例由模块级注册表保证;实例 API 一比一对齐;每个裁掉项都有明确原因与替代方案——将来迁移回标准 Pinia,业务调用方代码几乎零改动。

二、核心能力

setup 式 defineStore

import type { Ref, ComputedRef } from 'vue'
import { defineStore } from '@/uni_modules/ux-pinia'

export type CounterStore = {
	count: Ref<number>,               // state:Ref
	doubleCount: ComputedRef<number>, // getter:ComputedRef
	increment: () => void             // action:箭头函数
}

export const useCounterStore = defineStore<CounterStore>('counter', (): CounterStore => {
	const count: Ref<number> = ref(0)
	const doubleCount: ComputedRef<number> = computed((): number => count.value * 2)
	const increment = (): void => { count.value++ }
	return { count, doubleCount, increment } as CounterStore
})

state 用 Ref、getter 用 ComputedRef、action 用箭头函数,与 Pinia 官方推荐的 setup store 写法一致;返回类型显式 type 标注,编辑器全程提示。

免挂载单例,跨页面共享

模块级注册表保证应用级单例:同 id 多次 useStore 返回同一实例,跨页面共享状态,无需 app.use(实测原生端 app.use 不触发 install,免挂载是唯一双端一致的形态);同 id 重复 defineStore 警告并保持幂等。

实例 API 顶层函数映射

import { patch, dispose, getStoreId } from '@/uni_modules/ux-pinia'

patch(store, (s: CounterStore): void => { s.count.value = 10 }) // ≙ store.$patch(fn)
const id: string = getStoreId(store)                            // ≙ store.$id
dispose(store)                                                  // ≙ store.$dispose()

UTS 无 Proxy、对象不可动态注入属性,$patch / $id / $dispose 以顶层函数形态一比一映射,语义不变。

跨 store 与插件体系

// 跨 store 依赖:setup 内直接调用对方 useStore,注册表保证单例
const counterStore = useCounterStore()

// 插件:pinia.use 链式注册,PiniaPluginContext(pinia / store / storeId)对齐标准 Pinia
setActivePinia(createPinia().use(myPlugin))

一比一复刻,裁掉有据

设计原则对标 unix-router 复刻 vue-router:Pinia 的每个公开 API 都给出"直接实现 / 裁掉(附原因与替代)"的归属。裁掉项(Options 式、$subscribe、$onAction、$state、$patch 对象形态等)全部源于 UTS 平台硬约束并经双端实测裁决,详见差异对照。

三、平台支持现状

平台 状态
Web ✅ 全用例通过(9 个功能页:基础用法 / 响应式矩阵 / 单例幂等 / 实例 API / 跨 store / 订阅 / 插件 / 跨页面)
Android ✅ Kotlin 编译链真机全用例通过;云打包 release 编译零错误
iOS / 鸿蒙 ⏳ 代码全端同构(纯 UTS、无平台分支),待实测

关键双端实测裁决:reactive() 对 Ref 字段 Web 解包 / Android 保持 RefImpl(据采用透传形态,不依赖解包);deep watch 对 RefImpl 字段 Android 不触发($subscribe 据此裁掉,字段级 watch 替代);Kotlin 泛型擦除边界(error17)在库内收敛,业务侧零感知。

四、快速上手

pnpm add @meng-xi/unix-pinia
mkdir -p uni_modules && cp -R node_modules/@meng-xi/unix-pinia uni_modules/ux-pinia
<script setup lang="uts">
	import { storeToRefs } from '@/uni_modules/ux-pinia'
	import { useCounterStore } from '@/stores/counter.uts'

	const store = useCounterStore()
	const { count, doubleCount } = storeToRefs(store) // 模板解构自动解包
</script>

<template>
	<text>{{ count }} / {{ doubleCount }}</text>
</template>

不想搭工程?安卓真机可直接下载体验 App:下载体验 App(APK)——示例工程的云打包产物(vdom 模式),安装后进入各功能页即可在真机运行全部用例。

五、文档与资源

六、交流与关注

想了解设计思路与实现原理(模块级注册表、方案 B 定稿过程、UTS 无 Proxy 的形态约束、Kotlin release 编译红线等)?公众号「梦曦工作室」有系列解析,扫码关注:

在这里插入图片描述

相关链接

欢迎反馈与共建:GitHub

posted @ 2026-10-18 20:20  PedroQue99  阅读(11)  评论(0)    收藏  举报