@servicetitan/docs-uikit 30.1.0 → 30.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -34,12 +34,12 @@ and automatically [provides a store](#use-flags-in-mobx-store) that allows flag
|
|
|
34
34
|
|
|
35
35
|
#### Props
|
|
36
36
|
|
|
37
|
-
| Name | Type | Description
|
|
38
|
-
| :---------------------- | :-------- |
|
|
39
|
-
| `clientSideID` | `string` | The client-side ID that authorizes the client to connect to a particular LaunchDarkly project. The [getValueForEnvironment](./web-components
|
|
40
|
-
| `projectName` | `string` | The name of the LaunchDarkly project, for logs and error messages.
|
|
41
|
-
| `context` | `object` | (Optional) Context for targeting rules. Defaults to anonymous user. Use LaunchDarkly's [`identify`](https://docs.launchdarkly.com/sdk/features/identify) method to change the context after initialization.
|
|
42
|
-
| `waitForInitialization` | `boolean` | (Optional) Whether or not to wait until flags values are available before rendering children. Defaults to `true`
|
|
37
|
+
| Name | Type | Description |
|
|
38
|
+
| :---------------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| `clientSideID` | `string` | The client-side ID that authorizes the client to connect to a particular LaunchDarkly project. The [getValueForEnvironment](./web-components/get-value-for-environment) helper provides a convenient way to map Monolith environments to the corresponding client-side ID. |
|
|
40
|
+
| `projectName` | `string` | The name of the LaunchDarkly project, for logs and error messages. |
|
|
41
|
+
| `context` | `object` | (Optional) Context for targeting rules. Defaults to anonymous user. Use LaunchDarkly's [`identify`](https://docs.launchdarkly.com/sdk/features/identify) method to change the context after initialization. |
|
|
42
|
+
| `waitForInitialization` | `boolean` | (Optional) Whether or not to wait until flags values are available before rendering children. Defaults to `true` |
|
|
43
43
|
|
|
44
44
|
:::caution
|
|
45
45
|
When a `context` is provided, only the initial value takes affect. Subsequent calls with the same client-side ID reuse the client that was created with the initial context.
|
|
@@ -10,7 +10,7 @@ Use EventBus to exchange messages (aka events) between a host and MFEs, or betwe
|
|
|
10
10
|
### Providing EventBus
|
|
11
11
|
|
|
12
12
|
To use EventBus, provide an instance via `EVENT_BUS_TOKEN`.
|
|
13
|
-
[Loader](#loader) automatically passes the EventBus through to MFEs.
|
|
13
|
+
[Loader](../web-components#loader) automatically passes the EventBus through to MFEs.
|
|
14
14
|
For example,
|
|
15
15
|
|
|
16
16
|
```tsx
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: getValueForEnvironment
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`getValueForEnvironment` detects the host environment and returns a corresponding value.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
function getValueForEnvironment(
|
|
9
|
+
values: Record<string, string>,
|
|
10
|
+
defaultEnvironment: keyof typeof values = 'qa',
|
|
11
|
+
hostname: string = window.location.hostname
|
|
12
|
+
);
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
:::caution
|
|
16
|
+
When no value is provided for the detected environment, `getValueForEnvironment` returns `undefined`.
|
|
17
|
+
:::
|
|
18
|
+
|
|
19
|
+
### Parameters
|
|
20
|
+
|
|
21
|
+
| Name | Type | Description |
|
|
22
|
+
| :------------------- | :----------------------- | :------------------------------------------------------------------------------------------------------------------------ |
|
|
23
|
+
| `values` | `Record<string, string>` | Object that maps each environment to a value (see below). |
|
|
24
|
+
| `defaultEnvironment` | `keyof typeof values` | The environment to use when the current environment is not recognized or is not included in `values`. Defaults to `"qa"`. |
|
|
25
|
+
| `hostname` | `string` | The hostname of the current environment. Defaults to `window.location.hostname` |
|
|
26
|
+
|
|
27
|
+
The recognized environments are:
|
|
28
|
+
|
|
29
|
+
| Environment | Description |
|
|
30
|
+
| :---------------- | :--------------------------------------------------------------------------- |
|
|
31
|
+
| **dev** | Development environment (i.e., `localhost`, `127.0.0.1`) |
|
|
32
|
+
| **go** | Production environment |
|
|
33
|
+
| **qa** | QA environment |
|
|
34
|
+
| **next** | Next environment |
|
|
35
|
+
| **stage** | Staging environment |
|
|
36
|
+
| **test** | Unit test environment (i.e., `process.env.NODE_ENV === 'test'`) |
|
|
37
|
+
| `<string>` | Custom environment that matches against hostname `<string>.servicetitan.com` |
|
|
38
|
+
| `<string>.st.dev` | Custom environment that matches against hostname `<string>.st.dev` |
|
|
39
|
+
|
|
40
|
+
### Custom environments
|
|
41
|
+
|
|
42
|
+
Custom environments are for applications and services that run separately from the Monolith.
|
|
43
|
+
For example, to associate **prod** with `my-service.servicetitan.com` and **stage** with `my-service-stage.st.dev`:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"my-service": "prod", // Matches my-service.servicetitan.com
|
|
48
|
+
"stage.st.dev": "stage" // Matches *stage.st.dev
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Examples
|
|
53
|
+
|
|
54
|
+
Determine LaunchDarkly client-side ID for TitanAdvisor project.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
function useTitanAdvisorClientSideID() {
|
|
58
|
+
// Environment won't change and is safe to memoize
|
|
59
|
+
return useMemo(() => {
|
|
60
|
+
return getValueForEnvironment({
|
|
61
|
+
dev: '669fe6e5cc97eb103be7a620',
|
|
62
|
+
go: '669fe5bff00a0c0fa60b25e4',
|
|
63
|
+
next: '669fe5bff00a0c0fa60b25e4', // same a 'go' but could also be 'qa'
|
|
64
|
+
qa: '669fe6d6f00a0c0fa60b2721',
|
|
65
|
+
stage: '669fe65979abf310b860236e',
|
|
66
|
+
});
|
|
67
|
+
}, []);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
:::info
|
|
72
|
+
Note that because the environment is fixed for the life the application, it is safe to memoize the return value.
|
|
73
|
+
:::
|
|
74
|
+
|
|
75
|
+
:::caution
|
|
76
|
+
Do not call `getValueForEnvironment` globally, outside a React component or hook. That usage assumes that all the information needed to determine the environment is available immediately when the Javascript runtime loads and before the application is initialized. While that might work, it might also change in the future.
|
|
77
|
+
:::
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
title: Web Components
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
import Tabs from '@theme/Tabs';
|
|
6
|
+
import TabItem from '@theme/TabItem';
|
|
7
|
+
|
|
5
8
|
#### [CHANGELOG (@servicetitan/web-components)](https://github.com/servicetitan/uikit/blob/master/packages/web-components/CHANGELOG.md)
|
|
6
9
|
|
|
7
10
|
`@servicetitan/web-components` is used to build, register, and load Microfrontends (MFEs) into host applications.
|
|
@@ -13,19 +16,10 @@ The `Loader` component is used to load an MFE into a host application. See [Micr
|
|
|
13
16
|
### Usage
|
|
14
17
|
|
|
15
18
|
```tsx
|
|
16
|
-
...
|
|
17
|
-
|
|
18
19
|
import { Loader } from '@servicetitan/web-components';
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export const Foo: React.FC = () => {
|
|
23
|
-
...
|
|
24
|
-
return (
|
|
25
|
-
...
|
|
26
|
-
<Loader src="https://unpkg.servicetitan.com/{package_name}@{semver_range}" />
|
|
27
|
-
...
|
|
28
|
-
);
|
|
21
|
+
export const Foo = () => {
|
|
22
|
+
return <Loader src="https://unpkg.servicetitan.com/{package_name}@{semver_range}" />;
|
|
29
23
|
};
|
|
30
24
|
```
|
|
31
25
|
|
|
@@ -33,8 +27,8 @@ export const Foo: React.FC = () => {
|
|
|
33
27
|
|
|
34
28
|
| Name | Description |
|
|
35
29
|
| :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
36
|
-
| `src` |
|
|
37
|
-
| `fallbackSrc` | optional alternative
|
|
30
|
+
| `src` | url for the MFE's package |
|
|
31
|
+
| `fallbackSrc` | optional alternative url for the MFE's package (if request for src returns error) |
|
|
38
32
|
| `data` | additional data passed to an MFE as an object, where values are serializable, and preferably memoized ([see below](#passing-data-from-host-to-mfe)) |
|
|
39
33
|
| `basename` | prefix for all MFE URLs, you should inject it by the `BASENAME_TOKEN` and pass to the appropriate router property |
|
|
40
34
|
| `loadingFallback` | optional ReactNode to render when the MFE is loading |
|
|
@@ -60,7 +54,7 @@ When an MFE is loaded, `Loader` fetches the version and bundle data from the `sr
|
|
|
60
54
|
|
|
61
55
|
Use `data` to pass data from your host application to the MFE. The data should be an object where keys are strings and the values are any serializable data.
|
|
62
56
|
|
|
63
|
-
To avoid performance issues with re-rendering and re-serializing the value, we recommend memoizing the `data` object passed to
|
|
57
|
+
To avoid performance issues with re-rendering and re-serializing the value, we recommend memoizing the `data` object passed to `Loader`.
|
|
64
58
|
|
|
65
59
|
**Reminder:** Don't casually share data between the host and MFEs. When possible, MFEs should load the data they need instead of relying on the host to pass it.
|
|
66
60
|
|
|
@@ -116,115 +110,165 @@ export const MFEApp = (props: MyType) => {
|
|
|
116
110
|
// RESULTS IN A STRING, NOT A DATE OBJECT
|
|
117
111
|
```
|
|
118
112
|
|
|
119
|
-
As of version v22.12.0 of `@servicetitan/web-components`, if data passed into the `data` prop of
|
|
113
|
+
As of version v22.12.0 of `@servicetitan/web-components`, if data passed into the `data` prop of `Loader` changes during runtime, the data will re-render within your MFE component where appropriate. Previous versions would re-mounting the entire MFE application when data changed.
|
|
120
114
|
|
|
121
|
-
|
|
115
|
+
### Using EventBus to exchanges messages
|
|
122
116
|
|
|
123
|
-
|
|
117
|
+
Use [EventBus](./event-bus) to exchange messages between the host and MFEs.
|
|
118
|
+
When an EventBus is provided via `EVENT_BUS_TOKEN`, `Loader` automatically passes it through to MFEs.
|
|
119
|
+
For example,
|
|
120
|
+
|
|
121
|
+
<Tabs
|
|
122
|
+
defaultValue="host"
|
|
123
|
+
values={[
|
|
124
|
+
{ label: 'Host', value: 'host' },
|
|
125
|
+
{ label: 'MFE', value: 'mfe'},
|
|
126
|
+
{ label: 'Types', value: 'types' },
|
|
127
|
+
]}
|
|
128
|
+
>
|
|
129
|
+
<TabItem value="types">
|
|
124
130
|
|
|
125
131
|
```tsx
|
|
126
|
-
import {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
import { EventBus, typedEventBusToken } from '@servicetitan/web-components';
|
|
133
|
+
|
|
134
|
+
export enum Events {
|
|
135
|
+
example = 'example:event',
|
|
130
136
|
}
|
|
131
137
|
|
|
132
|
-
export
|
|
133
|
-
|
|
134
|
-
}
|
|
138
|
+
export interface ExampleEvents {
|
|
139
|
+
[Events.example]: undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type ExampleEventBus = EventBus<ExampleEvents>;
|
|
143
|
+
|
|
144
|
+
export const EXAMPLE_EVENT_BUS_TOKEN = typedEventBusToken<ExampleEvents>();
|
|
135
145
|
```
|
|
136
146
|
|
|
137
|
-
|
|
147
|
+
</TabItem>
|
|
148
|
+
<TabItem value="host">
|
|
138
149
|
|
|
139
|
-
|
|
150
|
+
```tsx
|
|
151
|
+
import { provide, useDependencies } from '@servicetitan/react-ioc';
|
|
152
|
+
import { EVENT_BUS_TOKEN, EventBus, Loader } from '@servicetitan/web-components';
|
|
153
|
+
import { FC, useCallback, useEffect } from 'react';
|
|
154
|
+
import { Events, EXAMPLE_EVENT_BUS_TOKEN } from './types';
|
|
155
|
+
|
|
156
|
+
const mfeUrl = 'https://unpkg.servicetitan.com/@servicetitan/examples';
|
|
157
|
+
|
|
158
|
+
export const App: FC = provide({
|
|
159
|
+
singletons: [{ provide: EVENT_BUS_TOKEN, useValue: new EventBus() }],
|
|
160
|
+
})(() => {
|
|
161
|
+
const [eventBus] = useDependencies(EXAMPLE_EVENT_BUS_TOKEN);
|
|
162
|
+
const handleExampleEvent = useCallback(() => {
|
|
163
|
+
/* Handle event */
|
|
164
|
+
}, []);
|
|
165
|
+
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
eventBus.on(Events.example, handleExampleEvent);
|
|
168
|
+
return () => {
|
|
169
|
+
eventBus.off(Events.example, handleExampleEvent);
|
|
170
|
+
};
|
|
171
|
+
}, [eventBus, handleExampleEvent]);
|
|
172
|
+
|
|
173
|
+
// Loader passes provided EventBus through to MFE
|
|
174
|
+
return <Loader src={mfeUrl} />;
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
</TabItem>
|
|
179
|
+
<TabItem value="mfe">
|
|
140
180
|
|
|
141
181
|
```tsx
|
|
142
|
-
import {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
182
|
+
import { Button } from '@servicetitan/anvil2';
|
|
183
|
+
import { useDependencies } from '@servicetitan/react-ioc';
|
|
184
|
+
import { useCallback } from 'react';
|
|
185
|
+
import { Events, EXAMPLE_EVENT_BUS_TOKEN } from './types';
|
|
186
|
+
|
|
187
|
+
export const App = () => {
|
|
188
|
+
// Loader passes through provided EventBus
|
|
189
|
+
const [eventBus] = useDependencies(EXAMPLE_EVENT_BUS_TOKEN);
|
|
190
|
+
|
|
191
|
+
const handleClick = useCallback(() => {
|
|
192
|
+
eventBus.emit(Events.example);
|
|
193
|
+
}, [eventBus]);
|
|
194
|
+
|
|
195
|
+
return <Button onClick={handleClick}>Click me</Button>;
|
|
146
196
|
};
|
|
147
197
|
```
|
|
148
198
|
|
|
149
|
-
|
|
199
|
+
</TabItem>
|
|
200
|
+
</Tabs>
|
|
150
201
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
| `shadowRoot` | ShadowRoot | ShadowRoot root node of which the MFE is rendered within |
|
|
154
|
-
| `portalShadowRoot` | ShadowRoot | ShadowRoot root node of the "portal" tied to the MFE, which is used to render elements in a div directly under the body element |
|
|
202
|
+
See [typedEventBusToken](./event-bus#typedeventbustoken) for a detailed explanation
|
|
203
|
+
of the types used in these examples.
|
|
155
204
|
|
|
156
|
-
|
|
205
|
+
#### Using legacy ref parameter
|
|
157
206
|
|
|
158
|
-
|
|
207
|
+
For backward compatibility, when no `EVENT_BUS_TOKEN` is provided, `Loader`
|
|
208
|
+
creates a private EventBus and returns it via the `ref` parameter.
|
|
209
|
+
This old approach should not be used in new code.
|
|
159
210
|
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
hostname: string = window.location.hostname
|
|
165
|
-
);
|
|
166
|
-
```
|
|
211
|
+
```tsx
|
|
212
|
+
import { FC, useCallback, useEffect, useState } from 'react';
|
|
213
|
+
import { Loader } from '@servicetitan/web-components';
|
|
214
|
+
import { Events, ExampleEventBus } from './types';
|
|
167
215
|
|
|
168
|
-
|
|
169
|
-
When no value is provided for the detected environment, `getValueForEnvironment` returns `undefined`.
|
|
170
|
-
:::
|
|
216
|
+
const mfeUrl = 'https://unpkg.servicetitan.com/@servicetitan/examples';
|
|
171
217
|
|
|
172
|
-
|
|
218
|
+
export const Component: FC = () => {
|
|
219
|
+
const [eventBus, setEventBus] = useState<ExampleEventBus | null>(null);
|
|
220
|
+
const handleExampleEvent = useCallback(() => {
|
|
221
|
+
/* Handle event */
|
|
222
|
+
}, []);
|
|
173
223
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
eventBus?.on(Events.example, handleExampleEvent);
|
|
226
|
+
return () => {
|
|
227
|
+
eventBus?.off(Events.example, handleExampleEvent);
|
|
228
|
+
};
|
|
229
|
+
}, [eventBus, handleExampleEvent]);
|
|
179
230
|
|
|
180
|
-
|
|
231
|
+
// Loader provides private EventBus and returns it via "ref"
|
|
232
|
+
return <Loader ref={ref => setEventBus(ref)} src={mfeUrl} />;
|
|
233
|
+
};
|
|
234
|
+
```
|
|
181
235
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
| **qa** | QA environment |
|
|
187
|
-
| **next** | Next environment |
|
|
188
|
-
| **stage** | Staging environment |
|
|
189
|
-
| **test** | Unit test environment (i.e., `process.env.NODE_ENV === 'test'`) |
|
|
190
|
-
| `<string>` | Custom environment that matches against hostname `<string>.servicetitan.com` |
|
|
191
|
-
| `<string>.st.dev` | Custom environment that matches against hostname `<string>.st.dev` |
|
|
236
|
+
:::caution
|
|
237
|
+
Note, if an `EVENT_BUS_TOKEN` is provided, `Loader` returns the provide value in `ref`
|
|
238
|
+
and doesn't create a private EventBus.
|
|
239
|
+
:::
|
|
192
240
|
|
|
193
|
-
|
|
241
|
+
## useMFEDataContext
|
|
194
242
|
|
|
195
|
-
|
|
196
|
-
For example, to associate **prod** with `my-service.servicetitan.com` and **stage** with `my-service-stage.st.dev`:
|
|
243
|
+
Data can be also be accessed within the MFE using the `useMFEDataContext` hook. You must provide the type of the data you expect to receive.
|
|
197
244
|
|
|
198
|
-
```
|
|
199
|
-
{
|
|
200
|
-
|
|
201
|
-
|
|
245
|
+
```tsx
|
|
246
|
+
import { useMFEDataContext } from '@servicetitan/web-components';
|
|
247
|
+
...
|
|
248
|
+
interface MFEAppData {
|
|
249
|
+
bar: string;
|
|
202
250
|
}
|
|
251
|
+
|
|
252
|
+
export const MFEApp = () => {
|
|
253
|
+
const { bar } = useMFEDataContext<MFEAppData>();
|
|
254
|
+
};
|
|
203
255
|
```
|
|
204
256
|
|
|
205
|
-
|
|
257
|
+
## useMFEMetadataContext
|
|
206
258
|
|
|
207
|
-
|
|
259
|
+
Some metadata is also provided to MFEs, and is accessible through the `useMFEMetadataContext` hook.
|
|
208
260
|
|
|
209
261
|
```tsx
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
go: '669fe5bff00a0c0fa60b25e4',
|
|
216
|
-
next: '669fe5bff00a0c0fa60b25e4', // same a 'go' but could also be 'qa'
|
|
217
|
-
qa: '669fe6d6f00a0c0fa60b2721',
|
|
218
|
-
stage: '669fe65979abf310b860236e',
|
|
219
|
-
});
|
|
220
|
-
}, []);
|
|
221
|
-
}
|
|
262
|
+
import { useMFEMetadataContext } from '@servicetitan/web-components';
|
|
263
|
+
...
|
|
264
|
+
export const MFEApp = () => {
|
|
265
|
+
const { shadowRoot, portalShadowRoot } = useMFEMetadataContext();
|
|
266
|
+
};
|
|
222
267
|
```
|
|
223
268
|
|
|
224
|
-
|
|
225
|
-
Note that because the environment is fixed for the life the application, it is safe to memoize the return value.
|
|
226
|
-
:::
|
|
269
|
+
The following metadata about an MFE is available from `useMFEMetadataContext` hook.
|
|
227
270
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
271
|
+
| Name | Type | Description |
|
|
272
|
+
| :----------------- | :--------- | :------------------------------------------------------------------------------------------------------------------------------ |
|
|
273
|
+
| `shadowRoot` | ShadowRoot | ShadowRoot root node of which the MFE is rendered within |
|
|
274
|
+
| `portalShadowRoot` | ShadowRoot | ShadowRoot root node of the "portal" tied to the MFE, which is used to render elements in a div directly under the body element |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/docs-uikit",
|
|
3
|
-
"version": "30.1.
|
|
3
|
+
"version": "30.1.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,5 +16,5 @@
|
|
|
16
16
|
"cli": {
|
|
17
17
|
"webpack": false
|
|
18
18
|
},
|
|
19
|
-
"gitHead": "
|
|
19
|
+
"gitHead": "76e26006c94d59038b9719ede1fa416d84d4a2c3"
|
|
20
20
|
}
|