@granite-js/micro-frontend 2.1.0 → 2.1.1
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 +7 -0
- package/README.md +5 -0
- package/dist/module/runtime/createMicroFrontendRuntime.js +2 -0
- package/dist/module/runtime/createMicroFrontendRuntime.js.map +1 -1
- package/dist/module/runtime/nativeComponentRegistryCompatibility.js +53 -0
- package/dist/module/runtime/nativeComponentRegistryCompatibility.js.map +1 -0
- package/dist/typescript/runtime/nativeComponentRegistryCompatibility.d.ts +1 -0
- package/package.json +4 -4
- package/src/runtime/createMicroFrontendRuntime.ts +2 -0
- package/src/runtime/nativeComponentRegistryCompatibility.ts +60 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -193,6 +193,11 @@ adapter.loadBundle({ appName: 'cart' })
|
|
|
193
193
|
Concurrent preload/import calls for one app share an evaluation. A successful
|
|
194
194
|
evaluation remains cached for the lifetime of the JavaScript runtime. Failed
|
|
195
195
|
evaluation removes the partial container so a later request can retry.
|
|
196
|
+
Before evaluating a remote, the runtime also adapts the shared React Native
|
|
197
|
+
component registry so a native view wrapper already evaluated by the host can
|
|
198
|
+
be evaluated again by a separate remote bundle. The canonical host registration
|
|
199
|
+
is reused only for React Native's exact duplicate-view invariant; other registry
|
|
200
|
+
errors continue to fail the remote evaluation.
|
|
196
201
|
Native `preloadApp` events invoke `preloadApp()` inside the runtime and are not
|
|
197
202
|
forwarded to session listeners. `onPreloadError` is optional and lets the host
|
|
198
203
|
route best-effort native preload failures to its observability provider.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { AppContainerNotFoundError, InvalidAppNameError } from "./errors.js";
|
|
4
4
|
import { getMicroFrontendGlobalContext } from "./globalContext.js";
|
|
5
|
+
import { installNativeComponentRegistryCompatibility } from "./nativeComponentRegistryCompatibility.js";
|
|
5
6
|
import { parseAppRequest } from "./parseAppRequest.js";
|
|
6
7
|
export function createMicroFrontendRuntimeWithDependencies(dependencies) {
|
|
7
8
|
// A fulfilled promise is the evaluated-state cache. Rejected evaluations remove themselves.
|
|
@@ -25,6 +26,7 @@ export function createMicroFrontendRuntimeWithDependencies(dependencies) {
|
|
|
25
26
|
}
|
|
26
27
|
function evaluateScript(filePath) {
|
|
27
28
|
getMicroFrontendGlobalContext();
|
|
29
|
+
installNativeComponentRegistryCompatibility();
|
|
28
30
|
return dependencies.nativeRuntime.evaluateScript({
|
|
29
31
|
filePath
|
|
30
32
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["AppContainerNotFoundError","InvalidAppNameError","getMicroFrontendGlobalContext","parseAppRequest","createMicroFrontendRuntimeWithDependencies","dependencies","appEvaluations","Map","resetFailedEvaluation","appName","delete","registry","removeContainer","removePendingHostComponentRoutes","preloadApp","length","Promise","reject","existingEvaluation","get","evaluation","evaluateApp","set","evaluateScript","filePath","nativeRuntime","adapter","loadBundle","hasContainer","error","importApp","request","importModule","onEvent","listener","subscription","event","parsedEvent","parseEvent","name","params","catch","onPreloadError","exhaustiveEvent","startEventDelivery"],"sourceRoot":"../../../src","sources":["runtime/createMicroFrontendRuntime.ts"],"mappings":";;AAOA,SAASA,yBAAyB,EAAEC,mBAAmB,QAAQ,aAAU;AACzE,SAASC,6BAA6B,QAAQ,oBAAiB;AAC/D,SAASC,eAAe,QAAQ,sBAAmB;AAmCnD,OAAO,SAASC,0CAA0CA,CACxDC,YAAoD,EAC3B;EACzB;EACA,MAAMC,cAAc,GAAG,IAAIC,GAAG,CAAwB,CAAC;EAEvD,SAASC,qBAAqBA,CAACC,OAAe,EAAE;IAC9CH,cAAc,CAACI,MAAM,CAACD,OAAO,CAAC;IAC9BJ,YAAY,CAACM,QAAQ,CAACC,eAAe,CAACH,OAAO,CAAC;IAC9CJ,YAAY,CAACQ,gCAAgC,CAACJ,OAAO,CAAC;EACxD;EAEA,SAASK,UAAUA,CAACL,OAAe,EAAiB;IAClD,IAAIA,OAAO,CAACM,MAAM,KAAK,CAAC,EAAE;MACxB,OAAOC,OAAO,CAACC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"names":["AppContainerNotFoundError","InvalidAppNameError","getMicroFrontendGlobalContext","installNativeComponentRegistryCompatibility","parseAppRequest","createMicroFrontendRuntimeWithDependencies","dependencies","appEvaluations","Map","resetFailedEvaluation","appName","delete","registry","removeContainer","removePendingHostComponentRoutes","preloadApp","length","Promise","reject","existingEvaluation","get","evaluation","evaluateApp","set","evaluateScript","filePath","nativeRuntime","adapter","loadBundle","hasContainer","error","importApp","request","importModule","onEvent","listener","subscription","event","parsedEvent","parseEvent","name","params","catch","onPreloadError","exhaustiveEvent","startEventDelivery"],"sourceRoot":"../../../src","sources":["runtime/createMicroFrontendRuntime.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { getMicroFrontendGlobalContext } from "./globalContext.js";
|
|
4
|
+
const NATIVE_COMPONENT_REGISTRY_MODULE = 'react-native/Libraries/NativeComponent/NativeComponentRegistry';
|
|
5
|
+
const COMPATIBILITY_MARKER = Symbol.for('granite.microFrontend.nativeComponentRegistryCompatibility');
|
|
6
|
+
export function installNativeComponentRegistryCompatibility() {
|
|
7
|
+
const sharedModules = getMicroFrontendGlobalContext().__SHARED__;
|
|
8
|
+
const sharedEntry = sharedModules[NATIVE_COMPONENT_REGISTRY_MODULE];
|
|
9
|
+
if (sharedEntry == null || Reflect.get(sharedEntry, COMPATIBILITY_MARKER) === true) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const nativeComponentRegistry = sharedEntry.get();
|
|
13
|
+
if (!isNativeComponentRegistry(nativeComponentRegistry)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const compatibleRegistry = new Proxy(nativeComponentRegistry, {
|
|
17
|
+
get(target, property, receiver) {
|
|
18
|
+
if (property !== 'get') {
|
|
19
|
+
return Reflect.get(target, property, receiver);
|
|
20
|
+
}
|
|
21
|
+
return (...args) => {
|
|
22
|
+
try {
|
|
23
|
+
return Reflect.apply(target.get, target, args);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
const componentName = args[0];
|
|
26
|
+
if (typeof componentName === 'string' && isDuplicateNativeViewRegistration(error, componentName)) {
|
|
27
|
+
return componentName;
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const compatibleEntry = {
|
|
35
|
+
get: () => compatibleRegistry,
|
|
36
|
+
loaded: sharedEntry.loaded
|
|
37
|
+
};
|
|
38
|
+
Reflect.defineProperty(compatibleEntry, COMPATIBILITY_MARKER, {
|
|
39
|
+
value: true
|
|
40
|
+
});
|
|
41
|
+
sharedModules[NATIVE_COMPONENT_REGISTRY_MODULE] = compatibleEntry;
|
|
42
|
+
}
|
|
43
|
+
function isNativeComponentRegistry(value) {
|
|
44
|
+
return typeof value === 'object' && value != null && typeof Reflect.get(value, 'get') === 'function';
|
|
45
|
+
}
|
|
46
|
+
function isDuplicateNativeViewRegistration(error, componentName) {
|
|
47
|
+
if (typeof error !== 'object' || error == null) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const message = Reflect.get(error, 'message');
|
|
51
|
+
return typeof message === 'string' && message.endsWith(`Tried to register two views with the same name ${componentName}`);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=nativeComponentRegistryCompatibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["getMicroFrontendGlobalContext","NATIVE_COMPONENT_REGISTRY_MODULE","COMPATIBILITY_MARKER","Symbol","for","installNativeComponentRegistryCompatibility","sharedModules","__SHARED__","sharedEntry","Reflect","get","nativeComponentRegistry","isNativeComponentRegistry","compatibleRegistry","Proxy","target","property","receiver","args","apply","error","componentName","isDuplicateNativeViewRegistration","compatibleEntry","loaded","defineProperty","value","message","endsWith"],"sourceRoot":"../../../src","sources":["runtime/nativeComponentRegistryCompatibility.ts"],"mappings":";;AAAA,SAASA,6BAA6B,QAAQ,oBAAiB;AAE/D,MAAMC,gCAAgC,GAAG,gEAAgE;AACzG,MAAMC,oBAAoB,GAAGC,MAAM,CAACC,GAAG,CAAC,4DAA4D,CAAC;AAErG,OAAO,SAASC,2CAA2CA,CAAA,EAAS;EAClE,MAAMC,aAAa,GAAGN,6BAA6B,CAAC,CAAC,CAACO,UAAU;EAChE,MAAMC,WAAW,GAAGF,aAAa,CAACL,gCAAgC,CAAC;EACnE,IAAIO,WAAW,IAAI,IAAI,IAAIC,OAAO,CAACC,GAAG,CAACF,WAAW,EAAEN,oBAAoB,CAAC,KAAK,IAAI,EAAE;IAClF;EACF;EAEA,MAAMS,uBAAuB,GAAGH,WAAW,CAACE,GAAG,CAAC,CAAC;EACjD,IAAI,CAACE,yBAAyB,CAACD,uBAAuB,CAAC,EAAE;IACvD;EACF;EAEA,MAAME,kBAAkB,GAAG,IAAIC,KAAK,CAACH,uBAAuB,EAAE;IAC5DD,GAAGA,CAACK,MAAM,EAAEC,QAAQ,EAAEC,QAAQ,EAAE;MAC9B,IAAID,QAAQ,KAAK,KAAK,EAAE;QACtB,OAAOP,OAAO,CAACC,GAAG,CAACK,MAAM,EAAEC,QAAQ,EAAEC,QAAQ,CAAC;MAChD;MAEA,OAAO,CAAC,GAAGC,IAAwB,KAAK;QACtC,IAAI;UACF,OAAOT,OAAO,CAACU,KAAK,CAACJ,MAAM,CAACL,GAAG,EAAEK,MAAM,EAAEG,IAAI,CAAC;QAChD,CAAC,CAAC,OAAOE,KAAK,EAAE;UACd,MAAMC,aAAa,GAAGH,IAAI,CAAC,CAAC,CAAC;UAC7B,IAAI,OAAOG,aAAa,KAAK,QAAQ,IAAIC,iCAAiC,CAACF,KAAK,EAAEC,aAAa,CAAC,EAAE;YAChG,OAAOA,aAAa;UACtB;UACA,MAAMD,KAAK;QACb;MACF,CAAC;IACH;EACF,CAAC,CAAC;EACF,MAAMG,eAAe,GAAG;IACtBb,GAAG,EAAEA,CAAA,KAAMG,kBAAkB;IAC7BW,MAAM,EAAEhB,WAAW,CAACgB;EACtB,CAAC;EACDf,OAAO,CAACgB,cAAc,CAACF,eAAe,EAAErB,oBAAoB,EAAE;IAAEwB,KAAK,EAAE;EAAK,CAAC,CAAC;EAC9EpB,aAAa,CAACL,gCAAgC,CAAC,GAAGsB,eAAe;AACnE;AAEA,SAASX,yBAAyBA,CAChCc,KAAc,EACuD;EACrE,OAAO,OAAOA,KAAK,KAAK,QAAQ,IAAIA,KAAK,IAAI,IAAI,IAAI,OAAOjB,OAAO,CAACC,GAAG,CAACgB,KAAK,EAAE,KAAK,CAAC,KAAK,UAAU;AACtG;AAEA,SAASJ,iCAAiCA,CAACF,KAAc,EAAEC,aAAqB,EAAW;EACzF,IAAI,OAAOD,KAAK,KAAK,QAAQ,IAAIA,KAAK,IAAI,IAAI,EAAE;IAC9C,OAAO,KAAK;EACd;EAEA,MAAMO,OAAO,GAAGlB,OAAO,CAACC,GAAG,CAACU,KAAK,EAAE,SAAS,CAAC;EAC7C,OACE,OAAOO,OAAO,KAAK,QAAQ,IAAIA,OAAO,CAACC,QAAQ,CAAC,kDAAkDP,aAAa,EAAE,CAAC;AAEtH","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installNativeComponentRegistryCompatibility(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@granite-js/micro-frontend",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Micro-frontend build, runtime, session, and Portal contracts for Granite brownfield applications",
|
|
5
5
|
"main": "./dist/module/index.js",
|
|
6
6
|
"types": "./dist/typescript/index.d.ts",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@babel/core": "7.28.5",
|
|
59
|
-
"@granite-js/utils": "2.1.
|
|
59
|
+
"@granite-js/utils": "2.1.1",
|
|
60
60
|
"@standard-schema/spec": "^1.0.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@babel/types": "7.28.5",
|
|
75
|
-
"@granite-js/plugin-core": "2.1.
|
|
76
|
-
"@granite-js/react-native": "2.1.
|
|
75
|
+
"@granite-js/plugin-core": "2.1.1",
|
|
76
|
+
"@granite-js/react-native": "2.1.1",
|
|
77
77
|
"@types/babel__core": "^7.20.5",
|
|
78
78
|
"@types/node": "24.10.12",
|
|
79
79
|
"@types/react": "19.2.0",
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from '../types';
|
|
8
8
|
import { AppContainerNotFoundError, InvalidAppNameError } from './errors';
|
|
9
9
|
import { getMicroFrontendGlobalContext } from './globalContext';
|
|
10
|
+
import { installNativeComponentRegistryCompatibility } from './nativeComponentRegistryCompatibility';
|
|
10
11
|
import { parseAppRequest } from './parseAppRequest';
|
|
11
12
|
|
|
12
13
|
export interface NativeMicroFrontendRuntimeEvent {
|
|
@@ -71,6 +72,7 @@ export function createMicroFrontendRuntimeWithDependencies(
|
|
|
71
72
|
|
|
72
73
|
function evaluateScript(filePath: string): Promise<void> {
|
|
73
74
|
getMicroFrontendGlobalContext();
|
|
75
|
+
installNativeComponentRegistryCompatibility();
|
|
74
76
|
return dependencies.nativeRuntime.evaluateScript({ filePath });
|
|
75
77
|
}
|
|
76
78
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getMicroFrontendGlobalContext } from './globalContext';
|
|
2
|
+
|
|
3
|
+
const NATIVE_COMPONENT_REGISTRY_MODULE = 'react-native/Libraries/NativeComponent/NativeComponentRegistry';
|
|
4
|
+
const COMPATIBILITY_MARKER = Symbol.for('granite.microFrontend.nativeComponentRegistryCompatibility');
|
|
5
|
+
|
|
6
|
+
export function installNativeComponentRegistryCompatibility(): void {
|
|
7
|
+
const sharedModules = getMicroFrontendGlobalContext().__SHARED__;
|
|
8
|
+
const sharedEntry = sharedModules[NATIVE_COMPONENT_REGISTRY_MODULE];
|
|
9
|
+
if (sharedEntry == null || Reflect.get(sharedEntry, COMPATIBILITY_MARKER) === true) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const nativeComponentRegistry = sharedEntry.get();
|
|
14
|
+
if (!isNativeComponentRegistry(nativeComponentRegistry)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const compatibleRegistry = new Proxy(nativeComponentRegistry, {
|
|
19
|
+
get(target, property, receiver) {
|
|
20
|
+
if (property !== 'get') {
|
|
21
|
+
return Reflect.get(target, property, receiver);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (...args: readonly unknown[]) => {
|
|
25
|
+
try {
|
|
26
|
+
return Reflect.apply(target.get, target, args);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
const componentName = args[0];
|
|
29
|
+
if (typeof componentName === 'string' && isDuplicateNativeViewRegistration(error, componentName)) {
|
|
30
|
+
return componentName;
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
const compatibleEntry = {
|
|
38
|
+
get: () => compatibleRegistry,
|
|
39
|
+
loaded: sharedEntry.loaded,
|
|
40
|
+
};
|
|
41
|
+
Reflect.defineProperty(compatibleEntry, COMPATIBILITY_MARKER, { value: true });
|
|
42
|
+
sharedModules[NATIVE_COMPONENT_REGISTRY_MODULE] = compatibleEntry;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isNativeComponentRegistry(
|
|
46
|
+
value: unknown
|
|
47
|
+
): value is { readonly get: (...args: readonly unknown[]) => unknown } {
|
|
48
|
+
return typeof value === 'object' && value != null && typeof Reflect.get(value, 'get') === 'function';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isDuplicateNativeViewRegistration(error: unknown, componentName: string): boolean {
|
|
52
|
+
if (typeof error !== 'object' || error == null) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const message = Reflect.get(error, 'message');
|
|
57
|
+
return (
|
|
58
|
+
typeof message === 'string' && message.endsWith(`Tried to register two views with the same name ${componentName}`)
|
|
59
|
+
);
|
|
60
|
+
}
|