@appshell/loader 0.0.1-alpha.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +60 -0
  4. package/__tests__/fetchDynamicScript.spec.ts +36 -0
  5. package/__tests__/fixtures/TestComponent.ts +3 -0
  6. package/__tests__/loadFederatedComponent.spec.ts +112 -0
  7. package/__tests__/remoteLoader.spec.ts +53 -0
  8. package/dist/main.js +1 -0
  9. package/dist/types/config/src/configmap.d.ts +7 -0
  10. package/dist/types/config/src/configmap.d.ts.map +1 -0
  11. package/dist/types/config/src/generate.d.ts +10 -0
  12. package/dist/types/config/src/generate.d.ts.map +1 -0
  13. package/dist/types/config/src/index.d.ts +9 -0
  14. package/dist/types/config/src/index.d.ts.map +1 -0
  15. package/dist/types/config/src/mappers/appshell.config.d.ts +3 -0
  16. package/dist/types/config/src/mappers/appshell.config.d.ts.map +1 -0
  17. package/dist/types/config/src/types.d.ts +207 -0
  18. package/dist/types/config/src/types.d.ts.map +1 -0
  19. package/dist/types/config/src/utils/copy.d.ts +11 -0
  20. package/dist/types/config/src/utils/copy.d.ts.map +1 -0
  21. package/dist/types/config/src/utils/index.d.ts +5 -0
  22. package/dist/types/config/src/utils/index.d.ts.map +1 -0
  23. package/dist/types/config/src/utils/list.d.ts +10 -0
  24. package/dist/types/config/src/utils/list.d.ts.map +1 -0
  25. package/dist/types/config/src/utils/load.d.ts +14 -0
  26. package/dist/types/config/src/utils/load.d.ts.map +1 -0
  27. package/dist/types/config/src/utils/merge.d.ts +4 -0
  28. package/dist/types/config/src/utils/merge.d.ts.map +1 -0
  29. package/dist/types/config/src/validators/appshell.config.d.ts +4 -0
  30. package/dist/types/config/src/validators/appshell.config.d.ts.map +1 -0
  31. package/dist/types/config/src/validators/appshell.manifest.d.ts +4 -0
  32. package/dist/types/config/src/validators/appshell.manifest.d.ts.map +1 -0
  33. package/dist/types/config/src/validators/index.d.ts +3 -0
  34. package/dist/types/config/src/validators/index.d.ts.map +1 -0
  35. package/dist/types/loader/src/fetchDynamicScript.d.ts +3 -0
  36. package/dist/types/loader/src/fetchDynamicScript.d.ts.map +1 -0
  37. package/dist/types/loader/src/index.d.ts +4 -0
  38. package/dist/types/loader/src/index.d.ts.map +1 -0
  39. package/dist/types/loader/src/loadFederatedComponent.d.ts +14 -0
  40. package/dist/types/loader/src/loadFederatedComponent.d.ts.map +1 -0
  41. package/dist/types/loader/src/remoteLoader.d.ts +4 -0
  42. package/dist/types/loader/src/remoteLoader.d.ts.map +1 -0
  43. package/dist/types/loader/src/types.d.ts +11 -0
  44. package/dist/types/loader/src/types.d.ts.map +1 -0
  45. package/package.json +24 -0
  46. package/src/fetchDynamicScript.ts +33 -0
  47. package/src/index.ts +5 -0
  48. package/src/loadFederatedComponent.ts +48 -0
  49. package/src/remoteLoader.ts +26 -0
  50. package/src/types.ts +10 -0
  51. package/tsconfig.json +7 -0
  52. package/webpack.config.js +37 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## 0.0.1-alpha.0 (2023-03-19)
