diff --git a/components/zephyr/repack/start-from-scratch.mdx b/components/zephyr/repack/start-from-scratch.mdx index a7ae024..121c725 100644 --- a/components/zephyr/repack/start-from-scratch.mdx +++ b/components/zephyr/repack/start-from-scratch.mdx @@ -536,4 +536,4 @@ You should see the applicaiton running in the iOS emulator: Zephyr Cloud Minimal example running in iOS emulator -The process should be the same for Android. \ No newline at end of file +The process should be the same for Android. diff --git a/docs/recipes/repack-mf.mdx b/docs/recipes/repack-mf.mdx index fbb5227..7bc84d6 100644 --- a/docs/recipes/repack-mf.mdx +++ b/docs/recipes/repack-mf.mdx @@ -76,7 +76,226 @@ On the downside, this approach increased coupling, which resulted in challenges There is also a third solution: using a single NavigationContainer in the host application while exposing navigators from the mini applications. This approach reduces coupling, allowing mini applications to maintain control over their navigators. However, it can lead to undesirable navigation structures, such as deeply nested stack navigators, and a complex linking setup that requires synchronization between the host and mini applications. - +## Running the application in release mode with Zephyr + +When you are using Zephyr with Re.Pack, the HostApp auto-loads MiniApps' bundles from Zephyr. To run the app in production/release mode with Zephyr, the process involves configuring your Zephyr environment - and `zephyr-repack-plugin` will auto-retrieving the latest deployed remote URLs as well as updating the HostApp’s module federation configuration during the bundling. Once completed, you can build and launch the app in release mode normally (e.g. via Xcode or react-native release build), and it will load MiniApps from the Zephyr Cloud URLs instead of localhost. + +We will soon launch `react-native-zephyr-sdk` to auto-rollback, roll-forward MiniApps during runtime. To use `react-native-zephyr-sdk`, you must use `zephyr-repack-plugin` during build time. + + +### Steps + +Follow these steps to configure and run the HostApp in release mode with Zephyr: + +Configure the Zephyr environment: + +1. Change your configs to divide debug builds and release builds: + + #### HostApp's configuration + + ```js title="HostApp/rspack.config.mjs"{9,17,72} + import path from 'node:path'; + import {fileURLToPath} from 'node:url'; + import * as Repack from '@callstack/repack'; + import {withZephyr} from 'zephyr-repack-plugin'; + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + + + const USE_ZEPHYR = Boolean(process.env.ZC); + /** + * Rspack configuration enhanced with Re.Pack defaults for React Native. + * + * Learn about Rspack configuration: https://rspack.dev/config/ + * Learn about Re.Pack configuration: https://re-pack.dev/docs/guides/configuration + */ + + const config = env => { + const { platform, mode } = env + return { + context: __dirname, + entry: './index.js', + resolve: { + // 1. Understand the file path of ios and android file extensions + // 2. Configure the output to be as close to Metro as possible + ...Repack.getResolveOptions(), + }, + output: { + // Unsure - for module federation HMR and runtime? + uniqueName: 'react-native-host-app', + }, + module: { + rules: [ + ...Repack.getJsTransformRules(), + ...Repack.getAssetTransformRules(), + ], + }, + plugins: [ + new Repack.RepackPlugin({ + platform, + }), + new Repack.plugins.ModuleFederationPluginV2({ + name: 'HostApp', + filename: 'HostApp.container.js.bundle', + dts: false, + remotes: { + MiniApp: `MiniApp@http://localhost:9001/${platform}/MiniApp.container.js.bundle`, + }, + shared: { + react: { + singleton: true, + version: '19.0.0', + eager: true, + }, + 'react-native': { + singleton: true, + version: '0.78.0', + eager: true, + } + }, + }), + // Supports for new architecture - Hermes can also use JS, it's not a requirement, it will still work the same but it's for performance optimization + new Repack.plugins.HermesBytecodePlugin({ + enabled: mode === 'production', + test: /\.(js)?bundle$/, + exclude: /index.bundle$/, + }), + ], + } + }; + + export default USE_ZEPHYR ? withZephyr()(config) : config; + ``` + + #### MiniApp's configuration + + ```js title="MiniApp/rspack.config.mjs"{9,19,68} + import path from 'node:path'; + import {fileURLToPath} from 'node:url'; + import * as Repack from '@callstack/repack'; + import {withZephyr} from 'zephyr-repack-plugin'; + + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + + const USE_ZEPHYR = Boolean(process.env.ZC); + const STANDALONE = Boolean(process.env.STANDALONE); + + /** + * Rspack configuration enhanced with Re.Pack defaults for React Native. + * + * Learn about Rspack configuration: https://rspack.dev/config/ + * Learn about Re.Pack configuration: https://re-pack.dev/docs/guides/configuration + */ + + const config = env => { + const {platform, mode} = env; + return { + mode, + context: __dirname, + entry: './index.js', + resolve: { + ...Repack.getResolveOptions(), + }, + output: { + uniqueName: 'react-native-mini-app', + }, + module: { + rules: [ + ...Repack.getJsTransformRules(), + ...Repack.getAssetTransformRules({inline: true}), + ], + }, + plugins: [ + new Repack.RepackPlugin(), + new Repack.plugins.ModuleFederationPluginV2({ + name: 'MiniApp', + filename: 'MiniApp.container.js.bundle', + dts: false, + exposes: { + './App': './App.tsx', + }, + shared: { + react: { + singleton: true, + version: '19.0.0', + eager: STANDALONE, + }, + 'react-native': { + singleton: true, + version: '0.78.0', + eager: STANDALONE, + }, + }, + }), + new Repack.plugins.HermesBytecodePlugin({ + enabled: mode === 'production', + test: /\.(js)?bundle$/, + exclude: /index.bundle$/, + }), + ], + }; + }; + + export default USE_ZEPHYR ? withZephyr()(config) : config; + + ``` + + - `ZC` is used to indicate that the bundles are for Zephyr Cloud. + + - Now, when you run or bundle with `ZC=1`, the bundles will be deployed to Zephyr Cloud. + +2. Add bundle scripts to the HostApp and MiniApp: + + - In the HostApp and MiniApp, add the following scripts to the package.json files: + + ```json title="HostApp/package.json" + "scripts": { + "bundle": "pnpm run bundle:ios && pnpm run bundle:android", + "bundle:ios": "react-native bundle --platform ios --dev false --entry-file index.js", + "bundle:android": "react-native bundle --platform android --dev false --entry-file index.js" + } + ``` + + ```json title="MiniApp/package.json" + "scripts": { + "bundle": "pnpm run bundle:ios && pnpm run bundle:android", + "bundle:ios": "react-native bundle --platform ios --dev false --entry-file index.js", + "bundle:android": "react-native bundle --platform android --dev false --entry-file index.js" + } + ``` + +2. Bundle HostApp and MiniApps, and deploy to Zephyr Cloud: + + - Bundle the MiniApp: + + ```bash + ZC=1 pnpm --filter MiniApp bundle + ``` + + - Bundle the HostApp: + + ```bash + ZC=1 pnpm --filter HostApp bundle + ``` + + - Command run with `ZC=1` will upload the bundles to Zephyr Cloud. + + +3. Build and run the HostApp in release mode: + + - For Android, you can use the following command from the HostApp android directory: + + ```bash + ZC=1 ./gradlew assembleRelease + ``` + + {/* TODO: set ZC for iOS */} + {/* - For iOS, you can use the following command: */} + + - The HostApp will now load each MiniApp's bundle from the specified Zephyr Cloud URLs instead of localhost. Verify that the app launches correctly and that each MiniApp is fetched successfully from the remote URL. + +By following these steps, you can run your HostApp in production mode with Zephyr, using the remote bundles (MiniApps) deployed on Zephyr Cloud.