@appshell/react 0.1.0-alpha.6
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/CHANGELOG.md +183 -0
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/__tests__/FederatedComponent.spec.tsx +53 -0
- package/__tests__/LoadingError.spec.tsx +14 -0
- package/__tests__/ManifestContext.spec.tsx +36 -0
- package/__tests__/ReactHost.spec.tsx +137 -0
- package/__tests__/__snapshots__/FederatedComponent.spec.tsx.snap +9 -0
- package/__tests__/__snapshots__/LoadingError.spec.tsx.snap +88 -0
- package/__tests__/__snapshots__/ReactHost.spec.tsx.snap +13 -0
- package/__tests__/fixtures/Manifest.ts +16 -0
- package/__tests__/fixtures/TestComponent.tsx +5 -0
- package/__tests__/fixtures/appshell.index.ts +5 -0
- package/__tests__/jsonResource.spec.ts +27 -0
- package/__tests__/utils/waitForResource.ts +15 -0
- package/dist/main.js +1 -0
- package/dist/types/config/src/axios.d.ts +3 -0
- package/dist/types/config/src/axios.d.ts.map +1 -0
- package/dist/types/config/src/configmap.d.ts +7 -0
- package/dist/types/config/src/configmap.d.ts.map +1 -0
- package/dist/types/config/src/generate.env.d.ts +3 -0
- package/dist/types/config/src/generate.env.d.ts.map +1 -0
- package/dist/types/config/src/generate.index.d.ts +4 -0
- package/dist/types/config/src/generate.index.d.ts.map +1 -0
- package/dist/types/config/src/generate.manifest.d.ts +9 -0
- package/dist/types/config/src/generate.manifest.d.ts.map +1 -0
- package/dist/types/config/src/generate.metadata.d.ts +4 -0
- package/dist/types/config/src/generate.metadata.d.ts.map +1 -0
- package/dist/types/config/src/index.d.ts +13 -0
- package/dist/types/config/src/index.d.ts.map +1 -0
- package/dist/types/config/src/mappers/appshell.config.d.ts +3 -0
- package/dist/types/config/src/mappers/appshell.config.d.ts.map +1 -0
- package/dist/types/config/src/register.d.ts +4 -0
- package/dist/types/config/src/register.d.ts.map +1 -0
- package/dist/types/config/src/types.d.ts +213 -0
- package/dist/types/config/src/types.d.ts.map +1 -0
- package/dist/types/config/src/utils/copy.d.ts +11 -0
- package/dist/types/config/src/utils/copy.d.ts.map +1 -0
- package/dist/types/config/src/utils/index.d.ts +7 -0
- package/dist/types/config/src/utils/index.d.ts.map +1 -0
- package/dist/types/config/src/utils/isValidUrl.d.ts +3 -0
- package/dist/types/config/src/utils/isValidUrl.d.ts.map +1 -0
- package/dist/types/config/src/utils/list.d.ts +10 -0
- package/dist/types/config/src/utils/list.d.ts.map +1 -0
- package/dist/types/config/src/utils/load.d.ts +14 -0
- package/dist/types/config/src/utils/load.d.ts.map +1 -0
- package/dist/types/config/src/utils/loadJson.d.ts +3 -0
- package/dist/types/config/src/utils/loadJson.d.ts.map +1 -0
- package/dist/types/config/src/utils/merge.d.ts +4 -0
- package/dist/types/config/src/utils/merge.d.ts.map +1 -0
- package/dist/types/config/src/validators/appshell.config.d.ts +4 -0
- package/dist/types/config/src/validators/appshell.config.d.ts.map +1 -0
- package/dist/types/config/src/validators/appshell.index.d.ts +4 -0
- package/dist/types/config/src/validators/appshell.index.d.ts.map +1 -0
- package/dist/types/config/src/validators/appshell.manifest.d.ts +4 -0
- package/dist/types/config/src/validators/appshell.manifest.d.ts.map +1 -0
- package/dist/types/config/src/validators/appshell.metadata.d.ts +4 -0
- package/dist/types/config/src/validators/appshell.metadata.d.ts.map +1 -0
- package/dist/types/config/src/validators/index.d.ts +6 -0
- package/dist/types/config/src/validators/index.d.ts.map +1 -0
- package/dist/types/config/src/validators/merge.manifests.d.ts +4 -0
- package/dist/types/config/src/validators/merge.manifests.d.ts.map +1 -0
- package/dist/types/loader/src/fetchDynamicScript.d.ts +3 -0
- package/dist/types/loader/src/fetchDynamicScript.d.ts.map +1 -0
- package/dist/types/loader/src/index.d.ts +4 -0
- package/dist/types/loader/src/index.d.ts.map +1 -0
- package/dist/types/loader/src/loadFederatedComponent.d.ts +14 -0
- package/dist/types/loader/src/loadFederatedComponent.d.ts.map +1 -0
- package/dist/types/loader/src/remoteLoader.d.ts +4 -0
- package/dist/types/loader/src/remoteLoader.d.ts.map +1 -0
- package/dist/types/loader/src/types.d.ts +11 -0
- package/dist/types/loader/src/types.d.ts.map +1 -0
- package/dist/types/react/src/components/FederatedComponent.d.ts +20 -0
- package/dist/types/react/src/components/FederatedComponent.d.ts.map +1 -0
- package/dist/types/react/src/components/LoadingError.d.ts +8 -0
- package/dist/types/react/src/components/LoadingError.d.ts.map +1 -0
- package/dist/types/react/src/components/ReactHost.d.ts +10 -0
- package/dist/types/react/src/components/ReactHost.d.ts.map +1 -0
- package/dist/types/react/src/contexts/ManifestContext.d.ts +12 -0
- package/dist/types/react/src/contexts/ManifestContext.d.ts.map +1 -0
- package/dist/types/react/src/contexts/MetadataContext.d.ts +11 -0
- package/dist/types/react/src/contexts/MetadataContext.d.ts.map +1 -0
- package/dist/types/react/src/contexts/RegistryContext.d.ts +11 -0
- package/dist/types/react/src/contexts/RegistryContext.d.ts.map +1 -0
- package/dist/types/react/src/hooks/useManifest.d.ts +4 -0
- package/dist/types/react/src/hooks/useManifest.d.ts.map +1 -0
- package/dist/types/react/src/hooks/useMetadata.d.ts +4 -0
- package/dist/types/react/src/hooks/useMetadata.d.ts.map +1 -0
- package/dist/types/react/src/hooks/useRegistry.d.ts +4 -0
- package/dist/types/react/src/hooks/useRegistry.d.ts.map +1 -0
- package/dist/types/react/src/index.d.ts +10 -0
- package/dist/types/react/src/index.d.ts.map +1 -0
- package/dist/types/react/src/resources/jsonResource.d.ts +5 -0
- package/dist/types/react/src/resources/jsonResource.d.ts.map +1 -0
- package/dist/types/react/src/types.d.ts +4 -0
- package/dist/types/react/src/types.d.ts.map +1 -0
- package/package.json +32 -0
- package/src/components/FederatedComponent.tsx +73 -0
- package/src/components/LoadingError.tsx +15 -0
- package/src/components/ReactHost.tsx +69 -0
- package/src/contexts/ManifestContext.tsx +22 -0
- package/src/contexts/MetadataContext.tsx +17 -0
- package/src/contexts/RegistryContext.tsx +17 -0
- package/src/hooks/useManifest.ts +7 -0
- package/src/hooks/useMetadata.ts +6 -0
- package/src/hooks/useRegistry.ts +6 -0
- package/src/index.ts +9 -0
- package/src/resources/jsonResource.ts +35 -0
- package/src/types.ts +3 -0
- package/tsconfig.json +7 -0
- package/webpack.config.js +42 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AppshellIndex } from '@appshell/config';
|
|
2
|
+
import React, { ReactElement, ReactNode } from 'react';
|
|
3
|
+
export type ExtendedProps = Record<string, unknown>;
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
__appshell_index__: AppshellIndex;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export type FederatedComponentProps<TProps extends ExtendedProps = ExtendedProps> = {
|
|
10
|
+
remote: string;
|
|
11
|
+
fallback?: ReactNode;
|
|
12
|
+
} & TProps;
|
|
13
|
+
declare const FederatedComponent: {
|
|
14
|
+
<TProps extends ExtendedProps>({ remote, fallback, ...rest }: FederatedComponentProps<TProps>): React.ReactElement<TProps, string | React.JSXElementConstructor<any>>;
|
|
15
|
+
defaultProps: {
|
|
16
|
+
fallback: undefined;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export default FederatedComponent;
|
|
20
|
+
//# sourceMappingURL=FederatedComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FederatedComponent.d.ts","sourceRoot":"","sources":["../../../../../src/components/FederatedComponent.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAE,EAAiB,YAAY,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAC;AAK3F,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,kBAAkB,EAAE,aAAa,CAAC;KACnC;CACF;AAED,MAAM,MAAM,uBAAuB,CAAC,MAAM,SAAS,aAAa,GAAG,aAAa,IAAI;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,GAAG,MAAM,CAAC;AAEX,QAAA,MAAM,kBAAkB;;;;;CA6CvB,CAAC;AAMF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingError.d.ts","sourceRoot":"","sources":["../../../../../src/components/LoadingError.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAElC,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,EAAE,CAAC,UAAU,CAKhC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactHost.d.ts","sourceRoot":"","sources":["../../../../../src/components/ReactHost.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAE,EAAE,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAKxD,QAAA,MAAM,SAAS,EAAE,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAiDA,CAAC;AAMF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AppshellManifest } from '@appshell/config';
|
|
2
|
+
import type { FC, ReactNode } from 'react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
interface ManifestProviderProps {
|
|
5
|
+
manifest: AppshellManifest;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare const ManifestContext: React.Context<AppshellManifest<import("@appshell/config").Metadata>>;
|
|
9
|
+
export declare const ManifestProvider: FC<ManifestProviderProps>;
|
|
10
|
+
export declare const ManifestConsumer: React.Consumer<AppshellManifest<import("@appshell/config").Metadata>>;
|
|
11
|
+
export default ManifestContext;
|
|
12
|
+
//# sourceMappingURL=ManifestContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManifestContext.d.ts","sourceRoot":"","sources":["../../../../../src/contexts/ManifestContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,KAAwB,MAAM,OAAO,CAAC;AAE7C,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,sEAI1B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAEtD,CAAC;AAEF,eAAO,MAAM,gBAAgB,uEAA2B,CAAC;AAEzD,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Metadata } from '@appshell/config';
|
|
2
|
+
import React, { FC, ReactNode } from 'react';
|
|
3
|
+
interface MetadataProviderProps {
|
|
4
|
+
metata: Metadata;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare const MetadataContext: React.Context<Metadata>;
|
|
8
|
+
export declare const MetadataProvider: FC<MetadataProviderProps>;
|
|
9
|
+
export declare const MetadataConsumer: React.Consumer<Metadata>;
|
|
10
|
+
export default MetadataContext;
|
|
11
|
+
//# sourceMappingURL=MetadataContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetadataContext.d.ts","sourceRoot":"","sources":["../../../../../src/contexts/MetadataContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,EAAiB,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D,UAAU,qBAAqB;IAC7B,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,yBAA8B,CAAC;AAE3D,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAEtD,CAAC;AAEF,eAAO,MAAM,gBAAgB,0BAA2B,CAAC;AAEzD,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AppshellIndex } from '@appshell/config';
|
|
2
|
+
import React, { FC, ReactNode } from 'react';
|
|
3
|
+
interface RegistryProviderProps {
|
|
4
|
+
index: AppshellIndex;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare const RegistryContext: React.Context<AppshellIndex>;
|
|
8
|
+
export declare const RegistryProvider: FC<RegistryProviderProps>;
|
|
9
|
+
export declare const RegistryConsumer: React.Consumer<AppshellIndex>;
|
|
10
|
+
export default RegistryContext;
|
|
11
|
+
//# sourceMappingURL=RegistryContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RegistryContext.d.ts","sourceRoot":"","sources":["../../../../../src/contexts/RegistryContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,EAAiB,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D,UAAU,qBAAqB;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,8BAAmC,CAAC;AAEhE,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAEtD,CAAC;AAEF,eAAO,MAAM,gBAAgB,+BAA2B,CAAC;AAEzD,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useManifest.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/useManifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;8BAMjC,gBAAgB;AAAnC,wBAA2F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMetadata.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/useMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;8BAKzB,QAAQ;AAA3B,wBAA2E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/useRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;8BAK9B,aAAa;AAAhC,wBAAqF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { default as FederatedComponent } from './components/FederatedComponent';
|
|
2
|
+
export { default as ReactHost } from './components/ReactHost';
|
|
3
|
+
export { ManifestProvider } from './contexts/ManifestContext';
|
|
4
|
+
export { MetadataProvider } from './contexts/MetadataContext';
|
|
5
|
+
export { RegistryProvider } from './contexts/RegistryContext';
|
|
6
|
+
export { default as useManifest } from './hooks/useManifest';
|
|
7
|
+
export { default as useMetadata } from './hooks/useMetadata';
|
|
8
|
+
export { default as useRegistry } from './hooks/useRegistry';
|
|
9
|
+
export { default as jsonResource } from './resources/jsonResource';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonResource.d.ts","sourceRoot":"","sources":["../../../../../src/resources/jsonResource.ts"],"names":[],"mappings":"yCAAgC,MAAM;;;AAAtC,wBAkCE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,CAAC,SAAS,GAAG,OAAO,IAAI;IAC1C,IAAI,IAAI,SAAS,GAAG,KAAK,GAAG,SAAS,CAAC;CACvC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appshell/react",
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
|
+
"description": "React utilities for loading federated components",
|
|
5
|
+
"main": "dist/main.js",
|
|
6
|
+
"types": "dist/types/react/src/index.d.ts",
|
|
7
|
+
"repository": "https://github.com/navaris/appshell.git",
|
|
8
|
+
"author": "Robert Hamilton <rh@navaris.com>",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public",
|
|
11
|
+
"registry": "https://registry.npmjs.org/"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "webpack --mode production && yarn build:types",
|
|
15
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
16
|
+
"clean": "rm -rf dist",
|
|
17
|
+
"start": "webpack --watch --mode development --stats-error-details",
|
|
18
|
+
"stats": "webpack --json > stats.json"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"webpack",
|
|
22
|
+
"module federation",
|
|
23
|
+
"micro-frontends",
|
|
24
|
+
"appshell"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": "^18.2.0",
|
|
29
|
+
"react-dom": "^18.2.0"
|
|
30
|
+
},
|
|
31
|
+
"gitHead": "d8a24472c2440217ef795b85eb3107b4f89395e7"
|
|
32
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* eslint-disable react/jsx-props-no-spreading */
|
|
2
|
+
import { AppshellIndex } from '@appshell/config';
|
|
3
|
+
import remoteLoader from '@appshell/loader';
|
|
4
|
+
import React, { ComponentType, ReactElement, ReactNode, useEffect, useState } from 'react';
|
|
5
|
+
import { ManifestProvider } from '../contexts/ManifestContext';
|
|
6
|
+
import useRegistry from '../hooks/useRegistry';
|
|
7
|
+
import LoadingError from './LoadingError';
|
|
8
|
+
|
|
9
|
+
export type ExtendedProps = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
__appshell_index__: AppshellIndex;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
|
17
|
+
export type FederatedComponentProps<TProps extends ExtendedProps = ExtendedProps> = {
|
|
18
|
+
remote: string;
|
|
19
|
+
fallback?: ReactNode;
|
|
20
|
+
} & TProps;
|
|
21
|
+
|
|
22
|
+
const FederatedComponent = <TProps extends ExtendedProps>({
|
|
23
|
+
remote,
|
|
24
|
+
fallback,
|
|
25
|
+
...rest
|
|
26
|
+
}: FederatedComponentProps<TProps>): ReactElement<TProps> => {
|
|
27
|
+
const index = useRegistry();
|
|
28
|
+
const [element, setElement] = useState<ReactElement>();
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
let active = false;
|
|
32
|
+
const loadComponent = remoteLoader(index);
|
|
33
|
+
|
|
34
|
+
async function load() {
|
|
35
|
+
try {
|
|
36
|
+
active = true;
|
|
37
|
+
setElement(undefined);
|
|
38
|
+
const [Component, manifest] = await loadComponent<ComponentType>(remote);
|
|
39
|
+
if (!Component) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
active = false;
|
|
43
|
+
setElement(
|
|
44
|
+
<ManifestProvider manifest={manifest}>
|
|
45
|
+
<Component {...rest} />
|
|
46
|
+
</ManifestProvider>,
|
|
47
|
+
);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
setElement(<LoadingError remote={remote} reason={`${err}`} />);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!active) {
|
|
54
|
+
load();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return () => {
|
|
58
|
+
active = false;
|
|
59
|
+
};
|
|
60
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
61
|
+
}, [remote, index]);
|
|
62
|
+
|
|
63
|
+
// eslint-disable-next-line no-console
|
|
64
|
+
console.debug(`rendering FederatedComponent[${remote}], loading=${!element}`);
|
|
65
|
+
// eslint-disable-next-line react/jsx-no-useless-fragment
|
|
66
|
+
return <>{element || fallback}</>;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
FederatedComponent.defaultProps = {
|
|
70
|
+
fallback: undefined,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default FederatedComponent;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
|
|
3
|
+
type ErrorProps = {
|
|
4
|
+
remote: string;
|
|
5
|
+
reason: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const LoadingError: FC<ErrorProps> = ({ remote, reason }) => (
|
|
9
|
+
<div style={{ border: '3px solid red' }}>
|
|
10
|
+
<h5>{`Error loading federated component '${remote}.'`}</h5>
|
|
11
|
+
<span style={{ fontSize: '1rem' }}>{reason}</span>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default LoadingError;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* eslint-disable react/jsx-props-no-spreading */
|
|
2
|
+
import { AppshellIndex, Metadata } from '@appshell/config';
|
|
3
|
+
import React, { FC, ReactNode, useEffect } from 'react';
|
|
4
|
+
import { MetadataProvider } from '../contexts/MetadataContext';
|
|
5
|
+
import { RegistryProvider } from '../contexts/RegistryContext';
|
|
6
|
+
import FederatedComponent from './FederatedComponent';
|
|
7
|
+
|
|
8
|
+
const ReactHost: FC<{
|
|
9
|
+
indexUrl: string;
|
|
10
|
+
metadataUrl: string;
|
|
11
|
+
remote: string;
|
|
12
|
+
fallback?: ReactNode;
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
}> = ({ indexUrl, metadataUrl, remote, fallback, ...rest }) => {
|
|
15
|
+
const [index, setIndex] = React.useState<AppshellIndex>();
|
|
16
|
+
const [metadata, setMetadata] = React.useState<Metadata>();
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const fetchIndex = async () => {
|
|
20
|
+
const res = await fetch(indexUrl);
|
|
21
|
+
|
|
22
|
+
if (res.ok) {
|
|
23
|
+
const data = await res.json();
|
|
24
|
+
setIndex(data);
|
|
25
|
+
} else {
|
|
26
|
+
setIndex({});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (!index) {
|
|
31
|
+
fetchIndex();
|
|
32
|
+
}
|
|
33
|
+
}, [index, indexUrl]);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const fetchMetadata = async () => {
|
|
37
|
+
const res = await fetch(metadataUrl);
|
|
38
|
+
|
|
39
|
+
if (res.ok) {
|
|
40
|
+
const data = await res.json();
|
|
41
|
+
setMetadata(data);
|
|
42
|
+
} else {
|
|
43
|
+
setMetadata({});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
if (!metadata) {
|
|
48
|
+
fetchMetadata();
|
|
49
|
+
}
|
|
50
|
+
}, [metadata, metadataUrl]);
|
|
51
|
+
|
|
52
|
+
if (!index || !metadata) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<RegistryProvider index={index}>
|
|
58
|
+
<MetadataProvider metata={metadata}>
|
|
59
|
+
<FederatedComponent remote={remote} fallback={fallback} {...rest} />
|
|
60
|
+
</MetadataProvider>
|
|
61
|
+
</RegistryProvider>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
ReactHost.defaultProps = {
|
|
66
|
+
fallback: undefined,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default ReactHost;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AppshellManifest } from '@appshell/config';
|
|
2
|
+
import type { FC, ReactNode } from 'react';
|
|
3
|
+
import React, { createContext } from 'react';
|
|
4
|
+
|
|
5
|
+
interface ManifestProviderProps {
|
|
6
|
+
manifest: AppshellManifest;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const ManifestContext = createContext<AppshellManifest>({
|
|
11
|
+
remotes: {},
|
|
12
|
+
modules: {},
|
|
13
|
+
environment: {},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const ManifestProvider: FC<ManifestProviderProps> = ({ manifest, children }) => (
|
|
17
|
+
<ManifestContext.Provider value={manifest}>{children}</ManifestContext.Provider>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export const ManifestConsumer = ManifestContext.Consumer;
|
|
21
|
+
|
|
22
|
+
export default ManifestContext;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Metadata } from '@appshell/config';
|
|
2
|
+
import React, { createContext, FC, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface MetadataProviderProps {
|
|
5
|
+
metata: Metadata;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const MetadataContext = createContext<Metadata>({});
|
|
10
|
+
|
|
11
|
+
export const MetadataProvider: FC<MetadataProviderProps> = ({ metata, children }) => (
|
|
12
|
+
<MetadataContext.Provider value={metata}>{children}</MetadataContext.Provider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export const MetadataConsumer = MetadataContext.Consumer;
|
|
16
|
+
|
|
17
|
+
export default MetadataContext;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AppshellIndex } from '@appshell/config';
|
|
2
|
+
import React, { createContext, FC, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface RegistryProviderProps {
|
|
5
|
+
index: AppshellIndex;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const RegistryContext = createContext<AppshellIndex>({});
|
|
10
|
+
|
|
11
|
+
export const RegistryProvider: FC<RegistryProviderProps> = ({ index, children }) => (
|
|
12
|
+
<RegistryContext.Provider value={index}>{children}</RegistryContext.Provider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export const RegistryConsumer = RegistryContext.Consumer;
|
|
16
|
+
|
|
17
|
+
export default RegistryContext;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AppshellManifest } from '@appshell/config';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line import/no-named-as-default
|
|
5
|
+
import ManifestContext from '../contexts/ManifestContext';
|
|
6
|
+
|
|
7
|
+
export default (): AppshellManifest => React.useContext<AppshellManifest>(ManifestContext);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Metadata } from '@appshell/config';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
// eslint-disable-next-line import/no-named-as-default
|
|
4
|
+
import MetadataContext from '../contexts/MetadataContext';
|
|
5
|
+
|
|
6
|
+
export default (): Metadata => React.useContext<Metadata>(MetadataContext);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AppshellIndex } from '@appshell/config';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
// eslint-disable-next-line import/no-named-as-default
|
|
4
|
+
import RegistryContext from '../contexts/RegistryContext';
|
|
5
|
+
|
|
6
|
+
export default (): AppshellIndex => React.useContext<AppshellIndex>(RegistryContext);
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { default as FederatedComponent } from './components/FederatedComponent';
|
|
2
|
+
export { default as ReactHost } from './components/ReactHost';
|
|
3
|
+
export { ManifestProvider } from './contexts/ManifestContext';
|
|
4
|
+
export { MetadataProvider } from './contexts/MetadataContext';
|
|
5
|
+
export { RegistryProvider } from './contexts/RegistryContext';
|
|
6
|
+
export { default as useManifest } from './hooks/useManifest';
|
|
7
|
+
export { default as useMetadata } from './hooks/useMetadata';
|
|
8
|
+
export { default as useRegistry } from './hooks/useRegistry';
|
|
9
|
+
export { default as jsonResource } from './resources/jsonResource';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export default <TResource>(url: string) => {
|
|
2
|
+
let status = 'pending';
|
|
3
|
+
let result: TResource | Error;
|
|
4
|
+
const suspender = fetch(url, {
|
|
5
|
+
headers: {
|
|
6
|
+
'Content-Type': 'application/json',
|
|
7
|
+
Accept: 'application/json',
|
|
8
|
+
},
|
|
9
|
+
// eslint-disable-next-line consistent-return
|
|
10
|
+
}).then((response) => {
|
|
11
|
+
if (response.ok) {
|
|
12
|
+
return response.json().then((data) => {
|
|
13
|
+
status = 'success';
|
|
14
|
+
result = data;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
status = 'error';
|
|
18
|
+
result = new Error(`${response.status} ${response.statusText} ${response.url}`);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
read() {
|
|
23
|
+
if (status === 'pending') {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
|
25
|
+
throw suspender as Promise<TResource>;
|
|
26
|
+
} else if (status === 'error') {
|
|
27
|
+
throw result as Error;
|
|
28
|
+
} else if (status === 'success') {
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return undefined;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
package/src/types.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|
2
|
+
const Visualizer = require('webpack-visualizer-plugin2');
|
|
3
|
+
|
|
4
|
+
module.exports = (env, { mode }) => {
|
|
5
|
+
const isDevelopment = mode === 'development';
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
entry: './src/index',
|
|
9
|
+
mode,
|
|
10
|
+
devtool: isDevelopment ? 'eval-source-map' : false,
|
|
11
|
+
output: {
|
|
12
|
+
filename: '[name].js',
|
|
13
|
+
pathinfo: false,
|
|
14
|
+
libraryTarget: 'umd',
|
|
15
|
+
},
|
|
16
|
+
resolve: {
|
|
17
|
+
extensions: ['.js', '.ts', '.tsx'],
|
|
18
|
+
plugins: [new TsconfigPathsPlugin()],
|
|
19
|
+
},
|
|
20
|
+
module: {
|
|
21
|
+
rules: [
|
|
22
|
+
{
|
|
23
|
+
test: /\.tsx?$/,
|
|
24
|
+
exclude: /node_modules/,
|
|
25
|
+
use: [
|
|
26
|
+
{
|
|
27
|
+
loader: 'babel-loader',
|
|
28
|
+
options: {
|
|
29
|
+
presets: ['@babel/preset-react', '@babel/preset-typescript'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
// plugins: [isDevelopment && new Visualizer()].filter(Boolean),
|
|
37
|
+
externals: {
|
|
38
|
+
react: 'react',
|
|
39
|
+
'react-dom': 'reactDOM',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
};
|