@ubean/runtime 0.1.7 → 0.1.8

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.
@@ -60,6 +60,50 @@ interface DefineAppOptions {
60
60
  errorComponent?: Component;
61
61
  loadingComponent?: Component;
62
62
  viewTransitions?: boolean | ViewTransitionOptions;
63
+ /**
64
+ * SSR 专用:在 `renderToString(app)` 完成后调用,从 app 实例提取需要
65
+ * 序列化到客户端的状态(如 Pinia 的 `pinia.state.value`)。
66
+ *
67
+ * 返回的对象会被 `safeJsonStringify` 序列化并注入到 HTML 的
68
+ * `__UBEAN_STATE__` script 标签中。
69
+ *
70
+ * 仅在 server mode 下生效;client mode 下被忽略。
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * import { createPinia } from 'pinia';
75
+ * defineApp({
76
+ * plugins: [createPinia()],
77
+ * serializeState: (app) => ({
78
+ * pinia: app.config.globalProperties.$pinia.state.value
79
+ * })
80
+ * });
81
+ * ```
82
+ */
83
+ serializeState?: (app: App) => Record<string, unknown> | Promise<Record<string, unknown>>;
84
+ /**
85
+ * Client 专用:在 `applyAppConfig`(注册插件/provide)之后、`app.mount()` 之前调用,
86
+ * 用于从 `__UBEAN_STATE__` 反序列化的状态回填到 app(如 Pinia 的水合)。
87
+ *
88
+ * `state` 即 `serializeState` 在服务端返回的对象;若服务端未配置 `serializeState`
89
+ * 或返回空,`state` 为 `null`。
90
+ *
91
+ * 仅在 client mode 下生效;server mode 下被忽略。
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * import { createPinia } from 'pinia';
96
+ * defineApp({
97
+ * plugins: [createPinia()],
98
+ * hydrateState: (app, state) => {
99
+ * if (state?.pinia) {
100
+ * app.config.globalProperties.$pinia.state.value = state.pinia;
101
+ * }
102
+ * }
103
+ * });
104
+ * ```
105
+ */
106
+ hydrateState?: (app: App, state: Record<string, unknown> | null) => void;
63
107
  }
64
108
  interface ResolvedAppConfig {
65
109
  plugins: AppPluginConfig[];
@@ -74,9 +118,21 @@ interface ResolvedAppConfig {
74
118
  errorComponent?: Component;
75
119
  loadingComponent?: Component;
76
120
  viewTransitions?: boolean | ViewTransitionOptions;
121
+ serializeState?: (app: App) => Record<string, unknown> | Promise<Record<string, unknown>>;
122
+ hydrateState?: (app: App, state: Record<string, unknown> | null) => void;
77
123
  }
78
124
  declare function defineApp(options: DefineAppOptions): ResolvedAppConfig;
79
125
  declare function applyAppConfig(app: App, config: ResolvedAppConfig, mode: 'client' | 'server'): void;
80
126
  declare function createDefaultAppConfig(): ResolvedAppConfig;
127
+ /**
128
+ * 从多个 `ResolvedAppConfig` 合并出一个最终配置(shared + client/server)。
129
+ *
130
+ * `serializeState` 与 `hydrateState` 的合并语义:server 配置的 `serializeState` 优先,
131
+ * client 配置的 `hydrateState` 优先;shared 配置作为默认值。
132
+ *
133
+ * 这个函数在 `virtual:ubean-app` 虚拟模块中以 JS 字符串形式重新实现
134
+ * (`_mergeAppConfig`),保持两者语义一致。
135
+ */
136
+ declare function mergeAppConfig(base: ResolvedAppConfig, ...configs: (ResolvedAppConfig | null | undefined)[]): ResolvedAppConfig;
81
137
  //#endregion
82
- export { AppPluginConfig, DefineAppOptions, ResolvedAppConfig, RouterConfig, applyAppConfig, createDefaultAppConfig, defineApp };
138
+ export { AppPluginConfig, DefineAppOptions, ResolvedAppConfig, RouterConfig, applyAppConfig, createDefaultAppConfig, defineApp, mergeAppConfig };
@@ -22,7 +22,9 @@ function defineApp(options) {
22
22
  onClientReady: options.onClientReady,
23
23
  errorComponent: options.errorComponent,
24
24
  loadingComponent: options.loadingComponent,
25
- viewTransitions: options.viewTransitions
25
+ viewTransitions: options.viewTransitions,
26
+ serializeState: options.serializeState,
27
+ hydrateState: options.hydrateState
26
28
  };
27
29
  }
