@umijs/plugins 4.0.0-beta.8 → 4.0.0-canary-20240513.3

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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -1
  3. package/dist/access.d.ts +1 -1
  4. package/dist/access.js +194 -4
  5. package/dist/{sass.d.ts → analytics.d.ts} +1 -1
  6. package/dist/analytics.js +118 -0
  7. package/dist/antd.d.ts +1 -1
  8. package/dist/antd.js +345 -157
  9. package/dist/{icons.d.ts → confetti.d.ts} +1 -1
  10. package/dist/confetti.js +64 -0
  11. package/dist/constants.d.ts +1 -0
  12. package/dist/constants.js +30 -0
  13. package/dist/dva.d.ts +4 -1
  14. package/dist/dva.js +302 -8
  15. package/dist/initial-state.d.ts +1 -1
  16. package/dist/initial-state.js +147 -4
  17. package/dist/layout.d.ts +1 -1
  18. package/dist/layout.js +754 -4
  19. package/dist/locale.d.ts +2 -1
  20. package/dist/locale.js +257 -4
  21. package/dist/mf.d.ts +2 -0
  22. package/dist/mf.js +358 -0
  23. package/dist/model.d.ts +1 -1
  24. package/dist/model.js +109 -4
  25. package/dist/moment2dayjs.d.ts +3 -0
  26. package/dist/moment2dayjs.js +125 -0
  27. package/dist/qiankun/constants.d.ts +5 -0
  28. package/dist/qiankun/constants.js +41 -0
  29. package/dist/qiankun/master.d.ts +6 -0
  30. package/dist/qiankun/master.js +236 -0
  31. package/dist/qiankun/slave.d.ts +3 -0
  32. package/dist/qiankun/slave.js +345 -0
  33. package/dist/qiankun.d.ts +1 -1
  34. package/dist/qiankun.js +51 -4
  35. package/dist/react-query.d.ts +3 -0
  36. package/dist/react-query.js +193 -0
  37. package/dist/request.d.ts +1 -1
  38. package/dist/request.js +384 -4
  39. package/dist/styled-components.d.ts +3 -0
  40. package/dist/styled-components.js +150 -0
  41. package/dist/tailwindcss.d.ts +3 -0
  42. package/dist/tailwindcss.js +106 -0
  43. package/dist/unocss.d.ts +3 -0
  44. package/dist/unocss.js +71 -0
  45. package/dist/utils/astUtils.d.ts +3 -0
  46. package/dist/utils/astUtils.js +49 -0
  47. package/dist/utils/localeUtils.d.ts +33 -0
  48. package/dist/utils/localeUtils.js +139 -0
  49. package/dist/utils/mfUtils.d.ts +14 -0
  50. package/dist/utils/mfUtils.js +56 -0
  51. package/dist/utils/modelUtils.d.ts +40 -0
  52. package/dist/utils/modelUtils.js +286 -0
  53. package/dist/utils/resolveProjectDep.d.ts +5 -0
  54. package/dist/utils/resolveProjectDep.js +40 -0
  55. package/dist/utils/withTmpPath.d.ts +6 -0
  56. package/dist/utils/withTmpPath.js +39 -0
  57. package/dist/valtio.d.ts +3 -0
  58. package/dist/valtio.js +81 -0
  59. package/libs/dva.tsx +45 -0
  60. package/libs/model.tsx +180 -0
  61. package/libs/qiankun/master/AntdErrorBoundary.tsx +34 -0
  62. package/libs/qiankun/master/AntdLoader.tsx +15 -0
  63. package/libs/qiankun/master/ErrorBoundary.tsx +7 -0
  64. package/libs/qiankun/master/MicroApp.tsx +327 -0
  65. package/libs/qiankun/master/MicroAppWithMemoHistory.tsx +43 -0
  66. package/libs/qiankun/master/common.ts +172 -0
  67. package/libs/qiankun/master/constants.ts +19 -0
  68. package/libs/qiankun/master/getMicroAppRouteComponent.tsx.tpl +45 -0
  69. package/libs/qiankun/master/masterRuntimePlugin.tsx +161 -0
  70. package/libs/qiankun/master/routeUtils.ts +26 -0
  71. package/libs/qiankun/master/types.ts +54 -0
  72. package/libs/qiankun/slave/MicroAppLink.tsx +122 -0
  73. package/libs/qiankun/slave/connectMaster.tsx +14 -0
  74. package/libs/qiankun/slave/constants.ts +5 -0
  75. package/libs/qiankun/slave/lifecycles.ts +164 -0
  76. package/libs/qiankun/slave/qiankunModel.ts +18 -0
  77. package/libs/qiankun/slave/slaveRuntimePlugin.ts +36 -0
  78. package/package.json +54 -24
  79. package/templates/antd/runtime.ts.tpl +170 -0
  80. package/templates/antd/types.d.ts.tpl +17 -0
  81. package/templates/locale/SelectLang.tpl +502 -0
  82. package/templates/locale/locale.tpl +82 -0
  83. package/templates/locale/localeExports.tpl +307 -0
  84. package/templates/locale/runtime.tpl +34 -0
  85. package/templates/mf/runtime.ts.tpl +149 -0
  86. package/dist/access.d.ts.map +0 -1
  87. package/dist/antd.d.ts.map +0 -1
  88. package/dist/dva.d.ts.map +0 -1
  89. package/dist/icons.d.ts.map +0 -1
  90. package/dist/icons.js +0 -5
  91. package/dist/initial-state.d.ts.map +0 -1
  92. package/dist/layout.d.ts.map +0 -1
  93. package/dist/locale.d.ts.map +0 -1
  94. package/dist/model.d.ts.map +0 -1
  95. package/dist/qiankun.d.ts.map +0 -1
  96. package/dist/request.d.ts.map +0 -1
  97. package/dist/sass.d.ts.map +0 -1
  98. package/dist/sass.js +0 -5
