@zxiaosi/sdk 0.5.1 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
  ## 快速开始
10
10
 
11
11
  ```bash
12
+ # 安装 @zxiaosi/sdk 对应的版本 0.5.x
12
13
  npm install -g @zxiaosi/create-sdk
13
14
 
14
15
  npx create-sdk
@@ -18,30 +19,20 @@ npx create-sdk
18
19
 
19
20
  - 整个 `SDK` 都是围绕 `getRoutesApi`、`getUserInfoApi` 这两个接口进行设计的,旨在简化微前端应用的开发
20
21
 
21
- - `getRoutesApi` 接口用于获取应用路由信息,包括主应用和微应用的路由配置。因为 `Qiankun` 的 `entry` 配置比较特殊,在本地开发时是本地服务 `"entry": "http://localhost:5174"`,在生产环境是文件路径 `"entry": "/subapp/"`,所以 `主应用` 需要使用 `vite-plugin-mock` 插件 `mock` 接口
22
+ - `getRoutesApi` 接口用于获取应用路由信息,包括主应用和微应用的路由配置。因为 `Qiankun` 的 `entry` 配置比较特殊,所以 `主应用` 需要使用 `vite-plugin-mock` 插件 `mock` 接口
23
+ - 在本地开发是本地服务 `"entry": "http://localhost:5174"`
24
+ - 在生产环境是文件路径 `"entry": "/subapp/"`
22
25
 
23
- - `getUserInfoApi` 接口用于获取用户 `user`、权限 `permissions`、角色 `role`、配置信息 `setting`,以便进行权限控制和个性化设置。理论上来说 `permissions` 中应当包含 `getRoutesApi` 中的所有的路由路径,否则页面出走 `<NotPermission />` 组件。(目前的方案是所有的组件手动包一层 `<NotPermission />`,不在 `SDK` 中处理权限控制)
26
+ - `getUserInfoApi` 接口用于获取用户相关数据,以便进行权限控制和个性化设置。
27
+ - `user`:用户信息(必选)
28
+ - `permissions`:权限信息(必选)
29
+ - `role`:角色信息(可选)
30
+ - `setting`:配置信息(可选)
24
31
 
25
- - 微应用使用 `sdk.ui.renderComponent('xxx')` 时,会报 `React 多实例` 的错误,需要使用 `vite-plugin-externals` 插件将 `React` 等依赖排除在打包之外,[更多详情](https://zxiaosi.com/archives/bc84a75a.html)
26
-
27
- - 微应用启动服务时需要加上 `--host` 参数,否则可能会出现微应用静态资源访问不到的情况。完整命令 `"dev": "vite --host"`
28
-
29
- - `SDK` 不能在 `组件外` 进行使用,否则会报 `SDK 未初始化` 错误
30
-
31
- ## 具体使用
32
+ ## 核心代码
32
33
 
33
34
  ### 主应用
34
35
 
35
- - 安装依赖
36
-
37
- ```sh
38
- // 必须的依赖
39
- npm install react react-dom react-router-dom@6.30.2 zustand @zxiaosi/sdk
40
-
41
- // 可选的依赖
42
- npm install antd dayjs
43
- ```
44
-
45
36
  - 在 `main.ts` 中进行 `SDK` 的挂载
46
37
 
47
38
  ```js
@@ -59,23 +50,29 @@ npx create-sdk
59
50
  import { createRoot } from 'react-dom/client';
60
51
  import App from './App';
61
52
 
53
+ const getRoutesApi = async () => ({
54
+ code: 0,
55
+ data: [
56
+ { path: '/home', name: '首页', component: 'Home' },
57
+ { path: '/subapp', name: '微应用', component: 'Microapp',
58
+ routeAttr: `{"name": "subapp", "entry": "http://localhost:5174", "activeRule": "/subapp", "rootId": "sub-app"}`,
59
+ },
60
+ ],
61
+ })
62
+
63
+ const getUserInfoApi = async () => ({
64
+ code: 0,
65
+ data: { user: {}, permissions: ['/home', '/subapp'], roles: [], settings: {} },
66
+ })
67
+
68
+ const loginApi = async () => ({ code: 0, data: { token: 'xxxx' } })
69
+
62
70
  /** 挂载 SDK */
