zephyr-metro-plugin 0.0.0 → 0.1.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/LICENSE +39 -0
- package/README.md +330 -0
- package/TESTING.md +153 -0
- package/dist/README.md +330 -0
- package/dist/TESTING.md +153 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/internal/extract-mf-remotes.d.ts +3 -0
- package/dist/lib/internal/extract-mf-remotes.js +22 -0
- package/dist/lib/internal/extract-mf-remotes.js.map +1 -0
- package/dist/lib/internal/extract-modules-from-exposes.d.ts +12 -0
- package/dist/lib/internal/extract-modules-from-exposes.js +66 -0
- package/dist/lib/internal/extract-modules-from-exposes.js.map +1 -0
- package/dist/lib/internal/get-package-dependencies.d.ts +4 -0
- package/dist/lib/internal/get-package-dependencies.js +9 -0
- package/dist/lib/internal/get-package-dependencies.js.map +1 -0
- package/dist/lib/internal/load-static-entries.d.ts +7 -0
- package/dist/lib/internal/load-static-entries.js +39 -0
- package/dist/lib/internal/load-static-entries.js.map +1 -0
- package/dist/lib/internal/metro-build-stats.d.ts +4 -0
- package/dist/lib/internal/metro-build-stats.js +53 -0
- package/dist/lib/internal/metro-build-stats.js.map +1 -0
- package/dist/lib/internal/metro-errors.d.ts +5 -0
- package/dist/lib/internal/metro-errors.js +7 -0
- package/dist/lib/internal/metro-errors.js.map +1 -0
- package/dist/lib/internal/mutate-mf-config.d.ts +10 -0
- package/dist/lib/internal/mutate-mf-config.js +50 -0
- package/dist/lib/internal/mutate-mf-config.js.map +1 -0
- package/dist/lib/internal/parse-shared-dependencies.d.ts +8 -0
- package/dist/lib/internal/parse-shared-dependencies.js +54 -0
- package/dist/lib/internal/parse-shared-dependencies.js.map +1 -0
- package/dist/lib/internal/types.d.ts +53 -0
- package/dist/lib/internal/types.js +3 -0
- package/dist/lib/internal/types.js.map +1 -0
- package/dist/lib/with-zephyr.d.ts +25 -0
- package/dist/lib/with-zephyr.js +143 -0
- package/dist/lib/with-zephyr.js.map +1 -0
- package/dist/lib/zephyr-metro-command-wrapper.d.ts +19 -0
- package/dist/lib/zephyr-metro-command-wrapper.js +42 -0
- package/dist/lib/zephyr-metro-command-wrapper.js.map +1 -0
- package/dist/lib/zephyr-metro-plugin.d.ts +30 -0
- package/dist/lib/zephyr-metro-plugin.js +162 -0
- package/dist/lib/zephyr-metro-plugin.js.map +1 -0
- package/dist/lib/zephyr-transformer.d.ts +16 -0
- package/dist/lib/zephyr-transformer.js +99 -0
- package/dist/lib/zephyr-transformer.js.map +1 -0
- package/dist/package.json +68 -0
- package/package.json +66 -10
package/dist/README.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# Zephyr Metro Plugin
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[Zephyr Cloud](https://zephyr-cloud.io) | [Zephyr Docs](https://docs.zephyr-cloud.io/bundlers/metro) | [Discord](https://zephyr-cloud.io/discord) | [Twitter](https://x.com/ZephyrCloudIO) | [LinkedIn](https://www.linkedin.com/company/zephyr-cloud/)
|
|
6
|
+
|
|
7
|
+
<hr/>
|
|
8
|
+
<img src="https://cdn.prod.website-files.com/669061ee3adb95b628c3acda/66981c766e352fe1f57191e2_Opengraph-zephyr.png" alt="Zephyr Logo" />
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
A React Native Metro bundler plugin for deploying cross-platform applications with Zephyr Cloud. This plugin integrates seamlessly with Metro bundler and React Native to enable Over-The-Air (OTA) updates, Module Federation, and seamless deployment to Zephyr Cloud.
|
|
12
|
+
|
|
13
|
+
## Get Started
|
|
14
|
+
|
|
15
|
+
For setup instructions, see [TESTING.md](./TESTING.md) or refer to our [documentation](https://docs.zephyr-cloud.io/bundlers/metro) for Metro and comprehensive guides for React Native integration.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Installing the `zephyr-metro-plugin` for your React Native application:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# npm
|
|
23
|
+
npm install --save-dev zephyr-metro-plugin
|
|
24
|
+
|
|
25
|
+
# yarn
|
|
26
|
+
yarn add --dev zephyr-metro-plugin
|
|
27
|
+
|
|
28
|
+
# pnpm
|
|
29
|
+
pnpm add --dev zephyr-metro-plugin
|
|
30
|
+
|
|
31
|
+
# bun
|
|
32
|
+
bun add --dev zephyr-metro-plugin
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Basic Configuration
|
|
38
|
+
|
|
39
|
+
The Metro plugin provides two main integration points depending on your setup:
|
|
40
|
+
|
|
41
|
+
#### 1. Using `withZephyr` Config Wrapper
|
|
42
|
+
|
|
43
|
+
For Metro configuration file integration:
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// metro.config.js
|
|
47
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
48
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
49
|
+
|
|
50
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
51
|
+
|
|
52
|
+
module.exports = (async () => {
|
|
53
|
+
const zephyrConfig = await withZephyr({
|
|
54
|
+
name: 'MyApp',
|
|
55
|
+
target: 'ios', // or 'android'
|
|
56
|
+
remotes: {
|
|
57
|
+
SharedComponents: 'SharedComponents@http://localhost:9000/remoteEntry.js',
|
|
58
|
+
},
|
|
59
|
+
})(baseConfig);
|
|
60
|
+
|
|
61
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
62
|
+
})();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### 2. Using Command Wrapper
|
|
66
|
+
|
|
67
|
+
For CLI-level integration with custom bundling commands:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
const { zephyrCommandWrapper } = require('zephyr-metro-plugin');
|
|
71
|
+
|
|
72
|
+
// Wrap your Metro bundling function
|
|
73
|
+
const wrappedBundleCommand = zephyrCommandWrapper(originalBundleFunction, loadMetroConfig, updateManifest);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Module Federation Configuration
|
|
77
|
+
|
|
78
|
+
The plugin works with Metro's Module Federation setup. Configure your federated modules.
|
|
79
|
+
|
|
80
|
+
> **Note:** Module Federation `exposes` configuration requires [@callstack/repack](https://re-pack.dev/) or a similar Metro Module Federation solution. This plugin handles the Zephyr Cloud deployment and OTA update aspects, while Re.Pack provides the underlying Module Federation runtime for React Native.
|
|
81
|
+
|
|
82
|
+
#### Host Application Example
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
// metro.config.js
|
|
86
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
87
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
88
|
+
|
|
89
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
90
|
+
|
|
91
|
+
module.exports = (async () => {
|
|
92
|
+
const zephyrConfig = await withZephyr({
|
|
93
|
+
name: 'MobileHost',
|
|
94
|
+
target: 'ios', // or 'android'
|
|
95
|
+
remotes: {
|
|
96
|
+
MobileCart: 'MobileCart@http://localhost:9000/ios/MobileCart.bundle',
|
|
97
|
+
MobileCheckout: 'MobileCheckout@http://localhost:9001/ios/MobileCheckout.bundle',
|
|
98
|
+
},
|
|
99
|
+
})(baseConfig);
|
|
100
|
+
|
|
101
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
102
|
+
})();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Remote/Mini-App Example
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
// metro.config.js
|
|
109
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
110
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
111
|
+
|
|
112
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
113
|
+
|
|
114
|
+
module.exports = (async () => {
|
|
115
|
+
const zephyrConfig = await withZephyr({
|
|
116
|
+
name: 'MobileCart',
|
|
117
|
+
target: 'ios',
|
|
118
|
+
})(baseConfig);
|
|
119
|
+
|
|
120
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
121
|
+
})();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Platform-Specific Configuration
|
|
125
|
+
|
|
126
|
+
The plugin supports both iOS and Android platforms:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// metro.config.js
|
|
130
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
131
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
132
|
+
|
|
133
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
134
|
+
const platform = process.env.PLATFORM || 'ios';
|
|
135
|
+
|
|
136
|
+
module.exports = (async () => {
|
|
137
|
+
const zephyrConfig = await withZephyr({
|
|
138
|
+
name: 'MyApp',
|
|
139
|
+
target: platform,
|
|
140
|
+
})(baseConfig);
|
|
141
|
+
|
|
142
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
143
|
+
})();
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Build Scripts
|
|
147
|
+
|
|
148
|
+
Add these scripts to your `package.json`:
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"scripts": {
|
|
153
|
+
"ios": "react-native run-ios",
|
|
154
|
+
"android": "react-native run-android",
|
|
155
|
+
"build:ios": "PLATFORM=ios NODE_ENV=production react-native bundle",
|
|
156
|
+
"build:android": "PLATFORM=android NODE_ENV=production react-native bundle"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Features
|
|
162
|
+
|
|
163
|
+
- 📱 **Cross-platform React Native support** - iOS and Android
|
|
164
|
+
- 🚀 **Over-The-Air (OTA) updates** - Deploy updates without app store releases
|
|
165
|
+
- 🏗️ **Module Federation support** - Share code between micro-frontends
|
|
166
|
+
- ⚡ **Metro bundler integration** - Works seamlessly with Metro's fast refresh
|
|
167
|
+
- 🔧 **Zero-config setup** - Minimal configuration required
|
|
168
|
+
- 📊 **Build analytics and monitoring** - Track deployments and performance
|
|
169
|
+
- 🌐 **Global CDN distribution** - Fast asset delivery worldwide
|
|
170
|
+
- 🔄 **Hot Module Replacement** - Development workflow with fast refresh
|
|
171
|
+
|
|
172
|
+
## Over-The-Air (OTA) Updates
|
|
173
|
+
|
|
174
|
+
For detailed information about implementing OTA updates with the Metro plugin, see [OTA_SETUP.md](./OTA_SETUP.md).
|
|
175
|
+
|
|
176
|
+
Key OTA features:
|
|
177
|
+
|
|
178
|
+
- Automatic update checks
|
|
179
|
+
- Silent background updates
|
|
180
|
+
- Rollback capabilities
|
|
181
|
+
- Version management
|
|
182
|
+
- Platform-specific updates
|
|
183
|
+
|
|
184
|
+
## Project Structure
|
|
185
|
+
|
|
186
|
+
Your React Native Metro project should follow this structure:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
my-react-native-app/
|
|
190
|
+
├── android/
|
|
191
|
+
├── ios/
|
|
192
|
+
├── src/
|
|
193
|
+
│ ├── components/
|
|
194
|
+
│ ├── screens/
|
|
195
|
+
│ └── App.tsx
|
|
196
|
+
├── metro.config.js
|
|
197
|
+
├── package.json
|
|
198
|
+
└── index.js
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Requirements
|
|
202
|
+
|
|
203
|
+
- **React Native**: 0.70 or higher
|
|
204
|
+
- **Metro**: 0.80 or higher
|
|
205
|
+
- **Node.js**: 18 or higher
|
|
206
|
+
- **Zephyr Cloud account**: Sign up at [zephyr-cloud.io](https://zephyr-cloud.io)
|
|
207
|
+
|
|
208
|
+
## Advanced Configuration
|
|
209
|
+
|
|
210
|
+
### Custom Manifest Path
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
// metro.config.js
|
|
214
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
215
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
216
|
+
|
|
217
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
218
|
+
|
|
219
|
+
module.exports = (async () => {
|
|
220
|
+
const zephyrConfig = await withZephyr({
|
|
221
|
+
name: 'MyApp',
|
|
222
|
+
target: 'ios',
|
|
223
|
+
manifestPath: '/custom-manifest.json', // Custom manifest endpoint
|
|
224
|
+
})(baseConfig);
|
|
225
|
+
|
|
226
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
227
|
+
})();
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Troubleshooting
|
|
231
|
+
|
|
232
|
+
### Missing Metro Federation Config
|
|
233
|
+
|
|
234
|
+
If you see `ERR_MISSING_METRO_FEDERATION_CONFIG`, ensure your Module Federation config is properly set up:
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
// Set global config before bundling
|
|
238
|
+
global.__METRO_FEDERATION_CONFIG = mfConfig;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Platform-Specific Issues
|
|
242
|
+
|
|
243
|
+
Make sure to specify the correct platform when building:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# iOS
|
|
247
|
+
PLATFORM=ios react-native bundle
|
|
248
|
+
|
|
249
|
+
# Android
|
|
250
|
+
PLATFORM=android react-native bundle
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Asset Loading Issues
|
|
254
|
+
|
|
255
|
+
Ensure your Metro config is correctly set up:
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
module.exports = (async () => {
|
|
259
|
+
const zephyrConfig = await withZephyr({
|
|
260
|
+
name: 'MyApp',
|
|
261
|
+
target: platform,
|
|
262
|
+
})(baseConfig);
|
|
263
|
+
|
|
264
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
265
|
+
})();
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Examples
|
|
269
|
+
|
|
270
|
+
Check out our [examples directory](../../examples/) for complete working examples:
|
|
271
|
+
|
|
272
|
+
- [metro-react-native](../../examples/metro-react-native/) - Complete React Native setup with Zephyr
|
|
273
|
+
|
|
274
|
+
## API Reference
|
|
275
|
+
|
|
276
|
+
### `withZephyr(options)`
|
|
277
|
+
|
|
278
|
+
Main configuration wrapper for Metro config.
|
|
279
|
+
|
|
280
|
+
**Options (`ZephyrMetroOptions`):**
|
|
281
|
+
|
|
282
|
+
| Option | Type | Description |
|
|
283
|
+
| --------------------- | ------------------------ | ---------------------------------------------------------------- |
|
|
284
|
+
| `name` | `string` | Application name (optional) |
|
|
285
|
+
| `target` | `'ios' \| 'android'` | Target platform (optional) |
|
|
286
|
+
| `remotes` | `Record<string, string>` | Remote module configurations (optional) |
|
|
287
|
+
| `manifestPath` | `string` | Custom manifest endpoint path (default: `/zephyr-manifest.json`) |
|
|
288
|
+
| `entryFiles` | `string[]` | Custom entry file patterns for runtime injection (optional) |
|
|
289
|
+
| `failOnManifestError` | `boolean` | Throw error if manifest generation fails (default: `false`) |
|
|
290
|
+
|
|
291
|
+
**Returns:** Async function that takes Metro `ConfigT` and returns enhanced config
|
|
292
|
+
|
|
293
|
+
**Example:**
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
const enhancedConfig = await withZephyr({
|
|
297
|
+
name: 'MyApp',
|
|
298
|
+
target: 'ios',
|
|
299
|
+
remotes: {
|
|
300
|
+
SharedUI: 'SharedUI@http://localhost:8081/remoteEntry.js',
|
|
301
|
+
},
|
|
302
|
+
})(baseMetroConfig);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### `zephyrCommandWrapper(bundleFn, loadConfigFn, updateManifestFn)`
|
|
306
|
+
|
|
307
|
+
Advanced CLI-level integration wrapper for custom bundling commands.
|
|
308
|
+
|
|
309
|
+
**Parameters:**
|
|
310
|
+
|
|
311
|
+
- `bundleFn` (function): Original Metro bundle function
|
|
312
|
+
- `loadConfigFn` (function): Metro config loader function
|
|
313
|
+
- `updateManifestFn` (function): Manifest update function
|
|
314
|
+
|
|
315
|
+
**Returns:** Wrapped bundling function with Zephyr integration
|
|
316
|
+
|
|
317
|
+
## Contributing
|
|
318
|
+
|
|
319
|
+
We welcome contributions! Please read our [contributing guidelines](../../CONTRIBUTING.md) for more information.
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
Licensed under the Apache-2.0 License. See [LICENSE](LICENSE) for more information.
|
|
324
|
+
|
|
325
|
+
## Support
|
|
326
|
+
|
|
327
|
+
- **Documentation**: [docs.zephyr-cloud.io](https://docs.zephyr-cloud.io)
|
|
328
|
+
- **Discord**: [Join our community](https://zephyr-cloud.io/discord)
|
|
329
|
+
- **GitHub Issues**: [Report bugs](https://github.com/ZephyrCloudIO/zephyr-packages/issues)
|
|
330
|
+
- **Twitter**: [@ZephyrCloudIO](https://x.com/ZephyrCloudIO)
|
package/dist/TESTING.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Testing Zephyr Metro Plugin
|
|
2
|
+
|
|
3
|
+
Step-by-step guide to test the plugin with a Host + Remote setup.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 18+
|
|
8
|
+
- Xcode (iOS) or Android Studio (Android)
|
|
9
|
+
- Zephyr account: `npx zephyr login`
|
|
10
|
+
|
|
11
|
+
## 1. Build the Plugin
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm nx build zephyr-metro-plugin
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 2. Create Host App
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @react-native-community/cli init MetroHost
|
|
21
|
+
cd MetroHost
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Install dependencies:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install zephyr-metro-plugin @module-federation/runtime
|
|
28
|
+
# Or link local plugin:
|
|
29
|
+
npm install file:../path/to/zephyr-packages/libs/zephyr-metro-plugin
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Update `metro.config.js`:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
36
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
37
|
+
|
|
38
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
39
|
+
|
|
40
|
+
module.exports = (async () => {
|
|
41
|
+
const zephyrConfig = await withZephyr({
|
|
42
|
+
name: 'MetroHost',
|
|
43
|
+
target: 'ios',
|
|
44
|
+
remotes: {
|
|
45
|
+
MetroRemote: 'MetroRemote@http://localhost:9001/remoteEntry.js',
|
|
46
|
+
},
|
|
47
|
+
})(baseConfig);
|
|
48
|
+
|
|
49
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
50
|
+
})();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 3. Create Remote App
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx @react-native-community/cli init MetroRemote
|
|
57
|
+
cd MetroRemote
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Install dependencies:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install zephyr-metro-plugin @module-federation/runtime
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Update `metro.config.js`:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
70
|
+
const { withZephyr } = require('zephyr-metro-plugin');
|
|
71
|
+
|
|
72
|
+
const baseConfig = getDefaultConfig(__dirname);
|
|
73
|
+
|
|
74
|
+
module.exports = (async () => {
|
|
75
|
+
const zephyrConfig = await withZephyr({
|
|
76
|
+
name: 'MetroRemote',
|
|
77
|
+
target: 'ios',
|
|
78
|
+
})(baseConfig);
|
|
79
|
+
|
|
80
|
+
return mergeConfig(baseConfig, zephyrConfig);
|
|
81
|
+
})();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 4. Start Remote
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cd MetroRemote
|
|
88
|
+
npx react-native start --port 9001
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 5. Start Host
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
cd MetroHost
|
|
95
|
+
npx react-native start
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 6. Verify Setup
|
|
99
|
+
|
|
100
|
+
Check manifest endpoint:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
curl http://localhost:8081/zephyr-manifest.json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Should return JSON with remote dependencies.
|
|
107
|
+
|
|
108
|
+
Run on simulator:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npx react-native run-ios
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 7. Deploy to Zephyr
|
|
115
|
+
|
|
116
|
+
Build and deploy:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx react-native bundle \
|
|
120
|
+
--platform ios \
|
|
121
|
+
--dev false \
|
|
122
|
+
--entry-file index.js \
|
|
123
|
+
--bundle-output dist/ios/main.bundle \
|
|
124
|
+
--assets-dest dist/ios
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Check for:
|
|
128
|
+
|
|
129
|
+
- `assets/zephyr-manifest.json` generated
|
|
130
|
+
- Zephyr upload logs in console
|
|
131
|
+
- Deployment URL displayed
|
|
132
|
+
|
|
133
|
+
## Verify Zephyr Integration
|
|
134
|
+
|
|
135
|
+
| Check | Expected |
|
|
136
|
+
| --------------------------------------------------------- | ----------------------------- |
|
|
137
|
+
| Console shows `ZEPHYR` logs | Plugin initialized |
|
|
138
|
+
| `http://localhost:8081/zephyr-manifest.json` returns JSON | Manifest endpoint works |
|
|
139
|
+
| `assets/zephyr-manifest.json` exists after build | Production manifest generated |
|
|
140
|
+
| Build logs show upload progress | Zephyr deployment working |
|
|
141
|
+
|
|
142
|
+
## Troubleshooting
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Clear Metro cache
|
|
146
|
+
npx react-native start --reset-cache
|
|
147
|
+
|
|
148
|
+
# Reset Zephyr state
|
|
149
|
+
rm -rf ~/.zephyr
|
|
150
|
+
|
|
151
|
+
# Re-login to Zephyr
|
|
152
|
+
npx zephyr login
|
|
153
|
+
```
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* istanbul ignore file */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.zephyrTransformer = exports.withZephyrMetro = exports.withZephyr = void 0;
|
|
5
|
+
// Metro plugin exports
|
|
6
|
+
var with_zephyr_1 = require("./lib/with-zephyr");
|
|
7
|
+
Object.defineProperty(exports, "withZephyr", { enumerable: true, get: function () { return with_zephyr_1.withZephyr; } });
|
|
8
|
+
Object.defineProperty(exports, "withZephyrMetro", { enumerable: true, get: function () { return with_zephyr_1.withZephyrMetro; } });
|
|
9
|
+
// Transformer (usually not imported directly but referenced by path)
|
|
10
|
+
var zephyr_transformer_1 = require("./lib/zephyr-transformer");
|
|
11
|
+
Object.defineProperty(exports, "zephyrTransformer", { enumerable: true, get: function () { return zephyr_transformer_1.transform; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0BAA0B;;;AAE1B,uBAAuB;AACvB,iDAK2B;AAJzB,yGAAA,UAAU,OAAA;AACV,8GAAA,eAAe,OAAA;AAKjB,qEAAqE;AACrE,+DAA0E;AAAjE,uHAAA,SAAS,OAAqB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extract_remotes_dependencies = extract_remotes_dependencies;
|
|
4
|
+
const zephyr_agent_1 = require("zephyr-agent");
|
|
5
|
+
function extract_remotes_dependencies(config) {
|
|
6
|
+
const depsPairs = [];
|
|
7
|
+
const { zephyrDependencies } = (0, zephyr_agent_1.readPackageJson)(config.context ?? process.cwd());
|
|
8
|
+
if (zephyrDependencies) {
|
|
9
|
+
Object.entries(zephyrDependencies).map(([name, version]) => {
|
|
10
|
+
depsPairs.push({ name, version });
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
if (config.mfConfig?.remotes) {
|
|
14
|
+
Object.entries(config.mfConfig.remotes).map(([name, remote]) => {
|
|
15
|
+
depsPairs.push({ name, version: remote });
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return depsPairs
|
|
19
|
+
.flat()
|
|
20
|
+
.filter((dep) => (0, zephyr_agent_1.is_zephyr_dependency_pair)(dep));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=extract-mf-remotes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-mf-remotes.js","sourceRoot":"","sources":["../../../src/lib/internal/extract-mf-remotes.ts"],"names":[],"mappings":";;AAOA,oEAqBC;AA5BD,+CAIsB;AAGtB,SAAgB,4BAA4B,CAC1C,MAAkC;IAElC,MAAM,SAAS,GAAuB,EAAE,CAAC;IAEzC,MAAM,EAAE,kBAAkB,EAAE,GAAG,IAAA,8BAAe,EAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAChF,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE;YACzD,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAsB,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE;YAC7D,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAsB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,SAAS;SACb,IAAI,EAAE;SACN,MAAM,CAAC,CAAC,GAAG,EAA2B,EAAE,CAAC,IAAA,wCAAyB,EAAC,GAAG,CAAC,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ModuleFederationPlugin } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts exposed modules from Module Federation configuration Creates formatted module
|
|
4
|
+
* entries for the build stats
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractModulesFromExposes(mfConfig: ModuleFederationPlugin['config'] | undefined, applicationID: string): Array<{
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
applicationID: string;
|
|
10
|
+
requires: string[];
|
|
11
|
+
file: string;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractModulesFromExposes = extractModulesFromExposes;
|
|
4
|
+
/**
|
|
5
|
+
* Extracts exposed modules from Module Federation configuration Creates formatted module
|
|
6
|
+
* entries for the build stats
|
|
7
|
+
*/
|
|
8
|
+
function extractModulesFromExposes(mfConfig, applicationID) {
|
|
9
|
+
if (!mfConfig?.exposes) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
// Extract exposed modules from the Module Federation config
|
|
13
|
+
return Object.entries(mfConfig.exposes).map(([exposedPath, filePath]) => {
|
|
14
|
+
// Handle different formats of exposes configuration
|
|
15
|
+
// In Module Federation, exposes can be an object where key is the exposed path and value is the file path
|
|
16
|
+
// Example: { './Button': './src/Button' }
|
|
17
|
+
// Normalize the file path (it might be an object in some federation implementations)
|
|
18
|
+
const normalizedFilePath = typeof filePath === 'string'
|
|
19
|
+
? filePath
|
|
20
|
+
: typeof filePath === 'object' && filePath !== null && 'import' in filePath
|
|
21
|
+
? String(filePath.import)
|
|
22
|
+
: String(filePath);
|
|
23
|
+
// Extract just the module name from the exposed path (removing './')
|
|
24
|
+
const name = exposedPath.startsWith('./') ? exposedPath.substring(2) : exposedPath;
|
|
25
|
+
// Create a unique ID for this module in the format used by Module Federation Dashboard
|
|
26
|
+
const id = `${name}:${name}`;
|
|
27
|
+
// Extract any potential requirements from shared dependencies
|
|
28
|
+
// In a more complete implementation, this would analyze the actual file to find imports
|
|
29
|
+
const requires = [];
|
|
30
|
+
// If we have shared dependencies and they're an object with keys, use them as requirements
|
|
31
|
+
if (mfConfig.shared) {
|
|
32
|
+
if (Array.isArray(mfConfig.shared)) {
|
|
33
|
+
// Handle array format: ['react', 'react-dom']
|
|
34
|
+
requires.push(...mfConfig.shared
|
|
35
|
+
.map((item) => {
|
|
36
|
+
return typeof item === 'string'
|
|
37
|
+
? item
|
|
38
|
+
: typeof item === 'object' && item !== null && 'libraryName' in item
|
|
39
|
+
? String(item.libraryName)
|
|
40
|
+
: '';
|
|
41
|
+
})
|
|
42
|
+
.filter(Boolean));
|
|
43
|
+
}
|
|
44
|
+
else if (typeof mfConfig.shared === 'object' && mfConfig.shared !== null) {
|
|
45
|
+
// Handle object format: { react: {...}, 'react-dom': {...} }
|
|
46
|
+
requires.push(...Object.keys(mfConfig.shared));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Handle additionalShared format from Nx webpack module federation
|
|
50
|
+
if (mfConfig.additionalShared && Array.isArray(mfConfig.additionalShared)) {
|
|
51
|
+
requires.push(...mfConfig.additionalShared
|
|
52
|
+
.map((item) => typeof item === 'object' && item !== null && 'libraryName' in item
|
|
53
|
+
? String(item.libraryName)
|
|
54
|
+
: '')
|
|
55
|
+
.filter(Boolean));
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
id,
|
|
59
|
+
name,
|
|
60
|
+
applicationID,
|
|
61
|
+
requires,
|
|
62
|
+
file: normalizedFilePath,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=extract-modules-from-exposes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-modules-from-exposes.js","sourceRoot":"","sources":["../../../src/lib/internal/extract-modules-from-exposes.ts"],"names":[],"mappings":";;AAMA,8DAgFC;AApFD;;;GAGG;AACH,SAAgB,yBAAyB,CACvC,QAAsD,EACtD,aAAqB;IAQrB,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,4DAA4D;IAC5D,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE;QACtE,oDAAoD;QACpD,0GAA0G;QAC1G,0CAA0C;QAE1C,qFAAqF;QACrF,MAAM,kBAAkB,GACtB,OAAO,QAAQ,KAAK,QAAQ;YAC1B,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,IAAI,QAAQ;gBACzE,CAAC,CAAC,MAAM,CAAE,QAA+B,CAAC,MAAM,CAAC;gBACjD,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEzB,qEAAqE;QACrE,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAEnF,uFAAuF;QACvF,MAAM,EAAE,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;QAE7B,8DAA8D;QAC9D,wFAAwF;QACxF,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,2FAA2F;QAC3F,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnC,8CAA8C;gBAC9C,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,CAAC,MAAM;qBACf,GAAG,CAAC,CAAC,IAAqC,EAAE,EAAE;oBAC7C,OAAO,OAAO,IAAI,KAAK,QAAQ;wBAC7B,CAAC,CAAC,IAAI;wBACN,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,aAAa,IAAI,IAAI;4BAClE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;4BAC1B,CAAC,CAAC,EAAE,CAAC;gBACX,CAAC,CAAC;qBACD,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;YACJ,CAAC;iBAAM,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC3E,6DAA6D;gBAC7D,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,mEAAmE;QACnE,IAAI,QAAQ,CAAC,gBAAgB,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC1E,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,CAAC,gBAAgB;iBACzB,GAAG,CAAC,CAAC,IAAqC,EAAE,EAAE,CAC7C,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,aAAa,IAAI,IAAI;gBAChE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;gBAC1B,CAAC,CAAC,EAAE,CACP;iBACA,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;QACJ,CAAC;QAED,OAAO;YACL,EAAE;YACF,IAAI;YACJ,aAAa;YACb,QAAQ;YACR,IAAI,EAAE,kBAAkB;SACzB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPackageDependencies = getPackageDependencies;
|
|
4
|
+
function getPackageDependencies(dependencies) {
|
|
5
|
+
if (!dependencies)
|
|
6
|
+
return [];
|
|
7
|
+
return Object.entries(dependencies).map(([name, version]) => ({ name, version }));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=get-package-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-package-dependencies.js","sourceRoot":"","sources":["../../../src/lib/internal/get-package-dependencies.ts"],"names":[],"mappings":";;AAAA,wDAKC;AALD,SAAgB,sBAAsB,CACpC,YAAgD;IAEhD,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,CAAC;IAC7B,OAAO,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AACpF,CAAC"}
|