@ubean/integrations 0.2.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/LICENSE +21 -0
- package/dist/electron/index.d.ts +37 -0
- package/dist/electron/index.js +61 -0
- package/dist/fonts/index.d.ts +43 -0
- package/dist/fonts/index.js +103 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +148 -0
- package/dist/pinia/index.d.ts +16 -0
- package/dist/pinia/index.js +30 -0
- package/dist/pwa/index.d.ts +47 -0
- package/dist/pwa/index.js +159 -0
- package/dist/runtime-C_0lCtWE.js +349 -0
- package/dist/types-BXiJV3cm.d.ts +37 -0
- package/dist/types-BsgAJnWk.d.ts +40 -0
- package/dist/types-CpVZH81i.d.ts +106 -0
- package/dist/types-D94CeRo-.d.ts +130 -0
- package/dist/types-Qd7x9Fbj.d.ts +52 -0
- package/dist/ui/index.d.ts +26 -0
- package/dist/ui/index.js +44 -0
- package/package.json +82 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { C as getFontshareUrl, D as normalizeFontName, E as normalizeFontFamily, O as parseFontFamilyCSS, S as getBunnyFontsUrl, T as googleFontMetrics, _ as generateFontCSSVariable, a as generateFontCSS, b as generatePreconnectLink, c as getFontHash, d as defaultFontDisplay, f as defaultFontStyles, g as fallbackFonts, h as extractFontUrlsFromCSS, i as defineLocalFont, k as weightsToString, l as getFontsConfig, m as defaultFontWeights, n as defineFontFamily, o as generateFontLinks, p as defaultFontSubsets, r as defineGoogleFont, s as getFontFamilies, t as configureFontsRuntime, u as createFontHash, v as generateFontFace, w as getGoogleFontsUrl, x as generatePreloadLink, y as generateFontFallbackCSS } from "./runtime-C_0lCtWE.js";
|
|
2
|
+
import { computed, onMounted, ref } from "vue";
|
|
3
|
+
//#region src/pwa/runtime.ts
|
|
4
|
+
let swRegistration = null;
|
|
5
|
+
async function registerSWFn(swUrl, opts = {}) {
|
|
6
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return null;
|
|
7
|
+
const { immediate = true, onNeedRefresh, onOfflineReady, onRegistered, onRegisterError, onUpdateFound } = opts;
|
|
8
|
+
if (!immediate) return null;
|
|
9
|
+
try {
|
|
10
|
+
const registration = await navigator.serviceWorker.register(swUrl, { scope: "/" });
|
|
11
|
+
swRegistration = registration;
|
|
12
|
+
onRegistered?.(swUrl);
|
|
13
|
+
registration.addEventListener("updatefound", () => {
|
|
14
|
+
const newWorker = registration.installing;
|
|
15
|
+
onUpdateFound?.();
|
|
16
|
+
if (newWorker) newWorker.addEventListener("statechange", () => {
|
|
17
|
+
if (newWorker.state === "installed" && navigator.serviceWorker.controller) onNeedRefresh?.();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
if (!navigator.serviceWorker.controller) onOfflineReady?.();
|
|
21
|
+
return registration;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
onRegisterError?.(error instanceof Error ? error : new Error(String(error)));
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function registerSW(swUrl = "/sw.js", options = {}) {
|
|
28
|
+
return registerSWFn(swUrl, options);
|
|
29
|
+
}
|
|
30
|
+
function updateSW() {
|
|
31
|
+
if (swRegistration?.waiting) swRegistration.waiting.postMessage({ type: "SKIP_WAITING" });
|
|
32
|
+
}
|
|
33
|
+
function getSWRegistration() {
|
|
34
|
+
return swRegistration;
|
|
35
|
+
}
|
|
36
|
+
function usePwa(options = {}) {
|
|
37
|
+
const { immediate = true, swUrl = "/sw.js", onNeedRefresh, onOfflineReady, onRegistered, onRegisterError, onUpdateFound } = options;
|
|
38
|
+
const isInstalled = ref(false);
|
|
39
|
+
const isUpdateAvailable = ref(false);
|
|
40
|
+
const isOfflineReady = ref(false);
|
|
41
|
+
const needRefresh = ref(false);
|
|
42
|
+
const registration = ref(null);
|
|
43
|
+
const state = computed(() => ({
|
|
44
|
+
isInstalled: isInstalled.value,
|
|
45
|
+
isUpdateAvailable: isUpdateAvailable.value,
|
|
46
|
+
isOfflineReady: isOfflineReady.value,
|
|
47
|
+
needRefresh: needRefresh.value,
|
|
48
|
+
registration: registration.value
|
|
49
|
+
}));
|
|
50
|
+
async function doRegister() {
|
|
51
|
+
if (typeof window === "undefined" || !("serviceWorker" in navigator)) return;
|
|
52
|
+
try {
|
|
53
|
+
const reg = await registerSWFn(swUrl, {
|
|
54
|
+
immediate,
|
|
55
|
+
onNeedRefresh: () => {
|
|
56
|
+
needRefresh.value = true;
|
|
57
|
+
isUpdateAvailable.value = true;
|
|
58
|
+
onNeedRefresh?.();
|
|
59
|
+
},
|
|
60
|
+
onOfflineReady: () => {
|
|
61
|
+
isOfflineReady.value = true;
|
|
62
|
+
isInstalled.value = true;
|
|
63
|
+
onOfflineReady?.();
|
|
64
|
+
},
|
|
65
|
+
onRegistered: (url) => {
|
|
66
|
+
registration.value = swRegistration;
|
|
67
|
+
onRegistered?.(url);
|
|
68
|
+
},
|
|
69
|
+
onRegisterError: (err) => {
|
|
70
|
+
onRegisterError?.(err);
|
|
71
|
+
},
|
|
72
|
+
onUpdateFound: () => {
|
|
73
|
+
onUpdateFound?.();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
if (reg) registration.value = reg;
|
|
77
|
+
} catch {}
|
|
78
|
+
}
|
|
79
|
+
function skipWaitingAndRefresh() {
|
|
80
|
+
updateSW();
|
|
81
|
+
}
|
|
82
|
+
function closeNeedRefresh() {
|
|
83
|
+
needRefresh.value = false;
|
|
84
|
+
isUpdateAvailable.value = false;
|
|
85
|
+
}
|
|
86
|
+
onMounted(() => {
|
|
87
|
+
if (immediate) doRegister();
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
state,
|
|
91
|
+
isInstalled,
|
|
92
|
+
isUpdateAvailable,
|
|
93
|
+
isOfflineReady,
|
|
94
|
+
needRefresh,
|
|
95
|
+
registration,
|
|
96
|
+
register: doRegister,
|
|
97
|
+
updateServiceWorker: skipWaitingAndRefresh,
|
|
98
|
+
skipWaiting: skipWaitingAndRefresh,
|
|
99
|
+
closePrompt: closeNeedRefresh
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/pinia/runtime.ts
|
|
104
|
+
function getPiniaFromApp(app) {
|
|
105
|
+
return app.config.globalProperties.$pinia ?? null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* SSR 序列化:从 Vue app 实例提取 Pinia 的 root state。
|
|
109
|
+
*
|
|
110
|
+
* 在服务端 `renderToString(app)` 完成后由 ubean SSR 渲染器调用。
|
|
111
|
+
* 返回的 `{ pinia }` 会被序列化到 HTML 的 `__UBEAN_STATE__` script 标签中。
|
|
112
|
+
*
|
|
113
|
+
* 若 app 上未检测到 `$pinia`(未安装 pinia 插件),返回空对象,
|
|
114
|
+
* 不会抛出错误(允许在部分页面不使用 pinia)。
|
|
115
|
+
*
|
|
116
|
+
* @param app Vue app 实例(SSR 渲染用的 app)
|
|
117
|
+
* @returns 序列化后的状态对象,包含 `pinia.state.value`
|
|
118
|
+
*/
|
|
119
|
+
function serializePiniaState(app) {
|
|
120
|
+
const pinia = getPiniaFromApp(app);
|
|
121
|
+
if (!pinia) return {};
|
|
122
|
+
return { pinia: JSON.parse(JSON.stringify(pinia.state.value)) };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 客户端水合:将 SSR 序列化的 state 注入到 Pinia 实例。
|
|
126
|
+
*
|
|
127
|
+
* 在 `applyAppConfig`(注册 `createPinia()` 插件)之后、`app.mount()` 之前调用。
|
|
128
|
+
* 必须在 mount 前执行,否则 store 已用默认 state 初始化,水合无效。
|
|
129
|
+
*
|
|
130
|
+
* 若 `state` 为 `null` 或不含 `pinia` 字段,直接返回(no-op),
|
|
131
|
+
* 允许在 CSR 模式或无 SSR state 时安全调用。
|
|
132
|
+
*
|
|
133
|
+
* @param app Vue app 实例(客户端 app,已 install pinia 插件)
|
|
134
|
+
* @param state 从 `__UBEAN_STATE__` 反序列化的状态对象,或 null
|
|
135
|
+
*/
|
|
136
|
+
function hydratePiniaState(app, state) {
|
|
137
|
+
if (!state) return;
|
|
138
|
+
const piniaState = state.pinia;
|
|
139
|
+
if (!piniaState || typeof piniaState !== "object") return;
|
|
140
|
+
const pinia = getPiniaFromApp(app);
|
|
141
|
+
if (!pinia) {
|
|
142
|
+
console.warn("[ubean/pinia] hydrateState 被调用但 app 上未检测到 $pinia。请确保 defineApp({ plugins: [createPinia()] }) 已配置。");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
pinia.state.value = piniaState;
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
export { configureFontsRuntime, createFontHash, defaultFontDisplay, defaultFontStyles, defaultFontSubsets, defaultFontWeights, defineFontFamily, defineGoogleFont, defineLocalFont, extractFontUrlsFromCSS, fallbackFonts, generateFontCSS, generateFontCSSVariable, generateFontFace, generateFontFallbackCSS, generateFontLinks, generatePreconnectLink, generatePreloadLink, getBunnyFontsUrl, getFontFamilies, getFontHash, getFontsConfig, getFontshareUrl, getGoogleFontsUrl, getSWRegistration, googleFontMetrics, hydratePiniaState, normalizeFontFamily, normalizeFontName, parseFontFamilyCSS, registerSW, serializePiniaState, updateSW, usePwa, weightsToString };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { n as UbeanPiniaOptions, t as PiniaSerializedState } from "../types-Qd7x9Fbj.js";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
//#region src/pinia/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* ubean Pinia Vite 插件
|
|
6
|
+
*
|
|
7
|
+
* @param options 配置选项(`pinia: true` 时传入 `{}`,`pinia: { ... }` 时传入该对象)
|
|
8
|
+
* @returns Vite 插件数组
|
|
9
|
+
*/
|
|
10
|
+
declare function ubeanPiniaPlugin(options?: UbeanPiniaOptions): Plugin[];
|
|
11
|
+
/**
|
|
12
|
+
* 类型安全的 Pinia 配置定义辅助函数(透传)
|
|
13
|
+
*/
|
|
14
|
+
declare function definePiniaConfig(options: UbeanPiniaOptions): UbeanPiniaOptions;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { type PiniaSerializedState, type UbeanPiniaOptions, ubeanPiniaPlugin as default, ubeanPiniaPlugin, definePiniaConfig };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/pinia/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* ubean Pinia Vite 插件
|
|
4
|
+
*
|
|
5
|
+
* @param options 配置选项(`pinia: true` 时传入 `{}`,`pinia: { ... }` 时传入该对象)
|
|
6
|
+
* @returns Vite 插件数组
|
|
7
|
+
*/
|
|
8
|
+
function ubeanPiniaPlugin(options = {}) {
|
|
9
|
+
if (options.enabled === false) return [{
|
|
10
|
+
name: "ubean:pinia:noop",
|
|
11
|
+
enforce: "post"
|
|
12
|
+
}];
|
|
13
|
+
const optimizeDeps = options.optimizeDeps !== false;
|
|
14
|
+
return [{
|
|
15
|
+
name: "ubean:pinia",
|
|
16
|
+
enforce: "pre",
|
|
17
|
+
config() {
|
|
18
|
+
if (!optimizeDeps) return void 0;
|
|
19
|
+
return { optimizeDeps: { include: ["pinia"] } };
|
|
20
|
+
}
|
|
21
|
+
}];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 类型安全的 Pinia 配置定义辅助函数(透传)
|
|
25
|
+
*/
|
|
26
|
+
function definePiniaConfig(options) {
|
|
27
|
+
return options;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { ubeanPiniaPlugin as default, ubeanPiniaPlugin, definePiniaConfig };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { a as ManifestScreenshot, c as RuntimeCachingRule, i as ManifestOrientation, l as UsePwaOptions, n as DisplayMode, o as PwaOptions, r as ManifestIcon, s as PwaState, t as CachingStrategy, u as WebAppManifest } from "../types-D94CeRo-.js";
|
|
2
|
+
import { VitePWAOptions } from "vite-plugin-pwa";
|
|
3
|
+
import { Plugin } from "vite";
|
|
4
|
+
//#region src/pwa/index.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* 将 ubean PwaOptions 转换为 vite-plugin-pwa 的 VitePluginPWOptions。
|
|
7
|
+
*
|
|
8
|
+
* 映射关系:
|
|
9
|
+
* - manifest → manifest
|
|
10
|
+
* - registerType → registerType
|
|
11
|
+
* - injectRegister → injectRegister
|
|
12
|
+
* - devOptions → devOptions
|
|
13
|
+
* - skipWaiting → workbox.skipWaiting
|
|
14
|
+
* - clientsClaim → workbox.clientsClaim
|
|
15
|
+
* - cleanupOutdatedCaches → workbox.cleanupOutdatedCaches
|
|
16
|
+
* - strategies + runtimeCaching → workbox.runtimeCaching
|
|
17
|
+
* - injectManifest + swSrc → strategies: 'injectManifest' + injectManifest.swSrc
|
|
18
|
+
*/
|
|
19
|
+
declare function toVitePwaOptions(options?: PwaOptions): VitePWAOptions;
|
|
20
|
+
/**
|
|
21
|
+
* ubean PWA Vite 插件(基于 vite-plugin-pwa)
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // vite.config.ts
|
|
26
|
+
* import { ubeanPwaPlugin } from '@ubean/integrations/pwa';
|
|
27
|
+
*
|
|
28
|
+
* export default defineConfig({
|
|
29
|
+
* plugins: [
|
|
30
|
+
* ubeanPwaPlugin({
|
|
31
|
+
* manifest: { name: 'My App', theme_color: '#ff0000' },
|
|
32
|
+
* registerType: 'prompt'
|
|
33
|
+
* })
|
|
34
|
+
* ]
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* 通常由 ubean module 系统在 `ubean.config.ts` 中 `pwa: true | PwaOptions` 自动加载,
|
|
39
|
+
* 无需在 vite.config.ts 中手动调用。
|
|
40
|
+
*/
|
|
41
|
+
declare function ubeanPwaPlugin(options?: PwaOptions): Plugin;
|
|
42
|
+
/**
|
|
43
|
+
* 类型安全的 PWA 配置定义辅助函数(透传)
|
|
44
|
+
*/
|
|
45
|
+
declare function definePwaConfig(options: PwaOptions): PwaOptions;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { type CachingStrategy, type DisplayMode, type ManifestIcon, type ManifestOrientation, type ManifestScreenshot, type PwaOptions, type PwaState, type RuntimeCachingRule, type UsePwaOptions, type WebAppManifest, ubeanPwaPlugin as default, ubeanPwaPlugin, definePwaConfig, toVitePwaOptions };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { VitePWA } from "vite-plugin-pwa";
|
|
2
|
+
import { defu } from "defu";
|
|
3
|
+
//#region src/pwa/index.ts
|
|
4
|
+
const DEFAULT_MANIFEST = {
|
|
5
|
+
name: "Ubean App",
|
|
6
|
+
short_name: "Ubean",
|
|
7
|
+
start_url: "/",
|
|
8
|
+
scope: "/",
|
|
9
|
+
display: "standalone",
|
|
10
|
+
background_color: "#ffffff",
|
|
11
|
+
theme_color: "#000000",
|
|
12
|
+
icons: [],
|
|
13
|
+
lang: "en"
|
|
14
|
+
};
|
|
15
|
+
const DEFAULT_STRATEGIES = {
|
|
16
|
+
assets: "cache-first",
|
|
17
|
+
pages: "network-first",
|
|
18
|
+
images: "stale-while-revalidate",
|
|
19
|
+
fonts: "cache-first",
|
|
20
|
+
crossOrigin: "network-first"
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* 将 ubean 的 strategies(按资源类型)转换为 workbox runtimeCaching 规则。
|
|
24
|
+
* 这些规则作为默认值,放在用户自定义 runtimeCaching 之前。
|
|
25
|
+
*/
|
|
26
|
+
function strategiesToRuntimeCaching(strategies) {
|
|
27
|
+
const rules = [];
|
|
28
|
+
if (strategies.assets) rules.push({
|
|
29
|
+
urlPattern: /\.(?:js|css|woff2?|ttf|eot)$/,
|
|
30
|
+
handler: strategies.assets,
|
|
31
|
+
options: { cacheName: "assets" }
|
|
32
|
+
});
|
|
33
|
+
if (strategies.pages) rules.push({
|
|
34
|
+
urlPattern: /\/$/,
|
|
35
|
+
handler: strategies.pages,
|
|
36
|
+
options: { cacheName: "pages" }
|
|
37
|
+
});
|
|
38
|
+
if (strategies.images) rules.push({
|
|
39
|
+
urlPattern: /\.(?:png|jpg|jpeg|gif|webp|svg|avif)$/,
|
|
40
|
+
handler: strategies.images,
|
|
41
|
+
options: {
|
|
42
|
+
cacheName: "images",
|
|
43
|
+
expiration: {
|
|
44
|
+
maxEntries: 60,
|
|
45
|
+
maxAgeSeconds: 2592e3
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
if (strategies.fonts) rules.push({
|
|
50
|
+
urlPattern: /\.(?:woff2?|ttf|eot|otf)$/,
|
|
51
|
+
handler: strategies.fonts,
|
|
52
|
+
options: {
|
|
53
|
+
cacheName: "fonts",
|
|
54
|
+
expiration: {
|
|
55
|
+
maxEntries: 10,
|
|
56
|
+
maxAgeSeconds: 31536e3
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
if (strategies.crossOrigin) rules.push({
|
|
61
|
+
urlPattern: /^https?:\/\/(?!localhost).*/,
|
|
62
|
+
handler: strategies.crossOrigin,
|
|
63
|
+
options: { cacheName: "cross-origin" }
|
|
64
|
+
});
|
|
65
|
+
return rules;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 将 ubean PwaOptions 转换为 vite-plugin-pwa 的 VitePluginPWOptions。
|
|
69
|
+
*
|
|
70
|
+
* 映射关系:
|
|
71
|
+
* - manifest → manifest
|
|
72
|
+
* - registerType → registerType
|
|
73
|
+
* - injectRegister → injectRegister
|
|
74
|
+
* - devOptions → devOptions
|
|
75
|
+
* - skipWaiting → workbox.skipWaiting
|
|
76
|
+
* - clientsClaim → workbox.clientsClaim
|
|
77
|
+
* - cleanupOutdatedCaches → workbox.cleanupOutdatedCaches
|
|
78
|
+
* - strategies + runtimeCaching → workbox.runtimeCaching
|
|
79
|
+
* - injectManifest + swSrc → strategies: 'injectManifest' + injectManifest.swSrc
|
|
80
|
+
*/
|
|
81
|
+
function toVitePwaOptions(options = {}) {
|
|
82
|
+
const { enabled = true, manifest, registerType = "autoUpdate", injectRegister = "auto", devOptions, strategies, runtimeCaching = [], skipWaiting = true, clientsClaim = true, cleanupOutdatedCaches = true, injectManifest = false, swSrc } = options;
|
|
83
|
+
if (!enabled) return { disable: true };
|
|
84
|
+
const resolvedManifest = defu(manifest ?? {}, DEFAULT_MANIFEST);
|
|
85
|
+
const allRuntimeCaching = [...strategiesToRuntimeCaching(defu(strategies ?? {}, DEFAULT_STRATEGIES)), ...runtimeCaching];
|
|
86
|
+
if (injectManifest) return {
|
|
87
|
+
strategies: "injectManifest",
|
|
88
|
+
registerType,
|
|
89
|
+
injectRegister: injectRegister ?? void 0,
|
|
90
|
+
manifest: resolvedManifest,
|
|
91
|
+
devOptions,
|
|
92
|
+
injectManifest: {
|
|
93
|
+
swSrc: swSrc ?? "src/sw.ts",
|
|
94
|
+
skipWaiting,
|
|
95
|
+
clientsClaim,
|
|
96
|
+
cleanupOutdatedCaches,
|
|
97
|
+
runtimeCaching: allRuntimeCaching
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
strategies: "generateSW",
|
|
102
|
+
registerType,
|
|
103
|
+
injectRegister: injectRegister ?? void 0,
|
|
104
|
+
manifest: resolvedManifest,
|
|
105
|
+
devOptions,
|
|
106
|
+
workbox: {
|
|
107
|
+
skipWaiting,
|
|
108
|
+
clientsClaim,
|
|
109
|
+
cleanupOutdatedCaches,
|
|
110
|
+
runtimeCaching: allRuntimeCaching
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* ubean PWA Vite 插件(基于 vite-plugin-pwa)
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* // vite.config.ts
|
|
120
|
+
* import { ubeanPwaPlugin } from '@ubean/integrations/pwa';
|
|
121
|
+
*
|
|
122
|
+
* export default defineConfig({
|
|
123
|
+
* plugins: [
|
|
124
|
+
* ubeanPwaPlugin({
|
|
125
|
+
* manifest: { name: 'My App', theme_color: '#ff0000' },
|
|
126
|
+
* registerType: 'prompt'
|
|
127
|
+
* })
|
|
128
|
+
* ]
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* 通常由 ubean module 系统在 `ubean.config.ts` 中 `pwa: true | PwaOptions` 自动加载,
|
|
133
|
+
* 无需在 vite.config.ts 中手动调用。
|
|
134
|
+
*/
|
|
135
|
+
function ubeanPwaPlugin(options = {}) {
|
|
136
|
+
if (options.enabled === false) return {
|
|
137
|
+
name: "ubean:pwa:noop",
|
|
138
|
+
enforce: "post"
|
|
139
|
+
};
|
|
140
|
+
const vitePwaOptions = toVitePwaOptions(options);
|
|
141
|
+
const plugins = VitePWA(vitePwaOptions);
|
|
142
|
+
const plugin = Array.isArray(plugins) ? plugins[0] : plugins;
|
|
143
|
+
if (!plugin) return {
|
|
144
|
+
name: "ubean:pwa:noop",
|
|
145
|
+
enforce: "post"
|
|
146
|
+
};
|
|
147
|
+
return {
|
|
148
|
+
...plugin,
|
|
149
|
+
name: `ubean:pwa(${plugin.name})`
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 类型安全的 PWA 配置定义辅助函数(透传)
|
|
154
|
+
*/
|
|
155
|
+
function definePwaConfig(options) {
|
|
156
|
+
return options;
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
159
|
+
export { ubeanPwaPlugin as default, ubeanPwaPlugin, definePwaConfig, toVitePwaOptions };
|