28
30
  function applyAppConfig(app, config, mode) {
@@ -40,5 +42,54 @@ function createDefaultAppConfig() {
40
42
  rootAttrs: {}
41
43
  };
42
44
  }
45
+ /**
46
+ * 从多个 `ResolvedAppConfig` 合并出一个最终配置(shared + client/server)。
47
+ *
48
+ * `serializeState` 与 `hydrateState` 的合并语义:server 配置的 `serializeState` 优先,
49
+ * client 配置的 `hydrateState` 优先;shared 配置作为默认值。
50
+ *
51
+ * 这个函数在 `virtual:ubean-app` 虚拟模块中以 JS 字符串形式重新实现
52
+ * (`_mergeAppConfig`),保持两者语义一致。
53
+ */
54
+ function mergeAppConfig(base, ...configs) {
55
+ const result = { ...base };
56
+ for (const cfg of configs) {
57
+ if (!cfg) continue;
58
+ if (cfg.plugins) result.plugins = [...result.plugins || [], ...cfg.plugins];
59
+ if (cfg.globalComponents) result.globalComponents = {
60
+ ...result.globalComponents,
61
+ ...cfg.globalComponents
62
+ };
63
+ if (cfg.provides) result.provides = {
64
+ ...result.provides,
65
+ ...cfg.provides
66
+ };
67
+ if (cfg.head) result.head = {
68
+ ...result.head,
69
+ ...cfg.head
70
+ };
71
+ if (cfg.rootId) result.rootId = cfg.rootId;
72
+ if (cfg.rootAttrs) result.rootAttrs = {
73
+ ...result.rootAttrs,
74
+ ...cfg.rootAttrs
75
+ };
76
+ if (cfg.onAppCreated) result.onAppCreated = cfg.onAppCreated;
77
+ if (cfg.onClientReady) result.onClientReady = cfg.onClientReady;
78
+ if (cfg.errorComponent) result.errorComponent = cfg.errorComponent;
79
+ if (cfg.loadingComponent) result.loadingComponent = cfg.loadingComponent;
80
+ if (cfg.viewTransitions !== void 0) result.viewTransitions = cfg.viewTransitions;
81
+ if (cfg.serializeState) result.serializeState = cfg.serializeState;
82
+ if (cfg.hydrateState) result.hydrateState = cfg.hydrateState;
83
+ if (cfg.router?.setup) {
84
+ const prevSetup = result.router?.setup;
85
+ if (prevSetup) result.router = { setup: (router) => {
86
+ prevSetup(router);
87
+ cfg.router.setup(router);
88
+ } };
89
+ else result.router = { setup: cfg.router.setup };
90
+ }
91
+ }
92
+ return result;
93
+ }
43
94
  //#endregion
44
- export { applyAppConfig, createDefaultAppConfig, defineApp };
95
+ export { applyAppConfig, createDefaultAppConfig, defineApp, mergeAppConfig };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as UbeanAppOptions, c as createUbeanApp, d as useRouter, f as useSeoMeta, g as createUbeanRouter, h as CreateUbeanRouterOptions, i as UbeanAppInstance, l as createUbeanSSRApp, m as useViewTransition, n as Link, p as useUnheadHead, r as PageView, s as VueHeadClient$1, t as Head, u as usePage } from "./app-CDOvFfdJ.js";
2
2
  import { a as withViewTransition, i as useViewTransitionState, n as getNavigationType, r as supportsViewTransitions, t as ViewTransitionOptions } from "./view-transitions-DRrLaRHL.js";
3
- import { AppPluginConfig, DefineAppOptions, ResolvedAppConfig, applyAppConfig, createDefaultAppConfig, defineApp } from "./define-app.js";
3
+ import { AppPluginConfig, DefineAppOptions, ResolvedAppConfig, applyAppConfig, createDefaultAppConfig, defineApp, mergeAppConfig } from "./define-app.js";
4
4
  import { VueHeadClient, injectHead } from "@unhead/vue";
5
5
  import { createHead as createClientHead } from "@unhead/vue/client";
6
6
  import { createHead as createServerHead } from "@unhead/vue/server";
@@ -12,6 +12,17 @@ import { DefineMetaResult, PageMeta } from "@ubean/routing";
12
12
  import { LinkTag, MetaTag, SeoMetadata } from "@ubean/seo";
13
13
  //#region src/client.d.ts
14
14
  declare function getInitialPageData<T = Record<string, unknown>>(): PageObject<T> | null;