63
71
  sdk
64
72
  .use(SdkApiPlugin, {
65
- getRoutesApi: async () => ({
66
- code: 0,
67
- data: [
68
- { path: '/home', name: '首页', component: 'Home' },
69
- { path: '/subapp', name: '微应用', component: 'Microapp',
70
- routeAttr: `{"name": "subapp", "entry": "http://localhost:5174", "activeRule": "/subapp", "rootId": "sub-app"}`,
71
- },
72
- ],
73
- }),
74
- getUserInfoApi: async () => ({
75
- code: 0,
76
- data: { user: {}, permissions: ['/home', '/subapp'], roles: [], settings: {} },
77
- }),
78
- loginApi: async () => ({ code: 0, data: { token: 'xxxx' } }),
73
+ getRoutesApi,
74
+ getUserInfoApi,
75
+ loginApi,
79
76
  })
80
77
  .use(SdkAppPlugin)
81
78
  .use(SdkClientPlugin)
@@ -111,17 +108,6 @@ npx create-sdk
111
108
 
112
109
  ### 微应用
113
110
 
114
- - 安装依赖
115
-
116
- ```sh
117
- // 必须的依赖
118
- npm install react react-dom react-router-dom@6.30.2 zustand @zxiaosi/sdk
119
- npm install vite-plugin-qiankun-lite --save-dev
120
-
121
- // 可选的依赖
122
- npm install antd dayjs
123
- ```
124
-
125
111
  - 在 `vite.config.ts` 中配置 `vite-plugin-qiankun-lite` 插件
126
112
 
127
113
  ```js
@@ -163,10 +149,6 @@ npx create-sdk
163
149
  render();
164
150
  }
165
151
 
166
- export async function bootstrap() {
167
- console.log(`Microapp bootstrap`);
168
- }
169
-
170
152
  export async function mount(props: any) {
171
153
  console.log(`Microapp mount`, props);
172
154
  sdk.extend('sdk'); // 继承 sdk 功能
@@ -177,10 +159,47 @@ npx create-sdk
177
159
  console.log(`Microapp unmount`, props);
178
160
  root.unmount();
179
161
  }
180
-
181
- export async function update(props: any) {
182
- console.log(`Microapp update`, props);
183
- }
184
162
  ```
185
163
 
