vue-page-store 0.3.1 → 0.4.0
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 +269 -86
- package/dist/index.cjs.js +191 -110
- package/dist/index.d.ts +86 -71
- package/dist/index.esm.js +191 -110
- package/dist/index.umd.js +191 -110
- package/dist/index.umd.min.js +10 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# vue-page-store
|
|
2
2
|
|
|
3
|
-
> Vue 2.6 页面级作用域运行时容器 ——
|
|
3
|
+
> Vue 2.6 页面级作用域运行时容器 —— source、state、getters、actions、watch、enter/leave,一个页面作用域全收。
|
|
4
4
|
|
|
5
5
|
## 它是什么
|
|
6
6
|
|
|
@@ -8,26 +8,29 @@
|
|
|
8
8
|
|
|
9
9
|
一个 `definePageStore` 定义一个 **Page Scope** —— 它统一管理这个页面作用域内的:
|
|
10
10
|
|
|
11
|
-
- **
|
|
11
|
+
- **source** — 页面输入 / 原始返回(如路由参数、接口响应)
|
|
12
|
+
- **state** — 响应式业务状态
|
|
12
13
|
- **getters** — 派生计算
|
|
13
14
|
- **actions** — 业务逻辑
|
|
14
15
|
- **watch** — 声明式副作用
|
|
15
|
-
- **
|
|
16
|
+
- **enter / leave** — 页面可见性生命周期
|
|
17
|
+
- **$setInterval** — 页面级定时器托管
|
|
16
18
|
- **event bus** — 页面内作用域通信
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
页面离开时可以自动清理页面级定时器,页面销毁时 `$destroy` 一键回收,不污染全局。
|
|
19
21
|
|
|
20
22
|
## 它不是什么
|
|
21
23
|
|
|
22
|
-
- **不是 Vuex / Pinia 替代品** — 全局状态(用户信息、权限、路由)请继续用 Vuex
|
|
23
|
-
- **不是全局状态管理方案** —
|
|
24
|
+
- **不是 Vuex / Pinia 替代品** — 全局状态(用户信息、权限、路由)请继续用 Vuex / Pinia
|
|
25
|
+
- **不是全局状态管理方案** — 它的作用域是“页面”,不是“应用”
|
|
26
|
+
- **不是大而全的框架** — 它只解决复杂页面的页面层状态编排
|
|
24
27
|
|
|
25
|
-
| | Vuex | vue-page-store |
|
|
28
|
+
| | Vuex / Pinia | vue-page-store |
|
|
26
29
|
|---|---|---|
|
|
27
30
|
| 作用域 | 全局 | 页面 |
|
|
28
|
-
| 生命周期 | 跟随应用 |
|
|
31
|
+
| 生命周期 | 跟随应用 | 跟随页面可见性 / 页面实例 |
|
|
29
32
|
| 适合 | 用户信息、权限、路由状态 | 仪表盘、漏斗详情、大型配置页 |
|
|
30
|
-
| 销毁 | 通常不销毁 |
|
|
33
|
+
| 销毁 | 通常不销毁 | 页面离开 / 销毁时可回收 |
|
|
31
34
|
|
|
32
35
|
## 安装
|
|
33
36
|
|
|
@@ -42,48 +45,78 @@ npm install vue-page-store
|
|
|
42
45
|
### 1. 定义 store
|
|
43
46
|
|
|
44
47
|
```js
|
|
45
|
-
// stores/
|
|
48
|
+
// stores/order-list.js
|
|
46
49
|
import { definePageStore } from 'vue-page-store'
|
|
47
50
|
|
|
48
|
-
export const
|
|
51
|
+
export const useOrderStore = definePageStore('orderList', {
|
|
52
|
+
source: () => ({
|
|
53
|
+
response: null,
|
|
54
|
+
query: {},
|
|
55
|
+
}),
|
|
56
|
+
|
|
49
57
|
state: () => ({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
keyword: '',
|
|
59
|
+
page: 1,
|
|
60
|
+
pageSize: 20,
|
|
61
|
+
selectedIds: [],
|
|
62
|
+
deleteDialogVisible: false,
|
|
53
63
|
}),
|
|
54
64
|
|
|
55
65
|
getters: {
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
list() {
|
|
67
|
+
return this.$source.response?.list || []
|
|
68
|
+
},
|
|
69
|
+
total() {
|
|
70
|
+
return this.$source.response?.total || 0
|
|
71
|
+
},
|
|
72
|
+
hasSelection() {
|
|
73
|
+
return this.selectedIds.length > 0
|
|
74
|
+
},
|
|
75
|
+
showEmpty() {
|
|
76
|
+
return !this.$loading.search && this.list.length === 0
|
|
77
|
+
}
|
|
58
78
|
},
|
|
59
79
|
|
|
60
80
|
actions: {
|
|
61
|
-
async
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
async search() {
|
|
82
|
+
const res = await api.getOrders({
|
|
83
|
+
keyword: this.keyword,
|
|
84
|
+
page: this.page,
|
|
85
|
+
pageSize: this.pageSize,
|
|
86
|
+
})
|
|
87
|
+
this.$source.response = res
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
async batchDelete() {
|
|
91
|
+
await api.deleteOrders(this.selectedIds)
|
|
92
|
+
this.selectedIds = []
|
|
93
|
+
this.deleteDialogVisible = false
|
|
94
|
+
this.search()
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
openDeleteDialog() {
|
|
98
|
+
this.deleteDialogVisible = true
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
closeDeleteDialog() {
|
|
102
|
+
this.deleteDialogVisible = false
|
|
68
103
|
}
|
|
69
104
|
},
|
|
70
105
|
|
|
71
106
|
watch: {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.fetchData()
|
|
75
|
-
},
|
|
76
|
-
// 对象写法 — 显式 deep
|
|
77
|
-
'filters': {
|
|
78
|
-
handler(val) { this.fetchData() },
|
|
79
|
-
deep: true
|
|
107
|
+
keyword() {
|
|
108
|
+
this.page = 1
|
|
80
109
|
}
|
|
81
110
|
},
|
|
82
111
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
112
|
+
enter() {
|
|
113
|
+
this.$source.query = this.$vm.$route.query
|
|
114
|
+
this.search()
|
|
115
|
+
this.$setInterval(() => this.search(), 5000)
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
leave() {
|
|
119
|
+
// interval 会自动清理
|
|
87
120
|
}
|
|
88
121
|
})
|
|
89
122
|
```
|
|
@@ -91,13 +124,13 @@ export const useFunnelStore = definePageStore('funnelDetail', {
|
|
|
91
124
|
### 2. 页面组件中使用
|
|
92
125
|
|
|
93
126
|
```js
|
|
94
|
-
//
|
|
95
|
-
import {
|
|
127
|
+
// OrderListPage.vue
|
|
128
|
+
import { useOrderStore } from './stores/order-list'
|
|
96
129
|
|
|
97
130
|
export default {
|
|
98
131
|
created() {
|
|
99
|
-
// 传入 this →
|
|
100
|
-
this.pageStore =
|
|
132
|
+
// 传入 this → 自动绑定 enter/leave + 自动 provide + 页面销毁时自动回收
|
|
133
|
+
this.pageStore = useOrderStore(this)
|
|
101
134
|
}
|
|
102
135
|
}
|
|
103
136
|
```
|
|
@@ -105,16 +138,17 @@ export default {
|
|
|
105
138
|
### 3. 子组件中使用
|
|
106
139
|
|
|
107
140
|
```js
|
|
108
|
-
// FilterPanel.vue — 不需要 import
|
|
141
|
+
// FilterPanel.vue — 不需要 import store 文件
|
|
109
142
|
export default {
|
|
110
143
|
inject: ['pageStore'],
|
|
111
144
|
mounted() {
|
|
112
|
-
this.pageStore.
|
|
145
|
+
this.pageStore.search()
|
|
113
146
|
}
|
|
114
147
|
}
|
|
115
148
|
```
|
|
116
149
|
|
|
117
|
-
所有页面统一用 `this.pageStore`,所有子组件统一 `inject: ['pageStore']
|
|
150
|
+
所有页面统一用 `this.pageStore`,所有子组件统一 `inject: ['pageStore']`。
|
|
151
|
+
不需要知道父页面用的哪个 store 定义,零耦合。
|
|
118
152
|
|
|
119
153
|
## API
|
|
120
154
|
|
|
@@ -126,11 +160,13 @@ export default {
|
|
|
126
160
|
|
|
127
161
|
| 字段 | 类型 | 说明 |
|
|
128
162
|
|---|---|---|
|
|
129
|
-
| `state` | `() => Object` |
|
|
163
|
+
| `state` | `() => Object` | **必填**,业务状态工厂函数 |
|
|
164
|
+
| `source` | `() => Object` | 页面输入 / 原始返回工厂函数 |
|
|
130
165
|
| `getters` | `{ [key]: function }` | 派生计算,`this` 指向 store |
|
|
131
166
|
| `actions` | `{ [key]: function }` | 业务方法,`this` 指向 store |
|
|
132
167
|
| `watch` | `{ [path]: handler \| options }` | 声明式 watcher,支持 dot-path |
|
|
133
|
-
| `
|
|
168
|
+
| `enter` | `function` | 页面进入可见 / 可交互状态时触发 |
|
|
169
|
+
| `leave` | `function` | 页面离开可见 / 可交互状态时触发 |
|
|
134
170
|
|
|
135
171
|
### Store 实例属性与方法
|
|
136
172
|
|
|
@@ -138,11 +174,15 @@ export default {
|
|
|
138
174
|
|---|---|
|
|
139
175
|
| `store.xxx` | 直接访问 state 字段 |
|
|
140
176
|
| `store.$state` | 原始响应式 state 对象 |
|
|
177
|
+
| `store.$source` | 原始响应式 source 对象 |
|
|
178
|
+
| `store.$loading` | action loading 状态对象,如 `store.$loading.search` |
|
|
141
179
|
| `store.$status` | `{ mounted, active }` 响应式状态 |
|
|
142
180
|
| `store.$disposed` | store 是否已销毁 |
|
|
143
181
|
| `store.$id` | store 唯一标识 |
|
|
182
|
+
| `store.$vm` | 绑定的页面组件实例(只读逃生口) |
|
|
144
183
|
| `store.$patch(partial \| fn)` | 批量更新 state(浅合并) |
|
|
145
|
-
| `store.$reset()` | 重置到 `state()` 初始值,清除动态字段 |
|
|
184
|
+
| `store.$reset()` | 重置到 `state()` + `source()` 初始值,清除动态字段 |
|
|
185
|
+
| `store.$setInterval(fn, delay)` | 注册页面级 interval,leave / destroy 自动清理 |
|
|
146
186
|
| `store.$emit(event, payload)` | 发射事件(当前 store 作用域) |
|
|
147
187
|
| `store.$on(event, handler)` | 订阅事件,返回取消函数 |
|
|
148
188
|
| `store.$off(event, handler?)` | 取消订阅 |
|
|
@@ -165,19 +205,158 @@ watch: {
|
|
|
165
205
|
}
|
|
166
206
|
```
|
|
167
207
|
|
|
168
|
-
##
|
|
208
|
+
## source 与 state
|
|
209
|
+
|
|
210
|
+
v0.4 引入了 `source`,用于把“页面输入 / 原始返回”和“业务状态”分开。
|
|
211
|
+
|
|
212
|
+
### 推荐分工
|
|
213
|
+
|
|
214
|
+
- **source**:路由参数、接口原始响应、页面输入上下文
|
|
215
|
+
- **state**:keyword、分页、选中项、弹窗状态、表单草稿等业务状态
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
source: () => ({
|
|
219
|
+
response: null,
|
|
220
|
+
query: {},
|
|
221
|
+
}),
|
|
222
|
+
|
|
223
|
+
state: () => ({
|
|
224
|
+
keyword: '',
|
|
225
|
+
page: 1,
|
|
226
|
+
selectedIds: [],
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 为什么要分开
|
|
231
|
+
|
|
232
|
+
- 原始返回不再和业务状态混在一起
|
|
233
|
+
- getters 可以同时基于 `this.$source` 和 `this.xxx` 计算
|
|
234
|
+
- `$reset()` 时 source / state 一起恢复,更清晰
|
|
235
|
+
|
|
236
|
+
## enter / leave
|
|
237
|
+
|
|
238
|
+
v0.4 用 `enter / leave` 替换了 v0.3 的 `lifecycle.mount / unmount / activate / deactivate`。
|
|
239
|
+
|
|
240
|
+
### 语义
|
|
241
|
+
|
|
242
|
+
- **enter**:页面进入可见 / 可交互状态
|
|
243
|
+
- **leave**:页面离开可见 / 可交互状态
|
|
244
|
+
|
|
245
|
+
### keep-alive 行为
|
|
246
|
+
|
|
247
|
+
- 首次 `mounted` → `enter`
|
|
248
|
+
- `activated` → `enter`
|
|
249
|
+
- `deactivated` → `leave`
|
|
250
|
+
- `beforeDestroy` → 如果当前还没 leave,先 leave,再 `$destroy`
|
|
251
|
+
|
|
252
|
+
### 适合放在 enter / leave 里的逻辑
|
|
253
|
+
|
|
254
|
+
- 首屏加载
|
|
255
|
+
- 根据 `$route` 初始化 source / state
|
|
256
|
+
- 启动页面轮询
|
|
257
|
+
- 页面离开时做收尾逻辑
|
|
258
|
+
|
|
259
|
+
```js
|
|
260
|
+
enter() {
|
|
261
|
+
this.$source.query = this.$vm.$route.query
|
|
262
|
+
this.search()
|
|
263
|
+
this.$setInterval(() => this.search(), 5000)
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
leave() {
|
|
267
|
+
// interval 自动清理
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## `$setInterval`
|
|
272
|
+
|
|
273
|
+
后台页面经常有轮询 / 倒计时需求,v0.4 提供 `$setInterval(fn, delay)` 统一托管页面级 interval。
|
|
274
|
+
|
|
275
|
+
### 特性
|
|
276
|
+
|
|
277
|
+
- 返回 `stop` 函数,可手动停止
|
|
278
|
+
- `leave` 时自动清理所有已注册 interval
|
|
279
|
+
- `$destroy()` 时兜底清理
|
|
280
|
+
- `enter` 时**不会自动恢复**,需要你自己重新注册
|
|
281
|
+
|
|
282
|
+
```js
|
|
283
|
+
enter() {
|
|
284
|
+
this.$setInterval(() => {
|
|
285
|
+
this.search()
|
|
286
|
+
}, 5000)
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## 异步 action 与 `$loading`
|
|
291
|
+
|
|
292
|
+
v0.4 对返回 Promise 的 action 自动追踪 loading 状态。
|
|
293
|
+
|
|
294
|
+
你不需要额外包装器,直接写普通 async 函数即可:
|
|
295
|
+
|
|
296
|
+
```js
|
|
297
|
+
actions: {
|
|
298
|
+
async search() {
|
|
299
|
+
const res = await api.getOrders(...)
|
|
300
|
+
this.$source.response = res
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
模板中可以直接使用:
|
|
306
|
+
|
|
307
|
+
```html
|
|
308
|
+
<!-- 搜索:只显示 loading -->
|
|
309
|
+
<el-button
|
|
310
|
+
:loading="pageStore.$loading.search"
|
|
311
|
+
@click="pageStore.search"
|
|
312
|
+
>
|
|
313
|
+
搜索
|
|
314
|
+
</el-button>
|
|
315
|
+
|
|
316
|
+
<!-- 保存:UI 层自己决定是否禁用 -->
|
|
317
|
+
<el-button
|
|
318
|
+
:loading="pageStore.$loading.save"
|
|
319
|
+
:disabled="pageStore.$loading.save"
|
|
320
|
+
@click="pageStore.save"
|
|
321
|
+
>
|
|
322
|
+
保存
|
|
323
|
+
</el-button>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### 说明
|
|
327
|
+
|
|
328
|
+
- 框架只做 **loading 追踪**
|
|
329
|
+
- **不自动跳过重复调用**
|
|
330
|
+
- 是否防重复,由 UI 层通过 `:disabled="pageStore.$loading.xxx"` 自己决定
|
|
169
331
|
|
|
170
|
-
|
|
332
|
+
## State / Source Shape 规则
|
|
333
|
+
|
|
334
|
+
### state
|
|
335
|
+
|
|
336
|
+
`state()` 返回值定义了推荐的业务状态边界:
|
|
171
337
|
|
|
172
338
|
- **推荐**:在 `state()` 中声明完整字段,即使初始值为 `null` 或空数组
|
|
173
339
|
- **允许**:通过 `$patch` 动态新增字段(会写入 `$state`,但不会自动成为 `store.xxx` 顶层代理)
|
|
174
340
|
- **注意**:`$reset()` 会清除所有不在 `state()` 中的动态字段
|
|
175
341
|
|
|
342
|
+
### source
|
|
343
|
+
|
|
344
|
+
`source()` 返回值定义了页面输入 / 原始返回的初始 shape:
|
|
345
|
+
|
|
346
|
+
- **推荐**:把常见 source 字段预先声明出来,如 `response`、`query`
|
|
347
|
+
- **允许**:运行时动态给 `$source` 增加字段
|
|
348
|
+
- **注意**:`$reset()` 同样会清除所有不在 `source()` 中的动态字段
|
|
349
|
+
|
|
176
350
|
```js
|
|
351
|
+
source: () => ({
|
|
352
|
+
response: null,
|
|
353
|
+
query: {},
|
|
354
|
+
}),
|
|
355
|
+
|
|
177
356
|
state: () => ({
|
|
178
357
|
filters: {},
|
|
179
|
-
|
|
180
|
-
detail: null
|
|
358
|
+
selectedIds: [],
|
|
359
|
+
detail: null,
|
|
181
360
|
})
|
|
182
361
|
```
|
|
183
362
|
|
|
@@ -203,15 +382,15 @@ state: () => ({
|
|
|
203
382
|
|
|
204
383
|
## 适用场景
|
|
205
384
|
|
|
206
|
-
- 仪表盘页面
|
|
207
|
-
-
|
|
208
|
-
- 大型配置页
|
|
209
|
-
- keep-alive 业务页
|
|
210
|
-
- 微前端子应用
|
|
385
|
+
- 仪表盘页面 —— 多模块共享筛选条件、加载状态
|
|
386
|
+
- 漏斗 / 留存等分析详情页 —— 复杂交互 + 异步数据 + 页面可见性管理
|
|
387
|
+
- 大型配置页 —— 多 tab / 多步骤表单的状态统一管理
|
|
388
|
+
- keep-alive 业务页 —— 需要 enter / leave 感知的页面
|
|
389
|
+
- 微前端子应用 —— 页面作用域隔离,不污染宿主全局状态
|
|
211
390
|
|
|
212
391
|
## 不适用场景
|
|
213
392
|
|
|
214
|
-
- 全局用户信息、权限、路由等 → 用 Vuex
|
|
393
|
+
- 全局用户信息、权限、路由等 → 用 Vuex / Pinia
|
|
215
394
|
- 简单页面的小 data 管理 → 用组件 data 就够了
|
|
216
395
|
- 需要同 id 多实例并存 → 当前版本不支持
|
|
217
396
|
|
|
@@ -222,11 +401,9 @@ state: () => ({
|
|
|
222
401
|
```js
|
|
223
402
|
actions: {
|
|
224
403
|
async fetchData() {
|
|
225
|
-
this.loading = true
|
|
226
404
|
const data = await api.getData()
|
|
227
405
|
// 即使页面已销毁,下面的赋值也会被自动静默,不会报错
|
|
228
|
-
this.
|
|
229
|
-
this.loading = false
|
|
406
|
+
this.$source.response = data
|
|
230
407
|
}
|
|
231
408
|
}
|
|
232
409
|
```
|
|
@@ -246,53 +423,59 @@ storeRegistry.forEach((store, id) => {
|
|
|
246
423
|
})
|
|
247
424
|
```
|
|
248
425
|
|
|
249
|
-
## 从 v0.
|
|
426
|
+
## 从 v0.3.x 升级
|
|
250
427
|
|
|
251
428
|
### Breaking Changes
|
|
252
429
|
|
|
253
|
-
**1.
|
|
430
|
+
**1. `lifecycle` 被移除,改为 `enter / leave`**
|
|
254
431
|
|
|
255
|
-
v0.
|
|
432
|
+
v0.3.x:
|
|
256
433
|
|
|
257
|
-
|
|
434
|
+
```js
|
|
435
|
+
lifecycle: {
|
|
436
|
+
mount() {},
|
|
437
|
+
unmount() {},
|
|
438
|
+
activate() {},
|
|
439
|
+
deactivate() {}
|
|
440
|
+
}
|
|
441
|
+
```
|
|
258
442
|
|
|
259
|
-
|
|
443
|
+
v0.4.0:
|
|
260
444
|
|
|
261
|
-
|
|
445
|
+
```js
|
|
446
|
+
enter() {},
|
|
447
|
+
leave() {}
|
|
448
|
+
```
|
|
262
449
|
|
|
263
|
-
|
|
450
|
+
迁移关系:
|
|
264
451
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
452
|
+
- `lifecycle.mount` → `enter`
|
|
453
|
+
- `lifecycle.unmount` → `leave`
|
|
454
|
+
- `lifecycle.activate` → `enter`
|
|
455
|
+
- `lifecycle.deactivate` → `leave`
|
|
270
456
|
|
|
271
|
-
|
|
272
|
-
watch: {
|
|
273
|
-
'filters': {
|
|
274
|
-
handler(val) { this.fetchData() },
|
|
275
|
-
deep: true
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
```
|
|
457
|
+
**2. `$reset()` 现在同时重置 source 和 state**
|
|
279
458
|
|
|
280
|
-
|
|
459
|
+
v0.4.0 中:
|
|
281
460
|
|
|
282
|
-
`
|
|
461
|
+
- `state` 恢复到 `state()` 初始值
|
|
462
|
+
- `source` 恢复到 `source()` 初始值
|
|
463
|
+
- 不在初始 shape 中的动态字段会被移除
|
|
283
464
|
|
|
284
465
|
### New Features
|
|
285
466
|
|
|
286
|
-
- `
|
|
287
|
-
- `
|
|
288
|
-
-
|
|
467
|
+
- `source`:页面输入 / 原始返回与业务状态分离
|
|
468
|
+
- `enter / leave`:更简单的页面可见性生命周期
|
|
469
|
+
- `$setInterval()`:页面级 interval 托管
|
|
470
|
+
- `$loading.xxx`:返回 Promise 的 action 自动追踪 loading
|
|
471
|
+
- `$vm`:只读逃生口,可在 enter 中访问 `$route / $router`
|
|
289
472
|
|
|
290
473
|
## Roadmap
|
|
291
474
|
|
|
292
|
-
- **Plugin system** — 可扩展能力(logger、persist、loading tracker)
|
|
293
475
|
- **Keyed instance** — `useStore(vm, scopeKey)` 支持同定义多实例
|
|
294
|
-
- **Page cache strategy** — TTL、revalidate、stale-while-
|
|
476
|
+
- **Page cache strategy** — TTL、revalidate、stale-while-enter
|
|
477
|
+
- **More page runtime helpers** — 在不增加心智负担的前提下继续补页面层能力
|
|
295
478
|
|
|
296
479
|
## License
|
|
297
480
|
|
|
298
|
-
MIT © weijianjun
|
|
481
|
+
MIT © weijianjun
|