15
+ /**
16
+ * 从 DOM 中的 `<script id="__UBEAN_STATE__">` 读取 SSR 序列化的状态。
17
+ *
18
+ * 该状态由服务端 `defineApp({ serializeState })` 产生,用于在客户端 mount 前
19
+ * 水合到对应的库实例(如 Pinia 的 `pinia.state.value`)。
20
+ *
21
+ * 必须在 `app.mount()` 之前调用(在 `defineApp({ hydrateState })` 内部使用)。
22
+ *
23
+ * @returns 解析后的状态对象,或 `null`(无状态 / 解析失败 / 非 DOM 环境)
24
+ */
25
+ declare function getInitialState(): Record<string, unknown> | null;
15
26
  //#endregion
16
27
  //#region src/head.d.ts
17
28
  declare function useHeadInstance(): import("@unhead/vue").VueHeadClient;
@@ -390,4 +401,4 @@ declare module 'vue-router' {
390
401
  }
391
402
  }
392
403
  //#endregion
393
- export { type AppPluginConfig, type CreateUbeanRouterOptions, type DataCacheStore, type DefineAppOptions, Head, type VueHeadClient as HeadClient, type HydrateIslandsOptions, type IslandHydrateOptions, type IslandRecord, Link, type LinkProps, type LinkTag, type MetaTag, PageView, type ResolvedAppConfig, type RouteLocation, type RouteLocationRaw, type SeoMetadata, type TypedLinkProps, type UbeanAppInstance, type UbeanAppOptions, type UbeanVueContext, type UseAsyncDataOptions, type UseAsyncDataReturn, type UseCacheViewsReturn, type UsePageTransitionReturn, type UseReloadSignalReturn, type ViewTransitionOptions, type VueHeadClient$1 as VueHeadClient, type VueI18nInstance, addLocale, applyAppConfig, clearCache, clearLocales, clearPageTransition, collectIslands, createClientHead, createDataCacheStore, createDefaultAppConfig, createLinkHandler, createServerHead, createUbeanApp, createUbeanRouter, createUbeanSSRApp, createUseAsyncData, defineApp, defineDataKey, defineLocale, defineMeta, defineMiddleware, definePage, detectBrowserLocale, detectLocale, disablePageCache, enablePageCache, excludePageCache, extractLocaleFromPath, extractPageData, getCacheEnabled, getCachedViewNames, getDefaultLocale, getExcludedViewNames, getI18nConfig, getInitialPageData, getInvalidatedKeysForAction, getLocale, getLocaleDir, getLocaleName, getNavigationType, getPageTransitionName, getRegisteredLocales, getReloadCounter, hydrateIsland, hydrateIslands, includePageCache, initCachedViewsFromRoutes, injectHead, invalidateCache, invalidatePageCache, isActiveRoute, isCacheEnabled, isPageCached, isPageExcluded, isReloading, localizePath, mergeLocale, onLocaleChange, reloadPage, resetRouteCache, resolveRoute, setI18nConfig, setLocale, setPageTransition, supportsViewTransitions, switchLocalePath, t, useCacheViews, useUnheadHead as useHead, useHeadInstance, useI18n, useLocalePath, usePage, usePageTransition, useReloadSignal, useRouter, useSeoMeta, useServerData, useSwitchLocalePath, useViewTransition, useViewTransitionState, withViewTransition };
404
+ export { type AppPluginConfig, type CreateUbeanRouterOptions, type DataCacheStore, type DefineAppOptions, Head, type VueHeadClient as HeadClient, type HydrateIslandsOptions, type IslandHydrateOptions, type IslandRecord, Link, type LinkProps, type LinkTag, type MetaTag, PageView, type ResolvedAppConfig, type RouteLocation, type RouteLocationRaw, type SeoMetadata, type TypedLinkProps, type UbeanAppInstance, type UbeanAppOptions, type UbeanVueContext, type UseAsyncDataOptions, type UseAsyncDataReturn, type UseCacheViewsReturn, type UsePageTransitionReturn, type UseReloadSignalReturn, type ViewTransitionOptions, type VueHeadClient$1 as VueHeadClient, type VueI18nInstance, addLocale, applyAppConfig, clearCache, clearLocales, clearPageTransition, collectIslands, createClientHead, createDataCacheStore, createDefaultAppConfig, createLinkHandler, createServerHead, createUbeanApp, createUbeanRouter, createUbeanSSRApp, createUseAsyncData, defineApp, defineDataKey, defineLocale, defineMeta, defineMiddleware, definePage, detectBrowserLocale, detectLocale, disablePageCache, enablePageCache, excludePageCache, extractLocaleFromPath, extractPageData, getCacheEnabled, getCachedViewNames, getDefaultLocale, getExcludedViewNames, getI18nConfig, getInitialPageData, getInitialState, getInvalidatedKeysForAction, getLocale, getLocaleDir, getLocaleName, getNavigationType, getPageTransitionName, getRegisteredLocales, getReloadCounter, hydrateIsland, hydrateIslands, includePageCache, initCachedViewsFromRoutes, injectHead, invalidateCache, invalidatePageCache, isActiveRoute, isCacheEnabled, isPageCached, isPageExcluded, isReloading, localizePath, mergeAppConfig, mergeLocale, onLocaleChange, reloadPage, resetRouteCache, resolveRoute, setI18nConfig, setLocale, setPageTransition, supportsViewTransitions, switchLocalePath, t, useCacheViews, useUnheadHead as useHead, useHeadInstance, useI18n, useLocalePath, usePage, usePageTransition, useReloadSignal, useRouter, useSeoMeta, useServerData, useSwitchLocalePath, useViewTransition, useViewTransitionState, withViewTransition };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { $ as setI18nConfig, A as initCachedViewsFromRoutes, B as defineLocale, C as disablePageCache, D as getCachedViewNames, E as getCacheEnabled, F as resetRouteCache, G as getI18nConfig, H as detectLocale, I as useCacheViews, J as getLocaleName, K as getLocale, L as createUbeanRouter, M as isCacheEnabled, N as isPageCached, O as getExcludedViewNames, P as isPageExcluded, Q as onLocaleChange, R as addLocale, S as useReloadSignal, T as excludePageCache, U as extractLocaleFromPath, V as detectBrowserLocale, W as getDefaultLocale, X as localizePath, Y as getRegisteredLocales, Z as mergeLocale, _ as getReloadCounter, a as createUbeanSSRApp, at as useSwitchLocalePath, b as setPageTransition, c as useSeoMeta, d as getNavigationType, et as setLocale, f as supportsViewTransitions, g as getPageTransitionName, h as clearPageTransition, i as createUbeanApp, it as useLocalePath, j as invalidatePageCache, k as includePageCache, l as useUnheadHead, m as withViewTransition, n as Link, nt as t, o as usePage, p as useViewTransitionState, q as getLocaleDir, r as PageView, rt as useI18n, s as useRouter, t as Head, tt as switchLocalePath, u as useViewTransition, v as isReloading, w as enablePageCache, x as usePageTransition, y as reloadPage, z as clearLocales } from "./app-dx92OPRP.js";
2
- import { applyAppConfig, createDefaultAppConfig, defineApp } from "./define-app.js";
2
+ import { applyAppConfig, createDefaultAppConfig, defineApp, mergeAppConfig } from "./define-app.js";
3
3
  import { injectHead, injectHead as injectHead$1 } from "@unhead/vue";