186
164
  - [可参考项目](https://github.com/zxiaosi-team/fontend-sdk/tree/master/packages)
165
+
166
+ ## 注意事项
167
+
168
+ - `SDK` 不能在 `组件外` 进行使用,否则会报 `SDK 未初始化` 错误
169
+
170
+ - 微应用使用 `sdk.ui.renderComponent('xxx')` 时,会报 `React 多实例` 的错误,需要使用 `vite-plugin-externals` 插件将 `React` 等依赖排除在打包之外。[更多详情](https://zxiaosi.com/archives/bc84a75a.html)
171
+ - 在主/子应用的 `index.html` 中使用 `cdn` 的方式去加载 `react` 和 `react-dom` 包
172
+
173
+ ```html
174
+ <!doctype html>
175
+ <html lang="en">
176
+ <head>
177
+ <title>%VITE_APP_TITLE%</title>
178
+ <script src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
179
+ <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
180
+ </head>
181
+ <body>
182
+ <div id="root"></div>
183
+ <script type="module" src="/src/main.tsx"></script>
184
+ </body>
185
+ </html>
186
+ ```
187
+
188
+ - 在主/子应用中使用 `vite-plugin-externals` 插件去排除 `react` 和 `react-dom` 包
189
+
190
+ ```ts
191
+ import { viteExternalsPlugin } from 'vite-plugin-externals';
192
+
193
+ export default defineConfig({
194
+ plugins: [
195
+ viteExternalsPlugin({
196
+ react: 'React',
197
+
198
+ // 开发环境不排除 react-dom 依赖, 防止热更新失效
199
+ // 或者 浏览器安装 React Developer Tools 插件
200
+ 'react-dom': 'ReactDOM',
201
+ 'react-dom/client': 'ReactDOM',
202
+ }),
203
+ ],
204
+ });
205
+ ```
package/dist/index.d.ts CHANGED
@@ -1,12 +1,8 @@
1
- import * as zustand from "zustand";
1
+ import * as _$zustand from "zustand";
2
2
  import { ComponentType, ReactElement } from "react";
3
3
  import { Location, NavigateFunction, RouteObject, UIMatch } from "react-router-dom";
4
- import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
5
- import { ConfigProviderProps } from "antd";
6
- import * as react_intl_universal0 from "react-intl-universal";
7
- import intl from "react-intl-universal";
8
- import { MenuDataItem, ProLayoutProps } from "@ant-design/pro-layout";
9
4
  import { MicroApp, ObjectType, RegistrableApp } from "qiankun";
5
+ import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
10
6
 
11
7
  //#region src/plugins/api/http.d.ts
12
8
  interface ApiRequestOption extends AxiosRequestConfig {
@@ -74,7 +70,7 @@ declare const SdkApiPlugin: Plugin<'api'>;
74
70
  //#region src/plugins/app/index.d.ts
75
71
  interface AppOptions {
76
72
  /** 菜单数据 */
77
- menuData?: MenuDataItem[];
73
+ menuData?: any[];
78
74
  /** 所有路由信息 */
79
75
  allRoutes?: RouteObject[];
80
76
  /** 微应用信息 */
@@ -178,10 +174,7 @@ interface ConfigOptions {
178
174
  * - 会合并到 sdk.app.allRoutes 中
179
175
  */
180
176
  customRoutes?: RouteObject[];
181
- /** Antd 配置 */
182
- antdConfig?: ConfigProviderProps;
183
- /** ProLayout 配置 */
184
- proLayoutConfig?: ProLayoutProps;
177
+ [key: string]: any;
185
178
  }
186
179
  interface ConfigResults extends Required<ConfigOptions> {}
187
180
  /**
@@ -191,19 +184,16 @@ interface ConfigResults extends Required<ConfigOptions> {}
191
184
  * - 配置 默认主题、语言
192
185
  * - 配置 Qiankun 模式
193
186
  * - 配置 默认登录路径、跳转路径、自定义路由
194
- * - 配置 Antd 配置、ProLayout 配置
195
187
  */
196
188
  declare const SdkConfigPlugin: Plugin<'config'>;
197
189
  //#endregion
198
190
  //#region src/plugins/i18n/index.d.ts
199
191
  interface I18nOptions {
200
192
  /**
201
- * React Intl Universal 实例
202
- * - 不要解构使用, const { get } = useIntl() 会报错
203
- * - 如果项目不使用 React Compiler, 可以直接使用 sdk.i18n.intl
204
- * @example const intl = useIntl(); intl.get(key).d(defaultValue)
193
+ * Intl 实例
194
+ * @example sdk.i18n.intl?.xxx
205
195
  */
206
- intl?: typeof intl;
196
+ intl?: any;
207
197
  /**
208
198
  * 自定义语言包
209
199
  * @example
@@ -217,37 +207,11 @@ interface I18nOptions {
217
207
  * }
218
208
  */
219
209
  intlConfig?: Record<string, any>;
220
- /**
221
- * 加载语言包
222
- * @param locale 语言包名
223
- * @example
224
- * import enUS from 'antd/es/locale/en_US';
225
- * import zhCN from 'antd/es/locale/zh_CN';
226
- * import dayjs from 'dayjs';
227
- * import 'dayjs/locale/en';
228
- * import 'dayjs/locale/zh';
229
- *
230
- * const loadLocale = (locale: string) => {
231
- * switch (locale) {
232
- * case 'en-US':
233
- * dayjs.locale('en');
234
- * return enUS;
235
- * case 'zh-CN':
236
- * dayjs.locale('zh');
237
- * return zhCN;
238
- * default:
239
- * return undefined;
240
- * }
241
- * }
242
- */
243
- loadLocale?(locale: string): any;
244
210
  }
245
211
  interface I18nResults extends Required<I18nOptions> {}
246
212
  /**
247
213
  * 多语言
248
214
  * - 详情参考 {@link I18nOptions} {@link I18nResults}
249
- * - 集成 React Intl Universal 和 Antd 国际化
250
- * - 需要从外部引入语言包, 详见 intlConfig 和 loadLocale 配置项
251
215
  */
252
216
  declare const SdkI18nPlugin: Plugin<'i18n'>;
253
217
  //#endregion
@@ -336,7 +300,7 @@ type StoreResults = typeof globalStore;
336
300
  * 创建 Store
337
301
  * - 这里单独声明变量, 主要是为了使用返回类型 StoreResults 🤔
338
302
  */
339
- declare const globalStore: Omit<zustand.StoreApi<StoreOptions>, "subscribe"> & {
303
+ declare const globalStore: Omit<_$zustand.StoreApi<StoreOptions>, "subscribe"> & {
340
304
  subscribe: {
341
305
  (listener: (selectedState: StoreOptions, previousSelectedState: StoreOptions) => void): () => void;
342
306
  <U>(selector: (state: StoreOptions) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
@@ -502,20 +466,7 @@ declare const useUserInfo: () => {
502
466
  * - 不要解构使用, const { get } = useIntl() 会报错
503
467
  * @example const intl = useIntl(); intl.get(key).d(defaultValue)
504
468
  */
505
- declare const useIntl: () => {
506
- determineLocale: typeof react_intl_universal0.determineLocale;
507
- formatHTMLMessage: typeof react_intl_universal0.formatHTMLMessage;
508
- formatMessage: typeof react_intl_universal0.formatMessage;
509
- get: typeof react_intl_universal0.get;
510
- getHTML: typeof react_intl_universal0.getHTML;
511
- getInitOptions: typeof react_intl_universal0.getInitOptions;
512
- init: typeof react_intl_universal0.init;
513
- load: typeof react_intl_universal0.load;
514
- formatList: typeof react_intl_universal0.formatList;
515
- formatParentheses: typeof react_intl_universal0.formatParentheses;
516
- getColon: typeof react_intl_universal0.getColon;
517
- formatNumber: typeof react_intl_universal0.formatNumber;
518
- };
469
+ declare const useIntl: () => any;
519
470
  //#endregion
520
471
  //#region src/hooks/useCrumb.d.ts
521
472
  /**
@@ -531,4 +482,11 @@ declare const useCrumb: () => any[];
531
482
  */
532
483
  declare const usePermission: (code?: string) => boolean;
533
484
  //#endregion
534
- 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, useIntl, usePermission, useUserInfo };
485
+ //#region src/hooks/useInitData.d.ts
486
+ /** 初始化数据 */
487
+ declare const useInitData: () => {
488
+ loading: boolean;
489
+ routes: RouteObject[];
490
+ };
491
+ //#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 };
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- 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 ee,Outlet as l,RouterProvider as te,createBrowserRouter as ne,useLocation as u,useMatches as d,useNavigate as f}from"react-router-dom";import{Fragment as p,jsx as m,jsxs as h}from"react/jsx-runtime";import g from"axios";import{Button as _,ConfigProvider as re,Flex as v,Form as y,Input as b,message as x,theme as S}from"antd";import C from"react-intl-universal";import{subscribeWithSelector as w}from"zustand/middleware";import T from"@ant-design/pro-layout";import{loadMicroApp as E,registerMicroApps as ie,start as ae}from"qiankun";const D=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,D),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}},O=()=>{let[e,r,i]=t(D.store,n(e=>[e.userInfo,e.setUserInfo,e.resetUserInfo]));return{userInfo:e,setUserInfo:r,resetUserInfo:i}};function k(e){return e==null||typeof e!=`object`&&typeof e!=`function`}function A(e){return ArrayBuffer.isView(e)&&!(e instanceof DataView)}function oe(e){return Object.getOwnPropertySymbols(e).filter(t=>Object.prototype.propertyIsEnumerable.call(e,t))}function se(e){return e==null?e===void 0?`[object Undefined]`:`[object Null]`:Object.prototype.toString.call(e)}function j(e,t,n,r=new Map,i=void 0){let a=i?.(e,t,n,r);if(a!==void 0)return a;if(k(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]=j(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,j(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(j(a,void 0,n,r,i));return t}if(typeof Buffer<`u`&&Buffer.isBuffer(e))return e.subarray();if(A(e)){let t=new(Object.getPrototypeOf(e)).constructor(e.length);r.set(e,t);for(let a=0;a<e.length;a++)t[a]=j(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),M(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),M(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),M(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,M(t,e,n,r,i),t}if(e instanceof Boolean){let t=new Boolean(e.valueOf());return r.set(e,t),M(t,e,n,r,i),t}if(e instanceof Number){let t=new Number(e.valueOf());return r.set(e,t),M(t,e,n,r,i),t}if(e instanceof String){let t=new String(e.valueOf());return r.set(e,t),M(t,e,n,r,i),t}if(typeof e==`object`&&ce(e)){let t=Object.create(Object.getPrototypeOf(e));return r.set(e,t),M(t,e,n,r,i),t}return e}function M(e,t,n=e,r,i){let a=[...Object.keys(t),...oe(t)];for(let o=0;o<a.length;o++){let s=a[o],c=Object.getOwnPropertyDescriptor(e,s);(c==null||c.writable)&&(e[s]=j(t[s],s,n,r,i))}}function ce(e){switch(se(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 N(e){return j(e,void 0,e,new Map,void 0)}function P(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 le(e){return e===`__proto__`}function F(e,t){let n=Object.keys(t);for(let r=0;r<n.length;r++){let i=n[r];if(le(i))continue;let a=t[i],o=e[i];I(a)&&I(o)?e[i]=F(o,a):Array.isArray(a)?e[i]=F([],a):P(a)?e[i]=F({},a):(o===void 0||a!==void 0)&&(e[i]=a)}return e}function I(e){return P(e)||Array.isArray(e)}const ue=()=>s(()=>N(D.i18n.intl),[t(D.store,e=>e.locale)]),L=()=>s(()=>D.client.matches,[u()]).filter(e=>!!e.handle?.crumb).map(e=>e.handle.crumb(e.data)),R=e=>{let{requestId:t,url:n,method:r,params:i,data:a}=e;return t||`${r}:${n}?${JSON.stringify(i)}&${JSON.stringify(a)}`},z=e=>{let t=R(e),n=D.api.controllers.get(t);n&&(n.abort(),D.api.controllers.delete(t))},B={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)}]},V=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`},H=e=>e.storage.getLocale()||e.config?.locale||navigator.language||`zh-CN`,U=e=>D.app.permissions?.includes?.(e),de=e=>{let t=new Map,n=W(e,t);return{microApps:[...t.values()],menuData:n}},W=(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:D},loader:e=>D.store.getState().setMicroAppLoading(e)};t.set(r,o),n=D.ui.renderComponent(`Microapp`,{name:r,rootId:i})}else if(o===`Microapp`)n=D.ui.renderComponent(`Microapp`);else if(o===`Outlet`)n=m(l,{});else{let e=U(i);n=D.ui.renderComponent(e?o:`NoPermission`)}return{...e,key:`${i}_${a}_${r}`,element:n,children:W(c,t),handle:{crumb:(t={})=>({...e,...t})}}}),G=e=>{let t=`/`;return!e||e.length===0?t:(t=e?.[0]?.path,e?.[0]?.children&&e?.[0]?.children.length>0&&(t=G(e?.[0]?.children)),t)},fe=e=>s(()=>U(e||D.client.location.pathname),[u().pathname,e]);var pe=class{instance;constructor(e={}){this.instance=g.create(e),this.defaultRequestInterceptor(),this.defaultResponseInterceptor()}defaultRequestInterceptor(){this.instance.interceptors.request.use(function(e){if(e?.isCancelRequest){let t=R(e);z(e);let n=new AbortController;D.api.controllers.set(t,n),e.requestId=t,e.signal=n.signal}let t=D.storage.getToken();return e.headers.lang=D.config.locale,e.headers.Authorization=t,F(e.headers,D.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&&(i&&x.error(s),console.error(`Sdk: defaultResponseInterceptor - Response error: `,n.url,s),o==20041&&D.app.pageToLogin()),a&&D.api.controllers.delete(n.requestId),r?e:e.data},function(e){let{response:t,config:n}=e,{isShowFailMsg:r}=n;if(g.isCancel(e))return Promise.reject(e);if(t){let{status:e,data:n,statusText:i}=t;r&&x.error(n.msg||i),e==401&&D.app.pageToLogin()}else r&&x.error(`请求超时或服务器异常,请检查网络或联系管理员`),console.error(`Sdk: defaultResponseInterceptor - Request error:`,n.url,e);return Promise.reject(e)})}getInstance(){return this.instance}};const me={name:`api`,install(e,t={}){let n={baseURL:`/`,timeout:0,...t.config},r=t?.instance||new pe(n).getInstance();e.api=F({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)}},he={name:`app`,install(e,t={}){e.app=F({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)}},K=`client`,ge={name:K,install(e,t={}){e[K]=F({location:null,navigate:null,matches:null},t)}},q=`config`,_e={name:q,install(e,t={}){e[q]=F({env:{},qiankunMode:`router`,theme:null,locale:null,loginPath:`/login`,defaultPath:``,customRoutes:[],antdConfig:{},proLayoutConfig:{title:`Demo`}},t)}},J=`i18n`,ve={name:J,install(e,t={}){e[J]=F({intl:C,intlConfig:{},loadLocale:e=>void 0},t)}},Y=`storage`,ye={name:Y,install(e,t={}){e[Y]=F({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)}},be=(e,t)=>({locale:null,setLocale:t=>{e(()=>({locale:t})),D.config.locale=t,D.storage.setLocale(t),document.documentElement.setAttribute(`lang`,t);let n=D.i18n.intlConfig;C.init({currentLocale:t,locales:n});try{let e=D.i18n.loadLocale?.(t)||void 0;F(D.config.antdConfig,{locale:e})}catch(e){console.error(`Sdk: createLocaleSlice - sdk.i18n.loadLocale error:`,e)}}}),xe=(e,t)=>({microAppLoading:!1,setMicroAppLoading:t=>e(()=>({microAppLoading:t}))}),{defaultAlgorithm:Se,darkAlgorithm:Ce}=S,we=(e,t)=>({theme:null,setTheme:t=>{e(()=>({theme:t})),D.config.theme=t,D.storage.setTheme(t),document.documentElement.setAttribute(`theme`,t);let n=t===`light`?Se:Ce;F(D.config.antdConfig,{theme:{algorithm:n}})}}),X={user:{},permissions:[],roles:[],settings:{}},Te=(e,t)=>({userInfo:X,setUserInfo:t=>{e(()=>({userInfo:t})),D.app={...D.app,...t}},resetUserInfo:()=>{e(()=>({userInfo:X}))}}),Ee=e()(w((...e)=>({...be(...e),...xe(...e),...we(...e),...Te(...e)}))),Z=`store`,De={name:Z,install(e,t={}){e[Z]=Ee}},Oe=()=>{let e=f(),n=u(),i=d(),a=t(D.store,e=>e.locale),o=i[i.length-1]?.handle?.crumb()||{},s=JSON.parse(o?.routeAttr||`{}`)?.noLayout,c=t=>{e(t.path)};return m(T,{locale:a,formatMessage:({id:e,defaultMessage:t})=>D.i18n.intl.get(e).d(t),location:n,menuItemRender:(e,t)=>m(`div`,{onClick:()=>c(e),children:t}),onMenuHeaderClick:()=>{e(`/`)},onPageChange:e=>{if(!D.app.user||Object.keys(D.app.user).length===0)return D.app.pageToLogin()},...s&&{headerRender:!1,footerRender:!1,menuRender:!1},menu:{request:async()=>D.app.menuData||[],...D.config.proLayoutConfig.menu},...D.config.proLayoutConfig,children:m(r,{fallback:D.ui.renderComponent(`Loading`,{isSuspense:!0}),children:m(l,{})})})},{useToken:Q}=S,ke=({isInitData:e=!1,isSuspense:t=!1,isMicroApp:n=!1})=>{let{token:r}=Q();return m(`div`,{style:e?{width:`100%`,height:`100%`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:r.colorBgContainer,color:r.colorText}:{},children:`Loading...`})},{useToken:Ae}=S,je=()=>{let{token:e}=Ae(),[t,n]=c(!1);return m(v,{style:{width:`100%`,height:`100%`,background:e.colorBgContainer},justify:`center`,align:`center`,children:h(y,{labelCol:{span:8},labelAlign:`left`,wrapperCol:{span:16},style:{maxWidth:600},initialValues:{username:`admin`,password:`admin`},onFinish:async e=>{try{n(()=>!0);let t=await D.api.loginApi(e);n(()=>!1);let r=t?.data?.token||``;if(!r)return;D.storage.setToken(r);let i=D.app.getRedirectPath();D.config.qiankunMode===`load`?(D.client.navigate(i,{replace:!0}),D.app.initData?.()):window.location.replace(i)}catch(e){console.log(`Sdk: Login - handleFinish: `,e),n(()=>!1)}},autoComplete:`off`,children:[m(y.Item,{label:`用户名`,name:`username`,rules:[{required:!0,message:`请输入用户名!`}],children:m(b,{})}),m(y.Item,{label:`密码`,name:`password`,rules:[{required:!0,message:`请输入密码!`}],children:m(b.Password,{})}),m(y.Item,{noStyle:!0,children:m(_,{block:!0,type:`primary`,htmlType:`submit`,loading:t,children:`登录`})})]})})},$=({children:e})=>{let t=u(),n=d(),r=f();return D.client.location=t,D.client.matches=n,D.client.navigate=r,e},Me=()=>{let e=D.config.loginPath,i=D.config.customRoutes,a=D.config.qiankunMode===`router`,l=e=>D.ui.renderComponent(`Loading`,e),u=D.ui.renderComponent(`Layout`),d=D.ui.renderComponent(`Login`),f=D.ui.renderComponent(`NotFound`),p=[{path:e,element:d},{path:`*`,element:f},...i].map(e=>({...e,element:m($,{children:e.element})})),[h,g]=c(!1),[_,v]=c(p),[y,b,x,S,C]=t(D.store,n(e=>[e.locale,e.setLocale,e.theme,e.setTheme,e.setUserInfo])),w=s(()=>N(D.config.antdConfig),[y,x]),T=(e,t)=>{S(e||V(D)),b(t||H(D))},E=async()=>{try{g(()=>!0);let[{data:e={}},{data:t=[]}]=await Promise.all([D.api.getUserInfoApi(),D.api.getRoutesApi()]);g(()=>!1),C(e);let{theme:n,locale:r}=e?.settings||{};T(n,r);let{microApps:i=[],menuData:o=[]}=de(t);a&&(ie(i,B),ae());let s=G(o),c=[...p,{path:`/`,element:m(ee,{to:s,replace:!0})},{path:`/`,element:m($,{children:u}),children:o,errorElement:f}];v(c),D.app={...D.app,allRoutes:c,microApps:i,menuData:o}}catch(e){console.error(e),g(()=>!1)}};return o(()=>{D.app.initData=E,D.app.allRoutes=p;let t=D.config.customRoutes?.map(e=>e.path),n=window.location.pathname;[e,...t]?.includes(n)?T():E()},[]),m(re,{...w,children:m(r,{fallback:l({isSuspense:!0}),children:h?l({isInitData:!0}):m(te,{router:ne(_,{basename:`/`}),future:{v7_startTransition:!1}})})})};var Ne=a(({name:e,rootId:r})=>{let[i,a]=t(D.store,n(e=>[e.microAppLoading,e.setMicroAppLoading]));return o(()=>{if(!e||D.config.qiankunMode!==`load`)return;let t=D.app.microAppsInstance.get(e);if(t)t?.mount();else{let n=D.app.microApps.find(t=>t.name===e);if(!n)return;a(!0),t=E(n,{},B),t?.mountPromise?.finally(()=>{a(!1)}),D.app.microAppsInstance.set(e,t)}return()=>{t?.unmount()}},[e]),h(p,{children:[i&&D.ui.renderComponent(`Loading`,{isMicroApp:!0}),m(`main`,{id:r})]})});const Pe=()=>m(`div`,{children:`无权限`}),{useToken:Fe}=S,Ie=()=>{let{token:e}=Fe();return m(`div`,{style:{width:`100%`,height:`100%`,display:`flex`,alignItems:`center`,justifyContent:`center`,background:e.colorBgContainer},children:`找不到页面`})},Le={name:`ui`,install(e,t={}){e.ui=F({Layout:Oe,Loading:ke,Login:je,Mainapp:Me,Microapp:Ne,NotFound:Ie,NoPermission:Pe,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{me as SdkApiPlugin,he as SdkAppPlugin,ge as SdkClientPlugin,_e as SdkConfigPlugin,ve as SdkI18nPlugin,ye as SdkStoragePlugin,De as SdkStorePlugin,Le as SdkUIPlugin,D as sdk,L as useCrumb,ue as useIntl,fe as usePermission,O as useUserInfo};
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};
package/dist/style.css ADDED
@@ -0,0 +1 @@
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}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zxiaosi/sdk",
3
- "version": "0.5.1",
3
+ "version": "1.0.0-beta.1",
4
4
  "description": "A micro frontend kit",
5
5
  "keywords": [
6
6
  "micro frontend",
@@ -18,8 +18,12 @@
18
18
  "dist"
19
19
  ],
20
20
  "type": "module",
21
- "main": "./dist/index.js",
22
21
  "types": "dist/index.d.ts",
22
+ "exports": {
23
+ ".": "./dist/index.js",
24
+ "./package.json": "./package.json",
25
+ "./style.css": "./dist/style.css"
26
+ },
23
27
  "publishConfig": {
24
28
  "access": "public",
25
29
  "registry": "https://registry.npmjs.org/"
@@ -29,23 +33,38 @@
29
33
  "dev": "tsdown --watch"
30
34
  },
31
35
  "dependencies": {
32
- "@ant-design/pro-layout": "^7.22.7",
33
- "axios": "^1.13.6",
34
- "qiankun": "^2.10.16",
35
- "react-intl-universal": "^2.13.4"
36
+ "axios": "^1.13.6"
36
37
  },
37
38
  "devDependencies": {
39
+ "@tsdown/css": "^0.21.6",
38
40
  "@types/react": "^18.3.12",
39
41
  "@types/react-dom": "^18.3.1",
40
42
  "es-toolkit": "^1.45.1",
41
- "tsdown": "^0.21.4",
43
+ "tsdown": "^0.21.6",
42
44
  "typescript": "^5.9.3"
43
45
  },
44
46
  "peerDependencies": {
45
- "antd": "^5.29.0 || ^6.0.0",
47
+ "qiankun": "^2.10.16",
46
48
  "react": "^18.3.1 || >=19.0.0",
47
49
  "react-dom": "^18.3.1 || >=19.0.0",
48
50
  "react-router-dom": "^6.30.0",
49
51
  "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
+ }
50
69
  }
51
70
  }