@servicetitan/web-components 28.1.0 → 28.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common.d.ts +10 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +1 -0
- package/dist/common.js.map +1 -1
- package/dist/get-value-for-environment.d.ts +4 -0
- package/dist/get-value-for-environment.d.ts.map +1 -0
- package/dist/get-value-for-environment.js +26 -0
- package/dist/get-value-for-environment.js.map +1 -0
- package/dist/globals.d.ts +4 -3
- package/dist/globals.d.ts.map +1 -1
- package/dist/globals.js +4 -2
- package/dist/globals.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +40 -9
- package/dist/loader.js.map +1 -1
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +21 -4
- package/dist/register.js.map +1 -1
- package/dist/utils/get-bundle-info.d.ts +13 -2
- package/dist/utils/get-bundle-info.d.ts.map +1 -1
- package/dist/utils/get-bundle-info.js +3 -1
- package/dist/utils/get-bundle-info.js.map +1 -1
- package/dist/utils/get-ld-service-token.d.ts +4 -0
- package/dist/utils/get-ld-service-token.d.ts.map +1 -0
- package/dist/utils/get-ld-service-token.js +11 -0
- package/dist/utils/get-ld-service-token.js.map +1 -0
- package/dist/utils/get-mfe-has-compatible-launchdarkly-version.d.ts +11 -0
- package/dist/utils/get-mfe-has-compatible-launchdarkly-version.d.ts.map +1 -0
- package/dist/utils/get-mfe-has-compatible-launchdarkly-version.js +16 -0
- package/dist/utils/get-mfe-has-compatible-launchdarkly-version.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/validate-bundle-info.d.ts +7 -4
- package/dist/utils/validate-bundle-info.d.ts.map +1 -1
- package/dist/utils/validate-bundle-info.js +30 -12
- package/dist/utils/validate-bundle-info.js.map +1 -1
- package/dist/utils/web-component.d.ts +4 -1
- package/dist/utils/web-component.d.ts.map +1 -1
- package/dist/utils/web-component.js +3 -1
- package/dist/utils/web-component.js.map +1 -1
- package/package.json +14 -9
- package/src/__tests__/get-value-for-environment.test.ts +77 -0
- package/src/__tests__/globals.test.ts +4 -8
- package/src/__tests__/loader.test.tsx +112 -13
- package/src/common.ts +10 -0
- package/src/get-value-for-environment.ts +42 -0
- package/src/globals.ts +12 -3
- package/src/index.ts +3 -2
- package/src/loader.tsx +56 -11
- package/src/register.tsx +20 -7
- package/src/utils/__tests__/get-mfe-has-compatible-launchdarkly-version.test.ts +54 -0
- package/src/utils/get-bundle-info.ts +25 -9
- package/src/utils/get-ld-service-token.ts +13 -0
- package/src/utils/get-mfe-has-compatible-launchdarkly-version.ts +20 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/validate-bundle-info.ts +40 -19
- package/src/utils/web-component.tsx +15 -2
package/src/loader.tsx
CHANGED
|
@@ -9,23 +9,27 @@ import {
|
|
|
9
9
|
useMemo,
|
|
10
10
|
} from 'react';
|
|
11
11
|
import { ErrorBoundary } from '@servicetitan/error-boundary';
|
|
12
|
+
import { type LDService } from '@servicetitan/launchdarkly-service';
|
|
12
13
|
import { Log } from '@servicetitan/log-service';
|
|
13
14
|
import { useOptionalDependencies } from '@servicetitan/react-ioc';
|
|
14
15
|
|
|
15
16
|
import {
|
|
16
17
|
EXPOSED_DEPENDENCIES_TOKEN,
|
|
18
|
+
EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,
|
|
17
19
|
ExposedDependencies,
|
|
20
|
+
ExposedInstanceDependencies,
|
|
18
21
|
GetJsonError,
|
|
19
22
|
useCancelation,
|
|
20
23
|
} from './common';
|
|
21
24
|
import { MFEContextData } from './contexts/mfe-data-context';
|
|
22
25
|
import { Delayed } from './delayed';
|
|
23
26
|
import { EventBus, EVENT_BUS_TOKEN, useEventBus } from './event-bus';
|
|
24
|
-
import { EXPOSED_DEPENDENCIES } from './globals';
|
|
27
|
+
import { EXPOSED_DEPENDENCIES, EXPOSED_INSTANCE_DEPENDENCIES } from './globals';
|
|
25
28
|
import {
|
|
26
29
|
BundleInfo,
|
|
27
30
|
TtlCache,
|
|
28
31
|
getBundleInfo,
|
|
32
|
+
getLDServiceToken,
|
|
29
33
|
validateBundleInfo,
|
|
30
34
|
loadScripts,
|
|
31
35
|
webComponent,
|
|
@@ -59,8 +63,18 @@ export const Loader = forwardRef<LoaderRef, LoaderProps<{}>>((props, ref) => {
|
|
|
59
63
|
const { loadingFallback, loadingFallbackDelayed = true } = props;
|
|
60
64
|
|
|
61
65
|
const bus = useEventBus();
|
|
62
|
-
const [
|
|
63
|
-
|
|
66
|
+
const [
|
|
67
|
+
logService,
|
|
68
|
+
exposedDependencies = EXPOSED_DEPENDENCIES,
|
|
69
|
+
exposedInstanceDependencies = EXPOSED_INSTANCE_DEPENDENCIES,
|
|
70
|
+
eventBus = bus,
|
|
71
|
+
] = useOptionalDependencies(
|
|
72
|
+
Log,
|
|
73
|
+
EXPOSED_DEPENDENCIES_TOKEN,
|
|
74
|
+
EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,
|
|
75
|
+
EVENT_BUS_TOKEN
|
|
76
|
+
);
|
|
77
|
+
const [ldService] = useOptionalDependencies(getLDServiceToken() ?? Symbol());
|
|
64
78
|
const cancelation = useCancelation();
|
|
65
79
|
|
|
66
80
|
const LoadingFallback = useMemo(() => {
|
|
@@ -73,6 +87,8 @@ export const Loader = forwardRef<LoaderRef, LoaderProps<{}>>((props, ref) => {
|
|
|
73
87
|
return getFallback(props.errorFallback, message);
|
|
74
88
|
}, [props.errorFallback, src]);
|
|
75
89
|
|
|
90
|
+
ensureLDService(exposedInstanceDependencies, ldService);
|
|
91
|
+
|
|
76
92
|
const Loader = useMemo(
|
|
77
93
|
() =>
|
|
78
94
|
lazyLoader({
|
|
@@ -80,6 +96,7 @@ export const Loader = forwardRef<LoaderRef, LoaderProps<{}>>((props, ref) => {
|
|
|
80
96
|
cache,
|
|
81
97
|
cancelation,
|
|
82
98
|
exposedDependencies,
|
|
99
|
+
exposedInstanceDependencies,
|
|
83
100
|
eventBus,
|
|
84
101
|
fallbackSrc,
|
|
85
102
|
logService,
|
|
@@ -92,6 +109,7 @@ export const Loader = forwardRef<LoaderRef, LoaderProps<{}>>((props, ref) => {
|
|
|
92
109
|
cache,
|
|
93
110
|
cancelation,
|
|
94
111
|
exposedDependencies,
|
|
112
|
+
exposedInstanceDependencies,
|
|
95
113
|
eventBus,
|
|
96
114
|
logService,
|
|
97
115
|
onRequestError,
|
|
@@ -119,6 +137,7 @@ export const Loader = forwardRef<LoaderRef, LoaderProps<{}>>((props, ref) => {
|
|
|
119
137
|
type LazyLoaderProps = LoaderProps<any> & {
|
|
120
138
|
cancelation: AbortController;
|
|
121
139
|
exposedDependencies?: ExposedDependencies;
|
|
140
|
+
exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
122
141
|
eventBus: EventBus;
|
|
123
142
|
logService?: Log;
|
|
124
143
|
};
|
|
@@ -150,6 +169,7 @@ function lazyWebComponent(props: LazyLoaderProps) {
|
|
|
150
169
|
basename,
|
|
151
170
|
cancelation,
|
|
152
171
|
exposedDependencies,
|
|
172
|
+
exposedInstanceDependencies,
|
|
153
173
|
eventBus,
|
|
154
174
|
fallbackSrc,
|
|
155
175
|
logService,
|
|
@@ -160,18 +180,19 @@ function lazyWebComponent(props: LazyLoaderProps) {
|
|
|
160
180
|
|
|
161
181
|
let { cache } = props;
|
|
162
182
|
|
|
163
|
-
return lazy<(
|
|
183
|
+
return lazy<(_: LoaderDataProps) => JSX.Element | null>(async () => {
|
|
164
184
|
let bundleInfo: BundleInfo | undefined = cache ? bundleCache.get(src) : undefined;
|
|
165
185
|
if (!bundleInfo) {
|
|
166
186
|
try {
|
|
167
|
-
bundleInfo = await getBundleInfo(
|
|
168
|
-
src,
|
|
169
|
-
fallbackSrc,
|
|
187
|
+
bundleInfo = await getBundleInfo({
|
|
188
|
+
mainPackageUrl: src,
|
|
189
|
+
fallbackPackageUrl: fallbackSrc,
|
|
170
190
|
exposedDependencies,
|
|
171
|
-
|
|
191
|
+
exposedInstanceDependencies,
|
|
192
|
+
signal: cancelation.signal,
|
|
172
193
|
retries,
|
|
173
|
-
onRequestError
|
|
174
|
-
);
|
|
194
|
+
onRequestError,
|
|
195
|
+
});
|
|
175
196
|
} catch (e) {
|
|
176
197
|
if (cancelation.signal.aborted) {
|
|
177
198
|
return {
|
|
@@ -190,17 +211,28 @@ function lazyWebComponent(props: LazyLoaderProps) {
|
|
|
190
211
|
bundleCache.set(src, bundleInfo, typeof cache === 'number' ? cache : undefined);
|
|
191
212
|
}
|
|
192
213
|
|
|
193
|
-
validateBundleInfo(bundleInfo, {
|
|
214
|
+
validateBundleInfo(bundleInfo, {
|
|
215
|
+
exposedDependencies,
|
|
216
|
+
exposedInstanceDependencies,
|
|
217
|
+
logService,
|
|
218
|
+
packageUrl: src,
|
|
219
|
+
});
|
|
194
220
|
}
|
|
195
221
|
|
|
196
222
|
await loadScripts(bundleInfo);
|
|
197
223
|
|
|
224
|
+
const ldService = bundleInfo.mfeHasCompatibleLaunchDarklyVersion
|
|
225
|
+
? exposedInstanceDependencies?.launchDarkly?.ldService
|
|
226
|
+
: undefined;
|
|
227
|
+
|
|
198
228
|
return {
|
|
199
229
|
default: webComponent({
|
|
200
230
|
basename,
|
|
201
231
|
bundleInfo,
|
|
202
232
|
eventBus,
|
|
203
233
|
exposedDependencies,
|
|
234
|
+
exposedInstanceDependencies,
|
|
235
|
+
ldService,
|
|
204
236
|
logService,
|
|
205
237
|
}),
|
|
206
238
|
};
|
|
@@ -220,5 +252,18 @@ function isLocalHost(source: string) {
|
|
|
220
252
|
return ['localhost', '127.0.0.1'].some(host => source.indexOf(host) >= 0);
|
|
221
253
|
}
|
|
222
254
|
|
|
255
|
+
function ensureLDService(
|
|
256
|
+
exposedInstanceDependencies?: ExposedInstanceDependencies,
|
|
257
|
+
ldService?: LDService
|
|
258
|
+
) {
|
|
259
|
+
if (
|
|
260
|
+
exposedInstanceDependencies?.launchDarkly?.version &&
|
|
261
|
+
!exposedInstanceDependencies.launchDarkly.ldService &&
|
|
262
|
+
ldService
|
|
263
|
+
) {
|
|
264
|
+
exposedInstanceDependencies.launchDarkly.ldService = ldService;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
223
268
|
const MINUTE = 1000 * 60;
|
|
224
269
|
const bundleCache = new TtlCache<BundleInfo>({ ttlMs: 15 * MINUTE });
|
package/src/register.tsx
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { FC, ComponentType, ReactElement, useEffect } from 'react';
|
|
2
|
+
import { type LDService } from '@servicetitan/launchdarkly-service';
|
|
2
3
|
import { Log } from '@servicetitan/log-service';
|
|
3
4
|
import { Provider } from '@servicetitan/react-ioc';
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
|
-
ExposedDependencies,
|
|
7
|
-
EXPOSED_DEPENDENCIES_TOKEN,
|
|
8
|
-
Entries,
|
|
9
|
-
IWebComponent,
|
|
10
7
|
BASENAME_TOKEN,
|
|
8
|
+
EXPOSED_DEPENDENCIES_TOKEN,
|
|
9
|
+
EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,
|
|
11
10
|
IS_WEB_COMPONENT_TOKEN,
|
|
12
11
|
RENDER_ROOT_TOKEN,
|
|
12
|
+
Entries,
|
|
13
|
+
ExposedDependencies,
|
|
14
|
+
ExposedInstanceDependencies,
|
|
15
|
+
IWebComponent,
|
|
13
16
|
} from './common';
|
|
14
17
|
import { MFEDataContext } from './contexts/mfe-data-context';
|
|
15
18
|
import { MFEMetadataContext } from './contexts/mfe-metadata-context';
|
|
@@ -17,7 +20,7 @@ import { EventBus, EVENT_BUS_TOKEN } from './event-bus';
|
|
|
17
20
|
import { WEB_COMPONENT_NAME } from './globals';
|
|
18
21
|
import { HistoryManager } from './history-manager';
|
|
19
22
|
import { render } from './render';
|
|
20
|
-
import { getElementName } from './utils';
|
|
23
|
+
import { getElementName, getLDServiceToken } from './utils';
|
|
21
24
|
|
|
22
25
|
function createLink(url: string, onLoad: () => void) {
|
|
23
26
|
const element = document.createElement('link');
|
|
@@ -50,9 +53,11 @@ export function register(Component: ComponentType, light: boolean, options?: Reg
|
|
|
50
53
|
elements: HTMLElement[];
|
|
51
54
|
} = { total: 0, loaded: 0, elements: [] };
|
|
52
55
|
|
|
56
|
+
private ldService?: LDService;
|
|
53
57
|
private logService?: Log;
|
|
54
58
|
private historyManager?: HistoryManager;
|
|
55
59
|
private exposedDependencies?: ExposedDependencies;
|
|
60
|
+
private exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
56
61
|
private eventBus?: EventBus;
|
|
57
62
|
private basename?: string;
|
|
58
63
|
private onReady?: () => void;
|
|
@@ -246,9 +251,17 @@ export function register(Component: ComponentType, light: boolean, options?: Reg
|
|
|
246
251
|
provide: EXPOSED_DEPENDENCIES_TOKEN,
|
|
247
252
|
useValue: this.exposedDependencies,
|
|
248
253
|
},
|
|
249
|
-
{
|
|
254
|
+
{
|
|
255
|
+
provide: EXPOSED_INSTANCE_DEPENDENCIES_TOKEN,
|
|
256
|
+
useValue: this.exposedInstanceDependencies,
|
|
257
|
+
},
|
|
250
258
|
{ provide: BASENAME_TOKEN, useValue: this.basename },
|
|
251
|
-
|
|
259
|
+
{ provide: EVENT_BUS_TOKEN, useValue: this.eventBus },
|
|
260
|
+
{ provide: getLDServiceToken(), useValue: this.ldService },
|
|
261
|
+
].filter(
|
|
262
|
+
({ provide, useValue }) =>
|
|
263
|
+
useValue !== undefined && provide !== undefined
|
|
264
|
+
)}
|
|
252
265
|
>
|
|
253
266
|
<MFEDataContext.Provider value={{ ...mfeData }}>
|
|
254
267
|
<MFEMetadataContext.Provider value={metadata}>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ExposedInstanceDependencies } from '../../common';
|
|
2
|
+
import { Metadata } from '../get-bundle-info';
|
|
3
|
+
import { getMFEHasCompatibleLaunchDarklyVersion } from '../get-mfe-has-compatible-launchdarkly-version';
|
|
4
|
+
|
|
5
|
+
describe(`[web-components] ${getMFEHasCompatibleLaunchDarklyVersion.name}`, () => {
|
|
6
|
+
const version = '1.0.0';
|
|
7
|
+
let metadata: Pick<Metadata, 'bundledWith'>;
|
|
8
|
+
let exposedInstanceDependencies: ExposedInstanceDependencies;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
metadata = {
|
|
12
|
+
bundledWith: { 'launchdarkly-js-client-sdk': version },
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
function itReturns(value: boolean | undefined) {
|
|
17
|
+
test(`return ${value}`, () => {
|
|
18
|
+
expect(subject()).toBe(value);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const subject = () =>
|
|
23
|
+
getMFEHasCompatibleLaunchDarklyVersion(metadata.bundledWith, exposedInstanceDependencies);
|
|
24
|
+
|
|
25
|
+
describe('when host and MFE use same LaunchDarkly version', () => {
|
|
26
|
+
beforeEach(() => (exposedInstanceDependencies = { launchDarkly: { version } }));
|
|
27
|
+
|
|
28
|
+
itReturns(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('when host uses different LaunchDarkly version', () => {
|
|
32
|
+
beforeEach(() => (exposedInstanceDependencies = { launchDarkly: { version: '1.0.1' } }));
|
|
33
|
+
|
|
34
|
+
itReturns(false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('when host does not use LaunchDarkly', () => {
|
|
38
|
+
beforeEach(() => (exposedInstanceDependencies = {}));
|
|
39
|
+
|
|
40
|
+
itReturns(undefined);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('when MFE does not use LaunchDarkly', () => {
|
|
44
|
+
beforeEach(() => (metadata.bundledWith = {}));
|
|
45
|
+
|
|
46
|
+
itReturns(undefined);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('when metadata omits "bundledWith"', () => {
|
|
50
|
+
beforeEach(() => delete metadata.bundledWith);
|
|
51
|
+
|
|
52
|
+
itReturns(undefined);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
2
|
import get from 'lodash.get';
|
|
3
3
|
|
|
4
|
-
import { ExposedDependencies, getJson, GetJsonError } from '../common';
|
|
4
|
+
import { ExposedDependencies, ExposedInstanceDependencies, getJson, GetJsonError } from '../common';
|
|
5
5
|
import { EntryPoints, getEntrypoints } from './get-entry-points';
|
|
6
6
|
import { getMFESupportsRerendering } from './get-mfe-supports-rerendering';
|
|
7
7
|
import { getVersionMismatches } from './get-version-mismatches';
|
|
8
8
|
import { isVersionedUrl } from './is-versioned-url';
|
|
9
|
+
import { getMFEHasCompatibleLaunchDarklyVersion } from './get-mfe-has-compatible-launchdarkly-version';
|
|
9
10
|
import { getMFEHasUniqueChunkNamespace } from './get-mfe-has-unique-chunk-namespace';
|
|
10
11
|
|
|
11
12
|
export interface Metadata {
|
|
@@ -18,14 +19,25 @@ export interface Metadata {
|
|
|
18
19
|
|
|
19
20
|
export type BundleInfo = Awaited<ReturnType<typeof getBundleInfo>>;
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
interface GetBundleInfoProps {
|
|
23
|
+
exposedDependencies?: ExposedDependencies;
|
|
24
|
+
exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
25
|
+
fallbackPackageUrl?: string;
|
|
26
|
+
mainPackageUrl: string;
|
|
27
|
+
onRequestError?: (error: GetJsonError) => void;
|
|
28
|
+
retries?: number;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getBundleInfo({
|
|
33
|
+
mainPackageUrl,
|
|
34
|
+
fallbackPackageUrl,
|
|
35
|
+
exposedDependencies = {},
|
|
36
|
+
exposedInstanceDependencies = {},
|
|
37
|
+
signal,
|
|
38
|
+
retries,
|
|
39
|
+
onRequestError,
|
|
40
|
+
}: GetBundleInfoProps) {
|
|
29
41
|
const { data: metadata, url: packageUrl } = await getMetadata({
|
|
30
42
|
fallbackPackageUrl,
|
|
31
43
|
mainPackageUrl,
|
|
@@ -84,6 +96,10 @@ export async function getBundleInfo(
|
|
|
84
96
|
disposer,
|
|
85
97
|
mfeSupportsRerendering: getMFESupportsRerendering(bundledWith, dependencies),
|
|
86
98
|
mfeHasUniqueChunkNamespace: getMFEHasUniqueChunkNamespace(bundledWith),
|
|
99
|
+
mfeHasCompatibleLaunchDarklyVersion: getMFEHasCompatibleLaunchDarklyVersion(
|
|
100
|
+
bundledWith,
|
|
101
|
+
exposedInstanceDependencies
|
|
102
|
+
),
|
|
87
103
|
mismatch: hasMismatch ? mismatch : undefined,
|
|
88
104
|
urls,
|
|
89
105
|
WebComponent: name,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type LDService } from '@servicetitan/launchdarkly-service';
|
|
2
|
+
import { SymbolToken } from '@servicetitan/react-ioc';
|
|
3
|
+
|
|
4
|
+
let token: SymbolToken<LDService>;
|
|
5
|
+
try {
|
|
6
|
+
token = require('@servicetitan/launchdarkly-service').LD_SERVICE_TOKEN;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
// ignore
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getLDServiceToken() {
|
|
12
|
+
return token;
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ExposedInstanceDependencies } from '../common';
|
|
2
|
+
import { Metadata } from './get-bundle-info';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param bundledWith THe MFE's metadata.bundledWith.
|
|
6
|
+
* @param exposedInstanceDependencies The hosts's EXPOSED_INSTANCE_DEPENDENCIES, if any.
|
|
7
|
+
* @returns Returns true when host and MFE use compatible version of LaunchDarkly
|
|
8
|
+
* and returns false when host and MGE use incompatible version.
|
|
9
|
+
* Returns undefined when either the host or MFE doesn't expose LaunchDarkly.
|
|
10
|
+
*/
|
|
11
|
+
export function getMFEHasCompatibleLaunchDarklyVersion(
|
|
12
|
+
bundledWith: Metadata['bundledWith'],
|
|
13
|
+
exposedInstanceDependencies: ExposedInstanceDependencies
|
|
14
|
+
) {
|
|
15
|
+
const mfeVersion = bundledWith?.['launchdarkly-js-client-sdk'];
|
|
16
|
+
const hostVersion = exposedInstanceDependencies.launchDarkly?.version;
|
|
17
|
+
if (hostVersion && mfeVersion) {
|
|
18
|
+
return hostVersion === mfeVersion;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './get-bundle-info';
|
|
2
2
|
export * from './get-element-name';
|
|
3
3
|
export * from './get-entry-points';
|
|
4
|
+
export * from './get-ld-service-token';
|
|
4
5
|
export * from './get-mfe-supports-rerendering';
|
|
5
6
|
export * from './get-version-mismatches';
|
|
6
7
|
export * from './is-versioned-url';
|
|
@@ -1,31 +1,52 @@
|
|
|
1
1
|
import { Log } from '@servicetitan/log-service';
|
|
2
|
-
import { ExposedDependencies } from '../common';
|
|
2
|
+
import { ExposedDependencies, ExposedInstanceDependencies } from '../common';
|
|
3
3
|
import { BundleInfo } from './get-bundle-info';
|
|
4
4
|
|
|
5
|
+
interface Context {
|
|
6
|
+
exposedDependencies?: ExposedDependencies;
|
|
7
|
+
exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
8
|
+
logService?: Log;
|
|
9
|
+
packageUrl: string;
|
|
10
|
+
}
|
|
5
11
|
export function validateBundleInfo(
|
|
6
|
-
{ mismatch }: BundleInfo,
|
|
7
|
-
{
|
|
8
|
-
exposedDependencies = {},
|
|
9
|
-
logService,
|
|
10
|
-
packageName,
|
|
11
|
-
}: { exposedDependencies?: ExposedDependencies; logService?: Log; packageName: string }
|
|
12
|
+
{ mismatch, mfeHasCompatibleLaunchDarklyVersion }: BundleInfo,
|
|
13
|
+
{ exposedDependencies = {}, exposedInstanceDependencies, logService, packageUrl }: Context
|
|
12
14
|
) {
|
|
13
|
-
if (!
|
|
15
|
+
if (!logService) {
|
|
14
16
|
return;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
if (mismatch) {
|
|
20
|
+
const data = { package: packageUrl, dependencies: JSON.stringify(mismatch) };
|
|
21
|
+
if (Object.keys(exposedDependencies).length === 0) {
|
|
22
|
+
logService.warning({
|
|
23
|
+
category: 'MicroFrontends.NoExposedDependencies',
|
|
24
|
+
message:
|
|
25
|
+
'Cannot use light bundle because the host is not exposing dependencies or the list of shared dependencies is empty.',
|
|
26
|
+
data,
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
logService.warning({
|
|
30
|
+
category: 'MicroFrontends.DependenciesMismatch',
|
|
31
|
+
message: 'Some of the package dependencies have incompatible versions.',
|
|
32
|
+
data,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Note, only checking false here because the value is undefined when the host
|
|
39
|
+
* or the MFE isn't using LaunchDarkly at all.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
if (mfeHasCompatibleLaunchDarklyVersion === false) {
|
|
43
|
+
const data = {
|
|
44
|
+
package: packageUrl,
|
|
45
|
+
hostVersion: exposedInstanceDependencies?.launchDarkly?.version ?? '',
|
|
46
|
+
};
|
|
26
47
|
logService.warning({
|
|
27
|
-
category: 'MicroFrontends.
|
|
28
|
-
message: '
|
|
48
|
+
category: 'MicroFrontends.LaunchDarklyMismatch',
|
|
49
|
+
message: 'LaunchDarkly versions are incompatible',
|
|
29
50
|
data,
|
|
30
51
|
});
|
|
31
52
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Fragment, useMemo, useState } from 'react';
|
|
2
2
|
import { Log } from '@servicetitan/log-service';
|
|
3
|
+
import { type LDService } from '@servicetitan/launchdarkly-service';
|
|
3
4
|
import { useOptionalDependencies } from '@servicetitan/react-ioc';
|
|
4
5
|
|
|
5
|
-
import { ExposedDependencies, IWebComponent } from '../common';
|
|
6
|
+
import { ExposedDependencies, ExposedInstanceDependencies, IWebComponent } from '../common';
|
|
6
7
|
import { MFEContextData } from '../contexts/mfe-data-context';
|
|
7
8
|
import { EventBus } from '../event-bus';
|
|
8
9
|
import { BundleInfo } from './get-bundle-info';
|
|
@@ -15,11 +16,21 @@ interface WebComponentProps {
|
|
|
15
16
|
bundleInfo: BundleInfo;
|
|
16
17
|
eventBus: EventBus;
|
|
17
18
|
exposedDependencies?: ExposedDependencies;
|
|
19
|
+
exposedInstanceDependencies?: ExposedInstanceDependencies;
|
|
20
|
+
ldService?: LDService;
|
|
18
21
|
logService?: Log;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
export function webComponent(props: WebComponentProps) {
|
|
22
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
basename,
|
|
27
|
+
bundleInfo,
|
|
28
|
+
eventBus,
|
|
29
|
+
exposedDependencies,
|
|
30
|
+
exposedInstanceDependencies,
|
|
31
|
+
ldService,
|
|
32
|
+
logService,
|
|
33
|
+
} = props;
|
|
23
34
|
const { WebComponent, disposer, mfeSupportsRerendering } = bundleInfo;
|
|
24
35
|
const elementName = getElementName(bundleInfo);
|
|
25
36
|
|
|
@@ -29,9 +40,11 @@ export function webComponent(props: WebComponentProps) {
|
|
|
29
40
|
|
|
30
41
|
const handleRef = (webComponent: IWebComponent | null) => {
|
|
31
42
|
webComponent?.provide({
|
|
43
|
+
ldService,
|
|
32
44
|
logService,
|
|
33
45
|
historyManager,
|
|
34
46
|
exposedDependencies,
|
|
47
|
+
exposedInstanceDependencies,
|
|
35
48
|
eventBus,
|
|
36
49
|
basename,
|
|
37
50
|
onReady: () => {
|