4
4
  import { createHead as createClientHead } from "@unhead/vue/client";
5
5
  import { createHead as createServerHead } from "@unhead/vue/server";
@@ -17,6 +17,28 @@ function getInitialPageData() {
17
17
  return null;
18
18
  }
19
19
  }
20
+ /**
21
+ * 从 DOM 中的 `<script id="__UBEAN_STATE__">` 读取 SSR 序列化的状态。
22
+ *
23
+ * 该状态由服务端 `defineApp({ serializeState })` 产生,用于在客户端 mount 前
24
+ * 水合到对应的库实例(如 Pinia 的 `pinia.state.value`)。
25
+ *
26
+ * 必须在 `app.mount()` 之前调用(在 `defineApp({ hydrateState })` 内部使用)。
27
+ *
28
+ * @returns 解析后的状态对象,或 `null`(无状态 / 解析失败 / 非 DOM 环境)
29
+ */
30
+ function getInitialState() {
31
+ if (typeof _global$2.document === "undefined") return null;
32
+ const el = _global$2.document.getElementById("__UBEAN_STATE__");
33
+ if (!el) return _global$2.__UBEAN_STATE__ ?? null;
34
+ try {
35
+ const text = el.textContent || "";
36
+ if (!text.trim()) return null;
37
+ return JSON.parse(text);
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
20
42
  //#endregion
21
43
  //#region src/head.ts
22
44
  function useHeadInstance() {
@@ -361,4 +383,4 @@ function resolveComponent(name, components, getComponent) {
361
383
  return null;
362
384
  }
363
385
  //#endregion
364
- export { Head, Link, PageView, addLocale, applyAppConfig, clearCache, clearLocales, clearPageTransition, collectIslands, createClientHead, createDataCacheStore, createDefaultAppConfig, createLinkHandler, createServerHead, createUbeanApp, createUbeanRouter, createUbeanSSRApp, createUseAsyncData, defineApp, defineDataKey, defineLocale, defineMeta, defineMiddleware, definePage, detectBrowserLocale, detectLocale, disablePageCache, enablePageCache, excludePageCache, extractLocaleFromPath, extractPageData, getCacheEnabled, getCachedViewNames, getDefaultLocale, getExcludedViewNames, getI18nConfig, getInitialPageData, getInvalidatedKeysForAction, getLocale, getLocaleDir, getLocaleName, getNavigationType, getPageTransitionName, getRegisteredLocales, getReloadCounter, hydrateIsland, hydrateIslands, includePageCache, initCachedViewsFromRoutes, injectHead, invalidateCache, invalidatePageCache, isActiveRoute, isCacheEnabled, isPageCached, isPageExcluded, isReloading, localizePath, mergeLocale, onLocaleChange, reloadPage, resetRouteCache, resolveRoute, setI18nConfig, setLocale, setPageTransition, supportsViewTransitions, switchLocalePath, t, useCacheViews, useUnheadHead as useHead, useHeadInstance, useI18n, useLocalePath, usePage, usePageTransition, useReloadSignal, useRouter, useSeoMeta, useServerData, useSwitchLocalePath, useViewTransition, useViewTransitionState, withViewTransition };
386
+ export { Head, Link, PageView, addLocale, applyAppConfig, clearCache, clearLocales, clearPageTransition, collectIslands, createClientHead, createDataCacheStore, createDefaultAppConfig, createLinkHandler, createServerHead, createUbeanApp, createUbeanRouter, createUbeanSSRApp, createUseAsyncData, defineApp, defineDataKey, defineLocale, defineMeta, defineMiddleware, definePage, detectBrowserLocale, detectLocale, disablePageCache, enablePageCache, excludePageCache, extractLocaleFromPath, extractPageData, getCacheEnabled, getCachedViewNames, getDefaultLocale, getExcludedViewNames, getI18nConfig, getInitialPageData, getInitialState, getInvalidatedKeysForAction, getLocale, getLocaleDir, getLocaleName, getNavigationType, getPageTransitionName, getRegisteredLocales, getReloadCounter, hydrateIsland, hydrateIslands, includePageCache, initCachedViewsFromRoutes, injectHead, invalidateCache, invalidatePageCache, isActiveRoute, isCacheEnabled, isPageCached, isPageExcluded, isReloading, localizePath, mergeAppConfig, mergeLocale, onLocaleChange, reloadPage, resetRouteCache, resolveRoute, setI18nConfig, setLocale, setPageTransition, supportsViewTransitions, switchLocalePath, t, useCacheViews, useUnheadHead as useHead, useHeadInstance, useI18n, useLocalePath, usePage, usePageTransition, useReloadSignal, useRouter, useSeoMeta, useServerData, useSwitchLocalePath, useViewTransition, useViewTransitionState, withViewTransition };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubean/runtime",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Vue client runtime for ubean (createUbeanApp, useRouter, useHead, Link, Head, PageView, composables, view-transitions, cache-views, islands hydrate)",
5
5
  "files": [
6
6
  "dist"
@@ -27,18 +27,18 @@
27
27
  "@unhead/vue": "^3.2.3",
28
28
  "vue": "^3.5.40",
29
29
  "vue-router": "^5.2.0",
30
- "@ubean/i18n": "0.1.7",
31
- "@ubean/pages": "0.1.7",
32
- "@ubean/types": "0.1.7"
30
+ "@ubean/i18n": "0.1.8",
31
+ "@ubean/types": "0.1.8",
32
+ "@ubean/pages": "0.1.8"
33
33
  },
34
34
  "devDependencies": {
35
- "@types/node": "^26.1.1",
36
- "typescript": "6.0.3",
35
+ "@types/node": "^26.1.2",
36
+ "typescript": "7.0.2",
37
37
  "vite-plus": "0.2.6"
38
38
  },
39
39
  "peerDependencies": {
40
- "@ubean/routing": "0.1.7",
41
- "@ubean/seo": "0.1.7"
40
+ "@ubean/routing": "0.1.8",
41
+ "@ubean/seo": "0.1.8"
42
42
  },
43
43
  "peerDependenciesMeta": {
44
44
  "@ubean/seo": {