@module-federation/electron 0.1.0 → 0.2.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 (51) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +177 -2
  3. package/dist/index.cjs +104 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +32 -1
  6. package/dist/index.d.cts.map +1 -1
  7. package/dist/index.d.ts +32 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +51 -1
  10. package/dist/index.js.map +1 -0
  11. package/dist/remote.cjs +287 -0
  12. package/dist/remote.cjs.map +1 -0
  13. package/dist/remote.d.cts +35 -0
  14. package/dist/remote.d.cts.map +1 -0
  15. package/dist/remote.d.ts +35 -0
  16. package/dist/remote.d.ts.map +1 -0
  17. package/dist/remote.js +227 -0
  18. package/dist/remote.js.map +1 -0
  19. package/dist/resolve.cjs +60 -0
  20. package/dist/resolve.cjs.map +1 -0
  21. package/dist/resolve.d.cts +7 -0
  22. package/dist/resolve.d.cts.map +1 -0
  23. package/dist/resolve.d.ts +7 -0
  24. package/dist/resolve.d.ts.map +1 -0
  25. package/dist/resolve.js +12 -0
  26. package/dist/resolve.js.map +1 -0
  27. package/dist/rsbuild.cjs +89 -0
  28. package/dist/rsbuild.cjs.map +1 -0
  29. package/dist/rsbuild.d.cts +31 -0
  30. package/dist/rsbuild.d.cts.map +1 -0
  31. package/dist/rsbuild.d.ts +31 -0
  32. package/dist/rsbuild.d.ts.map +1 -0
  33. package/dist/rsbuild.js +30 -0
  34. package/dist/rsbuild.js.map +1 -0
  35. package/dist/url.cjs +67 -0
  36. package/dist/url.cjs.map +1 -0
  37. package/dist/url.d.cts +22 -0
  38. package/dist/url.d.cts.map +1 -0
  39. package/dist/url.d.ts +22 -0
  40. package/dist/url.d.ts.map +1 -0
  41. package/dist/url.js +17 -0
  42. package/dist/url.js.map +1 -0
  43. package/dist/vite.cjs +84 -0
  44. package/dist/vite.cjs.map +1 -0
  45. package/dist/vite.d.cts +29 -0
  46. package/dist/vite.d.cts.map +1 -0
  47. package/dist/vite.d.ts +29 -0
  48. package/dist/vite.d.ts.map +1 -0
  49. package/dist/vite.js +25 -0
  50. package/dist/vite.js.map +1 -0
  51. package/package.json +82 -23
package/CHANGELOG.md CHANGED
@@ -1 +1,24 @@
1
1
  # Changelog
