vue-page-store 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,6 +17,7 @@
17
17
  - **enter / leave** — 页面可见性生命周期
18
18
  - **$setInterval** — 页面级定时器托管
19
19
  - **event bus** — 页面内作用域通信
20
+ - **plugin** — 外部扩展机制(v0.5 新增)
20
21
 
21
22
  页面离开时可以自动清理页面级定时器,页面销毁时 `$destroy` 一键回收,不污染全局。
22
23
 
@@ -176,6 +177,11 @@ export default {
176
177
  | `init` | `function` | store 创建后一次性调用,`$vm` 已可用。适合拉字典、注册事件监听 |
177
178
  | `enter` | `function` | 页面进入可见 / 可交互状态时触发 |
178
179
  | `leave` | `function` | 页面离开可见 / 可交互状态时触发 |
180
+ | *其它字段* | *any* | 注册过的 plugin 可声明自己的字段(见 [Plugin](#plugin)) |
181
+
182
+ ### `registerPlugin(plugin)` *(v0.5 新增)*
183
+
184
+ 注册全局插件,详见 [Plugin](#plugin) 节。
179
185
 
180
186
  ### Store 实例属性与方法
181
187
 
@@ -260,24 +266,29 @@ v0.4.1 新增 `init`,用于 store 创建后的一次性初始化。
260
266
  created() 开始
261
267
  └→ useStore(this)
262
268
  └→ createStoreInstance() ← state/source/getters/actions 就绪
269
+ └→ plugin.install() ← v0.5:plugin 安装($vm 尚未绑定)
263
270
  └→ bindTo(this) ← $vm 赋值
264
271
  └→ ★ init() ← $vm 可用,只执行一次
265
272
  └→ created() 剩余代码
266
273
  mounted()
267
274
  └→ ★ enter() ← DOM 就绪,每次可见都执行
275
+ └→ plugin.enter() ← v0.5:plugin enter 钩子
268
276
 
269
277
  --- keep-alive 切走 ---
270
278
  deactivated()
271
279
  └→ clearAllIntervals()
272
280
  └→ ★ leave()
281
+ └→ plugin.leave() ← v0.5:plugin leave 钩子
273
282
 
274
283
  --- keep-alive 切回 ---
275
284
  activated()
276
285
  └→ ★ enter() ← 重新开轮询、刷数据
286
+ └→ plugin.enter()
277
287
 
278
288
  --- 页面销毁 ---
279
289
  beforeDestroy()
280
290
  └→ ★ leave()(如果还没 leave)
291
+ └→ plugin.destroy() ← v0.5:plugin destroy 钩子
281
292
  └→ $destroy()
282
293
  ```
283
294
 
@@ -419,6 +430,128 @@ state: () => ({
419
430
  })
420
431
  ```
421
432
 
433
+ ## Plugin
434
+
435
+ *v0.5 新增。* Plugin 机制让外部库可以给 `definePageStore` options 增加**新字段**并消费它,同时挂钩 enter / leave / destroy 生命周期——而不需要修改 page-store 本身。
436
+
437
+ > 典型场景:`vue-page-runtime`(请求编排)、`vue-page-persist`(状态持久化)、devtools 扩展。
438
+
439
+ ### 协议
440
+
441
+ Plugin 是一个对象,包含 `name` 和 `install`:
442
+
443
+ ```js
444
+ {
445
+ name: 'tasks', // 同时作为 options 字段匹配键
446
+ install(store, fieldValue, { Vue }) { // fieldValue === options.tasks
447
+ // 初始化 plugin 自己的逻辑
448
+ return {
449
+ enter() { /* page enter 后调用 */ },
450
+ leave() { /* page leave 后调用 */ },
451
+ destroy() { /* store 销毁时调用 */ },
452
+ }
453
+ }
454
+ }
455
+ ```
456
+
457
+ - **匹配规则**:`options[plugin.name] !== undefined` 才会调用 `install`。没有声明字段的 store 完全不受影响。
458
+ - **install 时机**:store 创建末尾,state / getters / actions / $source / $setInterval / $emit 等全部就绪。`$vm` 此时**尚未**绑定。
459
+ - **返回值**:可选 `{ enter?, leave?, destroy? }`。不需要钩子可以不返回。
460
+
461
+ ### 注册
462
+
463
+ 全局注册一次即可:
464
+
465
+ ```js
466
+ // main.js
467
+ import { registerPlugin } from 'vue-page-store'
468
+ import taskPlugin from 'vue-page-runtime/plugin'
469
+
470
+ registerPlugin(taskPlugin)
471
+ ```
472
+
473
+ 之后正常写 store,声明插件字段:
474
+
475
+ ```js
476
+ import { definePageStore } from 'vue-page-store' // 入口不变
477
+
478
+ definePageStore('order', {
479
+ state: () => ({ /* ... */ }),
480
+
481
+ // page-store 不认识这个字段,但会递给注册过的 plugin
482
+ tasks: {
483
+ fetchUser: {
484
+ trigger: 'enter',
485
+ async run() { return api.getUser(this.$vm.$route.params.id) },
486
+ },
487
+ fetchOrders: {
488
+ deps: ['fetchUser'],
489
+ async run() { /* ... */ },
490
+ },
491
+ },
492
+ })
493
+ ```
494
+
495
+ ### 写一个 plugin
496
+
497
+ 最小示例——一个把 `persist` 字段声明持久化到 localStorage 的插件:
498
+
499
+ ```js
500
+ const persistPlugin = {
501
+ name: 'persist',
502
+
503
+ install(store, fieldValue /* options.persist */, { Vue }) {
504
+ const { key, paths } = fieldValue
505
+
506
+ // 恢复
507
+ try {
508
+ const saved = JSON.parse(localStorage.getItem(key) || '{}')
509
+ store.$patch(saved)
510
+ } catch (e) {}
511
+
512
+ // 持久化 —— 监听指定字段
513
+ const stopWatchers = paths.map(p =>
514
+ store._vm.$watch(
515
+ () => store[p],
516
+ (val) => {
517
+ const cur = JSON.parse(localStorage.getItem(key) || '{}')
518
+ cur[p] = val
519
+ localStorage.setItem(key, JSON.stringify(cur))
520
+ }
521
+ )
522
+ )
523
+
524
+ return {
525
+ destroy() {
526
+ stopWatchers.forEach(stop => stop())
527
+ }
528
+ }
529
+ }
530
+ }
531
+
532
+ registerPlugin(persistPlugin)
533
+ ```
534
+
535
+ 使用:
536
+
537
+ ```js
538
+ definePageStore('page', {
539
+ state: () => ({ keyword: '', filters: {} }),
540
+ persist: {
541
+ key: 'page:cache',
542
+ paths: ['keyword', 'filters']
543
+ }
544
+ })
545
+ ```
546
+
547
+ ### 注意事项
548
+
549
+ - **全局注册,影响所有 store**。plugin 只在对应 store 声明了 `options[plugin.name]` 时才激活,但注册本身是全局的。
550
+ - **同名 plugin 只能注册一次**,重复注册会被跳过并打印 warning。
551
+ - **install 返回的钩子会被按注册顺序依次调用**(FIFO)。
552
+ - **plugin 之间不通信**。如果两个 plugin 有依赖关系,应该合并成一个。
553
+ - **$vm 在 install 时为 null**。如果 plugin 需要组件实例,应在 `enter` 钩子里访问(此时 `$vm` 已绑定)。
554
+
422
555
  ## 实例模型:Singleton
423
556
 
424
557
  当前版本采用 **id → singleton** 模型:
@@ -471,17 +604,140 @@ actions: {
471
604
 
472
605
  ## 调试
473
606
 
474
- `storeRegistry` 是导出的 Map,可以在控制台直接查看:
607
+ ### `storeRegistry` —— 导出的 Map
608
+
609
+ `storeRegistry` 是导出的 Map,可以在代码里用于调试或自定义 devtools 集成:
475
610
 
476
611
  ```js
477
612
  import { storeRegistry } from 'vue-page-store'
478
613
 
479
- // 查看所有活跃 store
480
614
  storeRegistry.forEach((store, id) => {
481
615
  console.log(id, store.$status, store.$disposed)
482
616
  })
483
617
  ```
484
618
 
619
+ ### `window.__VUE_PAGE_STORE__` —— dev 自动挂载 *(v0.5 新增)*
620
+
621
+ 开发环境下(`process.env.NODE_ENV !== 'production'`)会自动挂到 `window.__VUE_PAGE_STORE__`,方便控制台访问。生产环境和 SSR 环境不会挂。
622
+
623
+ 控制台用法:
624
+
625
+ ```js
626
+ __VUE_PAGE_STORE__ // { registry, stores }
627
+ __VUE_PAGE_STORE__.stores // { orderList: {…}, userProfile: {…} }
628
+ __VUE_PAGE_STORE__.stores.orderList // ← 有属性自动补全
629
+ __VUE_PAGE_STORE__.stores.orderList.$source
630
+ __VUE_PAGE_STORE__.stores.orderList.$loading
631
+
632
+ // 原始 Map 也保留
633
+ __VUE_PAGE_STORE__.registry.forEach(...)
634
+ ```
635
+
636
+ - `registry`:导出的原始 Map,和 `import { storeRegistry }` 拿到的是同一个引用
637
+ - `stores`:getter,每次读取重建对象视图;销毁的 store 自动消失
638
+
639
+ **说明**:
640
+
641
+ - `__VUE_PAGE_STORE__` 是 dev-only 调试接口,shape 和键名可能在后续版本变化,**不要在生产代码里依赖**
642
+ - 微前端场景下,多个子应用都加载 vue-page-store 时,最后挂载的会覆盖前面的。如需共存,请退回手动挂载并用自己的命名
643
+
644
+ ### `window.PAGE_STORE_DEVTOOLS` —— debug 注册表 *(v0.5.1 新增)*
645
+
646
+ v0.5.1 新增了 dev-only 的 debug 模块,在 `window.PAGE_STORE_DEVTOOLS` 上暴露结构化调试数据:
647
+
648
+ ```js
649
+ window.PAGE_STORE_DEVTOOLS
650
+ // {
651
+ // stores: Map, ← store 元信息(id、active、destroyed、storeRef…)
652
+ // events: [], ← 事件时间线(最近 500 条)
653
+ // seq: number ← 全局递增计数
654
+ // }
655
+ ```
656
+
657
+ #### 自动采集的事件
658
+
659
+ | 事件 | 说明 |
660
+ |---|---|
661
+ | `store:create` | store 实例创建 |
662
+ | `store:destroy` | store 实例销毁 |
663
+ | `action:start` | action 调用开始(含参数快照) |
664
+ | `action:end` | action 调用结束(含 duration) |
665
+ | `action:error` | action 抛错或 reject(含错误信息和 duration) |
666
+
667
+ 每条事件包含 `seq`(全局序号)、`ts`(时间戳)、`storeId`、`type`、`payload`。
668
+
669
+ #### 控制台用法
670
+
671
+ ```js
672
+ // 查看当前存活的 store
673
+ PAGE_STORE_DEVTOOLS.stores
674
+
675
+ // 查看最近的事件
676
+ PAGE_STORE_DEVTOOLS.events.slice(-5)
677
+
678
+ // 筛选某个 store 的 action 事件
679
+ PAGE_STORE_DEVTOOLS.events
680
+ .filter(e => e.storeId === 'orderList' && e.type.startsWith('action:'))
681
+
682
+ // 查看 action 耗时
683
+ PAGE_STORE_DEVTOOLS.events
684
+ .filter(e => e.type === 'action:end')
685
+ .map(e => e.payload.action + ': ' + e.payload.duration + 'ms')
686
+ ```
687
+
688
+ 生产环境下 `PAGE_STORE_DEVTOOLS` 不会被挂载,所有 debug 逻辑为 no-op。
689
+
690
+ ### DevPanel —— 页面内悬浮面板 *(v0.5.1 新增)*
691
+
692
+ v0.5.1 提供了一个最小的页面内调试面板,在右下角悬浮显示:
693
+
694
+ - **左侧**:store 列表(显示 active / idle / destroyed 状态)
695
+ - **右侧四个 tab**:
696
+ - `$state` — 当前选中 store 的业务状态
697
+ - `$source` — 页面输入 / 原始返回
698
+ - `getters` — 派生计算值
699
+ - `events` — 该 store 最近 50 条事件
700
+
701
+ 面板每 500ms 刷新一次,实时反映 store 变化。
702
+
703
+ #### 接入方式
704
+
705
+ ```js
706
+ // main.js — 仅开发环境加载
707
+ if (process.env.NODE_ENV !== 'production') {
708
+ import('vue-page-store/debug/installPanel').then(m => m.installDevPanel())
709
+ }
710
+ ```
711
+
712
+ 面板会自动挂载到 `document.body`,不侵入业务组件树。生产环境下 `installDevPanel()` 是 no-op。
713
+
714
+ #### 注意事项
715
+
716
+ - DevPanel 是独立 Vue 实例,不影响业务组件树
717
+ - 需要构建链能处理 `.vue` SFC(webpack + vue-loader 或 Vite 默认支持)
718
+ - 微前端场景下,多个子应用各自挂面板,互不干扰
719
+ - 这是 dev-only 工具,不要在生产代码里依赖
720
+
721
+ #### 强制开启
722
+
723
+ Vite / webpack 5 等不 polyfill `process` 的环境下,如果 `isDev` 检测失败,可以在**页面加载前**手动设置:
724
+
725
+ ```js
726
+ window.__VUE_PAGE_STORE_DEV__ = true
727
+ ```
728
+
729
+ ### debug 模块文件结构
730
+
731
+ ```
732
+ src/debug/
733
+ ├── registry.js ← window.PAGE_STORE_DEVTOOLS 数据层
734
+ ├── emit.js ← emitDebugEvent 埋点入口
735
+ ├── DevPanel.vue ← 悬浮面板组件
736
+ └── installPanel.js ← 面板挂载器
737
+ ```
738
+
739
+ 所有 debug 文件仅在 dev 环境生效。生产构建中:`registry.js` 和 `emit.js` 中的所有函数早 return / 返回空值,不执行任何逻辑,不挂 `window`,不占内存。如果你的打包器支持 tree-shaking 且 `import('...installPanel')` 走动态导入,面板代码不会进入生产包。
740
+
485
741
  ## 从 v0.3.x 升级
486
742
 
487
743
  ### Breaking Changes
@@ -536,12 +792,36 @@ v0.4.0 中:
536
792
  - `$setInterval()`:页面级 interval 托管
537
793
  - `$loading.xxx`:返回 Promise 的 action 自动追踪 loading
538
794
  - `$vm`:只读逃生口,可在 init / enter 中访问 `$route / $router`
795
+ - `registerPlugin()`:外部扩展机制(v0.5)
796
+
797
+ ## 从 v0.4.x 升级到 v0.5
798
+
799
+ v0.5 **完全向后兼容** v0.4.x:
800
+
801
+ - 所有 v0.4 的 API 行为不变
802
+ - 新增 `registerPlugin()` 导出,不注册 plugin 等同于 v0.4 行为
803
+ - options 现在允许包含插件声明的额外字段(如 `tasks`、`persist`)
804
+ - dev 环境自动挂 `window.__VUE_PAGE_STORE__`,方便控制台调试
805
+
806
+ 升级只需要改版本号,无需改代码。
807
+
808
+ ## 从 v0.5.0 升级到 v0.5.1
809
+
810
+ v0.5.1 **完全向后兼容** v0.5.0:
811
+
812
+ - **修复**:`isDev` 检测改用 `try/catch` 兜底,修复 Vite / webpack 5 不 polyfill `process` 时模块加载报错的问题
813
+ - **新增**:dev-only debug 模块(`debug/registry.js`、`debug/emit.js`、`debug/DevPanel.vue`、`debug/installPanel.js`)
814
+ - **新增**:`window.PAGE_STORE_DEVTOOLS` 调试注册表,自动采集 store 创建/销毁和 action 调用事件
815
+ - **新增**:DevPanel 悬浮面板,可视化查看 store 列表、state/source/getters、事件时间线
816
+
817
+ 升级只需要改版本号。debug 模块为可选接入,不接入等同于 v0.5.0 行为。
539
818
 
540
819
  ## Roadmap
541
820
 
542
821
  - **Keyed instance** — `useStore(vm, scopeKey)` 支持同定义多实例
543
- - **Page cache strategy** — TTL、revalidate、stale-while-enter
822
+ - **Official plugins** — 随着 `vue-page-runtime` 等生态库成熟,补充第一方 plugin 文档
544
823
  - **More page runtime helpers** — 在不增加心智负担的前提下继续补页面层能力
824
+ - **Vue Devtools 集成** — 在 debug 模块基础上对接 Vue Devtools inspector / timeline API
545
825
 
546
826
  ## License
547
827