@zxiaosi/sdk 1.0.0-beta.1 → 1.0.0-beta.2

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/dist/index.d.ts CHANGED
@@ -1,259 +1,191 @@
1
- import * as _$zustand from "zustand";
2
1
  import { ComponentType, ReactElement } from "react";
3
- import { Location, NavigateFunction, RouteObject, UIMatch } from "react-router-dom";
2
+ import { NavigateFunction, UIMatch } from "react-router-dom";
4
3
  import { MicroApp, ObjectType, RegistrableApp } from "qiankun";
5
- import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
4
+ import { StateCreator } from "zustand";
6
5
 
7
- //#region src/plugins/api/http.d.ts
8
- interface ApiRequestOption extends AxiosRequestConfig {
9
- /** 请求唯一key(默认自动生成) */
10
- requestId?: string;
11
- /** 是否取消重复请求 */
12
- isCancelRequest?: boolean;
13
- /** 是否需要原始数据 */
14
- isOriginalData?: boolean;
15
- /** 是否显示错误信息 */
16
- isShowFailMsg?: boolean;
17
- }
18
- //#endregion
19
6
  //#region src/plugins/api/index.d.ts
20
- interface ApiOptions {
21
- /** Axios配置 */
22
- config?: CreateAxiosDefaults;
23
- /** 取消请求控制器 */
24
- controllers?: Map<string, AbortController>;
25
- /**
26
- * 自定义请求实例
27
- * - 替换 SDK 内置的请求实例
28
- * @example instance = axios.create(options)
29
- */
30
- instance?: AxiosInstance;
31
- /**
32
- * 获取用户信息
33
- * {@link UserInfo}
34
- * @example { code: 0, data: { user: {}, permissions: [], roles: [], settings: {} } }
35
- */
36
- getUserInfoApi?(): Promise<any>;
37
- /**
38
- * 获取路由数据
39
- * {@link RouteObject}
40
- * @example { code: 0, data: [{path: '/', name: '首页', component: 'Home'}] }
41
- */
42
- getRoutesApi?(): Promise<any>;
43
- /**
44
- * 登录接口
45
- * @example { code: 0, data: { token: 'xxxx' } }
46
- */
47
- loginApi?(params: any): Promise<any>;
48
- }
49
- interface ApiResults extends Required<ApiOptions> {
50
- /**
51
- * 请求
52
- * @param url 请求地址
53
- * @param options 自定义配置项
54
- */
55
- request(url: string, options?: ApiRequestOption): Promise<any>;
56
- }
7
+ interface ApiOptions {}
57
8
  /**
58
9
  * 请求插件
59
- * - 详情参考 {@link ApiOptions} {@link ApiResults}
60
- * - 内置了请求, 通过 sdk.api.request 发起请求
61
- * - 可通过外部传入 instance 自定义请求实例
62
- * - 预置了获取用户信息, 获取路由接口, 以便组件使用
63
- * @example sdk.api.request('/getTemp', { method: 'POST', ... })
64
- * @example sdk.api.request('/getTemp', { method: 'POST', isOriginalData: true }) // 返回原始数据
65
- * @example sdk.api.request('/getTemp', { method: 'POST', isShowFailMsg: false }) // 不显示错误信息
66
- * @example sdk.api.request('/getTemp', { method: 'POST', isCancelRequest: false }) // 不自动取消重复请求
67
10
  */
68
- declare const SdkApiPlugin: Plugin<'api'>;
11
+ declare const SDKApiPlugin: SDKPlugin;
69
12
  //#endregion
70
13
  //#region src/plugins/app/index.d.ts
71
14
  interface AppOptions {
72
15
  /** 菜单数据 */
73
- menuData?: any[];
16
+ menuData: any[];
74
17
  /** 所有路由信息 */
75
- allRoutes?: RouteObject[];
18
+ allRoutes: any[];
76
19
  /** 微应用信息 */
77
- microApps?: RegistrableApp<ObjectType>[];
20
+ microApps: RegistrableApp<ObjectType>[];
78
21
  /** 微应用实例 */
79
- microAppsInstance?: Map<string, MicroApp>;
22
+ microAppsInstance: Map<string, MicroApp>;
80
23
  /** 用户信息 */
81
- user?: UserInfo['user'];
24
+ user: UserInfo['user'];
82
25
  /** 用户权限 */
83
- permissions?: UserInfo['permissions'];
84
- /** 用户角色 */
85
- roles?: UserInfo['roles'];
26
+ permissions: UserInfo['permissions'];
86
27
  /** 用户设置 */
87
- settings?: UserInfo['settings'];
88
- }
89
- interface AppResults extends Required<AppOptions> {
28
+ settings: UserInfo['settings'];
90
29
  /**
91
- * 初始化数据
92
- * - sdk.config.qiankunMode = 'load' 时, 登录时用
30
+ * 获取国际化默认值
31
+ * - 1. 本地缓存 `sdk.storage.getItem(sdk.storage.localeKey)`
32
+ * - 2. sdk中国际化 `sdk.config.locale`
33
+ * - 3. 浏览器语言 `navigator.language`
34
+ * - 4. 默认 `zh-CN`
93
35
  */
94
- initData(): void;
36
+ getDefaultLocale(): LocaleProps;
95
37
  /**
96
- * 清空数据
97
- * - sdk.config.qiankunMode = 'load' 时, 登出时用
38
+ * 获取主题默认值
39
+ * - 1. 本地缓存 `sdk.storage.getItem(sdk.storage.themeKey)`
40
+ * - 2. sdk中主题 `sdk.config.theme`
41
+ * - 3. 系统主题 `window.matchMedia('(prefers-color-scheme: dark)').matches`
42
+ * - 4. 默认 `light`
98
43
  */
99
- clearData(): void;
44
+ getDefaultTheme(): ThemeProps;
45
+ /**
46
+ * 获取重定向路径
47
+ * - 1. 优先使用指定值 `sdk.config.defaultPath`
48
+ * - 2. 其次使用重定向的值 `sdk.config.redirectField`
49
+ * - 3. 最后使用菜单中第一项 `/`
50
+ */
51
+ getRedirectPath(): string;
52
+ /**
53
+ * 初始化数据
54
+ */
55
+ initData(): void | Promise<void>;
100
56
  /**
101
57
  * 跳转登录页
58
+ * - 1. 清除 Token
59
+ * - 2. 清除用户信息
60
+ * - 3. 获取当前页路由
61
+ * - 4. 清空微应用
102
62
  */
103
63
  pageToLogin(): void;
104
64
  /**
105
- * 获取重定向路径
65
+ * 卸载微应用
66
+ * - 默认卸载所有微应用
67
+ * - 传入名称数组则卸载指定微应用
106
68
  */
107
- getRedirectPath(): string;
69
+ unmountMicroApp(names?: string[]): void;
108
70
  }
109
71
  /**
110
- * 项目信息
111
- * - 详情参考 {@link AppOptions} {@link AppResults}
112
- * - 菜单信息 sdk.app.menuData
113
- * - 路由信息 sdk.app.allRoutes
114
- * - 微应用信息 sdk.app.microApps
115
- * - 用户信息 sdk.app.user
116
- * - 用户权限 sdk.app.permissions
117
- * - 用户角色 sdk.app.roles
118
- * - 用户设置 sdk.app.settings
72
+ * 应用插件
73
+ *
74
+ * @example
75
+ * sdk.use(SDKAppPlugin, { menuData: [...] }).mount('xxx');
76
+ * sdk.app.unmountMicroApp();
119
77
  */
120
- declare const SdkAppPlugin: Plugin<'app'>;
78
+ declare const SDKAppPlugin: SDKPlugin;
121
79
  //#endregion