2
+
3
+ ## [0.2.0](https://github.com/module-federation/electron/compare/0.1.1...0.2.0) (2026-11-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * load remotes from a URL with an offline cache ([#12](https://github.com/module-federation/electron/issues/12)) ([fbd816a](https://github.com/module-federation/electron/commit/fbd816ad54b6751b25a6835d2da9e6833d1b2872))
9
+
10
+ ## [0.1.1](https://github.com/module-federation/electron/compare/0.1.0...0.1.1) (2026-11-04)
11
+
12
+
13
+ ### Documentation
14
+
15
+ * list requirements in the package README ([#9](https://github.com/module-federation/electron/issues/9)) ([c35a574](https://github.com/module-federation/electron/commit/c35a574dfbe2e47354db63c48007279e9338b44a))
16
+
17
+ ## [0.1.0](https://github.com/module-federation/electron/compare/0.0.1...0.1.0) (2026-11-04)
18
+
19
+
20
+ ### Features
21
+
22
+ * add Electron integration for Rsbuild and Vite ([#4](https://github.com/module-federation/electron/issues/4)) ([edd080c](https://github.com/module-federation/electron/commit/edd080cfba75f9eb1829fd608ed649ca26dd8494))
23
+
24
+ ## Changelog
package/README.md CHANGED
@@ -1,3 +1,178 @@
1
- # @module-federation/electron
1
+ <h1 align="center">@module-federation/electron</h1>
2
2
 
3
- Project scaffold for a future Module Federation integration for Electron. No integration API is available yet.
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/@module-federation/electron">
5
+ <img src="https://img.shields.io/npm/v/@module-federation/electron?style=flat-square&colorA=564341&colorB=EDED91" alt="npm version" />
6
+ </a>
7
+ <a href="https://npmcharts.com/compare/@module-federation/electron?minimal=true">
8
+ <img src="https://img.shields.io/npm/dm/@module-federation/electron.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="downloads" />
9
+ </a>
10
+ <a href="https://github.com/module-federation/electron/blob/main/LICENSE">
11
+ <img src="https://img.shields.io/npm/l/@module-federation/electron?style=flat-square&colorA=564341&colorB=EDED91" alt="license" />
12
+ </a>
13
+ </p>
14
+
15
+ Module Federation for Electron renderers built with Rsbuild or Vite. Hosts and remotes can use either bundler.
16
+
17
+ In production every federated app is served from one privileged custom protocol, `mf://local/<app-id>/`. All apps share one origin, so remote entries, manifests and chunks load without CORS setup, whether an app's files sit on disk or come from a CDN. Remotes fetched from a URL are cached on disk, so the app keeps working offline.
18
+
19
+ ## Install
20
+
21
+ ```sh
22
+ pnpm add @module-federation/electron
23
+ # plus the Module Federation plugin for each bundler you use:
24
+ pnpm add -D @module-federation/rsbuild-plugin # Rsbuild
25
+ pnpm add -D @module-federation/vite # Vite, 1.23.9 or later
26
+ ```
27
+
28
+ Requires Electron 30 or later and Node.js 22.18+, 24.11+ or 26+ for builds. Rsbuild 2 and Vite 7 or 8 are supported.
29
+
30
+ ## Main process
31
+
32
+ ```ts
33
+ import { app, BrowserWindow } from 'electron';
34
+ import {
35
+ federationUrl,
36
+ registerFederationScheme,
37
+ serveFederatedApps,
38
+ } from '@module-federation/electron';
39
+
40
+ registerFederationScheme(); // before `app` is ready
41
+
42
+ app.whenReady().then(() => {
43
+ serveFederatedApps({
44
+ apps: { host: '/path/to/host/dist', remote: '/path/to/remote/dist' },
45
+ });
46
+ new BrowserWindow().loadURL(federationUrl('host', 'index.html'));
47
+ });
48
+ ```
49
+
50
+ `serveFederatedApps` maps each federation `name` to its build directory and returns a function that unregisters the handler. Requests outside an app's directory get a 404.
51
+
52
+ ## Remotes deployed to a URL
53
+
54
+ An app can also be an `http(s)` URL. Requests for `mf://local/<app-id>/<path>` are fetched from `<url>/<path>` in the main process, so the renderer still sees one origin and needs no CORS setup:
55
+
56
+ ```ts
57
+ serveFederatedApps({
58
+ apps: {
59
+ host: '/path/to/host/dist',
60
+ remote: 'https://cdn.example.com/remote/',
61
+ },
62
+ });
63
+ ```
64
+
65
+ Build the remote with the Rsbuild or Vite plugin from this package, so its chunks load from `mf://local/<app-id>/` too. A remote whose `publicPath` is an absolute `https://` URL loads its chunks directly, without the offline cache.
66
+
67
+ ### Offline cache
68
+
69
+ Responses from remote apps are cached on disk, so the app keeps working when a remote is down:
70
+
71
+ | Situation | Response |
72
+ | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
73
+ | Remote answers 2xx | The fresh response. It replaces the cached copy. |
74
+ | Offline, DNS failure, connection refused | The cached copy. |
75
+ | Remote answers an error status (a broken deploy returning 500 or 404) | The cached copy. Error responses are never cached. |
76
+ | No response within the connect timeout, or the body stalls for the read timeout | The cached copy. For the next 30 s, other cached requests to that origin skip the network. |
77
+ | Not reachable and never cached (first launch offline) | `502`, or `504` on a timeout. Module Federation reports a failed remote. |
78
+
79
+ - **Network first.** The cache is used only when the network fails, so a remote that is up serves its latest release. After any failed request, other cached requests to that origin skip the network for 30 s, so a remote that has just recovered is picked up after that window.
80
+ - **Only `GET` responses are cached**, together with their headers, so ES module remotes still pass MIME checks offline. Query strings are ignored, so cache-busting parameters still hit the cache.
81
+ - Responses served from the cache carry an `x-mf-cache: stale` header (exported as `CACHE_HEADER`). Fallbacks are logged with `console.warn`.
82
+ - Writes go through a temporary file and a rename, so a crash never leaves a partial entry. To reset the cache, quit the app and delete its directory.
83
+
84
+ ```ts
85
+ serveFederatedApps({
86
+ apps: { remote: 'https://cdn.example.com/remote/' },
87
+ cache: {
88
+ dir: path.join(app.getPath('userData'), 'remotes'), // default: <sessionData>/module-federation
89
+ connectTimeout: 10_000, // ms to wait for response headers
90
+ readTimeout: 10_000, // ms the body may stall, not a limit on the whole download
91
+ },
92
+ });
93
+ ```
94
+
95
+ Pass `cache: false` to proxy remote apps without caching.
96
+
97
+ ## Rsbuild
98
+
99
+ `./rsbuild` and `./vite` re-export the URL helpers, so build configs don't load `electron`.
100
+
101
+ ```ts
102
+ import { defineConfig } from '@rsbuild/core';
103
+ import { federationUrl, pluginModuleFederationElectron } from '@module-federation/electron/rsbuild';
104
+
105
+ export default defineConfig({
106
+ plugins: [
107
+ pluginModuleFederationElectron({
108
+ name: 'host',
109
+ remotes: { remote: `remote@${federationUrl('remote', 'mf-manifest.json')}` },
110
+ }),
111
+ ],
112
+ });
113
+ ```
114
+
115
+ ## Vite
116
+
117
+ ```ts
118
+ import { defineConfig } from 'vite';
119
+ import { federationElectron } from '@module-federation/electron/vite';
120
+
121
+ export default defineConfig({
122
+ plugins: [
123
+ federationElectron({
124
+ name: 'remote',
125
+ exposes: { './Card': './src/Card.tsx' },
126
+ }),
127
+ ],
128
+ });
129
+ ```
130
+
131
+ ## Options
132
+
133
+ Both plugins take a second argument, `{ electron: { protocol, scheme, host } }`:
134
+
135
+ - `protocol` (default `true`): set `output.assetPrefix` (Rsbuild) or `base` (Vite) to `mf://local/<app-id>/` for production builds. Dev servers, explicit values, and `protocol: false` are left alone.
136
+ - `scheme` / `host` (default `mf` / `local`): change the URL. Pass the same values to `registerFederationScheme` and `serveFederatedApps`.
137
+
138
+ The Rsbuild plugin also takes `{ rsbuild }`, which is passed through to `@module-federation/rsbuild-plugin`.
139
+
140
+ ## API
141
+
142
+ From `@module-federation/electron` (main process only, it imports `electron`):
143
+
144
+ | Export | Description |
145
+ | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
146
+ | `registerFederationScheme({ scheme? })` | Registers the scheme as privileged (standard, secure, fetch, CORS, streaming). Call before `app` is ready. |
147
+ | `serveFederatedApps({ apps, cache?, scheme?, host? })` | Serves each app from its directory or URL. Call after `app.whenReady()`. Returns an unregister function. |
148
+ | `resolveAppFile(pathname, dirs)` | Resolves an `mf://` path to a file inside an app's directory, or `undefined` if it falls outside. |
149
+ | `CACHE_HEADER` | `'x-mf-cache'`, set to `stale` on responses served from the offline cache. |
150
+
151
+ From every entry point, including `./rsbuild` and `./vite`:
152
+
153
+ | Export | Description |
154
+ | ------------------------------------- | ----------------------------------------------------------------------------------------- |
155
+ | `federationUrl(name, file, options?)` | URL of a file inside an app, e.g. `mf://local/remote-vite/mf-manifest.json`. |
156
+ | `federationBaseUrl(name, options?)` | Base URL an app is served from, e.g. `mf://local/remote-vite/`. |
157
+ | `toAppId(name)` | Normalizes a federation `name` into the URL path segment (`remote_vite` → `remote-vite`). |
158
+ | `DEFAULT_SCHEME`, `DEFAULT_HOST` | `'mf'` and `'local'`. |
159
+
160
+ From `./rsbuild`: `pluginModuleFederationElectron(federation, { electron?, rsbuild? })`, and `pluginElectron(name, options?)` if you register `@module-federation/rsbuild-plugin` yourself.
161
+
162
+ From `./vite`: `federationElectron(federation, { electron? })`, and `electron(name, options?)` if you register `@module-federation/vite` yourself.
163
+
164
+ ## Troubleshooting
165
+
166
+ - **A Vite remote's React bindings are `undefined` in an Rsbuild host**: use `@module-federation/vite` 1.23.9 or later ([module-federation/vite#1535](https://github.com/module-federation/vite/issues/1535)).
167
+ - **`does not provide an export named 'net'`**: `ELECTRON_RUN_AS_NODE=1` is set, usually by a terminal inside VS Code or another Electron app. Unset it before starting Electron.
168
+
169
+ ## Links
170
+
171
+ - [Repository and examples](https://github.com/module-federation/electron)
172
+ - [Module Federation documentation](https://module-federation.io/)
173
+ - [Discord](https://discord.gg/n69NnT3ACV)
174
+ - [Issues](https://github.com/module-federation/electron/issues)
175
+
176
+ ## License
177
+
178
+ [MIT](https://github.com/module-federation/electron/blob/main/LICENSE)
package/dist/index.cjs CHANGED
@@ -1,5 +1,29 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.n = (module)=>{
5
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
6
+ __webpack_require__.d(getter, {
7
+ a: getter
8
+ });
9
+ return getter;
10
+ };
11
+ })();
12
+ (()=>{
13
+ __webpack_require__.d = (exports1, getters, values)=>{
14
+ var define = (defs, kind)=>{
15
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
16
+ enumerable: true,
17
+ [kind]: defs[key]
18
+ });
19
+ };
20
+ define(getters, "get");
21
+ define(values, "value");
22
+ };
23
+ })();
24
+ (()=>{
25
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
26
+ })();
3
27
  (()=>{
4
28
  __webpack_require__.r = (exports1)=>{
5
29
  if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
@@ -12,7 +36,86 @@ var __webpack_require__ = {};
12
36
  })();
13
37
  var __webpack_exports__ = {};
14
38
  __webpack_require__.r(__webpack_exports__);
15
- for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
39
+ __webpack_require__.d(__webpack_exports__, {
40
+ CACHE_HEADER: ()=>external_remote_cjs_namespaceObject.CACHE_HEADER,
41
+ DEFAULT_HOST: ()=>external_url_cjs_namespaceObject.DEFAULT_HOST,
42
+ DEFAULT_SCHEME: ()=>external_url_cjs_namespaceObject.DEFAULT_SCHEME,
43
+ federationBaseUrl: ()=>external_url_cjs_namespaceObject.federationBaseUrl,
44
+ federationUrl: ()=>external_url_cjs_namespaceObject.federationUrl,
45
+ registerFederationScheme: ()=>registerFederationScheme,
46
+ resolveAppFile: ()=>external_resolve_cjs_namespaceObject.resolveAppFile,
47
+ serveFederatedApps: ()=>serveFederatedApps,
48
+ toAppId: ()=>external_url_cjs_namespaceObject.toAppId
49
+ });
50
+ const external_node_path_namespaceObject = require("node:path");
51
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
52
+ const external_node_url_namespaceObject = require("node:url");
53
+ const external_electron_namespaceObject = require("electron");
54
+ const external_remote_cjs_namespaceObject = require("./remote.cjs");
55
+ const external_resolve_cjs_namespaceObject = require("./resolve.cjs");
56
+ const external_url_cjs_namespaceObject = require("./url.cjs");
57
+ function registerFederationScheme(options = {}) {
58
+ external_electron_namespaceObject.protocol.registerSchemesAsPrivileged([
59
+ {
60
+ scheme: options.scheme ?? external_url_cjs_namespaceObject.DEFAULT_SCHEME,
61
+ privileges: {
62
+ standard: true,
63
+ secure: true,
64
+ supportFetchAPI: true,
65
+ corsEnabled: true,
66
+ stream: true,
67
+ codeCache: true
68
+ }
69
+ }
70
+ ]);
71
+ }
72
+ function serveFederatedApps(options) {
73
+ const scheme = options.scheme ?? external_url_cjs_namespaceObject.DEFAULT_SCHEME;
74
+ const host = options.host ?? external_url_cjs_namespaceObject.DEFAULT_HOST;
75
+ const dirs = {};
76
+ const urls = {};
77
+ for (const [name, location] of Object.entries(options.apps))((0, external_remote_cjs_namespaceObject.isRemoteLocation)(location) ? urls : dirs)[(0, external_url_cjs_namespaceObject.toAppId)(name)] = location;
78
+ const fetchRemote = (0, external_remote_cjs_namespaceObject.createRemoteHandler)({
79
+ fetch: (url, init)=>external_electron_namespaceObject.net.fetch(url, init),
80
+ cache: false === options.cache ? false : {
81
+ ...options.cache,
82
+ dir: options.cache?.dir ?? external_node_path_default().join(external_electron_namespaceObject.app.getPath('sessionData'), 'module-federation')
83
+ }
84
+ });
85
+ external_electron_namespaceObject.protocol.handle(scheme, async (request)=>{
86
+ const url = new URL(request.url);
87
+ if (url.host === host) {
88
+ const upstream = (0, external_remote_cjs_namespaceObject.resolveAppUrl)(url, urls);
89
+ if (upstream) return fetchRemote(request, upstream);
90
+ const file = (0, external_resolve_cjs_namespaceObject.resolveAppFile)(url.pathname, dirs);
91
+ if (file) return external_electron_namespaceObject.net.fetch((0, external_node_url_namespaceObject.pathToFileURL)(file).href);
92
+ }
93
+ return new Response('Not found', {
94
+ status: 404
95
+ });
96
+ });
97
+ return ()=>external_electron_namespaceObject.protocol.unhandle(scheme);
98
+ }
99
+ exports.CACHE_HEADER = __webpack_exports__.CACHE_HEADER;
100
+ exports.DEFAULT_HOST = __webpack_exports__.DEFAULT_HOST;
101
+ exports.DEFAULT_SCHEME = __webpack_exports__.DEFAULT_SCHEME;
102
+ exports.federationBaseUrl = __webpack_exports__.federationBaseUrl;
103
+ exports.federationUrl = __webpack_exports__.federationUrl;
104
+ exports.registerFederationScheme = __webpack_exports__.registerFederationScheme;
105
+ exports.resolveAppFile = __webpack_exports__.resolveAppFile;
106
+ exports.serveFederatedApps = __webpack_exports__.serveFederatedApps;
107
+ exports.toAppId = __webpack_exports__.toAppId;
108
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
109
+ "CACHE_HEADER",
110
+ "DEFAULT_HOST",
111
+ "DEFAULT_SCHEME",
112
+ "federationBaseUrl",
113
+ "federationUrl",
114
+ "registerFederationScheme",
115
+ "resolveAppFile",
116
+ "serveFederatedApps",
117
+ "toAppId"
118
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
16
119
  Object.defineProperty(exports, '__esModule', {
17
120
  value: true
18
121
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["webpack://webpack/runtime/make_namespace_object"],"sourcesContent":["// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};"],"names":["__webpack_require__","Symbol","Object"],"mappings":";;;IACAA,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,MAAlB,OAAOC,UAA0BA,OAAO,WAAW,EACrDC,OAAO,cAAc,CAAC,UAASD,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEC,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D"}
1
+ {"version":3,"file":"index.cjs","sources":["webpack://webpack/runtime/compat_get_default_export","webpack://webpack/runtime/define_property_getters","webpack://webpack/runtime/has_own_property","webpack://webpack/runtime/make_namespace_object","../src/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, getters, values) => {\n\tvar define = (defs, kind) => {\n\t\tfor(var key in defs) {\n\t\t\tif(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] });\n\t\t\t}\n\t\t}\n\t};\n\tdefine(getters, \"get\");\n\tdefine(values, \"value\");\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Electron main-process integration. Build configs should import the URL helpers\n * from `@module-federation/electron/rsbuild` or `/vite` instead: this entry imports `electron`.\n */\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { app, net, protocol } from 'electron';\nimport {\n createRemoteHandler,\n isRemoteLocation,\n resolveAppUrl,\n type RemoteCacheOptions,\n} from './remote.ts';\nimport { resolveAppFile } from './resolve.ts';\nimport { DEFAULT_HOST, DEFAULT_SCHEME, toAppId } from './url.ts';\n\nexport { CACHE_HEADER, type RemoteCacheOptions } from './remote.ts';\nexport { resolveAppFile } from './resolve.ts';\nexport {\n DEFAULT_HOST,\n DEFAULT_SCHEME,\n federationBaseUrl,\n federationUrl,\n toAppId,\n type FederationUrlOptions,\n} from './url.ts';\n\nexport interface RegisterSchemeOptions {\n scheme?: string;\n}\n\n/**\n * Registers the federation scheme as privileged (fetch, CORS, ESM, service workers).\n * Must be called before the `ready` event of `app`.\n */\nexport function registerFederationScheme(options: RegisterSchemeOptions = {}): void {\n protocol.registerSchemesAsPrivileged([\n {\n scheme: options.scheme ?? DEFAULT_SCHEME,\n privileges: {\n standard: true,\n secure: true,\n supportFetchAPI: true,\n corsEnabled: true,\n stream: true,\n codeCache: true,\n },\n },\n ]);\n}\n\nexport interface ServeFederatedAppsOptions {\n scheme?: string;\n host?: string;\n /**\n * Map of federation `name` (or app id) to the directory holding its build output,\n * or the http(s) URL it is deployed to.\n */\n apps: Record<string, string>;\n /**\n * Offline cache for apps served from a URL. Pass `false` to proxy them without caching.\n * By default responses are cached in `<sessionData>/module-federation`.\n */\n cache?: false | Partial<RemoteCacheOptions>;\n}\n\n/**\n * Serves each app on `<scheme>://<host>/<appId>/`, from its build directory or from the\n * URL it is deployed to. Call after `app.whenReady()`. Returns a function that unregisters\n * the handler.\n */\nexport function serveFederatedApps(options: ServeFederatedAppsOptions): () => void {\n const scheme = options.scheme ?? DEFAULT_SCHEME;\n const host = options.host ?? DEFAULT_HOST;\n const dirs: Record<string, string> = {};\n const urls: Record<string, string> = {};\n for (const [name, location] of Object.entries(options.apps)) {\n (isRemoteLocation(location) ? urls : dirs)[toAppId(name)] = location;\n }\n const fetchRemote = createRemoteHandler({\n fetch: (url, init) => net.fetch(url, init),\n cache:\n options.cache === false\n ? false\n : {\n ...options.cache,\n dir: options.cache?.dir ?? path.join(app.getPath('sessionData'), 'module-federation'),\n },\n });\n\n protocol.handle(scheme, async (request) => {\n const url = new URL(request.url);\n if (url.host === host) {\n const upstream = resolveAppUrl(url, urls);\n if (upstream) return fetchRemote(request, upstream);\n const file = resolveAppFile(url.pathname, dirs);\n if (file) return net.fetch(pathToFileURL(file).href);\n }\n return new Response('Not found', { status: 404 });\n });\n\n return () => protocol.unhandle(scheme);\n}\n"],"names":["__webpack_require__","module","getter","getters","values","define","defs","kind","key","Object","obj","prop","Symbol","registerFederationScheme","options","protocol","DEFAULT_SCHEME","serveFederatedApps","scheme","host","DEFAULT_HOST","dirs","urls","name","location","isRemoteLocation","toAppId","fetchRemote","createRemoteHandler","url","init","net","path","app","request","URL","upstream","resolveAppUrl","file","resolveAppFile","pathToFileURL","Response"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,2 +1,33 @@
1
- export {};
1
+ import { type RemoteCacheOptions } from './remote.cjs';
2
+ export { CACHE_HEADER, type RemoteCacheOptions } from './remote.cjs';
3
+ export { resolveAppFile } from './resolve.cjs';
4
+ export { DEFAULT_HOST, DEFAULT_SCHEME, federationBaseUrl, federationUrl, toAppId, type FederationUrlOptions, } from './url.cjs';
5
+ export interface RegisterSchemeOptions {
6
+ scheme?: string;
7
+ }
8
+ /**
9
+ * Registers the federation scheme as privileged (fetch, CORS, ESM, service workers).
10
+ * Must be called before the `ready` event of `app`.
11
+ */
12
+ export declare function registerFederationScheme(options?: RegisterSchemeOptions): void;
13
+ export interface ServeFederatedAppsOptions {
14
+ scheme?: string;
15
+ host?: string;
16
+ /**
17
+ * Map of federation `name` (or app id) to the directory holding its build output,
18
+ * or the http(s) URL it is deployed to.
19
+ */
20
+ apps: Record<string, string>;
21
+ /**
22
+ * Offline cache for apps served from a URL. Pass `false` to proxy them without caching.
23
+ * By default responses are cached in `<sessionData>/module-federation`.
24
+ */
25
+ cache?: false | Partial<RemoteCacheOptions>;
26
+ }
27
+ /**
28
+ * Serves each app on `<scheme>://<host>/<appId>/`, from its build directory or from the
29
+ * URL it is deployed to. Call after `app.whenReady()`. Returns a function that unregisters
30
+ * the handler.
31
+ */
32
+ export declare function serveFederatedApps(options: ServeFederatedAppsOptions): () => void;
2
33
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,OAAO,EACP,KAAK,oBAAoB,GAC1B,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,qBAA0B,GAAG,IAAI,CAclF;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,IAAI,CA+BjF"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,33 @@
1
- export {};
1
+ import { type RemoteCacheOptions } from './remote.js';
2
+ export { CACHE_HEADER, type RemoteCacheOptions } from './remote.js';
3
+ export { resolveAppFile } from './resolve.js';
4
+ export { DEFAULT_HOST, DEFAULT_SCHEME, federationBaseUrl, federationUrl, toAppId, type FederationUrlOptions, } from './url.js';
5
+ export interface RegisterSchemeOptions {
6
+ scheme?: string;
7
+ }
8
+ /**
9
+ * Registers the federation scheme as privileged (fetch, CORS, ESM, service workers).
10
+ * Must be called before the `ready` event of `app`.
11
+ */
12
+ export declare function registerFederationScheme(options?: RegisterSchemeOptions): void;
13
+ export interface ServeFederatedAppsOptions {
14
+ scheme?: string;
15
+ host?: string;
16
+ /**
17
+ * Map of federation `name` (or app id) to the directory holding its build output,
18
+ * or the http(s) URL it is deployed to.
19
+ */
20
+ apps: Record<string, string>;
21
+ /**
22
+ * Offline cache for apps served from a URL. Pass `false` to proxy them without caching.
23
+ * By default responses are cached in `<sessionData>/module-federation`.
24
+ */
25
+ cache?: false | Partial<RemoteCacheOptions>;
26
+ }
27
+ /**
28
+ * Serves each app on `<scheme>://<host>/<appId>/`, from its build directory or from the
29
+ * URL it is deployed to. Call after `app.whenReady()`. Returns a function that unregisters
30
+ * the handler.
31
+ */
32
+ export declare function serveFederatedApps(options: ServeFederatedAppsOptions): () => void;
2
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,OAAO,EACP,KAAK,oBAAoB,GAC1B,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,qBAA0B,GAAG,IAAI,CAclF;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,IAAI,CA+BjF"}
package/dist/index.js CHANGED
@@ -1 +1,51 @@
1
- export { };
1
+ import node_path from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+ import { app, net, protocol } from "electron";
4
+ import { CACHE_HEADER, createRemoteHandler, isRemoteLocation, resolveAppUrl } from "./remote.js";
5
+ import { resolveAppFile } from "./resolve.js";
6
+ import { DEFAULT_HOST, DEFAULT_SCHEME, federationBaseUrl, federationUrl, toAppId } from "./url.js";
7
+ function registerFederationScheme(options = {}) {
8
+ protocol.registerSchemesAsPrivileged([
9
+ {
10
+ scheme: options.scheme ?? DEFAULT_SCHEME,
11
+ privileges: {
12
+ standard: true,
13
+ secure: true,
14
+ supportFetchAPI: true,
15
+ corsEnabled: true,
16
+ stream: true,
17
+ codeCache: true
18
+ }
19
+ }
20
+ ]);
21
+ }
22
+ function serveFederatedApps(options) {
23
+ const scheme = options.scheme ?? DEFAULT_SCHEME;
24
+ const host = options.host ?? DEFAULT_HOST;
25
+ const dirs = {};
26
+ const urls = {};
27
+ for (const [name, location] of Object.entries(options.apps))(isRemoteLocation(location) ? urls : dirs)[toAppId(name)] = location;
28
+ const fetchRemote = createRemoteHandler({
29
+ fetch: (url, init)=>net.fetch(url, init),
30
+ cache: false === options.cache ? false : {
31
+ ...options.cache,
32
+ dir: options.cache?.dir ?? node_path.join(app.getPath('sessionData'), 'module-federation')
33
+ }
34
+ });
35
+ protocol.handle(scheme, async (request)=>{
36
+ const url = new URL(request.url);
37
+ if (url.host === host) {
38
+ const upstream = resolveAppUrl(url, urls);
39
+ if (upstream) return fetchRemote(request, upstream);
40
+ const file = resolveAppFile(url.pathname, dirs);
41
+ if (file) return net.fetch(pathToFileURL(file).href);
42
+ }
43
+ return new Response('Not found', {
44
+ status: 404
45
+ });
46
+ });
47
+ return ()=>protocol.unhandle(scheme);
48
+ }
49
+ export { CACHE_HEADER, DEFAULT_HOST, DEFAULT_SCHEME, federationBaseUrl, federationUrl, registerFederationScheme, resolveAppFile, serveFederatedApps, toAppId };
50
+
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * Electron main-process integration. Build configs should import the URL helpers\n * from `@module-federation/electron/rsbuild` or `/vite` instead: this entry imports `electron`.\n */\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { app, net, protocol } from 'electron';\nimport {\n createRemoteHandler,\n isRemoteLocation,\n resolveAppUrl,\n type RemoteCacheOptions,\n} from './remote.ts';\nimport { resolveAppFile } from './resolve.ts';\nimport { DEFAULT_HOST, DEFAULT_SCHEME, toAppId } from './url.ts';\n\nexport { CACHE_HEADER, type RemoteCacheOptions } from './remote.ts';\nexport { resolveAppFile } from './resolve.ts';\nexport {\n DEFAULT_HOST,\n DEFAULT_SCHEME,\n federationBaseUrl,\n federationUrl,\n toAppId,\n type FederationUrlOptions,\n} from './url.ts';\n\nexport interface RegisterSchemeOptions {\n scheme?: string;\n}\n\n/**\n * Registers the federation scheme as privileged (fetch, CORS, ESM, service workers).\n * Must be called before the `ready` event of `app`.\n */\nexport function registerFederationScheme(options: RegisterSchemeOptions = {}): void {\n protocol.registerSchemesAsPrivileged([\n {\n scheme: options.scheme ?? DEFAULT_SCHEME,\n privileges: {\n standard: true,\n secure: true,\n supportFetchAPI: true,\n corsEnabled: true,\n stream: true,\n codeCache: true,\n },\n },\n ]);\n}\n\nexport interface ServeFederatedAppsOptions {\n scheme?: string;\n host?: string;\n /**\n * Map of federation `name` (or app id) to the directory holding its build output,\n * or the http(s) URL it is deployed to.\n */\n apps: Record<string, string>;\n /**\n * Offline cache for apps served from a URL. Pass `false` to proxy them without caching.\n * By default responses are cached in `<sessionData>/module-federation`.\n */\n cache?: false | Partial<RemoteCacheOptions>;\n}\n\n/**\n * Serves each app on `<scheme>://<host>/<appId>/`, from its build directory or from the\n * URL it is deployed to. Call after `app.whenReady()`. Returns a function that unregisters\n * the handler.\n */\nexport function serveFederatedApps(options: ServeFederatedAppsOptions): () => void {\n const scheme = options.scheme ?? DEFAULT_SCHEME;\n const host = options.host ?? DEFAULT_HOST;\n const dirs: Record<string, string> = {};\n const urls: Record<string, string> = {};\n for (const [name, location] of Object.entries(options.apps)) {\n (isRemoteLocation(location) ? urls : dirs)[toAppId(name)] = location;\n }\n const fetchRemote = createRemoteHandler({\n fetch: (url, init) => net.fetch(url, init),\n cache:\n options.cache === false\n ? false\n : {\n ...options.cache,\n dir: options.cache?.dir ?? path.join(app.getPath('sessionData'), 'module-federation'),\n },\n });\n\n protocol.handle(scheme, async (request) => {\n const url = new URL(request.url);\n if (url.host === host) {\n const upstream = resolveAppUrl(url, urls);\n if (upstream) return fetchRemote(request, upstream);\n const file = resolveAppFile(url.pathname, dirs);\n if (file) return net.fetch(pathToFileURL(file).href);\n }\n return new Response('Not found', { status: 404 });\n });\n\n return () => protocol.unhandle(scheme);\n}\n"],"names":["registerFederationScheme","options","protocol","DEFAULT_SCHEME","serveFederatedApps","scheme","host","DEFAULT_HOST","dirs","urls","name","location","Object","isRemoteLocation","toAppId","fetchRemote","createRemoteHandler","url","init","net","path","app","request","URL","upstream","resolveAppUrl","file","resolveAppFile","pathToFileURL","Response"],"mappings":";;;;;;AAmCO,SAASA,yBAAyBC,UAAiC,CAAC,CAAC;IAC1EC,SAAS,2BAA2B,CAAC;QACnC;YACE,QAAQD,QAAQ,MAAM,IAAIE;YAC1B,YAAY;gBACV,UAAU;gBACV,QAAQ;gBACR,iBAAiB;gBACjB,aAAa;gBACb,QAAQ;gBACR,WAAW;YACb;QACF;KACD;AACH;AAsBO,SAASC,mBAAmBH,OAAkC;IACnE,MAAMI,SAASJ,QAAQ,MAAM,IAAIE;IACjC,MAAMG,OAAOL,QAAQ,IAAI,IAAIM;IAC7B,MAAMC,OAA+B,CAAC;IACtC,MAAMC,OAA+B,CAAC;IACtC,KAAK,MAAM,CAACC,MAAMC,SAAS,IAAIC,OAAO,OAAO,CAACX,QAAQ,IAAI,EACvDY,AAAAA,CAAAA,iBAAiBF,YAAYF,OAAOD,IAAG,CAAE,CAACM,QAAQJ,MAAM,GAAGC;IAE9D,MAAMI,cAAcC,oBAAoB;QACtC,OAAO,CAACC,KAAKC,OAASC,IAAI,KAAK,CAACF,KAAKC;QACrC,OACEjB,AAAkB,UAAlBA,QAAQ,KAAK,GACT,QACA;YACE,GAAGA,QAAQ,KAAK;YAChB,KAAKA,QAAQ,KAAK,EAAE,OAAOmB,UAAAA,IAAS,CAACC,IAAI,OAAO,CAAC,gBAAgB;QACnE;IACR;IAEAnB,SAAS,MAAM,CAACG,QAAQ,OAAOiB;QAC7B,MAAML,MAAM,IAAIM,IAAID,QAAQ,GAAG;QAC/B,IAAIL,IAAI,IAAI,KAAKX,MAAM;YACrB,MAAMkB,WAAWC,cAAcR,KAAKR;YACpC,IAAIe,UAAU,OAAOT,YAAYO,SAASE;YAC1C,MAAME,OAAOC,eAAeV,IAAI,QAAQ,EAAET;YAC1C,IAAIkB,MAAM,OAAOP,IAAI,KAAK,CAACS,cAAcF,MAAM,IAAI;QACrD;QACA,OAAO,IAAIG,SAAS,aAAa;YAAE,QAAQ;QAAI;IACjD;IAEA,OAAO,IAAM3B,SAAS,QAAQ,CAACG;AACjC"}