@@ -0,0 +1,327 @@
1
+ // @ts-nocheck
2
+ /* eslint-disable */
3
+ __USE_MODEL__;
4
+ import concat from 'lodash/concat';
5
+ import isEqual from 'lodash/isEqual';
6
+ import mergeWith from 'lodash/mergeWith';
7
+ import noop from 'lodash/noop';
8
+ import {
9
+ FrameworkConfiguration,
10
+ loadMicroApp,
11
+ MicroApp as MicroAppTypeDefinition,
12
+ prefetchApps,
13
+ } from 'qiankun';
14
+ import React, {
15
+ forwardRef,
16
+ Ref,
17
+ useEffect,
18
+ useImperativeHandle,
19
+ useRef,
20
+ useState,
21
+ } from 'react';
22
+ import { qiankunStateForSlaveModelNamespace } from './constants';
23
+ import defaultErrorBoundary from './defaultErrorBoundary';
24
+ import defaultLoader from './defaultLoader';
25
+ import { ErrorBoundary } from './ErrorBoundary';
26
+ import { getMasterOptions } from './masterOptions';
27
+ import MicroAppLoader from './MicroAppLoader';
28
+ import { MasterOptions } from './types';
29
+
30
+ type HashHistory = {
31
+ type?: 'hash';
32
+ } & any;
33
+
34
+ type BrowserHistory = {
35
+ type?: 'browser';
36
+ } & any;
37
+
38
+ type MemoryHistory = {
39
+ type?: 'memory';
40
+ } & any;
41
+
42
+ type MicroAppType = MicroAppTypeDefinition & {
43
+ _unmounting?: boolean;
44
+ _updatingPromise?: Promise<void>;
45
+ _updatingTimestamp?: number;
46
+ };
47
+
48
+ export type Props = {
49
+ name: string;
50
+ settings?: FrameworkConfiguration;
51
+ base?: string;
52
+ history?:
53
+ | 'hash'
54
+ | 'browser'
55
+ | 'memory'
56
+ | HashHistory
57
+ | BrowserHistory
58
+ | MemoryHistory;
59
+ getMatchedBase?: () => string;
60
+ loader?: (loading: boolean) => React.ReactNode;
61
+ errorBoundary?: (error: any) => React.ReactNode;
62
+ onHistoryInit?: (history: any) => void;
63
+ autoSetLoading?: boolean;
64
+ autoCaptureError?: boolean;
65
+ // 仅开启 loader 时需要
66
+ wrapperClassName?: string;
67
+ className?: string;
68
+ } & Record<string, any>;
69
+
70
+ function unmountMicroApp(microApp: MicroAppType) {
71
+ microApp.mountPromise.then(() => microApp.unmount());
72
+ }
73
+
74
+ function useDeepCompare<T>(value: T): T {
75
+ const ref = useRef<T>(value);
76
+ if (!isEqual(value, ref.current)) {
77
+ ref.current = value;
78
+ }
79
+
80
+ return ref.current;
81
+ }
82
+
83
+ let noneMounted = true;
84
+
85
+ export const MicroApp = forwardRef(
86
+ (componentProps: Props, componentRef: Ref<MicroAppType>) => {
87
+ const {
88
+ masterHistoryType,
89
+ apps = [],
90
+ lifeCycles: globalLifeCycles,
91
+ prefetch = true,
92
+ appNameKeyAlias = 'name',
93
+ prefetchThreshold = 5,
94
+ ...globalSettings
95
+ } = getMasterOptions() as MasterOptions;
96
+
97
+ const {
98
+ settings: settingsFromProps = {},
99
+ loader,
100
+ errorBoundary,
101
+ lifeCycles,
102
+ wrapperClassName,
103
+ className,
104
+ ...propsFromParams
105
+ } = componentProps;
106
+
107
+ // name 跟 appNameKeyAlias 这两个 key 同时存在时,优先使用 name,避免对存量应用造成 breaking change。
108
+ // 比如 appNameKeyAlias 配置是 id,但之前 id 正好作为普通的 props 使用过,如 <MicroApp name="app" id="123" />
109
+ // 正常场景会优先匹配 appNameKeyAlias 对应的字段,fallback 到 name,避免对已经使用 <MicroApp name="app" /> 的应用造成影响
110
+ const name =
111
+ componentProps.name && componentProps[appNameKeyAlias]
112
+ ? componentProps.name
113
+ : componentProps[appNameKeyAlias] || componentProps.name;
114
+ const isCurrentApp = (app: any) =>
115
+ app[appNameKeyAlias] === name || app.name === name;
116
+
117
+ const [loading, setLoading] = useState(true);
118
+ const [error, setError] = useState<any>(null);
119
+ // 未配置自定义 errorBoundary 且开启了 autoCaptureError 场景下,使用插件默认的 errorBoundary,否则使用自定义 errorBoundary
120
+ const microAppErrorBoundary =
121
+ errorBoundary ||
122
+ defaultErrorBoundary ||
123
+ (propsFromParams.autoCaptureError
124
+ ? (e) => <ErrorBoundary error={e} />
125
+ : null);
126
+
127
+ // 配置了 errorBoundary 才改 error 状态,否则直接往上抛异常
128
+ const setComponentError = (error: any) => {
129
+ if (microAppErrorBoundary) {
130
+ setError(error);
131
+ // error log 出来,不要吞
132
+ if (error) {
133
+ console.error(error);
134
+ }
135
+ } else if (error) {
136
+ throw error;
137
+ }
138
+ };
139
+
140
+ const containerRef = useRef<HTMLDivElement>();
141
+ const microAppRef = useRef<MicroAppType>();
142
+
143
+ useImperativeHandle(componentRef, () => microAppRef.current);
144
+
145
+ const appConfig = apps.find((app: any) => isCurrentApp(app));
146
+ useEffect(() => {
147
+ if (!appConfig) {
148
+ setComponentError(
149
+ new Error(
150
+ `[@umijs/plugin-qiankun]: Can not find the configuration of ${name} app! Currently, only the following apps are configured:\n${JSON.stringify(
151
+ apps,
152
+ null,
153
+ 2,
154
+ )}`,
155
+ ),
156
+ );
157
+ }
158
+ return noop;
159
+ }, []);
160
+
161
+ // 约定使用 src/app.ts/useQiankunStateForSlave 中的数据作为主应用透传给微应用的 props,优先级高于 propsFromConfig
162
+ const stateForSlave = (useModel || noop)(
163
+ qiankunStateForSlaveModelNamespace,
164
+ );
165
+ const {
166
+ entry,
167
+ props: { settings: settingsFromConfig = {}, ...propsFromConfig } = {},
168
+ } = appConfig || {};
169
+
170
+ useEffect(() => {
171
+ setComponentError(null);
172
+ setLoading(true);
173
+ const configuration = {
174
+ globalContext: window,
175
+ ...globalSettings,
176
+ ...settingsFromConfig,
177
+ ...settingsFromProps,
178
+ };
179
+ microAppRef.current = loadMicroApp(
180
+ {
181
+ name,
182
+ entry,
183
+ container: containerRef.current!,
184
+ props: {
185
+ ...propsFromConfig,
186
+ ...stateForSlave,
187
+ ...propsFromParams,
188
+ __globalRoutesInfo: {
189
+ appNameKeyAlias,
190
+ masterHistoryType,
191
+ base: globalSettings.base,
192
+ microAppRoutes: globalSettings.microAppRoutes,
193
+ },
194
+ setLoading,
195
+ },
196
+ },
197
+ configuration,
198
+ mergeWith({}, globalLifeCycles, lifeCycles, (v1, v2) =>
199
+ concat(v1 ?? [], v2 ?? []),
200
+ ),
201
+ );
202
+
203
+ // 当配置了 prefetch true 时,在第一个应用 mount 完成之后,再去预加载其他应用
204
+ if (prefetch && prefetch !== 'all' && noneMounted) {
205
+ microAppRef.current?.mountPromise.then(() => {
206
+ if (noneMounted) {
207
+ if (Array.isArray(prefetch)) {
208
+ const specialPrefetchApps = apps.filter(
209
+ (app) =>
210
+ !isCurrentApp(app) &&
211
+ (prefetch.indexOf(app[appNameKeyAlias]) !== -1 ||
212
+ prefetch.indexOf(app.name) !== -1),
213
+ );
214
+ prefetchApps(specialPrefetchApps, configuration);
215
+ } else {
216
+ // 不能无脑全量 prefetch,需要有一个阈值
217
+ const otherNotMountedApps = apps
218
+ .filter((app) => !isCurrentApp(app))
219
+ .slice(0, prefetchThreshold);
220
+ prefetchApps(otherNotMountedApps, configuration);
221
+ }
222
+ noneMounted = false;
223
+ }
224
+ });
225
+ }
226
+
227
+ (['loadPromise', 'bootstrapPromise', 'mountPromise'] as const).forEach(
228
+ (key) => {
229
+ const promise = microAppRef.current?.[key];
230
+ promise.catch((e) => {
231
+ setComponentError(e);
232
+ setLoading(false);
233
+ });
234
+ },
235
+ );
236
+
237
+ return () => {
238
+ const microApp = microAppRef.current;
239
+ if (microApp) {
240
+ // 微应用 unmount 是异步的,中间的流转状态不能确定,所有需要一个标志位来确保 unmount 开始之后不会再触发 update
241
+ microApp._unmounting = true;
242
+ unmountMicroApp(microApp);
243
+ }
244
+ };
245
+ }, [name]);
246
+
247
+ useEffect(() => {
248
+ const microApp = microAppRef.current;
249
+ if (microApp) {
250
+ if (!microApp._updatingPromise) {
251
+ // 初始化 updatingPromise 为 microApp.mountPromise,从而确保后续更新是在应用 mount 完成之后
252
+ microApp._updatingPromise = microApp.mountPromise;
253
+ microApp._updatingTimestamp = Date.now();
254
+ } else {
255
+ // 确保 microApp.update 调用是跟组件状态变更顺序一致的,且后一个微应用更新必须等待前一个更新完成
256
+ microApp._updatingPromise = microApp._updatingPromise.then(() => {
257
+ const canUpdate = (microApp?: MicroAppType) =>
258
+ microApp?.update &&
259
+ microApp.getStatus() === 'MOUNTED' &&
260
+ !microApp._unmounting;
261
+ if (canUpdate(microApp)) {
262
+ const props = {
263
+ ...propsFromConfig,
264
+ ...stateForSlave,
265
+ ...propsFromParams,
266
+ setLoading,
267
+ };
268
+
269
+ if (process.env.NODE_ENV === 'development') {
270
+ const updatingTimestamp = microApp._updatingTimestamp!;
271
+ if (Date.now() - updatingTimestamp < 200) {
272
+ console.warn(
273
+ `[@umijs/plugin-qiankun] It seems like microApp ${name} is updating too many times in a short time(200ms), you may need to do some optimization to avoid the unnecessary re-rendering.`,
274
+ );
275
+ }
276
+
277
+ console.info(
278
+ `[@umijs/plugin-qiankun] MicroApp ${name} is updating with props: `,
279
+ props,
280
+ );
281
+ microApp._updatingTimestamp = Date.now();
282
+ }
283
+
284
+ // 返回 microApp.update 形成链式调用
285
+ // @ts-ignore
286
+ return microApp.update(props);
287
+ }
288
+
289
+ return void 0;
290
+ });
291
+ }
292
+ }
293
+
294
+ return noop;
295
+ }, [useDeepCompare({ ...stateForSlave, ...propsFromParams })]);
296
+
297
+ // 未配置自定义 loader 且开启了 autoSetLoading 场景下,使用插件默认的 loader,否则使用自定义 loader
298
+ const microAppLoader =
299
+ loader ||
300
+ defaultLoader ||
301
+ (propsFromParams.autoSetLoading
302
+ ? (loading) => <MicroAppLoader loading={loading} />
303
+ : null);
304
+
305
+ const microAppWrapperClassName = wrapperClassName
306
+ ? `${wrapperClassName} qiankun-micro-app-wrapper`
307
+ : 'qiankun-micro-app-wrapper';
308
+ const microAppClassName = className
309
+ ? `${className} qiankun-micro-app-container`
310
+ : 'qiankun-micro-app-container';
311
+
312
+ return Boolean(microAppLoader) || Boolean(microAppErrorBoundary) ? (
313
+ <div
314
+ style={{ position: 'relative' }}
315
+ className={microAppWrapperClassName}
316
+ >
317
+ {Boolean(microAppLoader) && microAppLoader(loading)}
318
+ {Boolean(microAppErrorBoundary) &&
319
+ Boolean(error) &&
320
+ microAppErrorBoundary(error)}
321
+ <div ref={containerRef} className={microAppClassName} />
322
+ </div>
323
+ ) : (
324
+ <div ref={containerRef} className={microAppClassName} />
325
+ );
326
+ },
327
+ );
@@ -0,0 +1,43 @@
1
+ // @ts-nocheck
2
+ /* eslint-disable */
3
+
4
+ import React, { useCallback, useEffect, useRef } from 'react';
5
+ import { MicroApp, Props as MicroAppProps } from './MicroApp';
6
+
7
+ export interface Props extends MicroAppProps {
8
+ history?: never;
9
+ }
10
+
11
+ export function MicroAppWithMemoHistory(componentProps: Props) {
12
+ const { url, ...rest } = componentProps;
13
+ const history = useRef();
14
+ // url 的变更不会透传给下游,组件内自己会处理掉,所以这里直接用 ref 来存
15
+ const historyOpts = useRef({
16
+ type: 'memory',
17
+ initialEntries: [url],
18
+ initialIndex: 1,
19
+ });
20
+ const historyInitHandler = useCallback((h) => (history.current = h), []);
21
+
22
+ useEffect(() => {
23
+ // push history for slave app when url property changed
24
+ // the initial url will be ignored because the history has not been initialized
25
+ if (history.current && url) {
26
+ history.current.push(url);
27
+ }
28
+ }, [url]);
29
+
30
+ useEffect(() => {
31
+ // reset the history when name changed
32
+ historyOpts.current.initialEntries = [url];
33
+ historyOpts.current.initialIndex = 1;
34
+ }, [componentProps.name]);
35
+
36
+ return (
37
+ <MicroApp
38
+ {...rest}
39
+ history={historyOpts.current}
40
+ onHistoryInit={historyInitHandler}
41
+ />
42
+ );
43
+ }
@@ -0,0 +1,172 @@
1
+ // @ts-nocheck
2
+ /* eslint-disable */
3
+ /**
4
+ * @author Kuitos
5
+ * @since 2019-06-20
6
+ */
7
+
8
+ import React from 'react';
9
+ import { Navigate, type IRouteProps } from 'umi';
10
+ import { defaultMicroAppRouteMode, MicroAppRouteMode } from './constants';
11
+ import { getMicroAppRouteComponent } from './getMicroAppRouteComponent';
12
+ import type { MicroAppRoute } from './types';
13
+
14
+ export const defaultMountContainerId = 'root-subapp';
15
+
16
+ // @formatter:off
17
+ export const noop = () => {};
18
+ // @formatter:on
19
+
20
+ export function toArray<T>(source: T | T[]): T[] {
21
+ return Array.isArray(source) ? source : [source];
22
+ }
23
+
24
+ function testPathWithStaticPrefix(pathPrefix: string, realPath: string) {
25
+ if (pathPrefix.endsWith('/')) {
26
+ return realPath.startsWith(pathPrefix);
27
+ }
28
+
29
+ const pathRegex = new RegExp(`^${pathPrefix}([/?])+.*$`, 'g');
30
+ const normalizedPath = `${realPath}/`;
31
+ return pathRegex.test(normalizedPath);
32
+ }
33
+
34
+ // function testPathWithDynamicRoute(dynamicRoute: string, realPath: string) {
35
+ // // FIXME 这个是旧的使用方式才会调到的 api,先临时这么苟一下消除报错,引导用户去迁移吧
36
+ // const pathToRegexp = require('path-to-regexp');
37
+ // return pathToRegexp(dynamicRoute, { strict: true, end: false }).test(
38
+ // realPath,
39
+ // );
40
+ // }
41
+ //
42
+ // export function testPathWithPrefix(pathPrefix: string, realPath: string) {
43
+ // return (
44
+ // testPathWithStaticPrefix(pathPrefix, realPath) ||
45
+ // testPathWithDynamicRoute(pathPrefix, realPath)
46
+ // );
47
+ // }
48
+
49
+ export function patchMicroAppRoute(
50
+ route: MicroAppRoute,
51
+ masterOptions: {
52
+ base: string;
53
+ masterHistoryType: string;
54
+ routeBindingAlias: string;
55
+ },
56
+ ) {
57
+ const { base, masterHistoryType, routeBindingAlias } = masterOptions;
58
+ // 当配置了 routeBindingAlias 时,优先从 routeBindingAlias 里取配置,但同时也兼容使用了默认的 microApp 方式
59
+ const microAppName = route[routeBindingAlias] || route.microApp;
60
+ const microAppProps =
61
+ route[`${routeBindingAlias}Props`] || route.microAppProps || {};
62
+ if (microAppName) {
63
+ if (route.children?.length) {
64
+ const childrenRouteHasComponent = route.children.some(
65
+ (r: any) => r.element,
66
+ );
67
+ if (childrenRouteHasComponent) {
68
+ throw new Error(
69
+ `[@umijs/plugin-qiankun]: You can not attach micro app ${microAppName} to route ${route.path} whose children has own component!`,
70
+ );
71
+ }
72
+ }
73
+
74
+ const { mode = defaultMicroAppRouteMode } = route;
75
+ // 在前缀模式下,自动追加通配符,匹配子应用的路由
76
+ if (mode === MicroAppRouteMode.PREPEND && !route.path.endsWith('/*')) {
77
+ route.path = route.path.replace(/\/?$/, '/*');
78
+ }
79
+
80
+ const { settings = {}, ...componentProps } = microAppProps;
81
+ const routeProps = {
82
+ // 兼容以前的 settings 配置
83
+ settings: route.settings || settings || {},
84
+ ...componentProps,
85
+ };
86
+ const opts = {
87
+ appName: microAppName,
88
+ base,
89
+ routePath: route.path,
90
+ routeMode: route.mode,
91
+ masterHistoryType,
92
+ routeProps,
93
+ };
94
+ route.element = React.createElement(getMicroAppRouteComponent(opts), null);
95
+ } else if (route.redirect) {
96
+ // patchClientRoutes 插入的 redirect 不会被转换,所以这里需要手动处理成重定向组件
97
+ route.element = React.createElement(Navigate, {
98
+ to: route.redirect,
99
+ replace: true,
100
+ });
101
+ }
102
+ }
103
+
104
+ const recursiveSearch = (
105
+ routes: IRouteProps[],
106
+ path: string,
107
+ parentPath: string,
108
+ ): [IRouteProps, IRouteProps[], number, string] | null => {
109
+ for (let i = 0; i < routes.length; i++) {
110
+ if (routes[i].path === path) {
111
+ return [routes[i], routes, i, parentPath];
112
+ }
113
+ if (routes[i].children && routes[i].children?.length) {
114
+ const found = recursiveSearch(
115
+ routes[i].children || [],
116
+ path,
117
+ routes[i].path,
118
+ );
119
+ if (found) {
120
+ return found;
121
+ }
122
+ }
123
+ }
124
+ return null;
125
+ };
126
+
127
+ export function insertRoute(routes: IRouteProps[], microAppRoute: IRouteProps) {
128
+ const mod =
129
+ microAppRoute.appendChildTo || microAppRoute.insert
130
+ ? 'appendChildTo'
131
+ : microAppRoute.insertBefore
132
+ ? 'insertBefore'
133
+ : undefined;
134
+ const target =
135
+ microAppRoute.appendChildTo ||
136
+ microAppRoute.insert ||
137
+ microAppRoute.insertBefore;
138
+ const [found, foundParentRoutes = [], index = 0, parentPath] =
139
+ recursiveSearch(routes, target, '/') || [];
140
+ if (found) {
141
+ switch (mod) {
142
+ case 'appendChildTo':
143
+ if (
144
+ !microAppRoute.path ||
145
+ !found.path ||
146
+ !microAppRoute.path.startsWith(found.path)
147
+ ) {
148
+ throw new Error(
149
+ `[plugin-qiankun]: path "${microAppRoute.path}" need to starts with "${found.path}"`,
150
+ );
151
+ }
152
+ found.exact = false;
153
+ found.children = found.children || [];
154
+ found.children.push(microAppRoute);
155
+ break;
156
+ case 'insertBefore':
157
+ if (
158
+ !microAppRoute.path ||
159
+ !found.path ||
160
+ !microAppRoute.path.startsWith(parentPath)
161
+ ) {
162
+ throw new Error(
163
+ `[plugin-qiankun]: path "${microAppRoute.path}" need to starts with "${parentPath}"`,
164
+ );
165
+ }
166
+ foundParentRoutes.splice(index, 0, microAppRoute);
167
+ break;
168
+ }
169
+ } else {
170
+ throw new Error(`[plugin-qiankun]: path "${target}" not found`);
171
+ }
172
+ }
@@ -0,0 +1,19 @@
1
+ // @ts-nocheck
2
+ /* eslint-disable */
3
+
4
+ export const defaultMasterRootId = 'root-master';
5
+ export const defaultHistoryType = 'browser';
6
+ export const qiankunStateForSlaveModelNamespace = '@@qiankunStateForSlave';
7
+ export const qiankunStateFromMasterModelNamespace = '@@qiankunStateFromMaster';
8
+ export enum MicroAppRouteMode {
9
+ /**
10
+ * 既作为匹配规则,也作为子应用 router.basename
11
+ */
12
+ PREPEND = 'prepend',
13
+ /**
14
+ * 仅作为匹配规则
15
+ */
16
+ MATCH = 'match',
17
+ }
18
+
19
+ export const defaultMicroAppRouteMode = MicroAppRouteMode.PREPEND;
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { useMatch } from 'umi';
3
+ import { MicroApp } from './MicroApp';
4
+ import { defaultMicroAppRouteMode, MicroAppRouteMode } from './constants';
5
+
6
+ export function getMicroAppRouteComponent(opts: {
7
+ appName: string;
8
+ base: string;
9
+ routePath: string;
10
+ routeMode: MicroAppRouteMode;
11
+ masterHistoryType: string;
12
+ routeProps?: any;
13
+ }) {
14
+ const { base, masterHistoryType, appName, routeProps, routePath, routeMode = defaultMicroAppRouteMode } = opts;
15
+ const RouteComponent = () => {
16
+ const match = useMatch(routePath);
17
+ const url = match ? match.pathnameBase : '';
18
+ // 默认取静态配置的 base
19
+ let umiConfigBase = base === '/' ? '' : trimEndSlash(base);
20
+ // 匹配模式下,routePath 不会作为 prefix
21
+ const prefix = routeMode === MicroAppRouteMode.MATCH ? '' : trimEndSlash(url);
22
+
23
+ // 拼接子应用挂载路由
24
+ let runtimeMatchedBase = umiConfigBase + prefix;
25
+
26
+ {{#dynamicRoot}}
27
+ // @see https://github.com/umijs/umi/blob/master/packages/preset-built-in/src/plugins/commands/htmlUtils.ts#L102
28
+ runtimeMatchedBase = window.routerBase || location.pathname.split('/').slice(0, -(path.split('/').length - 1)).concat('').join('/');
29
+ {{/dynamicRoot}}
30
+
31
+ const componentProps = {
32
+ name: appName,
33
+ base: runtimeMatchedBase,
34
+ history: masterHistoryType,
35
+ ...routeProps,
36
+ };
37
+ return <MicroApp {...componentProps} />;
38
+ };
39
+
40
+ return RouteComponent;
41
+ }
42
+
43
+ function trimEndSlash(p: string) {
44
+ return p.endsWith('/') ? p.slice(0, -1) : p;
45
+ }