@rollipop/plugin-module-federation 1.0.0-beta.1 → 1.0.0-beta.3
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/README.md +18 -48
- package/dist/index.js +2 -2
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
# @rollipop/plugin-module-federation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Share modules and dependencies between React Native bundles.
|
|
4
4
|
|
|
5
5
|
## Status
|
|
6
6
|
|
|
7
|
-
>
|
|
8
|
-
> API and the bundle layout may change, and the role model is intentionally
|
|
9
|
-
> narrower than standard Module Federation — see [Roles](#roles) and
|
|
10
|
-
> [Constraints](#constraints).
|
|
11
|
-
>
|
|
12
|
-
> Notably, a single config takes exactly one role (host **or** remote). Standard
|
|
13
|
-
> (web) Module Federation lets one build both `expose` modules and `consume`
|
|
14
|
-
> remotes; that bidirectional / chained-federation model is **not supported
|
|
15
|
-
> yet**. Lifting it requires emitting the federation container as a separate
|
|
16
|
-
> artifact from the app bundle, which is not implemented at this stage.
|
|
7
|
+
> Experimental: the API and bundle layout may change. A config cannot both consume and expose remotes.
|
|
17
8
|
|
|
18
9
|
## Roles
|
|
19
10
|
|
|
20
11
|
A single Rollipop config takes one role. Defining both `remotes` and `exposes` throws.
|
|
21
12
|
|
|
22
|
-
| Role |
|
|
23
|
-
| ------ | --------- |
|
|
24
|
-
| Host | `remotes` |
|
|
25
|
-
| Remote | `exposes` |
|
|
13
|
+
| Role | Option | Purpose |
|
|
14
|
+
| ------ | --------- | ------------------------------------------------------ |
|
|
15
|
+
| Host | `remotes` | Loads remote modules and provides shared dependencies. |
|
|
16
|
+
| Remote | `exposes` | Exposes modules to hosts. |
|
|
26
17
|
|
|
27
18
|
## Host
|
|
28
19
|
|
|
@@ -36,7 +27,7 @@ import { federation } from '@rollipop/plugin-module-federation';
|
|
|
36
27
|
import { defineConfig } from 'rollipop';
|
|
37
28
|
|
|
38
29
|
export default defineConfig({
|
|
39
|
-
entry: 'src/host/index.
|
|
30
|
+
entry: 'src/host/index.ts',
|
|
40
31
|
plugins: [
|
|
41
32
|
federation({
|
|
42
33
|
name: 'host_app',
|
|
@@ -48,8 +39,6 @@ export default defineConfig({
|
|
|
48
39
|
'react-native': { singleton: true, eager: true, requiredVersion: '0.84.1' },
|
|
49
40
|
},
|
|
50
41
|
runtime: {
|
|
51
|
-
// Register a `ModuleFederationScriptLoader` on `globalThis.__rollipop_script_loader__`.
|
|
52
|
-
// Typically delegates to a native TurboModule that does fetch + JSI evaluate.
|
|
53
42
|
implement: `
|
|
54
43
|
const NativeScriptManager = globalThis.nativeModuleProxy.ScriptManager;
|
|
55
44
|
globalThis.__rollipop_script_loader__ = {
|
|
@@ -74,9 +63,7 @@ const RemoteNavigator = React.lazy(() =>
|
|
|
74
63
|
);
|
|
75
64
|
```
|
|
76
65
|
|
|
77
|
-
|
|
78
|
-
through the federation runtime and suspends while the request is pending, so render it inside a
|
|
79
|
-
React `Suspense` boundary. The bundled code does not use native `import()` to fetch the remote.
|
|
66
|
+
Render the imported component inside a React `Suspense` boundary while it loads.
|
|
80
67
|
|
|
81
68
|
Failed remote loads are thrown to the nearest React Error Boundary. From its retry action,
|
|
82
69
|
reload the remote before resetting the boundary:
|
|
@@ -88,8 +75,7 @@ await retryRemote('remote_app/RemoteNavigator');
|
|
|
88
75
|
resetErrorBoundary();
|
|
89
76
|
```
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
can keep showing its fallback until the user retries again.
|
|
78
|
+
Pass the import alias and exposed path to `retryRemote`. Failed retries reject.
|
|
93
79
|
|
|
94
80
|
## Remote
|
|
95
81
|
|
|
@@ -99,7 +85,7 @@ import { federation } from '@rollipop/plugin-module-federation';
|
|
|
99
85
|
import { defineConfig } from 'rollipop';
|
|
100
86
|
|
|
101
87
|
export default defineConfig({
|
|
102
|
-
entry: 'src/remote/index.
|
|
88
|
+
entry: 'src/remote/index.ts',
|
|
103
89
|
plugins: [
|
|
104
90
|
federation({
|
|
105
91
|
name: 'remote_app',
|
|
@@ -115,11 +101,7 @@ export default defineConfig({
|
|
|
115
101
|
});
|
|
116
102
|
```
|
|
117
103
|
|
|
118
|
-
|
|
119
|
-
runtime. Each shared dependency import (e.g. `import RN from 'react-native'`) is replaced with a
|
|
120
|
-
stub that reads from the host's `globalThis.__rollipop_shared__` registry and throws if the
|
|
121
|
-
dependency is not registered. Rollipop's prelude and polyfills are skipped because the host has
|
|
122
|
-
already initialized the React Native runtime.
|
|
104
|
+
Remotes support HMR when served by the development server.
|
|
123
105
|
|
|
124
106
|
## Script loader contract
|
|
125
107
|
|
|
@@ -131,26 +113,14 @@ export interface ModuleFederationScriptLoader {
|
|
|
131
113
|
}
|
|
132
114
|
```
|
|
133
115
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
## Globals exposed at runtime
|
|
137
|
-
|
|
138
|
-
| Global | Owner | Purpose |
|
|
139
|
-
| -------------------------------------- | ------ | ------------------------------------------------------------------------------------ |
|
|
140
|
-
| `__rollipop_script_loader__` | user | `ModuleFederationScriptLoader` implementation. |
|
|
141
|
-
| `__rollipop_shared__` | host | Shared dependency registry populated during host initialization; missing keys throw. |
|
|
142
|
-
| `__rollipop_module_federation_cache__` | plugin | Internal cache of loaded modules, pending requests, and load errors. |
|
|
143
|
-
|
|
144
|
-
Use `retryRemote` from `@rollipop/plugin-module-federation/runtime` to retry a failed request.
|
|
116
|
+
Register a loader on `globalThis.__rollipop_script_loader__`. Its `loadScript` method must download and evaluate the bundle before resolving.
|
|
145
117
|
|
|
146
118
|
## Constraints
|
|
147
119
|
|
|
148
|
-
- A
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
returns that proxy, rather than the remote module's namespace directly.
|
|
154
|
-
- Subpath imports of shared deps (`react/jsx-dev-runtime`, etc.) are bundled into the remote and consume the parent shared instance through `__rollipop_shared__`.
|
|
120
|
+
- A config cannot define both `remotes` and `exposes`. Run hosts and remotes as separate Rollipop processes.
|
|
121
|
+
- Remote imports support default React component exports.
|
|
122
|
+
- Shared dependency subpaths (such as `react/jsx-dev-runtime`) are bundled separately in each remote.
|
|
123
|
+
|
|
124
|
+
See `examples/module-federation` for a working RN 0.84 host + remote setup with a Kotlin/JNI and Obj-C++ script loader.
|
|
155
125
|
|
|
156
|
-
See
|
|
126
|
+
See [Configuration](https://rollipop.dev/docs/features/module-federation#configuration) for remote syntax, shared dependencies, and `shareStrategy`.
|
package/dist/index.js
CHANGED
|
@@ -361,11 +361,11 @@ function moduleFederationPlugin(config) {
|
|
|
361
361
|
load: {
|
|
362
362
|
filter: [include(id(prefixRegex(VIRTUAL_PREFIX)))],
|
|
363
363
|
handler(id) {
|
|
364
|
-
if (id.startsWith(
|
|
364
|
+
if (id.startsWith("\0rollipop:module-federation:shared:")) return {
|
|
365
365
|
code: generateSharedShimCode(id.slice(VIRTUAL_SHARED_SHIM_PREFIX.length)),
|
|
366
366
|
moduleType: "js"
|
|
367
367
|
};
|
|
368
|
-
if (id.startsWith(
|
|
368
|
+
if (id.startsWith("\0rollipop:module-federation:remote:")) return {
|
|
369
369
|
code: generateRemoteProxyCode({ remoteId: id.slice(VIRTUAL_REMOTE_PROXY_PREFIX.length) }),
|
|
370
370
|
moduleType: "js"
|
|
371
371
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rollipop/plugin-module-federation",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.3",
|
|
4
4
|
"homepage": "https://github.com/rollipop-dev/rollipop#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/rollipop-dev/rollipop/issues"
|
|
@@ -36,21 +36,22 @@
|
|
|
36
36
|
"build": "vp pack"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@module-federation/runtime": "2.9.
|
|
39
|
+
"@module-federation/runtime": "2.9.2",
|
|
40
40
|
"dedent": "1.7.2",
|
|
41
41
|
"es-toolkit": "1.52.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "19.2.14",
|
|
45
|
-
"@vitest/coverage-v8": "
|
|
45
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
46
46
|
"react": "19.2.3",
|
|
47
|
-
"rollipop": "1.0.0-beta.
|
|
47
|
+
"rollipop": "1.0.0-beta.3",
|
|
48
48
|
"typescript": "7.0.2",
|
|
49
|
-
"vite
|
|
50
|
-
"
|
|
49
|
+
"vite": "@voidzero-dev/vite-plus-core@1.3.0",
|
|
50
|
+
"vite-plus": "1.3.0",
|
|
51
|
+
"vitest": "5.0.5"
|
|
51
52
|
},
|
|
52
53
|
"peerDependencies": {
|
|
53
|
-
"rollipop": "1.0.0-beta.
|
|
54
|
+
"rollipop": "1.0.0-beta.3"
|
|
54
55
|
},
|
|
55
56
|
"installConfig": {
|
|
56
57
|
"hoistingLimits": "none"
|