7
+
8
+ **Note:** Version bump only for package @appshell/loader
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Navaris Technologies, LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ <div align="center">
2
+ <a href="https://github.com/navaris/appshell">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/navaris/appshell/blob/main/assets/branding/appshell-logo-white_2x.png">
5
+ <img alt="appshell" src="https://github.com/navaris/appshell/blob/main/assets/branding/appshell-logo_2x.png">
6
+ </picture>
7
+ </a>
8
+ </div>
9
+
10
+ [![Appshell CI](https://github.com/navaris/appshell/actions/workflows/pipeline.yml/badge.svg)](https://github.com/navaris/appshell/actions/workflows/pipeline.yml)
11
+
12
+ # @appshell/loader
13
+
14
+ Dynamically load federated components for Webpack Module federation micro-frontends.
15
+
16
+ Working examples can be found [here](https://github.com/navaris/appshell/tree/main/examples).
17
+
18
+ ## Getting Started
19
+
20
+ To begin, you'll need to install `@appshell/loader`:
21
+
22
+ ```console
23
+ npm install @appshell/loader --save-dev
24
+ ```
25
+
26
+ or
27
+
28
+ ```console
29
+ yarn add -D @appshell/loader
30
+ ```
31
+
32
+ or
33
+
34
+ ```console
35
+ pnpm add -D @appshell/loader
36
+ ```
37
+
38
+ The default export from this package is the loader function. It is given a manifest and returns an async function that can be called to dynamically load federated components.
39
+
40
+ ```ts
41
+ import componentLoader from '@appshell/loader';
42
+
43
+ const load = componentLoader(manifest);
44
+
45
+ const Component = load<MyComponent>('MyModule/MyComponent');
46
+
47
+ render(<Component />);
48
+ ```
49
+
50
+ **Where does the manifest come from?**
51
+
52
+ > See [@appshell/cli](https://www.npmjs.com/package/@appshell/cli)
53
+
54
+ ```bash
55
+ appshell generate manifest --configsDir appshell_configs
56
+ ```
57
+
58
+ **Do you have any framework specific loaders?**
59
+
60
+ > See [@appshell/react-federated-component](https://www.npmjs.com/package/@appshell/react-federated-component) for a `React` loader.
@@ -0,0 +1,36 @@
1
+ /** @jest-environment jsdom */
2
+ import { fireEvent } from '@testing-library/react';
3
+ import fetchDynamicScript from '../src/fetchDynamicScript';
4
+
5
+ const mockHead = (event: string) => {
6
+ const appendChildSpy = jest.spyOn(document.head, 'appendChild').mockImplementation((element) => {
7
+ fireEvent(element, new Event(event));
8
+ return element;
9
+ });
10
+ const removeChildSpy = jest.spyOn(document.head, 'removeChild').mockReturnThis();
11
+
12
+ return [appendChildSpy, removeChildSpy];
13
+ };
14
+
15
+ describe('fetchDynamicScript', () => {
16
+ it('should successfully resolve when valid script url is provided', async () => {
17
+ mockHead('load');
18
+ const url = 'http://test.com/somescript.js';
19
+ const success = await fetchDynamicScript(url);
20
+
21
+ expect(success).toBe(true);
22
+ });
23
+
24
+ it('should reject when fetching the script results in an error', async () => {
25
+ mockHead('error');
26
+ const url = 'http://test.com/somescript.js';
27
+
28
+ await expect(fetchDynamicScript(url)).rejects.toMatch(/Failed to fetch remote entry/i);
29
+ });
30
+
31
+ it('should cleanup script tags when finished', async () => {
32
+ const [, removeChildSpy] = mockHead('load');
33
+
34
+ expect(removeChildSpy).toHaveBeenCalled();
35
+ });
36
+ });
@@ -0,0 +1,3 @@
1
+ const TestComponent = () => 'test component';
2
+
3
+ export default TestComponent;
@@ -0,0 +1,112 @@
1
+ /** @jest-environment jsdom */
2
+ /* eslint-disable no-underscore-dangle */
3
+ import loadFederatedComponent from '../src/loadFederatedComponent';
4
+ import { ModuleContainer, ShareScope } from '../src/types';
5
+
6
+ type ComponentType = () => string;
7
+
8
+ const TestComponent = () => 'test component';
9
+ const mockModule = {
10
+ './TestComponent': {
11
+ get: jest.fn(),
12
+ from: '',
13
+ eager: false,
14
+ },
15
+ };
16
+ const scopes: Record<string, ShareScope<ComponentType>> = {
17
+ default: {
18
+ TestModule: mockModule,
19
+ },
20
+ test_scope: {
21
+ TestModule2: mockModule,
22
+ },
23
+ no_factory: {
24
+ TestModule3: mockModule,
25
+ },
26
+ };
27
+ const containers: Record<string, Record<string, ModuleContainer<ComponentType>>> = {
28
+ default: {
29
+ TestModule: {
30
+ init: jest.fn(),
31
+ get: jest.fn().mockReturnValue(() => ({
32
+ default: TestComponent,
33
+ })),
34
+ },
35
+ },
36
+ test_scope: {
37
+ TestModule2: {
38
+ init: jest.fn(),
39
+ get: jest.fn().mockReturnValue(() => ({
40
+ test_scope: TestComponent,
41
+ })),
42
+ },
43
+ },
44
+ no_factory: {
45
+ TestModule3: {
46
+ init: jest.fn(),
47
+ get: jest.fn().mockReturnValue(undefined),
48
+ },
49
+ },
50
+ };
51
+
52
+ describe('loadFederatedComponent', () => {
53
+ beforeEach(() => {
54
+ window.__webpack_init_sharing__ = jest.fn(async (shareScope: string) => {
55
+ // eslint-disable-next-line @typescript-eslint/dot-notation
56
+ Object.entries(containers[shareScope] || {}).forEach(([key, module]) => {
57
+ window[key] = module;
58
+ });
59
+ window.__webpack_share_scopes__ = {};
60
+ window.__webpack_share_scopes__[shareScope] = scopes[shareScope];
61
+ });
62
+ });
63
+
64
+ afterEach(() => {
65
+ Object.values(window.__webpack_share_scopes__ || {})
66
+ .flatMap((val) => Object.keys(val || {}))
67
+ .forEach((key) => {
68
+ delete window[key];
69
+ });
70
+ window.__webpack_share_scopes__ = {};
71
+ });
72
+
73
+ it('should load the federated component from the default scope', async () => {
74
+ const scope = 'TestModule';
75
+ const module = './TestComponent';
76
+ const shareScope = undefined;
77
+
78
+ const Component = await loadFederatedComponent<ComponentType>(scope, module, shareScope);
79
+
80
+ expect(Component).toBe(TestComponent);
81
+ });
82
+
83
+ it('should load the federated component from the share scope', async () => {
84
+ const scope = 'TestModule2';
85
+ const module = './TestComponent';
86
+ const shareScope = 'test_scope';
87
+
88
+ const Component = await loadFederatedComponent<ComponentType>(scope, module, shareScope);
89
+
90
+ expect(Component).toBe(TestComponent);
91
+ });
92
+
93
+ it('should throw if the share scope does not exist', async () => {
94
+ const scope = 'TestModule';
95
+ const module = './TestComponent';
96
+ const shareScope = 'does_not_exist';
97
+
98
+ await expect(loadFederatedComponent<ComponentType>(scope, module, shareScope)).rejects.toThrow(
99
+ /Failed to find module container/i,
100
+ );
101
+ });
102
+
103
+ it('should throw if the module factory does not exist', async () => {
104
+ const scope = 'TestModule3';
105
+ const module = './TestComponent';
106
+ const shareScope = 'no_factory';
107
+
108
+ await expect(loadFederatedComponent<ComponentType>(scope, module, shareScope)).rejects.toThrow(
109
+ /Invalid factory produced/i,
110
+ );
111
+ });
112
+ });
@@ -0,0 +1,53 @@
1
+ /** @jest-environment jsdom */
2
+ import { AppshellManifest } from '@appshell/config';
3
+ import * as loadFederatedComponent from '../src/loadFederatedComponent';
4
+ import remoteLoader from '../src/remoteLoader';
5
+
6
+ jest.mock('../src/fetchDynamicScript');
7
+ jest.mock('../src/loadFederatedComponent');
8
+
9
+ describe('remoteLoader', () => {
10
+ const manifest: AppshellManifest = {
11
+ remotes: {
12
+ 'TestModule/TestComponent': {
13
+ id: 'test-component',
14
+ scope: 'TestModule',
15
+ module: './TestComponent',
16
+ url: 'http://test.com/remoteEntry.js',
17
+ metadata: {},
18
+ },
19
+ },
20
+ modules: {},
21
+ };
22
+
23
+ it('should return the federated component if it is found in the manifest', async () => {
24
+ const ExpectedComponent = () => 'test component';
25
+ jest.spyOn(loadFederatedComponent, 'default').mockResolvedValue(ExpectedComponent);
26
+
27
+ const loadRemote = remoteLoader(manifest);
28
+ const ActualComponent = await loadRemote('TestModule/TestComponent');
29
+
30
+ expect(ActualComponent).toEqual(ExpectedComponent);
31
+ });
32
+
33
+ it('should throw if remote key is not found in the manifest', async () => {
34
+ const ExpectedComponent = () => 'test component';
35
+ jest.spyOn(loadFederatedComponent, 'default').mockResolvedValue(ExpectedComponent);
36
+
37
+ const loadRemote = remoteLoader(manifest);
38
+
39
+ await expect(loadRemote('TestModule/DoesNotExist')).rejects.toThrow(
40
+ /Remote resource not found in manifest/i,
41
+ );
42
+ });
43
+
44
+ it('should throw if load federated component fails', async () => {
45
+ jest.spyOn(loadFederatedComponent, 'default').mockRejectedValue(new Error('failed'));
46
+
47
+ const loadRemote = remoteLoader(manifest);
48
+
49
+ await expect(loadRemote('TestModule/TestComponent')).rejects.toThrow(
50
+ /Failed to load component/i,
51
+ );
52
+ });
53
+ });
package/dist/main.js ADDED
@@ -0,0 +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 d=[];return o[r]=d.length?Promise.all(d).then((()=>o[r]=1)):1}}})();var o={};e.r(o),e.d(o,{default:()=>r});const t=new Set,r=o=>async r=>{let n;const a=o.remotes[r];if(!a)throw new Error(`Remote resource not found in manifest. Expected: ${r}`);try{return await(async e=>{const o=document.createElement("script");return new Promise(((r,n)=>{o.src=e,o.type="text/javascript",o.async=!0,o.onload=()=>{t.add(e),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((()=>{t.delete(e),document.head.removeChild(o)}))})(a.url),n=await(async(o,t,r="default")=>{console.debug(`loading federated 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 d=a();return console.debug(`federated component loaded: { scope: ${o}, module: ${t}, shareScope: ${r} }`),d[r]})(a.scope,a.module,a.shareScope),n}catch(e){throw new Error(`Failed to load component '${r}'. ${e?.toString()}`)}};return o})()));
@@ -0,0 +1,7 @@
1
+ import { AppshellConfig, ConfigMap } from './types';
2
+ declare const _default: {
3
+ apply: <T extends object>(obj: T, configMap: ConfigMap) => T;
4
+ create: (config: AppshellConfig<Record<string, unknown>>) => Record<string, string>;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=configmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configmap.d.ts","sourceRoot":"","sources":["../../../../../config/src/configmap.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;;;;;AAgDpD,wBAGE"}
@@ -0,0 +1,10 @@
1
+ import { AppshellManifest } from './types';
2
+ /**
3
+ * Compiles all configuration into an appshell manifest
4
+ * @param configsDir directory of configs to compile into an appshell manifest
5
+ * @param searchDepth depth to which app configs should be searched in configsDir
6
+ * @returns an appshell manifest
7
+ */
8
+ declare const _default: <TMetadata extends Record<string, unknown>>(configsDir: string, searchDepth?: number) => AppshellManifest<TMetadata>;
9
+ export default _default;
10
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../../../config/src/generate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAI3C;;;;;GAKG;gFACoE,MAAM;AAA7E,wBAaE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @appshell/config package API
3
+ */
4
+ export { default as configmap } from './configmap';
5
+ export { default as generate } from './generate';
6
+ export type { AppshellConfig, AppshellConfigRemote, AppshellManifest, AppshellRemote, Schema, } from './types';
7
+ export * as utils from './utils';
8
+ export * as validators from './validators';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../config/src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,MAAM,GACP,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { AppshellConfig, AppshellManifest, ConfigMap } from '../types';
2
+ export declare const toAppshellManifest: <TMetadata extends Record<string, unknown>>(config: AppshellConfig, args: ConfigMap) => AppshellManifest<TMetadata>;
3
+ //# sourceMappingURL=appshell.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appshell.config.d.ts","sourceRoot":"","sources":["../../../../../../config/src/mappers/appshell.config.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,cAAc,EAEd,gBAAgB,EAEhB,SAAS,EACV,MAAM,UAAU,CAAC;AAwDlB,eAAO,MAAM,kBAAkB,sDACrB,cAAc,QAChB,SAAS,gCAQhB,CAAC"}
@@ -0,0 +1,207 @@
1
+ import { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema';
2
+ export type Schema = JSONSchema4 | JSONSchema6 | JSONSchema7;
3
+ export type ConfigValidator = {
4
+ validate: <T>(...config: T[]) => void;
5
+ };
6
+ export type ConfigMap = Record<string, string>;
7
+ export type AppshellConfigRemote<TMetadata = Record<string, unknown>> = {
8
+ id: string;
9
+ url: string;
10
+ metadata: TMetadata;
11
+ };
12
+ export type AppshellConfig<TMetadata = Record<string, unknown>> = {
13
+ name?: string;
14
+ remotes?: Record<string, AppshellConfigRemote<TMetadata>>;
15
+ module: ModuleFederationPluginOptions;
16
+ };
17
+ /** Appshell manifest types */
18
+ export type AppshellRemote<TMetadata = Record<string, unknown>> = {
19
+ id: string;
20
+ url: string;
21
+ scope: string;
22
+ module: string;
23
+ shareScope?: string;
24
+ metadata: TMetadata;
25
+ };
26
+ export type AppshellManifest<TMetadata = Record<string, unknown>> = {
27
+ remotes: Record<string, AppshellRemote<TMetadata>>;
28
+ modules: Record<string, ModuleFederationPluginOptions>;
29
+ };
30
+ /**
31
+ * Advanced configuration for modules that should be exposed by this container.
32
+ */
33
+ export interface ExposesConfig {
34
+ /**
35
+ * Request to a module that should be exposed by this container.
36
+ */
37
+ import: string | string[];
38
+ /**
39
+ * Custom chunk name for the exposed module.
40
+ */
41
+ name?: string;
42
+ }
43
+ export interface ExposesObject {
44
+ [index: string]: string | ExposesConfig | string[];
45
+ }
46
+ /**
47
+ * Set explicit comments for `commonjs`, `commonjs2`, `amd`, and `root`.
48
+ */
49
+ export interface LibraryCustomUmdCommentObject {
50
+ /**
51
+ * Set comment for `amd` section in UMD.
52
+ */
53
+ amd?: string;
54
+ /**
55
+ * Set comment for `commonjs` (exports) section in UMD.
56
+ */
57
+ commonjs?: string;
58
+ /**
59
+ * Set comment for `commonjs2` (module.exports) section in UMD.
60
+ */
61
+ commonjs2?: string;
62
+ /**
63
+ * Set comment for `root` (global variable) section in UMD.
64
+ */
65
+ root?: string;
66
+ }
67
+ /**
68
+ * Description object for all UMD variants of the library name.
69
+ */
70
+ export interface LibraryCustomUmdObject {
71
+ /**
72
+ * Name of the exposed AMD library in the UMD.
73
+ */
74
+ amd?: string;
75
+ /**
76
+ * Name of the exposed commonjs export in the UMD.
77
+ */
78
+ commonjs?: string;
79
+ /**
80
+ * Name of the property exposed globally by a UMD library.
81
+ */
82
+ root?: string | string[];
83
+ }
84
+ /**
85
+ * Options for library.
86
+ */
87
+ export interface LibraryOptions {
88
+ /**
89
+ * Add a comment in the UMD wrapper.
90
+ */
91
+ auxiliaryComment?: string | LibraryCustomUmdCommentObject;
92
+ /**
93
+ * Specify which export should be exposed as library.
94
+ */
95
+ export?: string | string[];
96
+ /**
97
+ * The name of the library (some types allow unnamed libraries too).
98
+ */
99
+ name?: string | string[] | LibraryCustomUmdObject;
100
+ /**
101
+ * Type of library (types included by default are 'var', 'module', 'assign', 'assign-properties', 'this', 'window', 'self', 'global', 'commonjs', 'commonjs2', 'commonjs-module', 'commonjs-static', 'amd', 'amd-require', 'umd', 'umd2', 'jsonp', 'system', but others might be added by plugins).
102
+ */
103
+ type: string;
104
+ /**
105
+ * If `output.libraryTarget` is set to umd and `output.library` is set, setting this to true will name the AMD module.
106
+ */
107
+ umdNamedDefine?: boolean;
108
+ }
109
+ export interface SharedConfig {
110
+ /**
111
+ * Include the provided and fallback module directly instead behind an async request. This allows to use this shared module in initial load too. All possible shared modules need to be eager too.
112
+ */
113
+ eager?: boolean;
114
+ /**
115
+ * Provided module that should be provided to share scope. Also acts as fallback module if no shared module is found in share scope or version isn't valid. Defaults to the property name.
116
+ */
117
+ import?: string | false;
118
+ /**
119
+ * Package name to determine required version from description file. This is only needed when package name can't be automatically determined from request.
120
+ */
121
+ packageName?: string;
122
+ /**
123
+ * Version requirement from module in share scope.
124
+ */
125
+ requiredVersion?: string | false;
126
+ /**
127
+ * Module is looked up under this key from the share scope.
128
+ */
129
+ shareKey?: string;
130
+ /**
131
+ * Share scope name.
132
+ */
133
+ shareScope?: string;
134
+ /**
135
+ * Allow only a single version of the shared module in share scope (disabled by default).
136
+ */
137
+ singleton?: boolean;
138
+ /**
139
+ * Do not accept shared module if version is not valid (defaults to yes, if local fallback module is available and shared module is not a singleton, otherwise no, has no effect if there is no required version specified).
140
+ */
141
+ strictVersion?: boolean;
142
+ /**
143
+ * Version of the provided module. Will replace lower matching versions, but not higher.
144
+ */
145
+ version?: string | false;
146
+ }
147
+ export interface SharedObject {
148
+ [index: string]: string | SharedConfig;
149
+ }
150
+ /**
151
+ * Advanced configuration for container locations from which modules should be resolved and loaded at runtime.
152
+ */
153
+ export interface RemotesConfig {
154
+ /**
155
+ * Container locations from which modules should be resolved and loaded at runtime.
156
+ */
157
+ external: string | string[];
158
+ /**
159
+ * The name of the share scope shared with this remote.
160
+ */
161
+ shareScope?: string;
162
+ }
163
+ /**
164
+ * Container locations from which modules should be resolved and loaded at runtime. Property names are used as request scopes.
165
+ */
166
+ export interface RemotesObject {
167
+ [index: string]: string | RemotesConfig | string[];
168
+ }
169
+ export interface ModuleFederationPluginOptions {
170
+ /**
171
+ * Modules that should be exposed by this container. When provided, property name is used as public name, otherwise public name is automatically inferred from request.
172
+ */
173
+ exposes?: (string | ExposesObject)[] | ExposesObject;
174
+ /**
175
+ * The filename of the container as relative path inside the `output.path` directory.
176
+ */
177
+ filename?: string;
178
+ /**
179
+ * Options for library.
180
+ */
181
+ library?: LibraryOptions;
182
+ /**
183
+ * The name of the container.
184
+ */
185
+ name?: string;
186
+ /**
187
+ * The external type of the remote containers.
188
+ */
189
+ remoteType?: 'import' | 'var' | 'module' | 'assign' | 'this' | 'window' | 'self' | 'global' | 'commonjs' | 'commonjs2' | 'commonjs-module' | 'commonjs-static' | 'amd' | 'amd-require' | 'umd' | 'umd2' | 'jsonp' | 'system' | 'promise' | 'script' | 'node-commonjs';
190
+ /**
191
+ * Container locations and request scopes from which modules should be resolved and loaded at runtime. When provided, property name is used as request scope, otherwise request scope is automatically inferred from container location.
192
+ */
193
+ remotes?: (string | RemotesObject)[] | RemotesObject;
194
+ /**
195
+ * The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.
196
+ */
197
+ runtime?: string | false;
198
+ /**
199
+ * Share scope name used for all shared modules (defaults to 'default').
200
+ */
201
+ shareScope?: string;
202
+ /**
203
+ * Modules that should be shared in the share scope. When provided, property names are used to match requested modules in this compilation.
204
+ */
205
+ shared?: (string | SharedObject)[] | SharedObject;
206
+ }
207
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../config/src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Safely copies files and makes directories if they don't exist.
3
+ * @param pattern { from: @type string, to: @type string }
4
+ * @returns void
5
+ */
6
+ declare const _default: (pattern: {
7
+ from: string;
8
+ to: string;
9
+ }) => void;
10
+ export default _default;
11
+ //# sourceMappingURL=copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../../../../config/src/utils/copy.ts"],"names":[],"mappings":"AAGA;;;;GAIG;kCACsB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AAArD,wBAOE"}
@@ -0,0 +1,5 @@
1
+ export { default as copy } from './copy';
2
+ export { default as list } from './list';
3
+ export { default as load, loadAll } from './load';
4
+ export { default as merge } from './merge';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../config/src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Lists all files found in dirPath or its subdirectories
3
+ * @param dirPath directory to search
4
+ * @param depth depth to which the search should execute
5
+ * @param target filename to filter results on
6
+ * @returns list of paths for all files found
7
+ */
8
+ declare const list: (dirPath: string, depth?: number, target?: string | RegExp) => string[];
9
+ export default list;
10
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../../../config/src/utils/list.ts"],"names":[],"mappings":"AAoBA;;;;;;GAMG;AACH,QAAA,MAAM,IAAI,YAAa,MAAM,2BAAqB,MAAM,GAAG,MAAM,aAMhE,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Reads the YAML file
3
+ * @param configPath to configuration file
4
+ * @returns a yaml object
5
+ */
6
+ declare const load: <TSchema>(configPath: string) => TSchema;
7
+ /**
8
+ * Loads the YAML files specified by paths
9
+ * @param paths Paths to configurations to process
10
+ * @returns yaml objects
11
+ */
12
+ export declare const loadAll: <TSchema>(...paths: string[]) => TSchema[];
13
+ export default load;
14
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../../../../config/src/utils/load.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,QAAA,MAAM,IAAI,wBAAyB,MAAM,YAWxC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,OAAO,sBAAuB,MAAM,EAAE,cAA+C,CAAC;AAEnG,eAAe,IAAI,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { ConfigValidator } from '../types';
2
+ declare const _default: <TSchema>(validator: ConfigValidator, ...documents: TSchema[]) => TSchema;
3
+ export default _default;
4
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../../../../../config/src/utils/merge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;6CAUP,eAAe;AAAnD,wBAiBE"}
@@ -0,0 +1,4 @@
1
+ import { ConfigValidator } from '../types';
2
+ declare const _default: ConfigValidator;
3
+ export default _default;
4
+ //# sourceMappingURL=appshell.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appshell.config.d.ts","sourceRoot":"","sources":["../../../../../../config/src/validators/appshell.config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,eAAe,EAAE,MAAM,UAAU,CAAC;;AAgB3D,wBAcqB"}
@@ -0,0 +1,4 @@
1
+ import { ConfigValidator } from '../types';
2
+ declare const _default: ConfigValidator;
3
+ export default _default;
4
+ //# sourceMappingURL=appshell.manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appshell.manifest.d.ts","sourceRoot":"","sources":["../../../../../../config/src/validators/appshell.manifest.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,eAAe,EAAE,MAAM,UAAU,CAAC;;AAkB7D,wBAcqB"}
@@ -0,0 +1,3 @@
1
+ export { default as appshell_config } from './appshell.config';
2
+ export { default as appshell_manifest } from './appshell.manifest';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../config/src/validators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: (url: string) => Promise<boolean>;
2
+ export default _default;
3
+ //# sourceMappingURL=fetchDynamicScript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchDynamicScript.d.ts","sourceRoot":"","sources":["../../../../src/fetchDynamicScript.ts"],"names":[],"mappings":"8BAE2B,MAAM;AAAjC,wBA8BE"}
@@ -0,0 +1,4 @@
1
+ import remoteLoader from './remoteLoader';
2
+ export * from './types';
3
+ export default remoteLoader;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAE1C,cAAc,SAAS,CAAC;AAExB,eAAe,YAAY,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { ShareScope } from './types';
2
+ declare global {
3
+ function __webpack_init_sharing__(id: string): Promise<void>;
4
+ const __webpack_share_scopes__: {
5
+ default: ShareScope;
6
+ };
7
+ interface Window {
8
+ [key: string]: unknown;
9
+ __webpack_share_scopes__: Record<string, ShareScope>;
10
+ }
11
+ }
12
+ declare const _default: <TComponent>(scope: string, module: string, shareScope?: string) => Promise<TComponent>;
13
+ export default _default;
14
+ //# sourceMappingURL=loadFederatedComponent.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,4 @@
1
+ import { type AppshellManifest } from '@appshell/config';
2
+ declare const _default: (manifest: AppshellManifest) => <TComponent>(key: string) => Promise<TComponent>;
3
+ export default _default;
4
+ //# sourceMappingURL=remoteLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remoteLoader.d.ts","sourceRoot":"","sources":["../../../../src/remoteLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;mCAI/B,gBAAgB,uBAChB,MAAM;AADhC,wBAqBI"}
@@ -0,0 +1,11 @@
1
+ export type ShareScope<TComponent = any> = Record<string, Record<string, {
2
+ loaded?: 1;
3
+ get: () => Promise<TComponent>;
4
+ from: string;
5
+ eager: boolean;
6
+ }>>;
7
+ export interface ModuleContainer<TComponent> {
8
+ init(shareScope: ShareScope<TComponent>): Promise<void>;
9
+ get(module: string): Promise<() => Record<string, TComponent>>;
10
+ }
11
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,UAAU,CAAC,UAAU,GAAG,GAAG,IAAI,MAAM,CAC/C,MAAM,EACN,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAC7F,CAAC;AAEF,MAAM,WAAW,eAAe,CAAC,UAAU;IACzC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAChE"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@appshell/loader",
3
+ "version": "0.0.1-alpha.0",
4
+ "description": "Utility for loading federated components",
5
+ "main": "dist/main.js",
6
+ "types": "dist/loader/src/index.d.ts",
7
+ "scripts": {
8
+ "build": "webpack --mode production && yarn build:types",
9
+ "build:types": "tsc --emitDeclarationOnly",
10
+ "clean": "rm -rf dist",
11
+ "prebuild": "npm run clean",
12
+ "start": "webpack --watch --mode development && yarn build:types",
13
+ "stats": "webpack --json > stats.json"
14
+ },
15
+ "keywords": [
16
+ "webpack",
17
+ "module federation",
18
+ "micro-frontends",
19
+ "appshell"
20
+ ],
21
+ "author": "Robert Hamilton <rh@navaris.com>",
22
+ "license": "MIT",
23
+ "gitHead": "305b39fb81e7c267918dda7d16336e37b2b36643"
24
+ }
@@ -0,0 +1,33 @@
1
+ const urlCache = new Set<string>();
2
+
3
+ export default async (url: string) => {
4
+ const element = document.createElement('script');
5
+
6
+ const cleanup = (): void => {
7
+ urlCache.delete(url);
8
+ document.head.removeChild(element);
9
+ };
10
+
11
+ return new Promise<boolean>((resolve, reject) => {
12
+ element.src = url;
13
+ element.type = 'text/javascript';
14
+ element.async = true;
15
+
16
+ element.onload = () => {
17
+ urlCache.add(url);
18
+ // eslint-disable-next-line no-console
19
+ console.debug(`Remote entry fetched from '${url}'.`);
20
+
21
+ resolve(true);
22
+ };
23
+
24
+ element.onerror = () => {
25
+ const message = `Failed to fetch remote entry from '${url}'.`;
26
+ // eslint-disable-next-line no-console
27
+ console.error(message);
28
+ reject(message);
29
+ };
30
+
31
+ document.head.appendChild(element);
32
+ }).finally(cleanup);
33
+ };
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ import remoteLoader from './remoteLoader';
2
+
3
+ export * from './types';
4
+
5
+ export default remoteLoader;
@@ -0,0 +1,48 @@
1
+ import { ModuleContainer, ShareScope } from './types';
2
+
3
+ /* eslint-disable @typescript-eslint/naming-convention */
4
+ declare global {
5
+ function __webpack_init_sharing__(id: string): Promise<void>;
6
+ // eslint-disable-next-line no-underscore-dangle
7
+ const __webpack_share_scopes__: { default: ShareScope };
8
+ interface Window {
9
+ [key: string]: unknown;
10
+ __webpack_share_scopes__: Record<string, ShareScope>;
11
+ }
12
+ }
13
+
14
+ type ShareScopes = keyof typeof __webpack_share_scopes__;
15
+
16
+ export default async <TComponent>(scope: string, module: string, shareScope = 'default') => {
17
+ // eslint-disable-next-line no-console
18
+ console.debug(
19
+ `loading federated component: { scope: ${scope}, module: ${module}, shareScope: ${shareScope} }`,
20
+ );
21
+
22
+ // Initializes the share scope. This fills it with known provided modules from this build and all remotes
23
+ await __webpack_init_sharing__(shareScope);
24
+ const container = window[scope] as ModuleContainer<TComponent>;
25
+
26
+ if (!container) {
27
+ throw new Error(`Failed to find module container ${scope}`);
28
+ }
29
+
30
+ // Initialize the container, it may provide shared modules
31
+ await container.init(__webpack_share_scopes__[shareScope as ShareScopes]);
32
+ const factory = await container.get(module);
33
+
34
+ if (!factory) {
35
+ throw new Error(`Invalid factory produced by container for module ${module}.`);
36
+ }
37
+
38
+ const Module = factory();
39
+
40
+ // eslint-disable-next-line no-console
41
+ console.debug(
42
+ `federated component loaded: { scope: ${scope}, module: ${module}, shareScope: ${shareScope} }`,
43
+ );
44
+
45
+ const Component = Module[shareScope as ShareScopes];
46
+
47
+ return Component;
48
+ };
@@ -0,0 +1,26 @@
1
+ import { type AppshellManifest } from '@appshell/config';
2
+ import fetchDynamicScript from './fetchDynamicScript';
3
+ import loadFederatedComponent from './loadFederatedComponent';
4
+
5
+ export default (manifest: AppshellManifest) =>
6
+ async <TComponent>(key: string) => {
7
+ let Component: TComponent;
8
+ const remote = manifest.remotes[key];
9
+ if (!remote) {
10
+ throw new Error(`Remote resource not found in manifest. Expected: ${key}`);
11
+ }
12
+
13
+ try {
14
+ await fetchDynamicScript(remote.url);
15
+ Component = await loadFederatedComponent<TComponent>(
16
+ remote.scope,
17
+ remote.module,
18
+ remote.shareScope,
19
+ );
20
+
21
+ return Component;
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ } catch (err: any) {
24
+ throw new Error(`Failed to load component '${key}'. ${err?.toString()}`);
25
+ }
26
+ };
package/src/types.ts ADDED
@@ -0,0 +1,10 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export type ShareScope<TComponent = any> = Record<
3
+ string,
4
+ Record<string, { loaded?: 1; get: () => Promise<TComponent>; from: string; eager: boolean }>
5
+ >;
6
+
7
+ export interface ModuleContainer<TComponent> {
8
+ init(shareScope: ShareScope<TComponent>): Promise<void>;
9
+ get(module: string): Promise<() => Record<string, TComponent>>;
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig",
3
+ "compilerOptions": {
4
+ "declarationDir": "./dist/types"
5
+ },
6
+ "include": ["./src"]
7
+ }
@@ -0,0 +1,37 @@
1
+ const path = require('path');
2
+ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
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'],
18
+ plugins: [new TsconfigPathsPlugin()],
19
+ },
20
+ module: {
21
+ rules: [
22
+ {
23
+ test: /\.ts$/,
24
+ exclude: /node_modules/,
25
+ use: [
26
+ {
27
+ loader: 'babel-loader',
28
+ options: {
29
+ presets: ['@babel/preset-typescript'],
30
+ },
31
+ },
32
+ ],
33
+ },
34
+ ],
35
+ },
36
+ };
37
+ };