122
- //#region src/plugins/client/index.d.ts
123
- interface ClientOptions {}
124
- interface ClientResults extends Required<ClientOptions> {
125
- /** 主应用 location */
126
- location: Location;
127
- /** 路由匹配(用于面包屑) */
128
- matches: UIMatch[];
129
- /** 主应用navigate(解决微应用跳转问题) */
130
- navigate: NavigateFunction;
80
+ //#region src/plugins/components/index.d.ts
81
+ interface ComponentsOptions {
82
+ /** 组件 */
83
+ [key: string]: any;
84
+ /**
85
+ * 设置组件
86
+ * @param component 组件
87
+ * @param name 组件名称
88
+ */
89
+ setComponent(component: ComponentType, name?: string): void;
90
+ /**
91
+ * 获取组件
92
+ * @param name 组件名称
93
+ */
94
+ getComponent(name: string): ComponentType | null;
95
+ /**
96
+ * 渲染组件
97
+ * @param name 组件名称
98
+ */
99
+ renderComponent(name: string, props?: any): ReactElement | null;
131
100
  }
132
101
  /**
133
- * 全局路由信息
134
- * - 详情参考 {@link ClientOptions} {@link ClientResults}
135
- * - 路由信息 sdk.client.location
136
- * - 路由跳转 sdk.client.navigate
137
- * - 面包屑信息 sdk.client.matches
102
+ * 组件插件
103
+ *
104
+ * @example
105
+ * sdk.use(SDKComponentsPlugin).mount('xxx');
106
+ * sdk.components.setComponent(组件, '组件名称');
107
+ * sdk.components.renderComponent('组件名称', props);
138
108
  */
139
- declare const SdkClientPlugin: Plugin<'client'>;
109
+ declare const SDKComponentsPlugin: SDKPlugin;
140
110
  //#endregion
141
111
  //#region src/plugins/config/index.d.ts
142
112
  interface ConfigOptions {
143
113
  /** 环境变量(主应用共享给微应用变量) */
144
- env?: Record<string, any>;
114
+ env: Record<string, any>;
145
115
  /** 主题 */
146
- theme?: ThemeProps;
116
+ theme: ThemeProps;
147
117
  /** 语言 */
148
- locale?: LocaleProps;
149
- /**
150
- * Qiankun模式(切换模式后请重新打开页面)
151
- * - 'router': 基于路由模式
152
- * - 登录时,刷新页面,会自动调用 getUserInfoApi、getRoutesApi 获取数据
153
- * - 拿到 routes 数据之后,需要 registerMicroApps 注册微应用 和 start 启动微应用
154
- * - 系统退出时,刷新页面,自动销毁 qiankun 声明周期和缓存的数据
155
- * - 系统登录和系统退出仅有一次刷新页面即可,为了销毁 qiankun 的声明周期,但数据需要手动加载或者清除
156
- * - 'load': 手动加载模式
157
- * - 登录时,不需刷新页面, 但需要手动调用 getUserInfoApi、getRoutesApi 获取数据
158
- * - 拿到 routes 数据之后,在 Microapp 组件中使用 loadMicroApp 手动加载微应用
159
- * - 系统退出时,不刷新页面,但需要手动销毁每个微应用,并清除缓存数据
160
- */
161
- qiankunMode?: 'router' | 'load';
118
+ locale: LocaleProps;
162
119
  /** 登录页路由 */
163
- loginPath?: string;
164
- /**
165
- * 登录后跳转的路由
166
- * - 优先使用指定值
167
- * - 其次使用重定向的值
168
- * - 最后使用菜单中第一项
169
- */
170
- defaultPath?: string;
171
- /**
172
- * 自定义路由信息
173
- * - 目前只支持最外层路由自定义
174
- * - 会合并到 sdk.app.allRoutes 中
175
- */
176
- customRoutes?: RouteObject[];
177
- [key: string]: any;
120
+ loginPath: string;
121
+ /** 登录后跳转的路由 */
122
+ defaultPath: string;
123
+ /** 重定向字段 */
124
+ redirectField?: string;
178
125
  }
179
- interface ConfigResults extends Required<ConfigOptions> {}
180
126
  /**
181
- * Sdk 配置信息
182
- * - 详情参考 {@link ConfigOptions} {@link ConfigResults}
183
- * - 配置 env 环境变量
184
- * - 配置 默认主题、语言
185
- * - 配置 Qiankun 模式
186
- * - 配置 默认登录路径、跳转路径、自定义路由
127
+ * 配置插件
128
+ *
129
+ * @example
130
+ * sdk.use(SDKConfigPlugin, { theme: 'light' }).mount('xxx');
131
+ * console.log(sdk.api.theme); // 'light'
187
132
  */
188
- declare const SdkConfigPlugin: Plugin<'config'>;
133
+ declare const SDKConfigPlugin: SDKPlugin;
189
134
  //#endregion
190
135
  //#region src/plugins/i18n/index.d.ts
191
- interface I18nOptions {
192
- /**
193
- * Intl 实例
194
- * @example sdk.i18n.intl?.xxx
195
- */
196
- intl?: any;
197
- /**
198
- * 自定义语言包
199
- * @example
200
- * {
201
- * 'zh-CN': {
202
- * test: '测试国际化'
203
- * },
204
- * 'en-US': {
205
- * test: 'Test Intl'
206
- * }
207
- * }
208
- */
209
- intlConfig?: Record<string, any>;
136
+ interface I18nOptions {}
137
+ /**
138
+ * 国际化插件
139
+ *
140
+ * @example
141
+ * sdk.use(SDKI18nPlugin).mount('xxx');
142
+ */
143
+ declare const SDKI18nPlugin: SDKPlugin;
144
+ //#endregion
145
+ //#region src/plugins/router/index.d.ts
146
+ interface RouterOptions {
147
+ /** 主应用 location */
148
+ location: Location;
149
+ /** 路由匹配(用于面包屑) */
150
+ matches: UIMatch[];
151
+ /** 主应用navigate(解决微应用跳转问题) */
152
+ navigate: NavigateFunction;
210
153
  }
211
- interface I18nResults extends Required<I18nOptions> {}
212
154
  /**
213
- * 多语言
214
- * - 详情参考 {@link I18nOptions} {@link I18nResults}
155
+ * 路由插件
156
+ *
157
+ * @example
158
+ * sdk.use(SDKI18nPlugin).mount('xxx');
159
+ * sdk.router.location; // 路由信息
160
+ * sdk.router.navigate; // 路由跳转
161
+ * sdk.router.matches; // 面包屑信息
215
162
  */
216
- declare const SdkI18nPlugin: Plugin<'i18n'>;
163
+ declare const SDKRouterPlugin: SDKPlugin;
217
164
  //#endregion
218
165
  //#region src/plugins/storage/index.d.ts
219
166
  interface StorageOptions {
220
167
  /** 语言存储名称 */
221
- localeKey?: string;
168
+ localeKey: string;
222
169
  /** 主题存储名称 */
223
- themeKey?: string;
170
+ themeKey: string;
224
171
  /** Token存储名称 */
225
- tokenKey?: string;
226
- }
227
- interface StorageResults extends Required<StorageOptions> {
228
- /** 获取当前语言 */
229
- getLocale(): LocaleProps;
230
- /** 设置/切换语言 */
231
- setLocale(locale: LocaleProps): void;
232
- /** 清空语言 */
233
- clearLocale(): void;
234
- /** 获取当前主题 */
235
- getTheme(): ThemeProps;
236
- /** 设置/切换主题 */
237
- setTheme(theme: ThemeProps): void;
238
- /** 清空主题 */
239
- clearTheme(): void;
240
- /** 获取当前 Token */
241
- getToken(): string;
242
- /** 设置 Token */
243
- setToken(token: string): void;
244
- /** 清空 Token */
245
- clearToken(): void;
172
+ tokenKey: string;
173
+ /** 设置缓存 */
174
+ setItem(key: string, value: string): void;
175
+ /** 获取缓存 */
176
+ getItem(key: string): string | null;
177
+ /** 删除缓存 */
178
+ removeItem(key: string): void;
179
+ /** 清空缓存 */
180
+ clear(): void;
246
181
  }
247
182
  /**
248
- * 本地缓存
249
- * - 详情参考 {@link StorageOptions} {@link StorageResults}
250
- * - 配置 localStorage 变量名称
251
- * - 提供 语言、主题、Token 的 get、change、clear 方法
252
- * @example sdk.storage.getToken() // 获取 Token
253
- * @example sdk.storage.setTheme('dark') // 设置主题
254
- * @example sdk.storage.clearLocale() // 清空语言
183
+ * 本地缓存插件
184
+ *
185
+ * @example
186
+ * sdk.use(SDKStoragePlugin).mount('xxx');
255
187
  */
256
- declare const SdkStoragePlugin: Plugin<'storage'>;
188
+ declare const SDKStoragePlugin: SDKPlugin;
257
189
  //#endregion
258
190
  //#region src/plugins/store/createLocale.d.ts
259
191
  interface LocaleStoreProps {
@@ -294,65 +226,33 @@ interface UserInfoStoreProps {
294
226
  /** 创建用户信息切片 */
295
227
  //#endregion
296
228
  //#region src/plugins/store/index.d.ts
297
- type StoreOptions = LocaleStoreProps & MicroAppLoadingStoreProps & ThemeStoreProps & UserInfoStoreProps;
298
- type StoreResults = typeof globalStore;
229
+ interface StoreProps extends LocaleStoreProps, MicroAppLoadingStoreProps, ThemeStoreProps, UserInfoStoreProps {}
230
+ type StoreSlice<T = any> = StateCreator<T>;
231
+ /** 插件 options */
232
+ type StorePluginOptions = Record<string, StoreSlice>;
299
233
  /**
300
234
  * 创建 Store
301
- * - 这里单独声明变量, 主要是为了使用返回类型 StoreResults 🤔
235
+ * - 这里单独声明变量, 主要是为了使用返回类型 StoreOptions 🤔
302
236
  */
303
- declare const globalStore: Omit<_$zustand.StoreApi<StoreOptions>, "subscribe"> & {
237
+ declare const createGlobalStore: (options?: StorePluginOptions) => Omit<import("zustand").StoreApi<StoreProps>, "subscribe"> & {
304
238
  subscribe: {
305
- (listener: (selectedState: StoreOptions, previousSelectedState: StoreOptions) => void): () => void;
306
- <U>(selector: (state: StoreOptions) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
239
+ (listener: (selectedState: StoreProps, previousSelectedState: StoreProps) => void): () => void;
240
+ <U>(selector: (state: StoreProps) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
307
241
  equalityFn?: (a: U, b: U) => boolean;
308
242
  fireImmediately?: boolean;
309
243
  }): () => void;
310
244
  };
311
245
  };
246
+ type StoreOptions = ReturnType<typeof createGlobalStore>;
312
247
  /**
313
- * 全局状态管理
314
- * - 详情参考 {@link StoreOptions} {@link StoreResults}
315
- * - 此插件不会合并传入属性
248
+ * 状态管理插件
316
249
  * @example const setTheme = useStore(sdk.store, (state) => state.setTheme)
317
250
  * @example const { theme, setTheme } = useStore(sdk.store, useShallow((state) => { theme: state.theme, setTheme: state.setTheme }))
318
251
  * @example const [theme, setTheme] = useStore(sdk.store, useShallow((state) => [state.theme, state.setTheme]))
319
252
  * @example sdk.store?.getState()?.setTheme('light')
320
253
  * @example sdk.store.subscribe((state) => state.theme, (theme) => { console.log('theme', theme) }, { fireImmediately: true }) // fireImmediately 立即变更
321
254
  */
322
- declare const SdkStorePlugin: Plugin<'store'>;
323
- //#endregion
324
- //#region src/plugins/ui/index.d.ts
325
- interface UIOptions {
326
- /** 组件 */
327
- [key: string]: ComponentType | ((name: string) => ComponentType) | ((component: ComponentType, name?: string) => void);
328
- }
329
- interface UIResults extends Required<UIOptions> {
330
- /**
331
- * 设置组件
332
- * @param component 组件
333
- * @param name 组件名称
334
- */
335
- setComponent(component: ComponentType, name?: string): void;
336
- /**
337
- * 获取组件
338
- * @param name 组件名称
339
- */
340
- getComponent(name: string): ComponentType;
341
- /**
342
- * 渲染组件
343
- * @param name 组件名称
344
- */
345
- renderComponent(name: string, props?: any): ReactElement;
346
- }
347
- /**
348
- * 可复用组件
349
- * - 详情参考 {@link UIOptions} {@link UIResults}
350
- * - 内置了 Layout、Loading、Login、Mainapp、Microapp、NotFound 等组件, 可传入覆盖
351
- * - 组件共享
352
- * - 在主应用中, 可通过 sdk.use(SdkUIPlugin, { MyComponent }) 传入组件
353
- * - 在微应用中, 可通过 sdk.ui.renderComponent('MyComponent') 使用组件
354
- */
355
- declare const SdkUIPlugin: Plugin<'ui'>;
255
+ declare const SDKStorePlugin: SDKPlugin;
356
256
  //#endregion
357
257
  //#region src/types.d.ts
358
258
  type ThemeProps = 'light' | 'dark' | (string & {});
@@ -362,131 +262,72 @@ interface UserInfo {
362
262
  user?: any;
363
263
  /** 用户权限 */
364
264
  permissions?: string[];
365
- /** 用户角色 */
366
- roles?: string[];
367
265
  /** 用户设置 */
368
266
  settings?: {
369
267
  theme?: ThemeProps;
370
268
  locale?: LocaleProps;
371
269
  };
372
270
  }
373
- interface PluginOptions {
374
- /** 全局请求 */
375
- api?: ApiOptions;
376
- /** 项目信息 */
377
- app?: AppOptions;
378
- /** 全局路由信息 */
379
- client?: ClientOptions;
380
- /** Sdk 配置信息 */
381
- config?: ConfigOptions;
382
- /** 多语言 */
383
- i18n?: I18nOptions;
384
- /** 本地缓存 */
385
- storage?: StorageOptions;
386
- /** 全局状态管理 */
387
- store?: StoreOptions;
388
- /** 可复用组件 */
389
- ui?: UIOptions;
271
+ declare global {
272
+ interface Window {
273
+ [key: string]: any;
274
+ }
390
275
  }
391
- interface PluginResults {
392
- /** 全局请求 */
393
- api: ApiResults;
394
- /** 项目信息 */
395
- app: AppResults;
396
- /** 全局路由信息 */
397
- client: ClientResults;
398
- /** Sdk 配置信息 */
399
- config: ConfigResults;
400
- /** 多语言 */
401
- i18n: I18nResults;
276
+ interface SDKPlugins {
277
+ /** 请求 */
278
+ api: ApiOptions;
279
+ /** 应用 */
280
+ app: AppOptions;
281
+ /** 组件 */
282
+ components: ComponentsOptions;
283
+ /** 配置 */
284
+ config: ConfigOptions;
285
+ /** 国际化 */
286
+ i18n: I18nOptions;
287
+ /** 路由 */
288
+ router: RouterOptions;
402
289
  /** 本地缓存 */
403
- storage: StorageResults;
404
- /** 全局状态管理 */
405
- store: StoreResults;
406
- /** 可复用组件 */
407
- ui: UIResults;
290
+ storage: StorageOptions;
291
+ /** 状态管理 */
292
+ store: StoreOptions;
408
293
  }
409
- type PluginName = keyof PluginOptions;
410
- interface Plugin<K extends PluginName> {
411
- /** 插件名字 */
412
- name: K;
294
+ interface SDKPlugin {
295
+ /** 插件名称 */
296
+ name: string;
413
297
  /** 插件安装方法 */
414
- install(sdk: SdkResult, options?: PluginOptions[K]): void;
298
+ install(sdk: SDKInstance, options?: Record<string, any>): void;
415
299
  /** 插件配置项 */
416
- options?: PluginOptions[K];
417
- }
418
- interface SdkBase {
419
- /** SDK 名称 */
420
- name: string;
421
- /** 插件列表 */
422
- _plugins: Map<string, any>;
423
- /** 挂载sdk - 主应用挂载 SDK 到 Window */
424
- mount(name: string): void;
425
- /** 继承sdk - 微应用从 Window 上继承 SDK */
426
- extend(name: string): void;
427
- /** 使用插件 */
428
- use<K extends PluginName>(plugin: Plugin<K>, options?: PluginOptions[K]): this;
300
+ options?: Record<string, any>;
429
301
  }
430
- type SdkResult = SdkBase & PluginResults;
302
+ type SDKPluginOptions = Record<string, any | ((...args: any[]) => any)>;
303
+ type SDKInstance = SDKCore & SDKPlugins;
431
304
  //#endregion
432
305
  //#region src/core/index.d.ts
433
- declare class Sdk implements SdkResult {
434
- name: SdkResult['name'];
435
- _plugins: SdkResult['_plugins'];
436
- api: SdkResult['api'];
437
- app: SdkResult['app'];
438
- client: SdkResult['client'];
439
- config: SdkResult['config'];
440
- i18n: SdkResult['i18n'];
441
- storage: SdkResult['storage'];
442
- store: SdkResult['store'];
443
- ui: SdkResult['ui'];
444
- constructor();
306
+ /** SDK */
307
+ declare class SDKCore {
308
+ /** 名称 */
309
+ name?: string;
310
+ /** 插件列表 */
311
+ _plugins: Map<string, any>;
312
+ /**
313
+ * 将实例挂载到 Window 对象上
314
+ * @param name - 要挂载的属性名
315
+ */
445
316
  mount(name: string): void;
317
+ /**
318
+ * 继承实例, 从 Window 对象上获取指定名称的实例并合并属性
319
+ * @param name - 要从 Window 对象上获取的实例名称
320
+ * @throws 当指定的 SDK 实例不存在时抛出错误
321
+ */
446
322
  extend(name: string): void;
447
- use<K extends keyof PluginOptions>(plugin: Plugin<K>, options?: PluginOptions[K]): this;
323
+ /**
324
+ * 使用插件
325
+ * @param plugin - 插件对象 {@link SDKPlugin}
326
+ * @param options - 插件选项
327
+ */
328
+ use(plugin: SDKPlugin, options?: SDKPlugin['options']): this;
448
329
  }
449
- /**
450
- * sdk 实例
451
- */
452
- declare const sdk: Sdk;
453
- //#endregion
454
- //#region src/hooks/useUserInfo.d.ts
455
- /** 用户信息 */
456
- declare const useUserInfo: () => {
457
- userInfo: UserInfo;
458
- setUserInfo: (userInfo: UserInfo) => void;
459
- resetUserInfo: () => void;
460
- };
461
- //#endregion
462
- //#region src/hooks/useIntl.d.ts
463
- /**
464
- * React Intl Universal
465
- * - 如果项目不使用 React Compiler, 可以直接使用 sdk.i18n.intl
466
- * - 不要解构使用, const { get } = useIntl() 会报错
467
- * @example const intl = useIntl(); intl.get(key).d(defaultValue)
468
- */
469
- declare const useIntl: () => any;
470
- //#endregion
471
- //#region src/hooks/useCrumb.d.ts
472
- /**
473
- * 获取面包屑
474
- * @see https://reactrouter.com/6.30.3/hooks/use-matches
475
- */
476
- declare const useCrumb: () => any[];
477
- //#endregion
478
- //#region src/hooks/usePermission.d.ts
479
- /**
480
- * 判断是否有权限
481
- * @param code 权限code (默认为当前路由)
482
- */
483
- declare const usePermission: (code?: string) => boolean;
484
- //#endregion
485
- //#region src/hooks/useInitData.d.ts
486
- /** 初始化数据 */
487
- declare const useInitData: () => {
488
- loading: boolean;
489
- routes: RouteObject[];
490
- };
330
+ /** 创建 SDK 实例 */
331
+ declare const sdk: SDKInstance;
491
332
  //#endregion
492
- export { type ApiOptions, type ApiResults, type AppOptions, type AppResults, type ClientOptions, type ClientResults, type ConfigOptions, type ConfigResults, type I18nOptions, type I18nResults, SdkApiPlugin, SdkAppPlugin, SdkClientPlugin, SdkConfigPlugin, SdkI18nPlugin, SdkStoragePlugin, SdkStorePlugin, SdkUIPlugin, type StorageOptions, type StorageResults, type StoreOptions, type StoreResults, type UIOptions, type UIResults, sdk, useCrumb, useInitData, useIntl, usePermission, useUserInfo };
333
+ export { type ApiOptions, type AppOptions, type ComponentsOptions, type ConfigOptions, type I18nOptions, LocaleProps, type RouterOptions, SDKApiPlugin, SDKAppPlugin, SDKComponentsPlugin, SDKConfigPlugin, SDKCore, SDKI18nPlugin, SDKInstance, SDKPlugin, SDKPluginOptions, SDKPlugins, SDKRouterPlugin, SDKStoragePlugin, SDKStorePlugin, type StorageOptions, type StoreOptions, type StoreProps, type StoreSlice, ThemeProps, UserInfo, sdk };
package/dist/index.js CHANGED
@@ -1,2 +1 @@
1
- import './style.css';
2
- import{createStore as e,useStore as t}from"zustand";import{useShallow as n}from"zustand/shallow";import{Suspense as r,createElement as i,memo as a,useEffect as o,useMemo as s,useState as c}from"react";import{Navigate as l,Outlet as u,useLocation as d,useMatches as f,useNavigate as p}from"react-router-dom";import{loadMicroApp as m,registerMicroApps as ee,start as te}from"qiankun";import{Fragment as h,jsx as g,jsxs as _}from"react/jsx-runtime";import v from"axios";import{subscribeWithSelector as y}from"zustand/middleware";const b=new class{name;_plugins;api;app;client;config;i18n;storage;store;ui;constructor(){this.name=``,this._plugins=new Map}mount(e){if(window[e])throw Error(`The SDK already exists - ${e}`);console.log(`%c SDK mounted:`,`color: pink; font-weight: bold;`,e,b),this.name=e;let t=new Proxy(this,{get:(e,t,n)=>e?Reflect.get(e,t,n):null,set:()=>(console.error(`The SDK cannot be modified.`),!1),deleteProperty:()=>(console.error(`The SDK cannot be deleted.`),!1)});window[this.name]=t}extend(e){if(!window[e])throw Error(`The SDK not found - ${e}`);console.log(`%c SDK extended:`,`color: pink; font-weight: bold;`,e),Object.assign(this,window[e])}use(e,t){let{name:n,install:r}=e;if(!n)throw Error(`${n} plugin has no name`);if(typeof r!=`function`)throw Error(`${n} plugin is not a function`);return r(this,t),this._plugins.set(n,{...e,options:t}),this}},x=()=>{let[e,r,i]=t(b.store,n(e=>[e.userInfo,e.setUserInfo,e.resetUserInfo]));return{userInfo:e,setUserInfo:r,resetUserInfo:i}};function S(e){return e==null||typeof e!=`object`&&typeof e!=`function`}function C(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function w(e){return Object.getOwnPropertySymbols(e).filter(t=>Object.prototype.propertyIsEnumerable.call(e,t))}function ne(e){return e==null?e===void 0?`[object Undefined]`:`[object Null]`:Object.prototype.toString.call(e)}function T(e,t,n,r=new Map,i=void 0){let a=i?.(e,t,n,r);if(a!==void 0)return a;if(S(e))return e;if(r.has(e))return r.get(e);if(Array.isArray(e)){let t=Array(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=T(e[a],a,n,r,i);return Object.hasOwn(e,`index`)&&(t.index=e.index),Object.hasOwn(e,`input`)&&(t.input=e.input),t}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp){let t=new RegExp(e.source,e.flags);return t.lastIndex=e.lastIndex,t}if(e instanceof Map){let t=new Map;r.set(e,t);for(let[a,o]of e)t.set(a,T(o,a,n,r,i));return t}if(e instanceof Set){let t=new Set;r.set(e,t);for(let a of e)t.add(T(a,void 0,n,r,i));return t}if(typeof Buffer<`u`&&Buffer.isBuffer(e))return e.subarray();if(C(e)){let t=new(Object.getPrototypeOf(e)).constructor(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=T(e[a],a,n,r,i);return t}if(e instanceof ArrayBuffer||typeof SharedArrayBuffer<`u`&&e instanceof SharedArrayBuffer)return e.slice(0);if(e instanceof DataView){let t=new DataView(e.buffer.slice(0),e.byteOffset,e.byteLength);return r.set(e,t),E(t,e,n,r,i),t}if(typeof File<`u`&&e instanceof File){let t=new File([e],e.name,{type:e.type});return r.set(e,t),E(t,e,n,r,i),t}if(typeof Blob<`u`&&e instanceof Blob){let t=new Blob([e],{type:e.type});return r.set(e,t),E(t,e,n,r,i),t}if(e instanceof Error){let t=structuredClone(e);return r.set(e,t),t.message=e.message,t.name=e.name,t.stack=e.stack,t.cause=e.cause,t.constructor=e.constructor,E(t,e,n,r,i),t}if(e instanceof Boolean){let t=new Boolean(e.valueOf());return r.set(e,t),E(t,e,n,r,i),t}if(e instanceof Number){let t=new Number(e.valueOf());return r.set(e,t),E(t,e,n,r,i),t}if(e instanceof String){let t=new String(e.valueOf());return r.set(e,t),E(t,e,n,r,i),t}if(typeof e==`object`&&D(e)){let t=Object.create(Object.getPrototypeOf(e));return r.set(e,t),E(t,e,n,r,i),t}return e}function E(e,t,n=e,r,i){let a=[...Object.keys(t),...w(t)];for(let o=0;o<a.length;o++){let s=a[o],c=Object.getOwnPropertyDescriptor(e,s);(c==null||c.writable)&&(e[s]=T(t[s],s,n,r,i))}}function D(e){switch(ne(e)){case`[object Arguments]`:case`[object Array]`:case`[object ArrayBuffer]`:case`[object DataView]`:case`[object Boolean]`:case`[object Date]`:case`[object Float32Array]`:case`[object Float64Array]`:case`[object Int8Array]`:case`[object Int16Array]`:case`[object Int32Array]`:case`[object Map]`:case`[object Number]`:case`[object Object]`:case`[object RegExp]`:case`[object Set]`:case`[object String]`:case`[object Symbol]`:case`[object Uint8Array]`:case`[object Uint8ClampedArray]`:case`[object Uint16Array]`:case`[object Uint32Array]`:return!0;default:return!1}}function O(e){return T(e,void 0,e,new Map,void 0)}function k(e){if(!e||typeof e!=`object`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype||Object.getPrototypeOf(t)===null?Object.prototype.toString.call(e)===`[object Object]`:!1}function A(e){return e===`__proto__`}function j(e,t){let n=Object.keys(t);for(let r=0;r<n.length;r++){let i=n[r];if(A(i))continue;let a=t[i],o=e[i];M(a)&&M(o)?e[i]=j(o,a):Array.isArray(a)?e[i]=j([],a):k(a)?e[i]=j({},a):(o===void 0||a!==void 0)&&(e[i]=a)}return e}function M(e){return k(e)||Array.isArray(e)}const re=()=>s(()=>O(b.i18n.intl),[t(b.store,e=>e.locale)]),ie=()=>s(()=>b.client.matches,[d()]).filter(e=>!!e.handle?.crumb).map(e=>e.handle.crumb(e.data)),ae=e=>s(()=>{let t=e||b.client.location.pathname;return b.app.permissions?.includes?.(t)},[d().pathname,e]),N=e=>{let{requestId:t,url:n,method:r,params:i,data:a}=e;return t||`${r}:${n}?${JSON.stringify(i)}&${JSON.stringify(a)}`},oe=e=>{let t=N(e),n=b.api.controllers.get(t);n&&(n.abort(),b.api.controllers.delete(t))},P={beforeLoad:[async e=>{console.log(`[LifeCycle] before load %c%s`,`color: green;`,e.name)}],beforeMount:[async e=>{console.log(`[LifeCycle] before mount %c%s`,`color: green;`,e.name)}],afterUnmount:[async e=>{console.log(`[LifeCycle] after unmount %c%s`,`color: green;`,e.name)}]},F=e=>{let t=e.storage.getTheme();if(t)return t;let n=e.config?.theme;if(n)return n;let r=window.matchMedia(`(prefers-color-scheme: dark)`);return r.matches&&r.matches?`dark`:`light`},I=e=>e.storage.getLocale()||e.config?.locale||navigator.language||`zh-CN`,L=e=>{let t=new Map,n=R(e,t);return{microApps:[...t.values()],menuData:n}},R=(e,t)=>!e||e?.length===0?[]:e.map(e=>{let n=null,{locale:r,path:i,icon:a,component:o,routeAttr:s,children:c}=e;if(s){let e={};try{e=JSON.parse(s)}catch(e){console.error(`Sdk: initData - Subapp routeAttr error: `,e)}let{name:r,rootId:i,...a}=e,o={...a,name:r,container:`#${i}`,props:{sdk:b},loader:e=>b.store.getState().setMicroAppLoading(e)};t.set(r,o),n=b.ui.renderComponent(`Microapp`,{name:r,rootId:i})}else n=o===`Microapp`?b.ui.renderComponent(`Microapp`):o===`Outlet`?g(u,{}):b.ui.renderComponent(o);return{...e,key:`${i}_${a}_${r}`,element:n,children:R(c,t),handle:e}}),z=e=>{let t=`/`;return!e||e.length===0?t:(t=e?.[0]?.path,e?.[0]?.children&&e?.[0]?.children.length>0&&(t=z(e?.[0]?.children)),t)},B=({children:e})=>{let t=d(),n=f(),r=p();return b.client.location=t,b.client.matches=n,b.client.navigate=r,e},V=()=>{let e=b.config.loginPath,r=b.config.customRoutes,i=b.config.qiankunMode===`router`,a=b.ui.renderComponent(`Layout`),s=b.ui.renderComponent(`Login`),u=b.ui.renderComponent(`NotFound`),d=[{path:e,element:s},{path:`*`,element:u},...r].map(e=>({...e,element:g(B,{children:e.element})})),[f,p]=c(!1),[m,h]=c(d),[_,v,y]=t(b.store,n(e=>[e.setLocale,e.setTheme,e.setUserInfo])),x=(e,t)=>{v(e||F(b)),_(t||I(b))},S=async()=>{try{p(()=>!0);let[{data:e={}},{data:t=[]}]=await Promise.all([b.api.getUserInfoApi(),b.api.getRoutesApi()]);p(()=>!1),y(e);let{theme:n,locale:r}=e?.settings||{};x(n,r);let{microApps:o=[],menuData:s=[]}=L(t);i&&(ee(o,P),te());let c=z(s),f=[...d,{path:`/`,element:g(l,{to:c,replace:!0})},{path:`/`,element:g(B,{children:a}),children:s,errorElement:u}];h(f),b.app={...b.app,allRoutes:f,microApps:o,menuData:s}}catch(e){console.error(e),p(()=>!1)}};return o(()=>{b.app.initData=S,b.app.allRoutes=d;let t=b.config.customRoutes?.map(e=>e.path),n=window.location.pathname;[e,...t]?.includes(n)?x():S()},[]),{loading:f,routes:m}};var H=class{instance;constructor(e={}){this.instance=v.create(e),this.defaultRequestInterceptor(),this.defaultResponseInterceptor()}defaultRequestInterceptor(){this.instance.interceptors.request.use(function(e){if(e?.isCancelRequest){let t=N(e);oe(e);let n=new AbortController;b.api.controllers.set(t,n),e.requestId=t,e.signal=n.signal}let t=b.storage.getToken();return e.headers.lang=b.config.locale,e.headers.Authorization=t,j(e.headers,b.api.config.headers||{}),e},function(e){return console.error(`Sdk: defaultRequestInterceptor - 请求错误`),Promise.reject(e)})}defaultResponseInterceptor(){this.instance.interceptors.response.use(function(e){let{data:t,config:n}=e,{isOriginalData:r,isShowFailMsg:i,isCancelRequest:a}=n,{code:o,msg:s}=t;return o!==0&&(console.error(`Sdk: defaultResponseInterceptor - Response error: `,n.url,s),o==20041&&b.app.pageToLogin()),a&&b.api.controllers.delete(n.requestId),r?e:e.data},function(e){let{response:t,config:n}=e,{isShowFailMsg:r}=n;if(v.isCancel(e))return Promise.reject(e);if(t){let{status:e,data:n,statusText:r}=t;e==401&&b.app.pageToLogin()}else console.error(`Sdk: defaultResponseInterceptor - Request error:`,n.url,e);return Promise.reject(e)})}getInstance(){return this.instance}};const U={name:`api`,install(e,t={}){let n={baseURL:`/`,timeout:0,...t.config},r=t?.instance||new H(n).getInstance();e.api=j({config:n,controllers:new Map,instance:null,request:(e,t={})=>r.request({url:e,isOriginalData:!1,isShowFailMsg:!0,isCancelRequest:!0,...t}),getUserInfoApi:()=>e.api.request(`/getUserInfo`,{method:`GET`}),getRoutesApi:()=>e.api.request(`/routes`,{method:`GET`}),loginApi:()=>e.api.request(`/login`,{method:`POST`})},t)}},W={name:`app`,install(e,t={}){e.app=j({menuData:[],allRoutes:[],microApps:[],microAppsInstance:new Map,user:null,permissions:[],roles:[],settings:{},initData:null,clearData:()=>{e.app.menuData=[],e.app.allRoutes=e.app.allRoutes.filter(e=>e.path!==`/`),e.app.microApps=[],e.app.microAppsInstance.forEach(e=>e.unmount()),e.app.microAppsInstance.clear(),e.store.getState().resetUserInfo()},pageToLogin:()=>{e.storage.clearToken();let t=window.location.pathname||`/`,n=e.config.loginPath,r=t===n?n:`${n}?redirect=${encodeURIComponent(t)}`;e.config.qiankunMode===`router`?window.location.replace(r):(e.app.clearData(),e.client.navigate(r,{replace:!0}))},getRedirectPath:()=>{let t=e.config.defaultPath;if(t)return t;let n=new URLSearchParams(window.location.search);return decodeURIComponent(n.get(`redirect`)||``)||`/`}},t)}},G=`client`,K={name:G,install(e,t={}){e[G]=j({location:null,navigate:null,matches:null},t)}},q=`config`,se={name:q,install(e,t={}){e[q]=j({env:{},qiankunMode:`router`,theme:null,locale:null,loginPath:`/login`,defaultPath:``,customRoutes:[]},t)}},J=`i18n`,ce={name:J,install(e,t={}){e[J]=j({intl:{},intlConfig:{}},t)}},Y=`storage`,le={name:Y,install(e,t={}){e[Y]=j({localeKey:`locale`,themeKey:`theme`,tokenKey:`token`,getLocale:()=>localStorage.getItem(e.storage.localeKey),setLocale:t=>{localStorage.setItem(e.storage.localeKey,t)},clearLocale:()=>{localStorage.removeItem(e.storage.localeKey)},getTheme:()=>localStorage.getItem(e.storage.themeKey),setTheme:t=>{localStorage.setItem(e.storage.themeKey,t)},clearTheme:()=>{localStorage.removeItem(e.storage.themeKey)},getToken:()=>localStorage.getItem(e.storage.tokenKey),setToken:t=>{localStorage.setItem(e.storage.tokenKey,t)},clearToken:()=>{localStorage.removeItem(e.storage.tokenKey)}},t)}},ue=(e,t)=>({locale:null,setLocale:t=>{e(()=>({locale:t})),b.config.locale=t,b.storage.setLocale(t),document.documentElement.setAttribute(`lang`,t)}}),de=(e,t)=>({microAppLoading:!1,setMicroAppLoading:t=>e(()=>({microAppLoading:t}))}),fe=(e,t)=>({theme:null,setTheme:t=>{e(()=>({theme:t})),b.config.theme=t,b.storage.setTheme(t),document.documentElement.setAttribute(`theme`,t)}}),X={user:{},permissions:[],roles:[],settings:{}},pe=(e,t)=>({userInfo:X,setUserInfo:t=>{e(()=>({userInfo:t})),b.app={...b.app,...t}},resetUserInfo:()=>{e(()=>({userInfo:X}))}}),me=e()(y((...e)=>({...ue(...e),...de(...e),...fe(...e),...pe(...e)}))),Z=`store`,he={name:Z,install(e,t={}){e[Z]=me}},Q=({items:e=[]})=>{let t=d(),n=p();return!e||e.length===0?null:e.map(e=>{let{key:r,name:i,path:a,locale:o,children:s,hideInMenu:c=!1}=e,l=!0;return s&&s.length>0&&s.filter(e=>!e.hideInMenu).length>0&&(l=!1),_(`li`,{className:`sdk-layout-menu-item`,children:[g(`div`,{className:`sdk-layout-menu-item-title`,style:{...t.pathname===a?{background:`#e6f4ff`,color:`#1677ff`}:{},...c?{display:`none`}:{},cursor:l?`pointer`:`not-allowed`},onClick:()=>l?n(a):{},children:b.i18n.intl?.get?.(o)||i}),g(`ul`,{className:`sdk-layout-menu-sub`,children:g(Q,{items:s})})]},r)})},ge=()=>{let e=p(),t=d();return o(()=>{if(!b.app.user||Object.keys(b.app.user).length===0)return b.app.pageToLogin();e(t.pathname)},[t.pathname]),_(`div`,{className:`sdk-layout`,children:[_(`div`,{className:`sdk-layout-header`,children:[g(`div`,{onClick:()=>{e(`/`)},children:`Logo`}),g(`button`,{onClick:()=>{b.app.pageToLogin()},children:`退出登录`})]}),_(`div`,{className:`sdk-layout-content`,children:[g(`ul`,{className:`sdk-layout-menu`,children:g(Q,{items:b.app.menuData||[]})}),g(`div`,{className:`sdk-layout-outlet`,children:g(r,{fallback:b.ui.renderComponent(`Loading`,{isSuspense:!0}),children:g(u,{})})})]})]})},$=({isInitData:e=!1,isSuspense:t=!1,isMicroApp:n=!1})=>g(`div`,{className:`${e?`sdk-loading-init`:``}`,children:`Loading...`}),_e=()=>{let[e,t]=c(!1),[n,r]=c(`admin`),[i,a]=c(`123456`);return g(`div`,{className:`sdk-login`,children:_(`form`,{className:`sdk-login-form`,children:[_(`div`,{className:`sdk-login-form-group`,children:[g(`label`,{children:`用 户 名`}),_(`div`,{className:`sdk-login-form-group-input`,children:[g(`input`,{type:`text`,value:n,placeholder:`your@email.com 或 昵称`,onChange:e=>r(e.target.value)}),g(`div`,{children:n?``:`请输入用户名`})]})]}),_(`div`,{className:`sdk-login-form-group`,children:[g(`label`,{children:`密 码`}),_(`div`,{className:`sdk-login-form-group-input`,children:[g(`input`,{type:`password`,value:i,placeholder:`请输入密码`,onChange:e=>a(e.target.value)}),g(`div`,{children:i?``:`请输入密码`})]})]}),g(`button`,{className:`sdk-login-form-btn`,onClick:async r=>{if(!e){r.preventDefault();try{t(()=>!0);let e=await b.api.loginApi({userName:n,password:i});t(()=>!1);let r=e?.data?.token||``;if(!r)return;b.storage.setToken(r);let a=b.app.getRedirectPath();b.config.qiankunMode===`load`?(b.client.navigate(a,{replace:!0}),b.app.initData?.()):window.location.replace(a)}catch(e){console.log(`Sdk: Login - handleFinish: `,e),t(()=>!1)}}},children:e?`登录中...`:`登录`})]})})};var ve=a(({name:e,rootId:r})=>{let[i,a]=t(b.store,n(e=>[e.microAppLoading,e.setMicroAppLoading]));return o(()=>{if(!e||b.config.qiankunMode!==`load`)return;let t=b.app.microAppsInstance.get(e);if(t)t?.mount();else{let n=b.app.microApps.find(t=>t.name===e);if(!n)return;a(!0),t=m(n,{},P),t?.mountPromise?.finally(()=>{a(!1)}),b.app.microAppsInstance.set(e,t)}return()=>{t?.unmount()}},[e]),_(h,{children:[i&&b.ui.renderComponent(`Loading`,{isMicroApp:!0}),g(`main`,{id:r})]})});const ye=()=>g(`div`,{children:`无权限`}),be=()=>g(`div`,{className:`sdk-notfound`,children:`找不到页面`}),xe={name:`ui`,install(e,t={}){e.ui=j({Layout:ge,Loading:$,Login:_e,Microapp:ve,NotFound:be,NoPermission:ye,setComponent:(t,n)=>{if(!t){console.error(`Sdk: SdkUIPlugin - component cannot be empty`);return}let r=n||t.displayName||t.name;if(!r){console.error(`Sdk: SdkUIPlugin - Component name cannot be empty`);return}e.ui[r]=t},getComponent:t=>t?e.ui[t]:(console.error(`Sdk: SdkUIPlugin - Component name cannot be empty`),null),renderComponent:(t,n={})=>{let r=e.ui.getComponent(t);return r?i(r,n):(console.error(`Sdk: SdkUIPlugin - Component ${t} not found`),null)}},t)}};export{U as SdkApiPlugin,W as SdkAppPlugin,K as SdkClientPlugin,se as SdkConfigPlugin,ce as SdkI18nPlugin,le as SdkStoragePlugin,he as SdkStorePlugin,xe as SdkUIPlugin,b as sdk,ie as useCrumb,V as useInitData,re as useIntl,ae as usePermission,x as useUserInfo};
1
+ import{Suspense as e,createElement as t,memo as n,useEffect as r,useState as i}from"react";import{Outlet as a,useLocation as o,useNavigate as s}from"react-router-dom";import{Fragment as c,jsx as l,jsxs as u}from"react/jsx-runtime";import{loadMicroApp as d}from"qiankun";import{createStore as f,useStore as p}from"zustand";import{useShallow as m}from"zustand/shallow";import{subscribeWithSelector as h}from"zustand/middleware";var g=class{name;_plugins=new Map;mount(e){this.name=e,window[e]=this}extend(e){let t=window[e];if(!t)throw Error(`SDK "${e}" not found`);Object.assign(this,t)}use(e,t={}){let{name:n,install:r}=e;if(!n)throw Error(`SDK - The plugin requires a name`);if(typeof r!=`function`)throw Error(`SDK - The plugin "${n}" requires an install function`);return r(this,t),this._plugins.set(n,{...e,options:t}),this}};const _=new g,v={name:`api`,install(e,t={}){e.api=t}};function y(e){if(!e||typeof e!=`object`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype||Object.getPrototypeOf(t)===null?Object.prototype.toString.call(e)===`[object Object]`:!1}function b(e){return e===`__proto__`}function x(e,t){let n=Object.keys(t);for(let r=0;r<n.length;r++){let i=n[r];if(b(i))continue;let a=t[i],o=e[i];S(a)&&S(o)?e[i]=x(o,a):Array.isArray(a)?e[i]=x([],a):y(a)?e[i]=x({},a):(o===void 0||a!==void 0)&&(e[i]=a)}return e}function S(e){return y(e)||Array.isArray(e)}const C={name:`app`,install(e,t={}){e.app=x({menuData:[],allRoutes:[],microApps:[],microAppsInstance:new Map,user:null,permissions:[],settings:{},getDefaultLocale(){return e.storage.getItem(e.storage.localeKey)||e.config?.locale||navigator.language||`zh-CN`},getDefaultTheme(){let t=e.storage.getItem(e.storage.themeKey);if(t)return t;let n=e.config?.theme;if(n)return n;let r=window.matchMedia(`(prefers-color-scheme: dark)`);return r.matches&&r.matches?`dark`:`light`},getRedirectPath(){let t=e.config.defaultPath;if(t)return t;let n=new URLSearchParams(window.location.search),r=e.config.redirectField||`redirect`;return decodeURIComponent(n.get(r)||``)||`/`},initData:()=>{},pageToLogin(){e.storage.removeItem(e.storage.tokenKey),e.app.user=null,e.app.permissions=[],e.app.settings={};let t=location.pathname,n=e.config.loginPath,r=e.config.redirectField||`redirect`,i=t===n?n:`${n}?${r}=${encodeURIComponent(t||`/`)}`;e.router.navigate(i,{replace:!0}),e.app.unmountMicroApp()},unmountMicroApp(t){t?t.forEach(t=>{let n=e.app.microAppsInstance.get(t);n&&(n.unmount(),e.app.microAppsInstance.delete(t),e.app.microApps=e.app.microApps.filter(e=>e.name!==t))}):(e.app.microAppsInstance.forEach(e=>e.unmount()),e.app.microAppsInstance.clear(),e.app.microApps=[])}},t)}},w={layout:{height:`100vh`,display:`flex`,flexDirection:`column`,background:`#f5f7fb`},header:{height:64,padding:`0 24px`,background:`#fff`,borderBottom:`1px solid #e5e7eb`,display:`flex`,alignItems:`center`,justifyContent:`space-between`,boxShadow:`0 2px 8px rgba(0,0,0,0.04)`,zIndex:10},logo:{fontSize:20,fontWeight:700,color:`#1677ff`,cursor:`pointer`,userSelect:`none`},logoutBtn:{height:36,padding:`0 16px`,border:`none`,borderRadius:8,background:`#ff4d4f`,color:`#fff`,cursor:`pointer`,transition:`0.2s`},main:{flex:1,display:`flex`,overflow:`hidden`},sidebar:{width:240,padding:16,background:`#fff`,borderRight:`1px solid #e5e7eb`,overflowY:`auto`},content:{flex:1,padding:20,overflowY:`auto`},contentCard:{minHeight:`100%`,padding:24,background:`#fff`,borderRadius:16,boxShadow:`0 2px 12px rgba(0,0,0,0.04)`},menuItem:{marginBottom:4},menuTitle:{height:42,padding:`0 14px`,display:`flex`,alignItems:`center`,borderRadius:10,color:`#1f2937`,cursor:`pointer`,transition:`0.2s`},menuChildren:{marginLeft:12,paddingLeft:12,borderLeft:`1px solid #e5e7eb`}},T=({items:e=[]})=>{let t=o(),n=s();return e?.length?e.map(e=>{let{key:r,name:i,path:a,children:o,hideInMenu:s=!1}=e;if(s)return null;let c=o&&o.filter(e=>!e.hideInMenu).length>0,d=t.pathname===a,f=e=>{d||(e.currentTarget.style.background=`#f3f4f6`)},p=e=>{d||(e.currentTarget.style.background=`transparent`)},m=()=>{c||n(a)};return u(`div`,{style:w.menuItem,children:[l(`div`,{style:{...w.menuTitle,...d?{background:`#e8f3ff`,color:`#1677ff`}:{},...c?{cursor:`not-allowed`}:{}},onMouseEnter:f,onMouseLeave:p,onClick:m,children:i}),c&&l(`div`,{style:w.menuChildren,children:l(T,{items:o})})]},r)}):null},E=()=>{let t=s(),n=o(),i=()=>{t(`/`)},c=()=>{_.app.pageToLogin()};return r(()=>{if(!_.app.user||Object.keys(_.app.user).length===0)return c();t(n.pathname)},[n.pathname]),u(`div`,{style:w.layout,children:[u(`header`,{style:w.header,children:[l(`div`,{style:w.logo,onClick:i,children:`Logo`}),l(`button`,{style:w.logoutBtn,onClick:c,onMouseEnter:e=>{e.currentTarget.style.opacity=`0.75`},onMouseLeave:e=>{e.currentTarget.style.opacity=`1`},children:`退出登录`})]}),u(`div`,{style:w.main,children:[l(`aside`,{style:w.sidebar,children:l(T,{items:_.app.menuData||[]})}),l(`main`,{style:w.content,children:l(`div`,{style:w.contentCard,children:l(e,{fallback:_.components.renderComponent(`Loading`,{isSuspense:!0}),children:l(a,{})})})})]})]})},D=({isInitData:e=!1,isSuspense:t=!1,isMicroApp:n=!1})=>l(`div`,{style:e?{width:`100%`,height:`100%`,display:`flex`,alignItems:`center`,justifyContent:`center`}:{},children:`Loading...`}),O={page:{height:`100vh`,display:`flex`,flexDirection:`column`,justifyContent:`center`,alignItems:`center`,gap:16},btn:{height:36,padding:`0 60px`,border:`none`,borderRadius:8,background:`#1677ff`,color:`#fff`,cursor:`pointer`,transition:`0.2s`}},k=()=>{let[e,t]=i(!1);return u(`div`,{style:O.page,children:[l(`h2`,{children:`欢迎登录系统`}),l(`button`,{style:O.btn,onClick:async()=>{if(e)return;t(()=>!0),await new Promise(e=>setTimeout(()=>e(!0),500)),t(()=>!1),_.storage.setItem(_.storage.tokenKey,`123456`);let n=_.app.getRedirectPath();_.router.navigate(n,{replace:!0}),await _.app.initData?.()},onMouseEnter:e=>{e.currentTarget.style.opacity=`0.75`},onMouseLeave:e=>{e.currentTarget.style.opacity=`1`},children:e?`登录中...`:`登录`})]})},A={beforeLoad:[async e=>{console.log(`[LifeCycle] before load %c%s`,`color: green;`,e.name)}],beforeMount:[async e=>{console.log(`[LifeCycle] before mount %c%s`,`color: green;`,e.name)}],afterUnmount:[async e=>{console.log(`[LifeCycle] after unmount %c%s`,`color: green;`,e.name)}]};var j=n(({name:e,rootId:t})=>{let[n,i]=p(_.store,m(e=>[e.microAppLoading,e.setMicroAppLoading]));return r(()=>{if(!e)return;let t=_.app.microAppsInstance.get(e);if(t)t?.mount();else{let n=_.app.microApps.find(t=>t.name===e);if(!n)return;i(!0),t=d(n,{},A),t?.mountPromise?.finally(()=>{i(!1)}),_.app.microAppsInstance.set(e,t)}return()=>{t?.unmount()}},[e]),u(c,{children:[n&&_.components.renderComponent(`Loading`,{isMicroApp:!0}),l(`main`,{id:t})]})});const M=`components`,N={name:M,install(e,n={}){e[M]=x({Layout:E,Loading:D,Login:k,Microapp:j,setComponent:(t,n)=>{if(!t){console.error(`SDKComponentsPlugin - Component cannot be empty`);return}let r=n||t.displayName||t.name;if(!r){console.error(`SDKComponentsPlugin - Component name cannot be empty`);return}e.components[r]=t},getComponent:t=>t?e.components[t]:(console.error(`SDKComponentsPlugin - Component name cannot be empty`),null),renderComponent:(n,r={})=>{let i=e.components.getComponent(n);return i?t(i,r):(console.error(`SDKComponentsPlugin - Component ${n} not found`),null)}},n)}},P=`config`,F={name:P,install(e,t){e[P]=x({env:{},theme:``,locale:``,loginPath:`/login`,defaultPath:``,redirectField:`redirect`},t)}},I=`i18n`,L={name:I,install(e,t){e[I]=x({},t)}},R=`router`,z={name:R,install(e,t){e[R]=x({location:null,navigate:null,matches:null},t)}},B=`storage`,V={name:B,install(e,t){e[B]=x({localeKey:`locale`,themeKey:`theme`,tokenKey:`token`,setItem(e,t){localStorage.setItem(e,t)},getItem(e){return localStorage.getItem(e)},removeItem(e){localStorage.removeItem(e)},clear(){localStorage.clear()}},t)}},H=(e,t)=>({locale:``,setLocale:t=>{e(()=>({locale:t})),_.config.locale=t,_.storage.setItem(_.storage.localeKey,t),document.documentElement.setAttribute(`lang`,t)}}),U=(e,t)=>({microAppLoading:!1,setMicroAppLoading:t=>e(()=>({microAppLoading:t}))}),W=(e,t)=>({theme:``,setTheme:t=>{e(()=>({theme:t})),_.config.theme=t,_.storage.setItem(_.storage.themeKey,t),document.documentElement.setAttribute(`theme`,t)}}),G={user:{},permissions:[],settings:{}},K=(e,t)=>({userInfo:G,setUserInfo:t=>{e(()=>({userInfo:t})),_.app={..._.app,...t}},resetUserInfo:()=>{e(()=>({userInfo:G}))}}),q=e=>f()(h((...t)=>({...H(...t),...U(...t),...W(...t),...K(...t),...Object.values(e||{}).reduce((e,n)=>({...e,...n(...t)}),{})}))),J=`store`,Y={name:J,install(e,t={}){e[J]=q(t)}};export{v as SDKApiPlugin,C as SDKAppPlugin,N as SDKComponentsPlugin,F as SDKConfigPlugin,g as SDKCore,L as SDKI18nPlugin,z as SDKRouterPlugin,V as SDKStoragePlugin,Y as SDKStorePlugin,_ as sdk};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zxiaosi/sdk",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "A micro frontend kit",
5
5
  "keywords": [
6
6
  "micro frontend",
@@ -21,8 +21,7 @@
21
21
  "types": "dist/index.d.ts",
22
22
  "exports": {
23
23
  ".": "./dist/index.js",
24
- "./package.json": "./package.json",
25
- "./style.css": "./dist/style.css"
24
+ "./package.json": "./package.json"
26
25
  },
27
26
  "publishConfig": {
28
27
  "access": "public",
@@ -36,11 +35,11 @@
36
35
  "axios": "^1.13.6"
37
36
  },
38
37
  "devDependencies": {
39
- "@tsdown/css": "^0.21.6",
38
+ "@tsdown/css": "^0.22.1",
40
39
  "@types/react": "^18.3.12",
41
40
  "@types/react-dom": "^18.3.1",
42
- "es-toolkit": "^1.45.1",
43
- "tsdown": "^0.21.6",
41
+ "es-toolkit": "^1.47.0",
42
+ "tsdown": "^0.22.1",
44
43
  "typescript": "^5.9.3"
45
44
  },
46
45
  "peerDependencies": {
@@ -49,22 +48,5 @@
49
48
  "react-dom": "^18.3.1 || >=19.0.0",
50
49
  "react-router-dom": "^6.30.0",
51
50
  "zustand": "^5.0.0"
52
- },
53
- "peerDependenciesMeta": {
54
- "react": {
55
- "optional": false
56
- },
57
- "react-dom": {
58
- "optional": false
59
- },
60
- "react-router-dom": {
61
- "optional": false
62
- },
63
- "qiankun": {
64
- "optional": true
65
- },
66
- "zustand": {
67
- "optional": true
68
- }
69
51
  }
70
52
  }
package/dist/style.css DELETED
@@ -1 +0,0 @@
1
- :root[theme=dark]{--sdk-bg-color:#141414;--sdk-text-color:#ffffffd9;--sdk-border-color:#ffffff26}:root[theme=light]{--sdk-bg-color:#fff;--sdk-text-color:#000000d9;--sdk-border-color:#00000026}.sdk-layout{height:100vh;color:var(--sdk-text-color);background:var(--sdk-bg-color)}.sdk-layout-header{border-bottom:1px solid var(--sdk-border-color);box-sizing:border-box;justify-content:space-between;align-items:center;height:64px;padding:0 24px;line-height:64px;display:flex}.sdk-layout-content{height:calc(100vh - 64px);display:flex}.sdk-layout-menu{box-sizing:border-box;border-right:1px solid var(--sdk-border-color);width:200px;height:100%;margin:0;padding:8px;list-style:none}.sdk-layout-outlet{flex:1;padding:24px;overflow:auto}.sdk-layout-menu-item{margin-bottom:6px}.sdk-layout-menu-item-title{padding:8px 12px}.sdk-layout-menu-item-title:hover{color:#1677ff;cursor:pointer;background:#e6f4ff}.sdk-layout-menu-sub{margin:0;padding:0;list-style:none}.sdk-layout-menu-sub .sdk-layout-menu-item-title{margin-top:8px;padding-left:24px}.sdk-loading-init{width:100%;height:100%;color:var(--sdk-text-color);background-color:var(--sdk-bg-color);justify-content:center;align-items:center;display:flex}.sdk-login{width:100vw;height:100vh;color:var(--sdk-text-color);background:var(--sdk-bg-color);justify-content:center;align-items:center;display:flex}.sdk-login-form{border-radius:8px;flex-direction:column;width:300px;padding:23px;display:flex;box-shadow:0 0 10px #0000004d}.sdk-login-form-group{align-items:flex-start;margin-bottom:24px;display:flex}.sdk-login-form-group>label{width:70px}.sdk-login-form-group-input{flex:1}.sdk-login-form-group-input>input{box-sizing:border-box;width:230px;padding:4px 11px;font-size:16px}.sdk-login-form-btn{padding:4px 11px}.sdk-notfound{width:100%;height:100%;color:var(--sdk-text-color);background-color:var(--sdk-bg-color);justify-content:center;align-items:center;display:flex}