@appshell/loader 0.2.1 → 0.3.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/CHANGELOG.md +11 -0
- package/README.md +2 -2
- package/__tests__/{loadFederatedComponent.spec.ts → loadAppshellComponent.spec.ts} +6 -6
- package/__tests__/remoteLoader.spec.ts +9 -9
- package/dist/main.js +1 -1
- package/dist/types/config/src/mappers/appshell.config.d.ts.map +1 -1
- package/dist/types/config/src/register.d.ts +1 -1
- package/dist/types/config/src/register.d.ts.map +1 -1
- package/dist/types/loader/src/{loadFederatedComponent.d.ts → loadAppshellComponent.d.ts} +1 -1
- package/dist/types/loader/src/loadAppshellComponent.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/{loadFederatedComponent.ts → loadAppshellComponent.ts} +2 -2
- package/src/remoteLoader.ts +2 -2
- package/dist/types/loader/src/loadFederatedComponent.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.3.0](https://github.com/navaris/appshell/compare/@appshell/loader@0.2.1...@appshell/loader@0.3.0) (2024-01-25)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* AppshellComponent impl ([2b82621](https://github.com/navaris/appshell/commit/2b82621c13302f790a8e1c457f9a82f39903fc1f))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [0.2.1](https://github.com/navaris/appshell/compare/@appshell/loader@0.2.0...@appshell/loader@0.2.1) (2023-08-29)
|
|
7
18
|
|
|
8
19
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
# @appshell/loader
|
|
13
13
|
|
|
14
|
-
Dynamically load
|
|
14
|
+
Dynamically load Appshell components for micro-frontends built with Appshell and Webpack Module federation.
|
|
15
15
|
|
|
16
16
|
Working examples can be found [here](https://github.com/navaris/appshell/tree/main/examples).
|
|
17
17
|
|
|
@@ -35,7 +35,7 @@ or
|
|
|
35
35
|
pnpm add -D @appshell/loader
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
The default export from this package is the loader function. It is given the global appshell configuration, and returns an async function that can be called to dynamically load
|
|
38
|
+
The default export from this package is the loader function. It is given the global appshell configuration, and returns an async function that can be called to dynamically load Appshell components.
|
|
39
39
|
|
|
40
40
|
```ts
|
|
41
41
|
import componentLoader from '@appshell/loader';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
2
|
/* eslint-disable no-underscore-dangle */
|
|
3
|
-
import
|
|
3
|
+
import loadAppshellComponent from '../src/loadAppshellComponent';
|
|
4
4
|
import { ModuleContainer, ShareScope } from '../src/types';
|
|
5
5
|
|
|
6
6
|
type ComponentType = () => string;
|
|
@@ -49,7 +49,7 @@ const containers: Record<string, Record<string, ModuleContainer<ComponentType>>>
|
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
describe('
|
|
52
|
+
describe('loadAppshellComponent', () => {
|
|
53
53
|
beforeEach(() => {
|
|
54
54
|
window.__webpack_init_sharing__ = jest.fn(async (shareScope: string) => {
|
|
55
55
|
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
@@ -70,12 +70,12 @@ describe('loadFederatedComponent', () => {
|
|
|
70
70
|
window.__webpack_share_scopes__ = {};
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
it('should load the
|
|
73
|
+
it('should load the Appshell component from the default scope', async () => {
|
|
74
74
|
const scope = 'TestModule';
|
|
75
75
|
const module = './TestComponent';
|
|
76
76
|
const shareScope = undefined;
|
|
77
77
|
|
|
78
|
-
const Component = await
|
|
78
|
+
const Component = await loadAppshellComponent<ComponentType>(scope, module, shareScope);
|
|
79
79
|
|
|
80
80
|
expect(Component).toBe(TestComponent);
|
|
81
81
|
});
|
|
@@ -85,7 +85,7 @@ describe('loadFederatedComponent', () => {
|
|
|
85
85
|
const module = './TestComponent';
|
|
86
86
|
const shareScope = 'does_not_exist';
|
|
87
87
|
|
|
88
|
-
await expect(
|
|
88
|
+
await expect(loadAppshellComponent<ComponentType>(scope, module, shareScope)).rejects.toThrow(
|
|
89
89
|
/Failed to find module container/i,
|
|
90
90
|
);
|
|
91
91
|
});
|
|
@@ -95,7 +95,7 @@ describe('loadFederatedComponent', () => {
|
|
|
95
95
|
const module = './TestComponent';
|
|
96
96
|
const shareScope = 'no_factory';
|
|
97
97
|
|
|
98
|
-
await expect(
|
|
98
|
+
await expect(loadAppshellComponent<ComponentType>(scope, module, shareScope)).rejects.toThrow(
|
|
99
99
|
/Invalid factory produced/i,
|
|
100
100
|
);
|
|
101
101
|
});
|
|
@@ -3,13 +3,13 @@ import { AppshellManifest } from '@appshell/config';
|
|
|
3
3
|
import { AppshellGlobalConfig } from '@appshell/config/src/types';
|
|
4
4
|
import fetch, { enableFetchMocks } from 'jest-fetch-mock';
|
|
5
5
|
import * as fetchDynamicScript from '../src/fetchDynamicScript';
|
|
6
|
-
import * as
|
|
6
|
+
import * as loadAppshellComponent from '../src/loadAppshellComponent';
|
|
7
7
|
import remoteLoader from '../src/remoteLoader';
|
|
8
8
|
|
|
9
9
|
enableFetchMocks();
|
|
10
10
|
|
|
11
11
|
jest.mock('../src/fetchDynamicScript');
|
|
12
|
-
jest.mock('../src/
|
|
12
|
+
jest.mock('../src/loadAppshellComponent');
|
|
13
13
|
|
|
14
14
|
describe('remoteLoader', () => {
|
|
15
15
|
const manifest: AppshellManifest = {
|
|
@@ -50,11 +50,11 @@ describe('remoteLoader', () => {
|
|
|
50
50
|
);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
it('should return the
|
|
53
|
+
it('should return the Appshell component if it is found in the registry', async () => {
|
|
54
54
|
const ExpectedComponent = () => 'test component';
|
|
55
55
|
jest.spyOn(fetchDynamicScript, 'default').mockReturnValueOnce(Promise.resolve(true));
|
|
56
56
|
jest
|
|
57
|
-
.spyOn(
|
|
57
|
+
.spyOn(loadAppshellComponent, 'default')
|
|
58
58
|
.mockResolvedValue(Promise.resolve(ExpectedComponent));
|
|
59
59
|
|
|
60
60
|
const loadRemote = remoteLoader(config);
|
|
@@ -70,7 +70,7 @@ describe('remoteLoader', () => {
|
|
|
70
70
|
.spyOn(fetchDynamicScript, 'default')
|
|
71
71
|
.mockReturnValueOnce(Promise.resolve(true));
|
|
72
72
|
jest
|
|
73
|
-
.spyOn(
|
|
73
|
+
.spyOn(loadAppshellComponent, 'default')
|
|
74
74
|
.mockResolvedValue(Promise.resolve(ExpectedComponent));
|
|
75
75
|
|
|
76
76
|
const loadRemote = remoteLoader(config);
|
|
@@ -86,7 +86,7 @@ describe('remoteLoader', () => {
|
|
|
86
86
|
const ExpectedComponent = () => 'test component';
|
|
87
87
|
jest.spyOn(fetchDynamicScript, 'default').mockReturnValueOnce(Promise.resolve(true));
|
|
88
88
|
jest
|
|
89
|
-
.spyOn(
|
|
89
|
+
.spyOn(loadAppshellComponent, 'default')
|
|
90
90
|
.mockResolvedValue(Promise.resolve(ExpectedComponent));
|
|
91
91
|
|
|
92
92
|
const loadRemote = remoteLoader(config);
|
|
@@ -99,7 +99,7 @@ describe('remoteLoader', () => {
|
|
|
99
99
|
|
|
100
100
|
it('should throw if remote key is not found in the registry', async () => {
|
|
101
101
|
const ExpectedComponent = () => 'test component';
|
|
102
|
-
jest.spyOn(
|
|
102
|
+
jest.spyOn(loadAppshellComponent, 'default').mockResolvedValue(ExpectedComponent);
|
|
103
103
|
|
|
104
104
|
const loadRemote = remoteLoader(config);
|
|
105
105
|
|
|
@@ -108,9 +108,9 @@ describe('remoteLoader', () => {
|
|
|
108
108
|
);
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
it('should throw if load
|
|
111
|
+
it('should throw if load Appshell component fails', async () => {
|
|
112
112
|
jest.spyOn(fetchDynamicScript, 'default').mockReturnValueOnce(Promise.resolve(true));
|
|
113
|
-
jest.spyOn(
|
|
113
|
+
jest.spyOn(loadAppshellComponent, 'default').mockRejectedValue(new Error('failed'));
|
|
114
114
|
|
|
115
115
|
const loadRemote = remoteLoader(config);
|
|
116
116
|
|
package/dist/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,o){if("object"==typeof exports&&"object"==typeof module)module.exports=o();else if("function"==typeof define&&define.amd)define([],o);else{var t=o();for(var r in t)("object"==typeof exports?exports:e)[r]=t[r]}}(self,(()=>(()=>{"use strict";var e={d:(o,t)=>{for(var r in t)e.o(t,r)&&!e.o(o,r)&&Object.defineProperty(o,r,{enumerable:!0,get:t[r]})},o:(e,o)=>Object.prototype.hasOwnProperty.call(e,o),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}};(()=>{e.S={};var o={},t={};e.I=(r,n)=>{n||(n=[]);var a=t[r];if(a||(a=t[r]={}),!(n.indexOf(a)>=0)){if(n.push(a),o[r])return o[r];e.o(e.S,r)||(e.S[r]={}),e.S[r];var
|
|
1
|
+
!function(e,o){if("object"==typeof exports&&"object"==typeof module)module.exports=o();else if("function"==typeof define&&define.amd)define([],o);else{var t=o();for(var r in t)("object"==typeof exports?exports:e)[r]=t[r]}}(self,(()=>(()=>{"use strict";var e={d:(o,t)=>{for(var r in t)e.o(t,r)&&!e.o(o,r)&&Object.defineProperty(o,r,{enumerable:!0,get:t[r]})},o:(e,o)=>Object.prototype.hasOwnProperty.call(e,o),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}};(()=>{e.S={};var o={},t={};e.I=(r,n)=>{n||(n=[]);var a=t[r];if(a||(a=t[r]={}),!(n.indexOf(a)>=0)){if(n.push(a),o[r])return o[r];e.o(e.S,r)||(e.S[r]={}),e.S[r];var i=[];return o[r]=i.length?Promise.all(i).then((()=>o[r]=1)):1}}})();var o={};e.r(o),e.d(o,{default:()=>a});const t=new Set,r=new Set,n=new Map,a=o=>async a=>{let i;const c=o.index[a];if(!c)throw new Error(`Remote resource not found in registry. Expected: ${a}`);try{const d=await(async e=>{if(n.has(e))return n.get(e);n.set(e,void 0);const o=await fetch(e);if(o.ok)return o.json();const t=await o.text();throw new Error(`Failed to get manifest from ${e}. ${t}`)})(c);if(d){n.set(c,d);const s=d.remotes[a],l=d.environment[s.scope]||{},f=o.overrides?.environment&&o.overrides?.environment[s.scope]||{};if(window[`__appshell_env__${s.scope}`]={...l,...f},r.has(s.remoteEntryUrl)||await(async e=>{const o=document.createElement("script");return new Promise(((r,n)=>{t.has(e)?r(!1):(t.add(e),o.src=e,o.type="text/javascript",o.async=!0,o.onload=()=>{console.debug(`Remote entry fetched from '${e}'.`),r(!0)},o.onerror=()=>{const o=`Failed to fetch remote entry from '${e}'.`;console.error(o),n(o)},document.head.appendChild(o))})).finally((()=>{document.head.contains(o)&&document.head.removeChild(o)}))})(s.remoteEntryUrl))return r.add(s.remoteEntryUrl),i=await(async(o,t,r="default")=>{console.debug(`loading Appshell component: { scope: ${o}, module: ${t}, shareScope: ${r} }`),await e.I(r);const n=window[o];if(!n)throw new Error(`Failed to find module container ${o}`);await n.init(e.S[r]);const a=await n.get(t);if(!a)throw new Error(`Invalid factory produced by container for module ${t}.`);const i=a();return console.debug(`Appshell component loaded: { scope: ${o}, module: ${t}, shareScope: ${r} }`),i.default})(s.scope,s.module,s.shareScope),[i,d]}return[null,null]}catch(e){throw new Error(`Failed to load component '${a}'. ${e?.toString()}`)}};return o})()));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appshell.config.d.ts","sourceRoot":"","sources":["../../../../../../config/src/mappers/appshell.config.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,gBAAgB,EAEhB,gBAAgB,EAChB,SAAS,EACV,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"appshell.config.d.ts","sourceRoot":"","sources":["../../../../../../config/src/mappers/appshell.config.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,gBAAgB,EAEhB,gBAAgB,EAChB,SAAS,EACV,MAAM,UAAU,CAAC;AAiElB,eAAO,MAAM,kBAAkB,wDACnB,gBAAgB,QACpB,SAAS,gCAQhB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { AppshellManifest } from './types';
|
|
2
|
-
declare const _default: (manifest: AppshellManifest, registryPathOrUrl: string) => Promise<void>;
|
|
2
|
+
declare const _default: (manifest: AppshellManifest, registryPathOrUrl: string, allowOverrides?: boolean) => Promise<void>;
|
|
3
3
|
export default _default;
|
|
4
4
|
//# sourceMappingURL=register.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../../config/src/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,gBAAgB,EAAmB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../../config/src/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,gBAAgB,EAAmB,MAAM,SAAS,CAAC;mCAetE,gBAAgB,qBACP,MAAM;AAF3B,wBA2CE"}
|
|
@@ -11,4 +11,4 @@ declare global {
|
|
|
11
11
|
}
|
|
12
12
|
declare const _default: <TComponent>(scope: string, module: string, shareScope?: string) => Promise<TComponent>;
|
|
13
13
|
export default _default;
|
|
14
|
-
//# sourceMappingURL=
|
|
14
|
+
//# sourceMappingURL=loadAppshellComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadAppshellComponent.d.ts","sourceRoot":"","sources":["../../../../src/loadAppshellComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,UAAU,EAAE,MAAM,SAAS,CAAC;AAGtD,OAAO,CAAC,MAAM,CAAC;IACb,SAAS,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7D,MAAM,wBAAwB,EAAE;QAAE,OAAO,EAAE,UAAU,CAAA;KAAE,CAAC;IACxD,UAAU,MAAM;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACvB,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;KACtD;CACF;4CAIwC,MAAM,UAAU,MAAM;AAA/D,wBAgCE"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appshell/loader",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Utility for loading
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Utility for loading Appshell components",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"types": "dist/loader/src/index.d.ts",
|
|
7
7
|
"repository": "https://github.com/navaris/appshell.git",
|
|
@@ -25,5 +25,5 @@
|
|
|
25
25
|
"appshell"
|
|
26
26
|
],
|
|
27
27
|
"license": "MIT",
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "554727a36140e4b8f609159795e1011801824108"
|
|
29
29
|
}
|
|
@@ -16,7 +16,7 @@ type ShareScopes = keyof typeof __webpack_share_scopes__;
|
|
|
16
16
|
export default async <TComponent>(scope: string, module: string, shareScope = 'default') => {
|
|
17
17
|
// eslint-disable-next-line no-console
|
|
18
18
|
console.debug(
|
|
19
|
-
`loading
|
|
19
|
+
`loading Appshell component: { scope: ${scope}, module: ${module}, shareScope: ${shareScope} }`,
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
// Initializes the share scope. This fills it with known provided modules from this build and all remotes
|
|
@@ -39,7 +39,7 @@ export default async <TComponent>(scope: string, module: string, shareScope = 'd
|
|
|
39
39
|
|
|
40
40
|
// eslint-disable-next-line no-console
|
|
41
41
|
console.debug(
|
|
42
|
-
`
|
|
42
|
+
`Appshell component loaded: { scope: ${scope}, module: ${module}, shareScope: ${shareScope} }`,
|
|
43
43
|
);
|
|
44
44
|
|
|
45
45
|
const Component = Module.default;
|
package/src/remoteLoader.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { type AppshellManifest } from '@appshell/config';
|
|
3
3
|
import { AppshellGlobalConfig } from 'packages/config/src/types';
|
|
4
4
|
import fetchDynamicScript from './fetchDynamicScript';
|
|
5
|
-
import
|
|
5
|
+
import loadAppshellComponent from './loadAppshellComponent';
|
|
6
6
|
|
|
7
7
|
const fetchedScriptCache = new Set<string>();
|
|
8
8
|
const fetchedManifestCache = new Map<string, AppshellManifest | undefined>();
|
|
@@ -53,7 +53,7 @@ export default (config: AppshellGlobalConfig) =>
|
|
|
53
53
|
(await fetchDynamicScript(remote.remoteEntryUrl));
|
|
54
54
|
if (loaded) {
|
|
55
55
|
fetchedScriptCache.add(remote.remoteEntryUrl);
|
|
56
|
-
Component = await
|
|
56
|
+
Component = await loadAppshellComponent<TComponent>(
|
|
57
57
|
remote.scope,
|
|
58
58
|
remote.module,
|
|
59
59
|
remote.shareScope,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loadFederatedComponent.d.ts","sourceRoot":"","sources":["../../../../src/loadFederatedComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,UAAU,EAAE,MAAM,SAAS,CAAC;AAGtD,OAAO,CAAC,MAAM,CAAC;IACb,SAAS,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7D,MAAM,wBAAwB,EAAE;QAAE,OAAO,EAAE,UAAU,CAAA;KAAE,CAAC;IACxD,UAAU,MAAM;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACvB,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;KACtD;CACF;4CAIwC,MAAM,UAAU,MAAM;AAA/D,wBAgCE"}
|