@servicetitan/web-components 22.10.0 → 22.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +8 -4
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +42 -16
- package/dist/loader.js.map +1 -1
- package/dist/mfe-data-context.d.ts +15 -0
- package/dist/mfe-data-context.d.ts.map +1 -0
- package/dist/mfe-data-context.js +13 -0
- package/dist/mfe-data-context.js.map +1 -0
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +44 -13
- package/dist/register.js.map +1 -1
- package/package.json +12 -8
- package/src/__tests__/register.test.tsx +100 -0
- package/src/index.ts +2 -0
- package/src/loader.tsx +262 -207
- package/src/mfe-data-context.ts +33 -0
- package/src/register.tsx +71 -32
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './common';
|
|
2
2
|
export * from './event-bus';
|
|
3
3
|
export * from './history-manager';
|
|
4
|
+
// Specific exports below in order to exclude `MFEContextData` from being included in the bundle
|
|
5
|
+
export { useMFEDataContext } from './mfe-data-context';
|
|
4
6
|
export * from './register';
|
|
5
7
|
export * from './loader';
|
|
6
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,gGAAgG;AAChG,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { ReactElement, ReactNode, Ref } from 'react';
|
|
2
2
|
import { GetJsonError } from './common';
|
|
3
3
|
import { EventBus } from './event-bus';
|
|
4
|
+
import { MFEContextData } from './mfe-data-context';
|
|
4
5
|
export declare type LoaderRef = EventBus;
|
|
5
|
-
export interface LoaderProps {
|
|
6
|
+
export interface LoaderProps<T> {
|
|
6
7
|
src: string;
|
|
7
8
|
fallbackSrc?: string;
|
|
8
|
-
|
|
9
|
+
/** Values in the object will be stringified and then parsed before being delivered to the MFE via props or context. */
|
|
10
|
+
data?: MFEContextData<T>;
|
|
9
11
|
basename?: string;
|
|
10
12
|
loadingFallback?: NonNullable<ReactNode> | null;
|
|
11
13
|
errorFallback?: NonNullable<ReactNode> | null;
|
|
@@ -13,5 +15,7 @@ export interface LoaderProps {
|
|
|
13
15
|
retries?: number;
|
|
14
16
|
onRequestError?(error: GetJsonError): boolean;
|
|
15
17
|
}
|
|
16
|
-
export declare const Loader:
|
|
18
|
+
export declare const Loader: <T>(props: LoaderProps<T> & {
|
|
19
|
+
ref?: Ref<LoaderRef>;
|
|
20
|
+
}) => ReactElement | null;
|
|
17
21
|
//# sourceMappingURL=loader.d.ts.map
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQH,YAAY,EACZ,SAAS,EACT,GAAG,EACN,MAAM,OAAO,CAAC;AAUf,OAAO,EAKH,YAAY,EAEf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,QAAQ,EAAgC,MAAM,aAAa,CAAC;AAIrE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAmHpD,oBAAY,SAAS,GAAG,QAAQ,CAAC;AAEjC,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uHAAuH;IACvH,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAChD,aAAa,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;CACjD;AAKD,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;CAAE,KAAK,YAAY,GAAG,IA+PxF,CAAC"}
|
package/dist/loader.js
CHANGED
|
@@ -74,6 +74,8 @@ function getBundleInfo(mainPackageUrl, fallbackPackageUrl, exposedDependencies =
|
|
|
74
74
|
const withBaseUrl = (path) => {
|
|
75
75
|
return `${exactPackageUrl}/dist/bundle/${bundleType}/${path}`;
|
|
76
76
|
};
|
|
77
|
+
// Check if the MFE's startup supports re-rendering the MFE component when data changes
|
|
78
|
+
const supportWatchForDataChanges = startupVersion && semver.gte(startupVersion, '22.12.0');
|
|
77
79
|
let entrypoints;
|
|
78
80
|
if ((_b = metadata.entrypoints) === null || _b === void 0 ? void 0 : _b[bundleType]) {
|
|
79
81
|
entrypoints = metadata.entrypoints[bundleType];
|
|
@@ -96,20 +98,17 @@ function getBundleInfo(mainPackageUrl, fallbackPackageUrl, exposedDependencies =
|
|
|
96
98
|
}
|
|
97
99
|
},
|
|
98
100
|
mismatch: hasMismatch ? mismatch : undefined,
|
|
101
|
+
supportWatchForDataChanges,
|
|
99
102
|
};
|
|
100
103
|
});
|
|
101
104
|
}
|
|
105
|
+
// Type complexity below is required to pass a generic type through forwardRef
|
|
102
106
|
export const Loader = forwardRef(({ src, fallbackSrc, data = {}, basename, loadingFallback, errorFallback, className, retries, onRequestError, }, ref) => {
|
|
103
107
|
const [isLoading, setIsLoading] = useState(true);
|
|
104
108
|
const bus = useEventBus();
|
|
105
109
|
const [logService, historyManager, exposedDependencies = EXPOSED_DEPENDENCIES, eventBus = bus,] = useOptionalDependencies(Log, HistoryManager, EXPOSED_DEPENDENCIES_TOKEN, EVENT_BUS_TOKEN);
|
|
106
|
-
const dataAttrs = useMemo(() => Object.fromEntries(Object.entries(data).map(([key, value]) => [
|
|
107
|
-
'data-' + key.replace(/[A-Z]/g, letter => '-' + letter.toLowerCase()),
|
|
108
|
-
value,
|
|
109
|
-
])), [...Object.entries(data).map(v => v.join())] // eslint-disable-line react-hooks/exhaustive-deps
|
|
110
|
-
);
|
|
111
110
|
const Loader = useMemo(() => {
|
|
112
|
-
const Component = forwardRef((
|
|
111
|
+
const Component = forwardRef((props, ref) => {
|
|
113
112
|
const cancelation = useCancelation();
|
|
114
113
|
useImperativeHandle(ref, () => eventBus, []);
|
|
115
114
|
useEffect(() => {
|
|
@@ -131,7 +130,7 @@ export const Loader = forwardRef(({ src, fallbackSrc, data = {}, basename, loadi
|
|
|
131
130
|
}
|
|
132
131
|
throw e;
|
|
133
132
|
}
|
|
134
|
-
const { urls, WebComponent, disposer, mismatch } = bundleInfo;
|
|
133
|
+
const { urls, WebComponent, disposer, mismatch, supportWatchForDataChanges, } = bundleInfo;
|
|
135
134
|
if (mismatch) {
|
|
136
135
|
logService === null || logService === void 0 ? void 0 : logService.warning({
|
|
137
136
|
category: 'MicroFrontends.DependenciesMismatch',
|
|
@@ -184,15 +183,44 @@ export const Loader = forwardRef(({ src, fallbackSrc, data = {}, basename, loadi
|
|
|
184
183
|
});
|
|
185
184
|
};
|
|
186
185
|
return {
|
|
187
|
-
default: () =>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
default: (props) => {
|
|
187
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
188
|
+
const stringifiedData = useMemo(() => JSON.stringify(props.data), [props.data]);
|
|
189
|
+
/*
|
|
190
|
+
* Set key for rendering the web component so that if the data from the Host change,
|
|
191
|
+
* and the MFE's version of startup doesn't support watching for data changes, then
|
|
192
|
+
* the web component will be re-mounted whenever the data changes.
|
|
193
|
+
* This is only used as a fallback when the MFE's version is older.
|
|
194
|
+
*/
|
|
195
|
+
const key = supportWatchForDataChanges
|
|
196
|
+
? undefined
|
|
197
|
+
: stringifiedData;
|
|
198
|
+
/*
|
|
199
|
+
* Convert camelCase data props to kebab-case data attributes, prepended with data-
|
|
200
|
+
* Ex: fooBar -> data-foo-bar
|
|
201
|
+
*/
|
|
202
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
203
|
+
const dataAttrs = useMemo(() => {
|
|
204
|
+
var _a;
|
|
205
|
+
return supportWatchForDataChanges
|
|
206
|
+
? {}
|
|
207
|
+
: Object.fromEntries(Object.entries((_a = props.data) !== null && _a !== void 0 ? _a : {}).map(([key, value]) => [
|
|
208
|
+
'data-' +
|
|
209
|
+
key.replace(/[A-Z]/g, letter => '-' +
|
|
210
|
+
letter.toLowerCase()),
|
|
211
|
+
value,
|
|
212
|
+
]));
|
|
213
|
+
}, [props.data]);
|
|
214
|
+
return (_jsx(WebComponent, Object.assign({ ref: handleRef, class: props.className }, (urls.css.length
|
|
215
|
+
? {
|
|
216
|
+
'style-urls': encodeURIComponent(JSON.stringify(urls.css)),
|
|
217
|
+
}
|
|
218
|
+
: {}), dataAttrs, { "data-mfe-data": stringifiedData }), key));
|
|
219
|
+
},
|
|
192
220
|
};
|
|
193
221
|
})), [] // eslint-disable-line react-hooks/exhaustive-deps
|
|
194
222
|
);
|
|
195
|
-
return _jsx(Lazy, {});
|
|
223
|
+
return _jsx(Lazy, { data: props.data, className: props.className });
|
|
196
224
|
});
|
|
197
225
|
return Component;
|
|
198
226
|
}, [
|
|
@@ -204,8 +232,6 @@ export const Loader = forwardRef(({ src, fallbackSrc, data = {}, basename, loadi
|
|
|
204
232
|
logService,
|
|
205
233
|
historyManager,
|
|
206
234
|
basename,
|
|
207
|
-
className,
|
|
208
|
-
dataAttrs,
|
|
209
235
|
eventBus,
|
|
210
236
|
]);
|
|
211
237
|
const LoadingFallback = useMemo(() => () => {
|
|
@@ -220,6 +246,6 @@ export const Loader = forwardRef(({ src, fallbackSrc, data = {}, basename, loadi
|
|
|
220
246
|
}
|
|
221
247
|
return _jsx("h2", { children: "Something went wrong" });
|
|
222
248
|
}, [errorFallback]);
|
|
223
|
-
return (_jsxs(ErrorBoundary, Object.assign({ moduleName: src, fallback: ErrorFallback }, { children: [isLoading && _jsx(LoadingFallback, {}), _jsx(Suspense, Object.assign({ fallback: null }, { children: _jsx(Loader, { ref: ref }) }))] })));
|
|
249
|
+
return (_jsxs(ErrorBoundary, Object.assign({ moduleName: src, fallback: ErrorFallback }, { children: [isLoading && _jsx(LoadingFallback, {}), _jsx(Suspense, Object.assign({ fallback: null }, { children: _jsx(Loader, { ref: ref, data: data, className: className }) }))] })));
|
|
224
250
|
});
|
|
225
251
|
//# sourceMappingURL=loader.js.map
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EACH,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,OAAO,EACP,QAAQ,EACR,UAAU,EACV,mBAAmB,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context used to pass data from the host to the MFEs
|
|
3
|
+
*/
|
|
4
|
+
/// <reference types="react" />
|
|
5
|
+
declare type JSONPrimitive = string | number | boolean | null | undefined;
|
|
6
|
+
declare type JSON = {
|
|
7
|
+
[key: string]: JSONPrimitive | JSON[] | JSON;
|
|
8
|
+
};
|
|
9
|
+
export declare type MFEContextData<T> = {
|
|
10
|
+
[P in keyof T]: T[P] extends JSONPrimitive ? T[P] : T[P] extends (infer U)[] ? MFEContextData<U>[] : T[P] extends JSON ? MFEContextData<T[P]> : never;
|
|
11
|
+
};
|
|
12
|
+
export declare const MFEDataContext: import("react").Context<JSON>;
|
|
13
|
+
export declare function useMFEDataContext<T extends MFEContextData<T>>(): T;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=mfe-data-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mfe-data-context.d.ts","sourceRoot":"","sources":["../src/mfe-data-context.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAIH,aAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAGlE,aAAK,IAAI,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;CAAE,CAAC;AAG7D,oBAAY,cAAc,CAAC,CAAC,IAAI;KAC3B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,GACpC,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACxB,cAAc,CAAC,CAAC,CAAC,EAAE,GACnB,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,GACjB,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACpB,KAAK;CACd,CAAC;AAEF,eAAO,MAAM,cAAc,+BAA0B,CAAC;AAEtD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,cAAc,CAAC,CAAC,CAAC,OAQ5D"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context used to pass data from the host to the MFEs
|
|
3
|
+
*/
|
|
4
|
+
import { createContext, useContext } from 'react';
|
|
5
|
+
export const MFEDataContext = createContext({});
|
|
6
|
+
export function useMFEDataContext() {
|
|
7
|
+
const context = useContext(MFEDataContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error('useMFEDataContext must be used within a MFEDataContext.Provider');
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=mfe-data-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mfe-data-context.js","sourceRoot":"","sources":["../src/mfe-data-context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAkBlD,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAO,EAAE,CAAC,CAAC;AAEtD,MAAM,UAAU,iBAAiB;IAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,cAAc,CAAM,CAAC;IAEhD,IAAI,CAAC,OAAO,EAAE;QACV,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;KACtF;IAED,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
package/dist/register.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAM,aAAa,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAM,aAAa,EAAE,MAAM,OAAO,CAAC;AAmC1C,wBAAgB,QAAQ,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,QA6LhE"}
|
package/dist/register.js
CHANGED
|
@@ -7,6 +7,7 @@ import { EXPOSED_DEPENDENCIES_TOKEN, BASENAME_TOKEN, IS_WEB_COMPONENT_TOKEN, REN
|
|
|
7
7
|
import { EVENT_BUS_TOKEN } from './event-bus';
|
|
8
8
|
import { HistoryManager } from './history-manager';
|
|
9
9
|
import { WEB_COMPONENT_NAME } from './globals';
|
|
10
|
+
import { MFEDataContext } from './mfe-data-context';
|
|
10
11
|
function createLink(url, onLoad) {
|
|
11
12
|
const element = document.createElement('link');
|
|
12
13
|
element.href = url;
|
|
@@ -126,19 +127,36 @@ export function register(Component, light) {
|
|
|
126
127
|
configurable: true,
|
|
127
128
|
writable: true,
|
|
128
129
|
value: () => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
130
|
+
/*
|
|
131
|
+
* Check for this.root first, otherwise we get error when
|
|
132
|
+
* attributeChangedCallback happens on load
|
|
133
|
+
*/
|
|
134
|
+
if (this.root) {
|
|
135
|
+
const mfeData = this.dataset.mfeData
|
|
136
|
+
? /*
|
|
137
|
+
* Data was stringified in order to come through the data-mfe-data attribute
|
|
138
|
+
* So we must JSON.parse it here to get an object back
|
|
139
|
+
*/
|
|
140
|
+
JSON.parse(this.dataset.mfeData)
|
|
141
|
+
: /*
|
|
142
|
+
* If mfeData isn't there, then the Host may not be up to date with web-components
|
|
143
|
+
* and is instead passing data through separate data-attributes, so we want to
|
|
144
|
+
* spread all of those instead
|
|
145
|
+
*/ Object.assign({}, this.dataset);
|
|
146
|
+
render(_jsx(Provider, Object.assign({ singletons: [
|
|
147
|
+
{ provide: IS_WEB_COMPONENT_TOKEN, useValue: true },
|
|
148
|
+
{ provide: RENDER_ROOT_TOKEN, useValue: this.root },
|
|
149
|
+
] }, { children: _jsx(DefaultPortalContext.Provider, Object.assign({ value: this.portal }, { children: _jsx(TablePopupPropsContext.Provider, Object.assign({ value: props => (Object.assign(Object.assign({}, props), { appendTo: this.root })) }, { children: _jsx(Provider, Object.assign({ singletons: [
|
|
150
|
+
{ provide: Log, useValue: this.logService },
|
|
151
|
+
{ provide: HistoryManager, useValue: this.historyManager },
|
|
152
|
+
{
|
|
153
|
+
provide: EXPOSED_DEPENDENCIES_TOKEN,
|
|
154
|
+
useValue: this.exposedDependencies,
|
|
155
|
+
},
|
|
156
|
+
{ provide: EVENT_BUS_TOKEN, useValue: this.eventBus },
|
|
157
|
+
{ provide: BASENAME_TOKEN, useValue: this.basename },
|
|
158
|
+
].filter(({ useValue }) => useValue !== undefined) }, { children: _jsx(MFEDataContext.Provider, Object.assign({ value: Object.assign({}, mfeData) }, { children: _jsx(Component, Object.assign({}, mfeData)) })) })) })) })) })), this.root, this.onReady);
|
|
159
|
+
}
|
|
142
160
|
}
|
|
143
161
|
});
|
|
144
162
|
}
|
|
@@ -167,6 +185,12 @@ export function register(Component, light) {
|
|
|
167
185
|
elements: [],
|
|
168
186
|
};
|
|
169
187
|
this.root = (_c = this.shadowRoot) !== null && _c !== void 0 ? _c : this.attachShadow({ mode: 'open' });
|
|
188
|
+
/*
|
|
189
|
+
* Portal shadow dom is created at the bottom of the body in order to be used as
|
|
190
|
+
* the element for the design system components to attach modals and popups to.
|
|
191
|
+
* This element is passed down the tree through context, and used within
|
|
192
|
+
* the design system components.
|
|
193
|
+
*/
|
|
170
194
|
this.portal = document.body
|
|
171
195
|
.appendChild(document.createElement('div'))
|
|
172
196
|
.attachShadow({ mode: 'open' });
|
|
@@ -188,6 +212,13 @@ export function register(Component, light) {
|
|
|
188
212
|
this.portal = undefined;
|
|
189
213
|
(_b = this.onDispose) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
190
214
|
}
|
|
215
|
+
// Observe changes to the data-mfe-data attribute so that we can re-render when it changes
|
|
216
|
+
static get observedAttributes() {
|
|
217
|
+
return ['data-mfe-data'];
|
|
218
|
+
}
|
|
219
|
+
attributeChangedCallback() {
|
|
220
|
+
this.render();
|
|
221
|
+
}
|
|
191
222
|
}
|
|
192
223
|
if (!WEB_COMPONENT_NAME) {
|
|
193
224
|
// eslint-disable-next-line no-console
|
package/dist/register.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,GAAG,EAAE,MAAM,2BAA2B,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAEH,0BAA0B,EAG1B,cAAc,EACd,sBAAsB,EACtB,iBAAiB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAY,eAAe,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/web-components",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.12.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,15 +15,18 @@
|
|
|
15
15
|
"src"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@servicetitan/error-boundary": "22.
|
|
18
|
+
"@servicetitan/error-boundary": "22.12.0",
|
|
19
19
|
"lodash.get": "~4.4.2",
|
|
20
20
|
"mitt": "~3.0.1",
|
|
21
21
|
"semver": "~7.5.4"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@servicetitan/design-system": "~12.6.2",
|
|
25
|
-
"@servicetitan/log-service": "22.
|
|
26
|
-
"@servicetitan/react-ioc": "22.
|
|
25
|
+
"@servicetitan/log-service": "22.12.0",
|
|
26
|
+
"@servicetitan/react-ioc": "22.12.0",
|
|
27
|
+
"@testing-library/dom": "^8.20.1",
|
|
28
|
+
"@testing-library/jest-dom": "^6.1.2",
|
|
29
|
+
"@testing-library/react": "^12.1.5",
|
|
27
30
|
"@types/history": "~4.7.10",
|
|
28
31
|
"@types/lodash.get": "~4.4.6",
|
|
29
32
|
"@types/react": "~17.0.38",
|
|
@@ -31,12 +34,13 @@
|
|
|
31
34
|
"@types/semver": "~7.5.0",
|
|
32
35
|
"history": "~4.10.1",
|
|
33
36
|
"react": "~17.0.2",
|
|
34
|
-
"react-dom": "~17.0.2"
|
|
37
|
+
"react-dom": "~17.0.2",
|
|
38
|
+
"shadow-dom-testing-library": "^1.11.0"
|
|
35
39
|
},
|
|
36
40
|
"peerDependencies": {
|
|
37
41
|
"@servicetitan/design-system": "~12.6.2",
|
|
38
|
-
"@servicetitan/log-service": "22.
|
|
39
|
-
"@servicetitan/react-ioc": "22.
|
|
42
|
+
"@servicetitan/log-service": "22.12.0",
|
|
43
|
+
"@servicetitan/react-ioc": "22.12.0",
|
|
40
44
|
"history": "~4.10.1",
|
|
41
45
|
"react": "~17.0.2",
|
|
42
46
|
"react-dom": "~17.0.2"
|
|
@@ -47,5 +51,5 @@
|
|
|
47
51
|
"cli": {
|
|
48
52
|
"webpack": false
|
|
49
53
|
},
|
|
50
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "73052543a3a2d1341bf4ca7877fcbc1c7ad86391"
|
|
51
55
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// eslint-disable-next-line @servicetitan/react/destructure-default-import
|
|
2
|
+
import React, { FC } from 'react';
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import { screen } from 'shadow-dom-testing-library';
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
|
+
|
|
7
|
+
import { register } from '../register';
|
|
8
|
+
import { IWebComponent } from '../common';
|
|
9
|
+
import { useMFEDataContext } from '../mfe-data-context';
|
|
10
|
+
|
|
11
|
+
describe(`[web-component] ${register.name}`, () => {
|
|
12
|
+
const Component: any = WEB_COMPONENT_NAME;
|
|
13
|
+
const handleRef = (webComponent: IWebComponent | null) => {
|
|
14
|
+
webComponent?.provide({
|
|
15
|
+
onReady: () => {},
|
|
16
|
+
onDispose: () => {},
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const TestComponent: FC<Record<string, any>> = props => {
|
|
20
|
+
const data = useMFEDataContext();
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
{Object.entries(props).map(([name, value]) => (
|
|
24
|
+
<span key={name}>{`Prop: ${name}, Value: ${JSON.stringify(value)}`}</span>
|
|
25
|
+
))}
|
|
26
|
+
{Object.entries(data).map(([name, value]) => (
|
|
27
|
+
<span key={name}>{`Data: ${name}, Value: ${JSON.stringify(value)}`}</span>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
beforeAll(() => {
|
|
34
|
+
/*
|
|
35
|
+
* This register can only happen once, unfortunately. So the TestComponent needs to
|
|
36
|
+
* work for all tests. If ran more than once, window.customElements.define will throw
|
|
37
|
+
* the error: "NotSupportedError: This name has already been registered in the registry."
|
|
38
|
+
*
|
|
39
|
+
* The other issue is that the global WEB_COMPONENT_NAME can only be set in the jest config
|
|
40
|
+
* via package.json, so we can only have one WEB_COMPONENT_NAME name for the test suite.
|
|
41
|
+
*
|
|
42
|
+
* Also note that there is not way to "unregister" a web component, so an afterAll
|
|
43
|
+
* cannot be used.
|
|
44
|
+
*/
|
|
45
|
+
register(TestComponent, true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const subject = (props: Record<string, any>) => {
|
|
49
|
+
const data = props && { 'data-mfe-data': JSON.stringify(props) };
|
|
50
|
+
return render(<Component ref={handleRef} {...data} />);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe('when component has custom data-attributes', () => {
|
|
54
|
+
const props = {
|
|
55
|
+
string: 'foo',
|
|
56
|
+
array: JSON.stringify(['foo', 'bar']),
|
|
57
|
+
object: JSON.stringify({ foo: 'bar' }),
|
|
58
|
+
objectNotStringified: { foo: 'bar' },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
it('passes data attributes as props', () => {
|
|
62
|
+
subject(props);
|
|
63
|
+
|
|
64
|
+
Object.entries(props).forEach(([name, value]) =>
|
|
65
|
+
expect(
|
|
66
|
+
screen.getByShadowText(`Prop: ${name}, Value: ${JSON.stringify(value)}`)
|
|
67
|
+
).toBeInTheDocument()
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('useMFEDataContext exposes data attributes', () => {
|
|
72
|
+
subject(props);
|
|
73
|
+
|
|
74
|
+
Object.entries(props).forEach(([name, value]) =>
|
|
75
|
+
expect(
|
|
76
|
+
screen.getByShadowText(`Data: ${name}, Value: ${JSON.stringify(value)}`)
|
|
77
|
+
).toBeInTheDocument()
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('when the web component data attr is changed', () => {
|
|
82
|
+
const setup = () => {
|
|
83
|
+
subject(props);
|
|
84
|
+
|
|
85
|
+
const webComponent = document.getElementsByTagName(Component);
|
|
86
|
+
webComponent[0]?.setAttribute(
|
|
87
|
+
'data-mfe-data',
|
|
88
|
+
JSON.stringify({ ...props, string: 'baz' })
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
test('useMFEDataContext provides updated data', () => {
|
|
93
|
+
setup();
|
|
94
|
+
|
|
95
|
+
expect(screen.getByShadowText(`Prop: string, Value: "baz"`)).toBeInTheDocument();
|
|
96
|
+
expect(screen.getByShadowText(`Data: string, Value: "baz"`)).toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from './common';
|
|
2
2
|
export * from './event-bus';
|
|
3
3
|
export * from './history-manager';
|
|
4
|
+
// Specific exports below in order to exclude `MFEContextData` from being included in the bundle
|
|
5
|
+
export { useMFEDataContext } from './mfe-data-context';
|
|
4
6
|
export * from './register';
|
|
5
7
|
export * from './loader';
|
package/src/loader.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
useImperativeHandle,
|
|
9
9
|
ReactElement,
|
|
10
10
|
ReactNode,
|
|
11
|
+
Ref,
|
|
11
12
|
} from 'react';
|
|
12
13
|
|
|
13
14
|
import semver from 'semver';
|
|
@@ -30,6 +31,7 @@ import { EventBus, EVENT_BUS_TOKEN, useEventBus } from './event-bus';
|
|
|
30
31
|
import { HistoryManager } from './history-manager';
|
|
31
32
|
import { EXPOSED_DEPENDENCIES } from './globals';
|
|
32
33
|
import { getVersionMismatches, isVersionedUrl } from './utils';
|
|
34
|
+
import { MFEContextData } from './mfe-data-context';
|
|
33
35
|
|
|
34
36
|
interface EntryPoints {
|
|
35
37
|
css: string[];
|
|
@@ -114,6 +116,9 @@ async function getBundleInfo(
|
|
|
114
116
|
return `${exactPackageUrl}/dist/bundle/${bundleType}/${path}`;
|
|
115
117
|
};
|
|
116
118
|
|
|
119
|
+
// Check if the MFE's startup supports re-rendering the MFE component when data changes
|
|
120
|
+
const supportWatchForDataChanges = startupVersion && semver.gte(startupVersion, '22.12.0');
|
|
121
|
+
|
|
117
122
|
let entrypoints: EntryPoints;
|
|
118
123
|
|
|
119
124
|
if (metadata.entrypoints?.[bundleType]) {
|
|
@@ -137,15 +142,17 @@ async function getBundleInfo(
|
|
|
137
142
|
}
|
|
138
143
|
},
|
|
139
144
|
mismatch: hasMismatch ? mismatch : undefined,
|
|
145
|
+
supportWatchForDataChanges,
|
|
140
146
|
};
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
export type LoaderRef = EventBus;
|
|
144
150
|
|
|
145
|
-
export interface LoaderProps {
|
|
151
|
+
export interface LoaderProps<T> {
|
|
146
152
|
src: string;
|
|
147
153
|
fallbackSrc?: string;
|
|
148
|
-
|
|
154
|
+
/** Values in the object will be stringified and then parsed before being delivered to the MFE via props or context. */
|
|
155
|
+
data?: MFEContextData<T>;
|
|
149
156
|
basename?: string;
|
|
150
157
|
loadingFallback?: NonNullable<ReactNode> | null;
|
|
151
158
|
errorFallback?: NonNullable<ReactNode> | null;
|
|
@@ -154,214 +161,262 @@ export interface LoaderProps {
|
|
|
154
161
|
onRequestError?(error: GetJsonError): boolean;
|
|
155
162
|
}
|
|
156
163
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
bundleInfo = await getBundleInfo(
|
|
218
|
-
src,
|
|
219
|
-
fallbackSrc,
|
|
220
|
-
exposedDependencies,
|
|
221
|
-
cancelation.signal,
|
|
222
|
-
retries,
|
|
223
|
-
onRequestError
|
|
224
|
-
);
|
|
225
|
-
} catch (e) {
|
|
226
|
-
if (cancelation.signal.aborted) {
|
|
227
|
-
return {
|
|
228
|
-
default: () => null,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
throw e;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const { urls, WebComponent, disposer, mismatch } = bundleInfo;
|
|
236
|
-
|
|
237
|
-
if (mismatch) {
|
|
238
|
-
logService?.warning({
|
|
239
|
-
category: 'MicroFrontends.DependenciesMismatch',
|
|
240
|
-
message:
|
|
241
|
-
'Some of the package dependencies have incompatible versions.',
|
|
242
|
-
data: {
|
|
243
|
-
package: src,
|
|
244
|
-
dependencies: JSON.stringify(mismatch),
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
await Promise.all(
|
|
250
|
-
urls.js.map(url => {
|
|
251
|
-
const script = Array.from(document.scripts).find(
|
|
252
|
-
({ src }) => src === url
|
|
164
|
+
type DataProps = Pick<LoaderProps<{}>, 'data' | 'className'>;
|
|
165
|
+
|
|
166
|
+
// Type complexity below is required to pass a generic type through forwardRef
|
|
167
|
+
export const Loader: <T>(props: LoaderProps<T> & { ref?: Ref<LoaderRef> }) => ReactElement | null =
|
|
168
|
+
forwardRef<LoaderRef, LoaderProps<{}>>(
|
|
169
|
+
(
|
|
170
|
+
{
|
|
171
|
+
src,
|
|
172
|
+
fallbackSrc,
|
|
173
|
+
data = {},
|
|
174
|
+
basename,
|
|
175
|
+
loadingFallback,
|
|
176
|
+
errorFallback,
|
|
177
|
+
className,
|
|
178
|
+
retries,
|
|
179
|
+
onRequestError,
|
|
180
|
+
},
|
|
181
|
+
ref
|
|
182
|
+
) => {
|
|
183
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
184
|
+
|
|
185
|
+
const bus = useEventBus();
|
|
186
|
+
const [
|
|
187
|
+
logService,
|
|
188
|
+
historyManager,
|
|
189
|
+
exposedDependencies = EXPOSED_DEPENDENCIES,
|
|
190
|
+
eventBus = bus,
|
|
191
|
+
] = useOptionalDependencies(
|
|
192
|
+
Log,
|
|
193
|
+
HistoryManager,
|
|
194
|
+
EXPOSED_DEPENDENCIES_TOKEN,
|
|
195
|
+
EVENT_BUS_TOKEN
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const Loader = useMemo(() => {
|
|
199
|
+
const Component = forwardRef<LoaderRef, DataProps>((props: DataProps, ref) => {
|
|
200
|
+
const cancelation = useCancelation();
|
|
201
|
+
|
|
202
|
+
useImperativeHandle(ref, () => eventBus, []);
|
|
203
|
+
|
|
204
|
+
useEffect(() => {
|
|
205
|
+
setIsLoading(true);
|
|
206
|
+
|
|
207
|
+
return () => {
|
|
208
|
+
cancelation.abort();
|
|
209
|
+
};
|
|
210
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
211
|
+
|
|
212
|
+
const Lazy = useMemo(
|
|
213
|
+
() =>
|
|
214
|
+
lazy<(props: DataProps) => JSX.Element | null>(async () => {
|
|
215
|
+
let bundleInfo: Awaited<ReturnType<typeof getBundleInfo>>;
|
|
216
|
+
try {
|
|
217
|
+
bundleInfo = await getBundleInfo(
|
|
218
|
+
src,
|
|
219
|
+
fallbackSrc,
|
|
220
|
+
exposedDependencies,
|
|
221
|
+
cancelation.signal,
|
|
222
|
+
retries,
|
|
223
|
+
onRequestError
|
|
253
224
|
);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
script.onload = () => {
|
|
260
|
-
script.dataset.webComponent = WebComponent;
|
|
261
|
-
resolve();
|
|
262
|
-
};
|
|
263
|
-
script.async = true;
|
|
264
|
-
script.src = url;
|
|
265
|
-
|
|
266
|
-
document.body.append(script);
|
|
267
|
-
});
|
|
268
|
-
} else if (!script.dataset.webComponent) {
|
|
269
|
-
return new Promise<void>(resolve => {
|
|
270
|
-
const originalOnload = script.onload;
|
|
271
|
-
script.onload = (...args) => {
|
|
272
|
-
originalOnload?.call(script, ...args);
|
|
273
|
-
resolve();
|
|
274
|
-
};
|
|
275
|
-
});
|
|
225
|
+
} catch (e) {
|
|
226
|
+
if (cancelation.signal.aborted) {
|
|
227
|
+
return {
|
|
228
|
+
default: () => null,
|
|
229
|
+
};
|
|
276
230
|
}
|
|
277
231
|
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
const handleRef = (webComponent: IWebComponent | null) => {
|
|
283
|
-
webComponent?.provide({
|
|
284
|
-
logService,
|
|
285
|
-
historyManager,
|
|
286
|
-
exposedDependencies,
|
|
287
|
-
eventBus,
|
|
288
|
-
basename,
|
|
289
|
-
onReady: () => {
|
|
290
|
-
setIsLoading(false);
|
|
291
|
-
},
|
|
292
|
-
onDispose: () => {
|
|
293
|
-
disposer();
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
return {
|
|
299
|
-
default: () => (
|
|
300
|
-
<WebComponent
|
|
301
|
-
ref={handleRef}
|
|
302
|
-
class={className}
|
|
303
|
-
{...(urls.css.length
|
|
304
|
-
? {
|
|
305
|
-
'style-urls': encodeURIComponent(
|
|
306
|
-
JSON.stringify(urls.css)
|
|
307
|
-
),
|
|
308
|
-
}
|
|
309
|
-
: {})}
|
|
310
|
-
{...dataAttrs}
|
|
311
|
-
/>
|
|
312
|
-
),
|
|
313
|
-
};
|
|
314
|
-
}),
|
|
315
|
-
[] // eslint-disable-line react-hooks/exhaustive-deps
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
return <Lazy />;
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
return Component;
|
|
322
|
-
}, [
|
|
323
|
-
src,
|
|
324
|
-
fallbackSrc,
|
|
325
|
-
exposedDependencies,
|
|
326
|
-
retries,
|
|
327
|
-
onRequestError,
|
|
328
|
-
logService,
|
|
329
|
-
historyManager,
|
|
330
|
-
basename,
|
|
331
|
-
className,
|
|
332
|
-
dataAttrs,
|
|
333
|
-
eventBus,
|
|
334
|
-
]);
|
|
335
|
-
|
|
336
|
-
const LoadingFallback = useMemo(
|
|
337
|
-
() => () => {
|
|
338
|
-
if (loadingFallback !== undefined) {
|
|
339
|
-
return loadingFallback as ReactElement;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return <h2>Loading...</h2>;
|
|
343
|
-
},
|
|
344
|
-
[loadingFallback]
|
|
345
|
-
);
|
|
232
|
+
throw e;
|
|
233
|
+
}
|
|
346
234
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
235
|
+
const {
|
|
236
|
+
urls,
|
|
237
|
+
WebComponent,
|
|
238
|
+
disposer,
|
|
239
|
+
mismatch,
|
|
240
|
+
supportWatchForDataChanges,
|
|
241
|
+
} = bundleInfo;
|
|
242
|
+
|
|
243
|
+
if (mismatch) {
|
|
244
|
+
logService?.warning({
|
|
245
|
+
category: 'MicroFrontends.DependenciesMismatch',
|
|
246
|
+
message:
|
|
247
|
+
'Some of the package dependencies have incompatible versions.',
|
|
248
|
+
data: {
|
|
249
|
+
package: src,
|
|
250
|
+
dependencies: JSON.stringify(mismatch),
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
}
|
|
352
254
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
255
|
+
await Promise.all(
|
|
256
|
+
urls.js.map(url => {
|
|
257
|
+
const script = Array.from(document.scripts).find(
|
|
258
|
+
({ src }) => src === url
|
|
259
|
+
);
|
|
260
|
+
if (!script) {
|
|
261
|
+
return new Promise<void>(resolve => {
|
|
262
|
+
const script = document.createElement('script');
|
|
263
|
+
|
|
264
|
+
script.crossOrigin = 'anonymous';
|
|
265
|
+
script.onload = () => {
|
|
266
|
+
script.dataset.webComponent = WebComponent;
|
|
267
|
+
resolve();
|
|
268
|
+
};
|
|
269
|
+
script.async = true;
|
|
270
|
+
script.src = url;
|
|
271
|
+
|
|
272
|
+
document.body.append(script);
|
|
273
|
+
});
|
|
274
|
+
} else if (!script.dataset.webComponent) {
|
|
275
|
+
return new Promise<void>(resolve => {
|
|
276
|
+
const originalOnload = script.onload;
|
|
277
|
+
script.onload = (...args) => {
|
|
278
|
+
originalOnload?.call(script, ...args);
|
|
279
|
+
resolve();
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return Promise.resolve();
|
|
285
|
+
})
|
|
286
|
+
);
|
|
357
287
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
288
|
+
const handleRef = (webComponent: IWebComponent | null) => {
|
|
289
|
+
webComponent?.provide({
|
|
290
|
+
logService,
|
|
291
|
+
historyManager,
|
|
292
|
+
exposedDependencies,
|
|
293
|
+
eventBus,
|
|
294
|
+
basename,
|
|
295
|
+
onReady: () => {
|
|
296
|
+
setIsLoading(false);
|
|
297
|
+
},
|
|
298
|
+
onDispose: () => {
|
|
299
|
+
disposer();
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
default: (props: DataProps) => {
|
|
306
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
307
|
+
const stringifiedData = useMemo(
|
|
308
|
+
() => JSON.stringify(props.data),
|
|
309
|
+
[props.data]
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
/*
|
|
313
|
+
* Set key for rendering the web component so that if the data from the Host change,
|
|
314
|
+
* and the MFE's version of startup doesn't support watching for data changes, then
|
|
315
|
+
* the web component will be re-mounted whenever the data changes.
|
|
316
|
+
* This is only used as a fallback when the MFE's version is older.
|
|
317
|
+
*/
|
|
318
|
+
const key = supportWatchForDataChanges
|
|
319
|
+
? undefined
|
|
320
|
+
: stringifiedData;
|
|
321
|
+
|
|
322
|
+
/*
|
|
323
|
+
* Convert camelCase data props to kebab-case data attributes, prepended with data-
|
|
324
|
+
* Ex: fooBar -> data-foo-bar
|
|
325
|
+
*/
|
|
326
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
327
|
+
const dataAttrs = useMemo(
|
|
328
|
+
() =>
|
|
329
|
+
supportWatchForDataChanges
|
|
330
|
+
? {}
|
|
331
|
+
: Object.fromEntries(
|
|
332
|
+
Object.entries(props.data ?? {}).map(
|
|
333
|
+
([key, value]) => [
|
|
334
|
+
'data-' +
|
|
335
|
+
key.replace(
|
|
336
|
+
/[A-Z]/g,
|
|
337
|
+
letter =>
|
|
338
|
+
'-' +
|
|
339
|
+
letter.toLowerCase()
|
|
340
|
+
),
|
|
341
|
+
value,
|
|
342
|
+
]
|
|
343
|
+
)
|
|
344
|
+
),
|
|
345
|
+
[props.data]
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
return (
|
|
349
|
+
<WebComponent
|
|
350
|
+
key={key}
|
|
351
|
+
ref={handleRef}
|
|
352
|
+
class={props.className}
|
|
353
|
+
{...(urls.css.length
|
|
354
|
+
? {
|
|
355
|
+
'style-urls': encodeURIComponent(
|
|
356
|
+
JSON.stringify(urls.css)
|
|
357
|
+
),
|
|
358
|
+
}
|
|
359
|
+
: {})}
|
|
360
|
+
/*
|
|
361
|
+
* Continue to spread data as separate data attributes for backwards compatibility,
|
|
362
|
+
* in case the Host has updated web-components, but the MFE has not
|
|
363
|
+
*/
|
|
364
|
+
{...dataAttrs}
|
|
365
|
+
// Stringify data object so that it can be passed as a data-attribute
|
|
366
|
+
data-mfe-data={stringifiedData}
|
|
367
|
+
/>
|
|
368
|
+
);
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}),
|
|
372
|
+
[] // eslint-disable-line react-hooks/exhaustive-deps
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
return <Lazy data={props.data} className={props.className} />;
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
return Component;
|
|
379
|
+
}, [
|
|
380
|
+
src,
|
|
381
|
+
fallbackSrc,
|
|
382
|
+
exposedDependencies,
|
|
383
|
+
retries,
|
|
384
|
+
onRequestError,
|
|
385
|
+
logService,
|
|
386
|
+
historyManager,
|
|
387
|
+
basename,
|
|
388
|
+
eventBus,
|
|
389
|
+
]);
|
|
390
|
+
|
|
391
|
+
const LoadingFallback = useMemo(
|
|
392
|
+
() => () => {
|
|
393
|
+
if (loadingFallback !== undefined) {
|
|
394
|
+
return loadingFallback as ReactElement;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return <h2>Loading...</h2>;
|
|
398
|
+
},
|
|
399
|
+
[loadingFallback]
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
const ErrorFallback = useMemo(
|
|
403
|
+
() => () => {
|
|
404
|
+
if (errorFallback !== undefined) {
|
|
405
|
+
return errorFallback as ReactElement;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return <h2>Something went wrong</h2>;
|
|
409
|
+
},
|
|
410
|
+
[errorFallback]
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<ErrorBoundary moduleName={src} fallback={ErrorFallback}>
|
|
415
|
+
{isLoading && <LoadingFallback />}
|
|
416
|
+
<Suspense fallback={null}>
|
|
417
|
+
<Loader ref={ref} data={data} className={className} />
|
|
418
|
+
</Suspense>
|
|
419
|
+
</ErrorBoundary>
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context used to pass data from the host to the MFEs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createContext, useContext } from 'react';
|
|
6
|
+
|
|
7
|
+
type JSONPrimitive = string | number | boolean | null | undefined;
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
10
|
+
type JSON = { [key: string]: JSONPrimitive | JSON[] | JSON };
|
|
11
|
+
|
|
12
|
+
// Type complexity below is required to support Interfaces being used
|
|
13
|
+
export type MFEContextData<T> = {
|
|
14
|
+
[P in keyof T]: T[P] extends JSONPrimitive
|
|
15
|
+
? T[P]
|
|
16
|
+
: T[P] extends (infer U)[]
|
|
17
|
+
? MFEContextData<U>[]
|
|
18
|
+
: T[P] extends JSON
|
|
19
|
+
? MFEContextData<T[P]>
|
|
20
|
+
: never;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const MFEDataContext = createContext<JSON>({});
|
|
24
|
+
|
|
25
|
+
export function useMFEDataContext<T extends MFEContextData<T>>() {
|
|
26
|
+
const context = useContext(MFEDataContext) as T;
|
|
27
|
+
|
|
28
|
+
if (!context) {
|
|
29
|
+
throw new Error('useMFEDataContext must be used within a MFEDataContext.Provider');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return context;
|
|
33
|
+
}
|
package/src/register.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { EventBus, EVENT_BUS_TOKEN } from './event-bus';
|
|
18
18
|
import { HistoryManager } from './history-manager';
|
|
19
19
|
import { WEB_COMPONENT_NAME } from './globals';
|
|
20
|
+
import { MFEDataContext } from './mfe-data-context';
|
|
20
21
|
|
|
21
22
|
function createLink(url: string, onLoad: () => void) {
|
|
22
23
|
const element = document.createElement('link');
|
|
@@ -80,6 +81,12 @@ export function register(Component: ComponentType, light: boolean) {
|
|
|
80
81
|
};
|
|
81
82
|
|
|
82
83
|
this.root = this.shadowRoot ?? this.attachShadow({ mode: 'open' });
|
|
84
|
+
/*
|
|
85
|
+
* Portal shadow dom is created at the bottom of the body in order to be used as
|
|
86
|
+
* the element for the design system components to attach modals and popups to.
|
|
87
|
+
* This element is passed down the tree through context, and used within
|
|
88
|
+
* the design system components.
|
|
89
|
+
*/
|
|
83
90
|
this.portal = document.body
|
|
84
91
|
.appendChild(document.createElement('div'))
|
|
85
92
|
.attachShadow({ mode: 'open' });
|
|
@@ -106,6 +113,15 @@ export function register(Component: ComponentType, light: boolean) {
|
|
|
106
113
|
this.onDispose?.();
|
|
107
114
|
}
|
|
108
115
|
|
|
116
|
+
// Observe changes to the data-mfe-data attribute so that we can re-render when it changes
|
|
117
|
+
static get observedAttributes() {
|
|
118
|
+
return ['data-mfe-data'];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
attributeChangedCallback() {
|
|
122
|
+
this.render();
|
|
123
|
+
}
|
|
124
|
+
|
|
109
125
|
provide = (entries: Entries) => {
|
|
110
126
|
for (const [key, value] of Object.entries(entries)) {
|
|
111
127
|
this[key as keyof IWebComponent] = value;
|
|
@@ -139,40 +155,63 @@ export function register(Component: ComponentType, light: boolean) {
|
|
|
139
155
|
};
|
|
140
156
|
|
|
141
157
|
private render = () => {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
/*
|
|
159
|
+
* Check for this.root first, otherwise we get error when
|
|
160
|
+
* attributeChangedCallback happens on load
|
|
161
|
+
*/
|
|
162
|
+
if (this.root) {
|
|
163
|
+
const mfeData = this.dataset.mfeData
|
|
164
|
+
? /*
|
|
165
|
+
* Data was stringified in order to come through the data-mfe-data attribute
|
|
166
|
+
* So we must JSON.parse it here to get an object back
|
|
167
|
+
*/
|
|
168
|
+
JSON.parse(this.dataset.mfeData)
|
|
169
|
+
: /*
|
|
170
|
+
* If mfeData isn't there, then the Host may not be up to date with web-components
|
|
171
|
+
* and is instead passing data through separate data-attributes, so we want to
|
|
172
|
+
* spread all of those instead
|
|
173
|
+
*/
|
|
174
|
+
{ ...this.dataset };
|
|
175
|
+
|
|
176
|
+
render(
|
|
177
|
+
<Provider
|
|
178
|
+
singletons={[
|
|
179
|
+
{ provide: IS_WEB_COMPONENT_TOKEN, useValue: true },
|
|
180
|
+
{ provide: RENDER_ROOT_TOKEN, useValue: this.root },
|
|
181
|
+
]}
|
|
182
|
+
>
|
|
183
|
+
<DefaultPortalContext.Provider
|
|
184
|
+
value={this.portal as unknown as HTMLElement}
|
|
155
185
|
>
|
|
156
|
-
<Provider
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
provide: EXPOSED_DEPENDENCIES_TOKEN,
|
|
162
|
-
useValue: this.exposedDependencies,
|
|
163
|
-
},
|
|
164
|
-
{ provide: EVENT_BUS_TOKEN, useValue: this.eventBus },
|
|
165
|
-
{ provide: BASENAME_TOKEN, useValue: this.basename },
|
|
166
|
-
].filter(({ useValue }) => useValue !== undefined)}
|
|
186
|
+
<TablePopupPropsContext.Provider
|
|
187
|
+
value={props => ({
|
|
188
|
+
...props,
|
|
189
|
+
appendTo: this.root as unknown as HTMLElement,
|
|
190
|
+
})}
|
|
167
191
|
>
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
192
|
+
<Provider
|
|
193
|
+
singletons={[
|
|
194
|
+
{ provide: Log, useValue: this.logService },
|
|
195
|
+
{ provide: HistoryManager, useValue: this.historyManager },
|
|
196
|
+
{
|
|
197
|
+
provide: EXPOSED_DEPENDENCIES_TOKEN,
|
|
198
|
+
useValue: this.exposedDependencies,
|
|
199
|
+
},
|
|
200
|
+
{ provide: EVENT_BUS_TOKEN, useValue: this.eventBus },
|
|
201
|
+
{ provide: BASENAME_TOKEN, useValue: this.basename },
|
|
202
|
+
].filter(({ useValue }) => useValue !== undefined)}
|
|
203
|
+
>
|
|
204
|
+
<MFEDataContext.Provider value={{ ...mfeData }}>
|
|
205
|
+
<Component {...mfeData} />
|
|
206
|
+
</MFEDataContext.Provider>
|
|
207
|
+
</Provider>
|
|
208
|
+
</TablePopupPropsContext.Provider>
|
|
209
|
+
</DefaultPortalContext.Provider>
|
|
210
|
+
</Provider>,
|
|
211
|
+
this.root!,
|
|
212
|
+
this.onReady
|
|
213
|
+
);
|
|
214
|
+
}
|
|
176
215
|
};
|
|
177
216
|
}
|
|
178
217
|
|