├── .editorconfig ├── .github ├── actions │ ├── android-e2e │ │ └── action.yaml │ ├── ios-e2e │ │ └── action.yaml │ └── prepare-repo │ │ └── action.yaml └── workflows │ ├── code-quality.yaml │ └── e2e-trigger.yaml ├── .gitignore ├── .nvmrc ├── .ruby-version ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── E2E.md ├── LICENSE ├── README.md ├── apps ├── example-host │ ├── .bundle │ │ └── config │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc.js │ ├── .watchmanconfig │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── android │ │ ├── app │ │ │ ├── build.gradle │ │ │ ├── debug.keystore │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── mf │ │ │ │ │ └── example │ │ │ │ │ └── host │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── e2e │ │ ├── config.yaml │ │ └── flows │ │ │ └── core.yaml │ ├── index.js │ ├── ios │ │ ├── .xcode.env │ │ ├── MFExampleHost.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── MFExampleHost.xcscheme │ │ ├── MFExampleHost.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── MFExampleHost │ │ │ ├── AppDelegate.swift │ │ │ ├── Images.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── LaunchScreen.storyboard │ │ │ └── PrivacyInfo.xcprivacy │ │ ├── Podfile │ │ └── Podfile.lock │ ├── jest.config.js │ ├── metro.config.js │ ├── package.json │ ├── rnef.config.mjs │ ├── runtime-plugin.ts │ ├── src │ │ ├── App.tsx │ │ ├── Card.tsx │ │ └── Fallback.tsx │ └── tsconfig.json ├── example-mini │ ├── .bundle │ │ └── config │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc.js │ ├── .watchmanconfig │ ├── App.tsx │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── __tests__ │ │ └── App.test.tsx │ ├── android │ │ ├── app │ │ │ ├── build.gradle │ │ │ ├── debug.keystore │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── mini │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── ios │ │ ├── .xcode.env │ │ ├── Podfile │ │ ├── Podfile.lock │ │ ├── mini.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── mini.xcscheme │ │ ├── mini.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── mini │ │ │ ├── AppDelegate.swift │ │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── LaunchScreen.storyboard │ │ │ └── PrivacyInfo.xcprivacy │ ├── jest.config.js │ ├── metro.config.js │ ├── package.json │ ├── rnef.config.mjs │ ├── src │ │ └── info.tsx │ └── tsconfig.json ├── example-nested-mini │ ├── .bundle │ │ └── config │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc.js │ ├── .watchmanconfig │ ├── App.tsx │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── __tests__ │ │ └── App.test.tsx │ ├── android │ │ ├── app │ │ │ ├── build.gradle │ │ │ ├── debug.keystore │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── mini │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── ios │ │ ├── .xcode.env │ │ ├── Podfile │ │ ├── Podfile.lock │ │ ├── mini.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── mini.xcscheme │ │ ├── mini.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── mini │ │ │ ├── AppDelegate.swift │ │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── LaunchScreen.storyboard │ │ │ └── PrivacyInfo.xcprivacy │ ├── jest.config.js │ ├── metro.config.js │ ├── package.json │ ├── rnef.config.mjs │ ├── src │ │ └── nested-mini-info.tsx │ └── tsconfig.json ├── showcase-host │ ├── .bundle │ │ └── config │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc.js │ ├── .watchmanconfig │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── android │ │ ├── app │ │ │ ├── build.gradle │ │ │ ├── debug.keystore │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── host │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── MainApplication.kt │ │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── ios │ │ ├── .xcode.env │ │ ├── Podfile │ │ ├── Podfile.lock │ │ ├── host.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── host.xcscheme │ │ ├── host.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── host │ │ │ ├── AppDelegate.swift │ │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── LaunchScreen.storyboard │ │ │ └── PrivacyInfo.xcprivacy │ ├── jest.config.js │ ├── metro.config.js │ ├── package.json │ ├── rnef.config.mjs │ ├── runtime-plugin.ts │ ├── src │ │ ├── App.tsx │ │ ├── Card.tsx │ │ ├── Fallback.tsx │ │ └── aura.png │ └── tsconfig.json └── showcase-mini │ ├── .bundle │ └── config │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierrc.js │ ├── .watchmanconfig │ ├── App.tsx │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── __tests__ │ └── App.test.tsx │ ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── mini │ │ │ │ ├── MainActivity.kt │ │ │ │ └── MainApplication.kt │ │ │ └── res │ │ │ ├── drawable │ │ │ └── rn_edit_text_material.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── ios │ ├── .xcode.env │ ├── Podfile │ ├── Podfile.lock │ ├── mini.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── mini.xcscheme │ ├── mini.xcworkspace │ │ └── contents.xcworkspacedata │ └── mini │ │ ├── AppDelegate.swift │ │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── PrivacyInfo.xcprivacy │ ├── jest.config.js │ ├── metro.config.js │ ├── package.json │ ├── rnef.config.mjs │ ├── src │ ├── button.tsx │ ├── confetti-asset.json │ ├── confetti.tsx │ └── gift-asset.json │ └── tsconfig.json ├── biome.jsonc ├── nodemon.json ├── package.json ├── packages ├── core │ ├── LICENSE │ ├── README.md │ ├── babel-plugin │ │ ├── index.js │ │ ├── patch-initialize-core.js │ │ └── patch-require.js │ ├── bootstrap │ │ ├── index.d.ts │ │ └── index.js │ ├── dev │ │ ├── commands.js │ │ ├── index.js │ │ └── utils │ │ │ └── setup.js │ ├── package.json │ ├── rslib.config.ts │ ├── src │ │ ├── babel │ │ │ └── transformer.js │ │ ├── commands │ │ │ ├── bundle-host │ │ │ │ ├── index.ts │ │ │ │ ├── options.ts │ │ │ │ └── types.ts │ │ │ ├── bundle-remote │ │ │ │ ├── index.ts │ │ │ │ ├── options.ts │ │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils │ │ │ │ ├── create-module-path-remapper.ts │ │ │ │ ├── create-resolver.ts │ │ │ │ ├── get-community-plugin.ts │ │ │ │ ├── load-metro-config.ts │ │ │ │ └── save-bundle-and-map.ts │ │ ├── index.ts │ │ ├── modules │ │ │ ├── HMRClient.ts │ │ │ ├── HMRClientShim.ts │ │ │ ├── asyncRequire.ts │ │ │ ├── asyncStartup.tsx │ │ │ ├── getDevServer.ts │ │ │ └── metroCorePlugin.ts │ │ ├── plugin │ │ │ ├── babel-transformer.ts │ │ │ ├── constants.ts │ │ │ ├── generators.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── manifest.ts │ │ │ ├── normalize-extra-options.ts │ │ │ ├── normalize-options.ts │ │ │ ├── resolver.ts │ │ │ ├── rewrite-request.ts │ │ │ ├── serializer.ts │ │ │ └── validate-options.ts │ │ ├── runtime │ │ │ ├── host-entry.js │ │ │ ├── init-host.js │ │ │ ├── remote-entry.js │ │ │ ├── remote-hmr.js │ │ │ ├── remote-module-registry.js │ │ │ └── remote-module.js │ │ ├── types.ts │ │ ├── types │ │ │ ├── metro │ │ │ │ ├── baseJSBundle.d.ts │ │ │ │ ├── bundleToString.d.ts │ │ │ │ ├── getAppendScripts.d.ts │ │ │ │ ├── processModules.d.ts │ │ │ │ └── relativizeSourceMap.d.ts │ │ │ ├── react-native.d.ts │ │ │ └── runtime.d.ts │ │ └── utils │ │ │ ├── errors.ts │ │ │ ├── index.ts │ │ │ └── vm-manager.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── plugin-rnc-cli │ ├── LICENSE │ ├── README.md │ ├── index.js │ ├── package.json │ └── react-native.config.js └── plugin-rnef │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── rslib.config.ts │ ├── src │ ├── index.ts │ └── plugin.ts │ ├── tsconfig.build.json │ └── tsconfig.json ├── patches └── lottie-react-native.patch ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── tsconfig.base.json └── turbo.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /.github/actions/prepare-repo/action.yaml: -------------------------------------------------------------------------------- 1 | name: Prepare repository 2 | 3 | runs: 4 | using: "composite" 5 | steps: 6 | - uses: pnpm/action-setup@v3 7 | 8 | - name: Setup Node 9 | uses: actions/setup-node@v4 10 | with: 11 | node-version: 22 12 | cache: 'pnpm' 13 | 14 | - name: Install dependencies 15 | run: pnpm install --frozen-lockfile 16 | shell: bash 17 | -------------------------------------------------------------------------------- /.github/workflows/code-quality.yaml: -------------------------------------------------------------------------------- 1 | name: Code Quality Checks 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | with: 15 | submodules: true 16 | clean: true 17 | 18 | - name: Prepare repository 19 | uses: ./.github/actions/prepare-repo 20 | 21 | - name: Lint 22 | run: pnpm lint:ci 23 | 24 | typecheck: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | with: 29 | submodules: true 30 | clean: true 31 | 32 | - name: Prepare repository 33 | uses: ./.github/actions/prepare-repo 34 | 35 | - name: Typecheck 36 | run: pnpm typecheck 37 | -------------------------------------------------------------------------------- /.github/workflows/e2e-trigger.yaml: -------------------------------------------------------------------------------- 1 | name: Trigger E2E Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | permissions: 11 | actions: read 12 | contents: read 13 | checks: write 14 | pull-requests: write 15 | id-token: write 16 | 17 | concurrency: 18 | group: e2e-tests-${{ github.workflow }}-${{ github.ref }} 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | e2e-matrix-android: 23 | runs-on: ubuntu-latest 24 | timeout-minutes: 60 25 | strategy: 26 | matrix: 27 | app_name: [example-host] 28 | env: 29 | ANDROID_EMULATOR_API_LEVEL: 28 30 | ANDROID_EMULATOR_TARGET: default 31 | ANDROID_EMULATOR_ARCH: x86_64 32 | ANDROID_EMULATOR_DISK_SPACE: 1024M 33 | ANDROID_EMULATOR_RAM_SIZE: 256M 34 | ANDROID_EMULATOR_HEAP_SIZE: 256M 35 | ANDROID_EMULATOR_BOOT_TIMEOUT: 2700 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v4 39 | 40 | - name: Android E2E Tests 41 | uses: ./.github/actions/android-e2e 42 | with: 43 | app_name: ${{ matrix.app_name }} 44 | github_token: ${{ secrets.GITHUB_TOKEN }} 45 | e2e-matrix-ios: 46 | runs-on: macos-latest 47 | timeout-minutes: 60 48 | strategy: 49 | matrix: 50 | app_name: [example-host] 51 | env: 52 | RUBY_VERSION: 2.7.6 53 | MAESTRO_VERSION: 1.39.13 54 | MAESTRO_DRIVER_STARTUP_TIMEOUT: 360000 55 | steps: 56 | - name: Checkout repository 57 | uses: actions/checkout@v4 58 | 59 | - name: iOS E2E Tests 60 | uses: ./.github/actions/ios-e2e 61 | with: 62 | app_name: ${{ matrix.app_name }} 63 | github_token: ${{ secrets.GITHUB_TOKEN }} 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .yarn/* 2 | !.yarn/patches 3 | !.yarn/plugins 4 | !.yarn/releases 5 | !.yarn/sdks 6 | !.yarn/versions 7 | 8 | # Whether you use PnP or not, the node_modules folder is often used to store 9 | # build artifacts that should be gitignored 10 | node_modules 11 | 12 | # Swap the comments on the following lines if you wish to use zero-installs 13 | # In that case, don't forget to run `yarn config set enableGlobalCache false`! 14 | # Documentation here: https://yarnpkg.com/features/caching#zero-installs 15 | 16 | #!.yarn/cache 17 | .pnp.* 18 | 19 | # turbo 20 | .turbo 21 | 22 | # dist 23 | apps/*/dist 24 | packages/*/dist 25 | 26 | # RNEF 27 | apps/*/.rnef 28 | 29 | # TypeScript build cache 30 | *.tsbuildinfo 31 | 32 | /apps/.DS_Store -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.1.0 -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["biomejs.biome"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "css.validate": false, 3 | "editor.defaultFormatter": "biomejs.biome", 4 | "editor.formatOnSave": true, 5 | "files.associations": { 6 | "package.json": "json", 7 | "*.json": "jsonc" 8 | }, 9 | "javascript.preferences.importModuleSpecifierEnding": "js", 10 | "typescript.preferences.importModuleSpecifierEnding": "js", 11 | "editor.codeActionsOnSave": { 12 | "source.organizeImports.biome": "explicit" 13 | }, 14 | "npm.packageManager": "pnpm", 15 | "[css]": { 16 | "editor.formatOnSave": true, 17 | "editor.defaultFormatter": "biomejs.biome" 18 | }, 19 | "[javascript]": { 20 | "editor.formatOnSave": true, 21 | "editor.defaultFormatter": "biomejs.biome" 22 | }, 23 | "[javascriptreact]": { 24 | "editor.formatOnSave": true, 25 | "editor.defaultFormatter": "biomejs.biome" 26 | }, 27 | "[json]": { 28 | "editor.formatOnSave": true, 29 | "editor.defaultFormatter": "biomejs.biome" 30 | }, 31 | "[jsonc]": { 32 | "editor.formatOnSave": true, 33 | "editor.defaultFormatter": "biomejs.biome" 34 | }, 35 | "[html]": { 36 | "editor.formatOnSave": true, 37 | "editor.defaultFormatter": "biomejs.biome" 38 | }, 39 | "[typescript]": { 40 | "editor.formatOnSave": true, 41 | "editor.defaultFormatter": "biomejs.biome" 42 | }, 43 | "[typescriptreact]": { 44 | "editor.formatOnSave": true, 45 | "editor.defaultFormatter": "biomejs.biome" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /E2E.md: -------------------------------------------------------------------------------- 1 | # End-to-End (E2E) Testing Guide 2 | 3 | This project uses [**Maestro**](https://maestro.mobile.dev/) for automated end-to-end testing across multiple example applications located in the `apps/` directory. 4 | 5 | ## 📦 Overview 6 | 7 | - Each app in the `apps/` directory serves as both: 8 | - An example use-case for the monorepo. 9 | - A target for E2E tests using Maestro. 10 | - E2E tests are integrated into the CI pipeline for **both Android and iOS**. 11 | 12 | ## 🚀 Getting Started 13 | 14 | ### 1. Prerequisites 15 | 16 | - [Maestro CLI](https://maestro.mobile.dev/docs/getting-started/installation) 17 | 18 | ### 2. Start Required Mini Apps 19 | 20 | Before running E2E tests, ensure the Metro bundler for the host app is running as well as all the dependent mini apps. 21 | 22 | ```bash 23 | pnpm --filter 24 | pnpm --filter start 25 | pnpm --filter start 26 | ``` 27 | 28 | or alternatively you can run: 29 | 30 | ```bash 31 | pnpm --filter 32 | pnpm --filter start 33 | pnpm --filter e2e:prepare: 34 | ``` 35 | 36 | ## 🧪 Running E2E Tests 37 | 38 | You can run E2E test by executing the following command: 39 | 40 | ```bash 41 | pnpm --filter e2e:run 42 | ``` 43 | 44 | ## 🛠 CI Integration 45 | 46 | - All E2E tests are run **automatically in CI**. 47 | - The CI handles environment setup, builds, and Maestro execution for: 48 | - `iOS` 49 | - `Android` 50 | 51 | You can review CI logs and Maestro test output for each platform as part of the build pipeline. 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Callstack and Zephyr Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apps/example-host/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /apps/example-host/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /apps/example-host/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | 77 | # build artifacts 78 | dist/ 79 | 80 | # RNEF 81 | .rnef 82 | -------------------------------------------------------------------------------- /apps/example-host/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /apps/example-host/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /apps/example-host/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /apps/example-host/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/debug.keystore -------------------------------------------------------------------------------- /apps/example-host/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /apps/example-host/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/java/com/mf/example/host/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mf.example.host 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "MFExampleHost" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/java/com/mf/example/host/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.mf.example.host 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | 13 | class MainApplication : Application(), ReactApplication { 14 | 15 | override val reactNativeHost: ReactNativeHost = 16 | object : DefaultReactNativeHost(this) { 17 | override fun getPackages(): List = 18 | PackageList(this).packages.apply { 19 | // Packages that cannot be autolinked yet can be added manually here, for example: 20 | // add(MyReactNativePackage()) 21 | } 22 | 23 | override fun getJSMainModuleName(): String = "index" 24 | 25 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 26 | 27 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 28 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 29 | } 30 | 31 | override val reactHost: ReactHost 32 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | loadReactNative(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MFExampleHost 3 | 4 | -------------------------------------------------------------------------------- /apps/example-host/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-host/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.1.20" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /apps/example-host/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /apps/example-host/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-host/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/example-host/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/example-host/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../../../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand(['npx', 'rnef', 'config', '-p', 'android']) } 4 | rootProject.name = "MFExampleHost" 5 | include ':app' 6 | includeBuild('../../../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /apps/example-host/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MFExampleHost", 3 | "displayName": "MF Example Host" 4 | } 5 | -------------------------------------------------------------------------------- /apps/example-host/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/example-host/e2e/config.yaml: -------------------------------------------------------------------------------- 1 | flows: 2 | - 'flows/*' 3 | -------------------------------------------------------------------------------- /apps/example-host/e2e/flows/core.yaml: -------------------------------------------------------------------------------- 1 | appId: com.mf.example.host 2 | --- 3 | - launchApp: 4 | clearState: true 5 | - waitForAnimationToEnd 6 | 7 | # Check Host Info 8 | - assertVisible: 9 | id: "host-app-info" 10 | - copyTextFrom: 11 | id: "host-lodash" 12 | - assertTrue: 13 | condition: ${maestro.copiedText === "4.16.6"} 14 | 15 | # Check Mini App Info 16 | - assertNotVisible: 17 | id: "mini-info" 18 | - tapOn: 19 | id: "load-mini-button" 20 | - assertVisible: 21 | id: "mini-info" 22 | - copyTextFrom: 23 | id: "mini-lodash" 24 | - assertTrue: 25 | condition: ${maestro.copiedText === "4.17.21"} 26 | 27 | # Check Nested Mini App Info 28 | - assertVisible: 29 | id: "nested-mini-info" 30 | - copyTextFrom: 31 | id: "nested-mini-lodash" 32 | - assertTrue: 33 | condition: ${maestro.copiedText === "4.16.6"} 34 | -------------------------------------------------------------------------------- /apps/example-host/index.js: -------------------------------------------------------------------------------- 1 | import { withAsyncStartup } from '@module-federation/metro/bootstrap'; 2 | import { AppRegistry } from 'react-native'; 3 | import { name as appName } from './app.json'; 4 | 5 | // create async boundry through withAsyncStartup helper 6 | // and pass the getter function for the app component 7 | // optionally a getter function for the fallback component 8 | AppRegistry.registerComponent( 9 | appName, 10 | withAsyncStartup( 11 | () => require('./src/App'), 12 | () => require('./src/Fallback') 13 | ) 14 | ); 15 | -------------------------------------------------------------------------------- /apps/example-host/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /apps/example-host/ios/MFExampleHost.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/example-host/ios/MFExampleHost/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "MFExampleHost", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/example-host/ios/MFExampleHost/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "iphone", 5 | "scale": "2x", 6 | "size": "20x20" 7 | }, 8 | { 9 | "idiom": "iphone", 10 | "scale": "3x", 11 | "size": "20x20" 12 | }, 13 | { 14 | "idiom": "iphone", 15 | "scale": "2x", 16 | "size": "29x29" 17 | }, 18 | { 19 | "idiom": "iphone", 20 | "scale": "3x", 21 | "size": "29x29" 22 | }, 23 | { 24 | "idiom": "iphone", 25 | "scale": "2x", 26 | "size": "40x40" 27 | }, 28 | { 29 | "idiom": "iphone", 30 | "scale": "3x", 31 | "size": "40x40" 32 | }, 33 | { 34 | "idiom": "iphone", 35 | "scale": "2x", 36 | "size": "60x60" 37 | }, 38 | { 39 | "idiom": "iphone", 40 | "scale": "3x", 41 | "size": "60x60" 42 | }, 43 | { 44 | "idiom": "ios-marketing", 45 | "scale": "1x", 46 | "size": "1024x1024" 47 | } 48 | ], 49 | "info": { 50 | "author": "xcode", 51 | "version": 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/example-host/ios/MFExampleHost/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/example-host/ios/MFExampleHost/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | MFExampleHost 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSLocationWhenInUseUsageDescription 35 | 36 | RCTNewArchEnabled 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | arm64 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /apps/example-host/ios/MFExampleHost/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /apps/example-host/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'MFExampleHost' do 18 | config = use_native_modules!(['npx', 'rnef', 'config', '-p', 'ios']) 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /apps/example-host/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /apps/example-host/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 3 | 4 | const { withModuleFederation } = require('@module-federation/metro'); 5 | 6 | /** 7 | * Metro configuration 8 | * https://reactnative.dev/docs/metro 9 | * 10 | * @type {import('@react-native/metro-config').MetroConfig} 11 | */ 12 | 13 | const config = { 14 | resolver: { useWatchman: false }, 15 | watchFolders: [ 16 | path.resolve(__dirname, '../../node_modules'), 17 | path.resolve(__dirname, '../../packages/core'), 18 | ], 19 | }; 20 | 21 | module.exports = withModuleFederation( 22 | mergeConfig(getDefaultConfig(__dirname), config), 23 | { 24 | name: 'MFExampleHost', 25 | remotes: { 26 | mini: 'mini@http://localhost:8082/mf-manifest.json', 27 | nestedMini: 'nestedMini@http://localhost:8083/mf-manifest.json', 28 | }, 29 | shared: { 30 | react: { 31 | singleton: true, 32 | eager: true, 33 | requiredVersion: '19.1.0', 34 | version: '19.1.0', 35 | }, 36 | 'react-native': { 37 | singleton: true, 38 | eager: true, 39 | requiredVersion: '0.80.0', 40 | version: '0.80.0', 41 | }, 42 | lodash: { 43 | singleton: false, 44 | eager: false, 45 | requiredVersion: '4.16.6', 46 | version: '4.16.6', 47 | }, 48 | }, 49 | shareStrategy: 'loaded-first', 50 | plugins: [path.resolve(__dirname, './runtime-plugin.ts')], 51 | }, 52 | { 53 | flags: { 54 | unstable_patchHMRClient: true, 55 | unstable_patchInitializeCore: true, 56 | unstable_patchRuntimeRequire: true, 57 | }, 58 | } 59 | ); 60 | -------------------------------------------------------------------------------- /apps/example-host/rnef.config.mjs: -------------------------------------------------------------------------------- 1 | import { pluginMetroModuleFederation } from '@module-federation/metro-plugin-rnef'; 2 | import { platformAndroid } from '@rnef/platform-android'; 3 | // @ts-check 4 | import { platformIOS } from '@rnef/platform-ios'; 5 | import { pluginMetro } from '@rnef/plugin-metro'; 6 | 7 | /** @type {import('@rnef/config').Config} */ 8 | export default { 9 | bundler: pluginMetro(), 10 | platforms: { 11 | ios: platformIOS(), 12 | android: platformAndroid(), 13 | }, 14 | remoteCacheProvider: 'github-actions', 15 | plugins: [pluginMetroModuleFederation()], 16 | }; 17 | -------------------------------------------------------------------------------- /apps/example-host/runtime-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { FederationRuntimePlugin } from '@module-federation/runtime'; 2 | 3 | export default function (): FederationRuntimePlugin { 4 | return { 5 | name: 'custom-plugin-build', 6 | beforeLoadShare(args) { 7 | console.log('[build time inject] beforeLoadShare', args.pkgName); 8 | return args; 9 | }, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /apps/example-host/src/Fallback.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ActivityIndicator, LayoutAnimation, Text, View } from 'react-native'; 3 | 4 | export default function Fallback() { 5 | React.useEffect(() => { 6 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut, () => 7 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) 8 | ); 9 | }); 10 | 11 | return ( 12 | 20 | 21 | 22 | Async Startup in progress... 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/example-host/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config" 3 | } 4 | -------------------------------------------------------------------------------- /apps/example-mini/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /apps/example-mini/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /apps/example-mini/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | 77 | # build artifacts 78 | dist/ 79 | 80 | # RNEF 81 | .rnef -------------------------------------------------------------------------------- /apps/example-mini/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /apps/example-mini/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /apps/example-mini/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /apps/example-mini/__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | import ReactTestRenderer from 'react-test-renderer'; 2 | import App from '../App'; 3 | 4 | test('renders correctly', async () => { 5 | await ReactTestRenderer.act(() => { 6 | ReactTestRenderer.create(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/debug.keystore -------------------------------------------------------------------------------- /apps/example-mini/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/java/com/mini/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mini 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "mini" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/java/com/mini/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.mini 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | 13 | class MainApplication : Application(), ReactApplication { 14 | 15 | override val reactNativeHost: ReactNativeHost = 16 | object : DefaultReactNativeHost(this) { 17 | override fun getPackages(): List = 18 | PackageList(this).packages.apply { 19 | // Packages that cannot be autolinked yet can be added manually here, for example: 20 | // add(MyReactNativePackage()) 21 | } 22 | 23 | override fun getJSMainModuleName(): String = "index" 24 | 25 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 26 | 27 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 28 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 29 | } 30 | 31 | override val reactHost: ReactHost 32 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | loadReactNative(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | mini 3 | 4 | -------------------------------------------------------------------------------- /apps/example-mini/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-mini/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.1.20" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /apps/example-mini/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /apps/example-mini/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-mini/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/example-mini/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/example-mini/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand(['npx', 'rnef', 'config', '-p', 'android']) } 4 | rootProject.name = 'mini' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /apps/example-mini/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini", 3 | "displayName": "mini" 4 | } 5 | -------------------------------------------------------------------------------- /apps/example-mini/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/example-mini/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import { AppRegistry } from 'react-native'; 6 | import App from './App'; 7 | import { name as appName } from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /apps/example-mini/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /apps/example-mini/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'mini' do 18 | config = use_native_modules!(['npx', 'rnef', 'config', '-p', 'ios']) 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /apps/example-mini/ios/mini.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/example-mini/ios/mini/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "mini", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/example-mini/ios/mini/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "iphone", 5 | "scale": "2x", 6 | "size": "20x20" 7 | }, 8 | { 9 | "idiom": "iphone", 10 | "scale": "3x", 11 | "size": "20x20" 12 | }, 13 | { 14 | "idiom": "iphone", 15 | "scale": "2x", 16 | "size": "29x29" 17 | }, 18 | { 19 | "idiom": "iphone", 20 | "scale": "3x", 21 | "size": "29x29" 22 | }, 23 | { 24 | "idiom": "iphone", 25 | "scale": "2x", 26 | "size": "40x40" 27 | }, 28 | { 29 | "idiom": "iphone", 30 | "scale": "3x", 31 | "size": "40x40" 32 | }, 33 | { 34 | "idiom": "iphone", 35 | "scale": "2x", 36 | "size": "60x60" 37 | }, 38 | { 39 | "idiom": "iphone", 40 | "scale": "3x", 41 | "size": "60x60" 42 | }, 43 | { 44 | "idiom": "ios-marketing", 45 | "scale": "1x", 46 | "size": "1024x1024" 47 | } 48 | ], 49 | "info": { 50 | "author": "xcode", 51 | "version": 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/example-mini/ios/mini/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/example-mini/ios/mini/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | mini 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSLocationWhenInUseUsageDescription 35 | 36 | RCTNewArchEnabled 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | arm64 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /apps/example-mini/ios/mini/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /apps/example-mini/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /apps/example-mini/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 3 | 4 | const { withModuleFederation } = require('@module-federation/metro'); 5 | 6 | /** 7 | * Metro configuration 8 | * https://reactnative.dev/docs/metro 9 | * 10 | * @type {import('@react-native/metro-config').MetroConfig} 11 | */ 12 | const config = { 13 | resolver: { useWatchman: false }, 14 | watchFolders: [ 15 | path.resolve(__dirname, '../../node_modules'), 16 | path.resolve(__dirname, '../../packages/core'), 17 | ], 18 | }; 19 | 20 | module.exports = withModuleFederation( 21 | mergeConfig(getDefaultConfig(__dirname), config), 22 | { 23 | name: 'MFExampleMini', 24 | filename: 'mini.bundle', 25 | exposes: { 26 | './info': './src/info.tsx', 27 | }, 28 | shared: { 29 | react: { 30 | singleton: true, 31 | eager: false, 32 | requiredVersion: '19.1.0', 33 | version: '19.1.0', 34 | import: false, 35 | }, 36 | 'react-native': { 37 | singleton: true, 38 | eager: false, 39 | requiredVersion: '0.80.0', 40 | version: '0.80.0', 41 | import: false, 42 | }, 43 | lodash: { 44 | singleton: false, 45 | eager: false, 46 | version: '4.17.21', 47 | }, 48 | }, 49 | shareStrategy: 'version-first', 50 | }, 51 | { 52 | flags: { 53 | unstable_patchHMRClient: true, 54 | unstable_patchInitializeCore: true, 55 | unstable_patchRuntimeRequire: true, 56 | }, 57 | } 58 | ); 59 | -------------------------------------------------------------------------------- /apps/example-mini/rnef.config.mjs: -------------------------------------------------------------------------------- 1 | import { pluginMetroModuleFederation } from '@module-federation/metro-plugin-rnef'; 2 | import { platformAndroid } from '@rnef/platform-android'; 3 | // @ts-check 4 | import { platformIOS } from '@rnef/platform-ios'; 5 | import { pluginMetro } from '@rnef/plugin-metro'; 6 | 7 | /** @type {import('@rnef/config').Config} */ 8 | export default { 9 | bundler: pluginMetro(), 10 | platforms: { 11 | ios: platformIOS(), 12 | android: platformAndroid(), 13 | }, 14 | remoteCacheProvider: 'github-actions', 15 | plugins: [pluginMetroModuleFederation()], 16 | }; 17 | -------------------------------------------------------------------------------- /apps/example-mini/src/info.tsx: -------------------------------------------------------------------------------- 1 | import { VERSION } from 'lodash'; 2 | import { Platform, StyleSheet, Text, View } from 'react-native'; 3 | 4 | type Props = { 5 | testID?: string; 6 | sections?: Array<{ name: string; value: string; testID: string }>; 7 | }; 8 | 9 | const SECTIONS = [ 10 | { 11 | name: 'lodash version', 12 | value: VERSION, 13 | testID: 'mini-lodash', 14 | }, 15 | ]; 16 | 17 | export default function Info({ 18 | testID = 'mini-info', 19 | sections = SECTIONS, 20 | }: Props) { 21 | return ( 22 | 23 | {sections.map((section) => ( 24 | 25 | 26 | {section.name} 27 | 28 | 29 | {section.value} 30 | 31 | 32 | ))} 33 | 34 | ); 35 | } 36 | 37 | const styles = StyleSheet.create({ 38 | container: {}, 39 | monospace: { 40 | fontFamily: Platform.select({ 41 | ios: 'Menlo', 42 | default: 'monospace', 43 | }), 44 | }, 45 | sectionContainer: { 46 | flexDirection: 'row', 47 | }, 48 | sectionTitle: { 49 | marginRight: 8, 50 | }, 51 | }); 52 | -------------------------------------------------------------------------------- /apps/example-mini/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config" 3 | } 4 | -------------------------------------------------------------------------------- /apps/example-nested-mini/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /apps/example-nested-mini/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /apps/example-nested-mini/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | 77 | # build artifacts 78 | dist/ 79 | 80 | # RNEF 81 | .rnef 82 | -------------------------------------------------------------------------------- /apps/example-nested-mini/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /apps/example-nested-mini/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /apps/example-nested-mini/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /apps/example-nested-mini/__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | import ReactTestRenderer from 'react-test-renderer'; 2 | import App from '../App'; 3 | 4 | test('renders correctly', async () => { 5 | await ReactTestRenderer.act(() => { 6 | ReactTestRenderer.create(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/debug.keystore -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/java/com/mini/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mini 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "mini" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/java/com/mini/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.mini 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | 13 | class MainApplication : Application(), ReactApplication { 14 | 15 | override val reactNativeHost: ReactNativeHost = 16 | object : DefaultReactNativeHost(this) { 17 | override fun getPackages(): List = 18 | PackageList(this).packages.apply { 19 | // Packages that cannot be autolinked yet can be added manually here, for example: 20 | // add(MyReactNativePackage()) 21 | } 22 | 23 | override fun getJSMainModuleName(): String = "index" 24 | 25 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 26 | 27 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 28 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 29 | } 30 | 31 | override val reactHost: ReactHost 32 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | loadReactNative(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | mini 3 | 4 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.1.20" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/example-nested-mini/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/example-nested-mini/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/example-nested-mini/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand(['npx', 'rnef', 'config', '-p', 'android']) } 4 | rootProject.name = 'mini' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /apps/example-nested-mini/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini", 3 | "displayName": "mini" 4 | } 5 | -------------------------------------------------------------------------------- /apps/example-nested-mini/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/example-nested-mini/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import { AppRegistry } from 'react-native'; 6 | import App from './App'; 7 | import { name as appName } from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'mini' do 18 | config = use_native_modules!(['npx', 'rnef', 'config', '-p', 'ios']) 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/mini.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/mini/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "mini", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/mini/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "iphone", 5 | "scale": "2x", 6 | "size": "20x20" 7 | }, 8 | { 9 | "idiom": "iphone", 10 | "scale": "3x", 11 | "size": "20x20" 12 | }, 13 | { 14 | "idiom": "iphone", 15 | "scale": "2x", 16 | "size": "29x29" 17 | }, 18 | { 19 | "idiom": "iphone", 20 | "scale": "3x", 21 | "size": "29x29" 22 | }, 23 | { 24 | "idiom": "iphone", 25 | "scale": "2x", 26 | "size": "40x40" 27 | }, 28 | { 29 | "idiom": "iphone", 30 | "scale": "3x", 31 | "size": "40x40" 32 | }, 33 | { 34 | "idiom": "iphone", 35 | "scale": "2x", 36 | "size": "60x60" 37 | }, 38 | { 39 | "idiom": "iphone", 40 | "scale": "3x", 41 | "size": "60x60" 42 | }, 43 | { 44 | "idiom": "ios-marketing", 45 | "scale": "1x", 46 | "size": "1024x1024" 47 | } 48 | ], 49 | "info": { 50 | "author": "xcode", 51 | "version": 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/mini/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/mini/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | mini 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSLocationWhenInUseUsageDescription 35 | 36 | RCTNewArchEnabled 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | arm64 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /apps/example-nested-mini/ios/mini/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /apps/example-nested-mini/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /apps/example-nested-mini/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 3 | 4 | const { withModuleFederation } = require('@module-federation/metro'); 5 | 6 | /** 7 | * Metro configuration 8 | * https://reactnative.dev/docs/metro 9 | * 10 | * @type {import('@react-native/metro-config').MetroConfig} 11 | */ 12 | const config = { 13 | resolver: { useWatchman: false }, 14 | watchFolders: [ 15 | path.resolve(__dirname, '../../node_modules'), 16 | path.resolve(__dirname, '../../packages/core'), 17 | ], 18 | }; 19 | 20 | module.exports = withModuleFederation( 21 | mergeConfig(getDefaultConfig(__dirname), config), 22 | { 23 | name: 'MFExampleNestedMini', 24 | filename: 'nestedMini.bundle', 25 | exposes: { 26 | './nestedMiniInfo': './src/nested-mini-info.tsx', 27 | }, 28 | remotes: { 29 | mini: 'mini@http://localhost:8082/mf-manifest.json', 30 | }, 31 | shared: { 32 | react: { 33 | singleton: true, 34 | eager: false, 35 | requiredVersion: '19.1.0', 36 | version: '19.1.0', 37 | import: false, 38 | }, 39 | 'react-native': { 40 | singleton: true, 41 | eager: false, 42 | requiredVersion: '0.80.0', 43 | version: '0.80.0', 44 | import: false, 45 | }, 46 | lodash: { 47 | singleton: false, 48 | eager: false, 49 | requiredVersion: '4.16.6', 50 | version: '4.16.6', 51 | }, 52 | }, 53 | shareStrategy: 'version-first', 54 | }, 55 | { 56 | flags: { 57 | unstable_patchHMRClient: true, 58 | unstable_patchInitializeCore: true, 59 | unstable_patchRuntimeRequire: true, 60 | }, 61 | } 62 | ); 63 | -------------------------------------------------------------------------------- /apps/example-nested-mini/rnef.config.mjs: -------------------------------------------------------------------------------- 1 | import { pluginMetroModuleFederation } from '@module-federation/metro-plugin-rnef'; 2 | import { platformAndroid } from '@rnef/platform-android'; 3 | // @ts-check 4 | import { platformIOS } from '@rnef/platform-ios'; 5 | import { pluginMetro } from '@rnef/plugin-metro'; 6 | 7 | /** @type {import('@rnef/config').Config} */ 8 | export default { 9 | bundler: pluginMetro(), 10 | platforms: { 11 | ios: platformIOS(), 12 | android: platformAndroid(), 13 | }, 14 | remoteCacheProvider: 'github-actions', 15 | plugins: [pluginMetroModuleFederation()], 16 | }; 17 | -------------------------------------------------------------------------------- /apps/example-nested-mini/src/nested-mini-info.tsx: -------------------------------------------------------------------------------- 1 | import { VERSION } from 'lodash'; 2 | // @ts-ignore 3 | import Info from 'mini/info'; 4 | import React from 'react'; 5 | import { View } from 'react-native'; 6 | 7 | export default function NestedMiniInfo() { 8 | return ( 9 | 10 | 11 | 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /apps/example-nested-mini/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config" 3 | } 4 | -------------------------------------------------------------------------------- /apps/showcase-host/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /apps/showcase-host/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /apps/showcase-host/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | 77 | # RNEF 78 | .rnef/ 79 | -------------------------------------------------------------------------------- /apps/showcase-host/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /apps/showcase-host/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /apps/showcase-host/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/debug.keystore -------------------------------------------------------------------------------- /apps/showcase-host/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/java/com/host/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.host 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "host" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/java/com/host/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.host 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | 13 | class MainApplication : Application(), ReactApplication { 14 | 15 | override val reactNativeHost: ReactNativeHost = 16 | object : DefaultReactNativeHost(this) { 17 | override fun getPackages(): List = 18 | PackageList(this).packages.apply { 19 | // Packages that cannot be autolinked yet can be added manually here, for example: 20 | // add(MyReactNativePackage()) 21 | } 22 | 23 | override fun getJSMainModuleName(): String = "index" 24 | 25 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 26 | 27 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 28 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 29 | } 30 | 31 | override val reactHost: ReactHost 32 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | loadReactNative(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | host 3 | 4 | -------------------------------------------------------------------------------- /apps/showcase-host/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/showcase-host/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.1.20" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /apps/showcase-host/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /apps/showcase-host/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/showcase-host/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/showcase-host/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../../../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand(['npx', 'rnef', 'config', '-p', 'android']) } 4 | rootProject.name = 'host' 5 | include ':app' 6 | includeBuild('../../../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /apps/showcase-host/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "host", 3 | "displayName": "host" 4 | } 5 | -------------------------------------------------------------------------------- /apps/showcase-host/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/showcase-host/index.js: -------------------------------------------------------------------------------- 1 | import { withAsyncStartup } from '@module-federation/metro/bootstrap'; 2 | import { AppRegistry } from 'react-native'; 3 | import { name as appName } from './app.json'; 4 | 5 | // create async boundry through withAsyncStartup helper 6 | // and pass the getter function for the app component 7 | // optionally a getter function for the fallback component 8 | AppRegistry.registerComponent( 9 | appName, 10 | withAsyncStartup( 11 | () => require('./src/App'), 12 | () => require('./src/Fallback') 13 | ) 14 | ); 15 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'host' do 18 | config = use_native_modules!(['npx', 'rnef', 'config', '-p', 'ios']) 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/host.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/host/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "host", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/host/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "iphone", 5 | "scale": "2x", 6 | "size": "20x20" 7 | }, 8 | { 9 | "idiom": "iphone", 10 | "scale": "3x", 11 | "size": "20x20" 12 | }, 13 | { 14 | "idiom": "iphone", 15 | "scale": "2x", 16 | "size": "29x29" 17 | }, 18 | { 19 | "idiom": "iphone", 20 | "scale": "3x", 21 | "size": "29x29" 22 | }, 23 | { 24 | "idiom": "iphone", 25 | "scale": "2x", 26 | "size": "40x40" 27 | }, 28 | { 29 | "idiom": "iphone", 30 | "scale": "3x", 31 | "size": "40x40" 32 | }, 33 | { 34 | "idiom": "iphone", 35 | "scale": "2x", 36 | "size": "60x60" 37 | }, 38 | { 39 | "idiom": "iphone", 40 | "scale": "3x", 41 | "size": "60x60" 42 | }, 43 | { 44 | "idiom": "ios-marketing", 45 | "scale": "1x", 46 | "size": "1024x1024" 47 | } 48 | ], 49 | "info": { 50 | "author": "xcode", 51 | "version": 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/host/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/host/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | host 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSLocationWhenInUseUsageDescription 35 | 36 | RCTNewArchEnabled 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | arm64 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /apps/showcase-host/ios/host/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /apps/showcase-host/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /apps/showcase-host/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 3 | 4 | const { withModuleFederation } = require('@module-federation/metro'); 5 | 6 | /** 7 | * Metro configuration 8 | * https://reactnative.dev/docs/metro 9 | * 10 | * @type {import('@react-native/metro-config').MetroConfig} 11 | */ 12 | 13 | const config = { 14 | resolver: { useWatchman: false }, 15 | watchFolders: [ 16 | path.resolve(__dirname, '../../node_modules'), 17 | path.resolve(__dirname, '../../packages/core'), 18 | ], 19 | }; 20 | 21 | module.exports = withModuleFederation( 22 | mergeConfig(getDefaultConfig(__dirname), config), 23 | { 24 | name: 'host', 25 | remotes: { 26 | mini: 'mini@http://localhost:8082/mf-manifest.json', 27 | }, 28 | shared: { 29 | react: { 30 | singleton: true, 31 | eager: true, 32 | requiredVersion: '19.1.0', 33 | version: '19.1.0', 34 | }, 35 | 'react-native': { 36 | singleton: true, 37 | eager: true, 38 | requiredVersion: '0.80.0', 39 | version: '0.80.0', 40 | }, 41 | lodash: { 42 | singleton: false, 43 | eager: false, 44 | requiredVersion: '4.16.6', 45 | version: '4.16.6', 46 | }, 47 | 'lottie-react-native': { 48 | singleton: true, 49 | eager: true, 50 | requiredVersion: '7.2.2', 51 | version: '7.2.2', 52 | }, 53 | }, 54 | shareStrategy: 'loaded-first', 55 | plugins: [path.resolve(__dirname, './runtime-plugin.ts')], 56 | }, 57 | { 58 | flags: { 59 | unstable_patchHMRClient: true, 60 | unstable_patchInitializeCore: true, 61 | unstable_patchRuntimeRequire: true, 62 | }, 63 | } 64 | ); 65 | -------------------------------------------------------------------------------- /apps/showcase-host/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "showcase-host", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "rnef run:android", 7 | "ios": "rnef run:ios", 8 | "lint": "eslint .", 9 | "dev": "nodemon --config ../../nodemon.json --exec NODE_OPTIONS='--conditions=dev' pnpm start", 10 | "start": "rnef start --reset-cache --client-logs", 11 | "pods": "(cd ios && bundle install && (bundle exec pod install || bundle exec pod update))", 12 | "test": "jest" 13 | }, 14 | "dependencies": { 15 | "lodash": "4.16.6", 16 | "lottie-react-native": "^7.2.2", 17 | "react": "19.1.0", 18 | "react-native": "0.80.0" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.25.2", 22 | "@babel/preset-env": "^7.25.3", 23 | "@babel/runtime": "^7.25.0", 24 | "@module-federation/metro": "workspace:*", 25 | "@module-federation/metro-plugin-rnef": "workspace:*", 26 | "@module-federation/runtime": "^0.15.0", 27 | "@react-native/babel-preset": "0.80.0", 28 | "@react-native/eslint-config": "0.80.0", 29 | "@react-native/metro-config": "0.80.0", 30 | "@react-native/typescript-config": "0.80.0", 31 | "@rnef/cli": "^0.7.25", 32 | "@rnef/platform-android": "^0.7.25", 33 | "@rnef/platform-ios": "^0.7.25", 34 | "@rnef/plugin-metro": "^0.7.25", 35 | "@types/jest": "^29.5.13", 36 | "@types/lodash": "^4", 37 | "@types/react": "^19.1.0", 38 | "@types/react-test-renderer": "^19.1.0", 39 | "eslint": "^8.19.0", 40 | "jest": "^29.6.3", 41 | "nodemon": "^3.1.9", 42 | "prettier": "2.8.8", 43 | "react-test-renderer": "19.1.0", 44 | "typescript": "5.0.4" 45 | }, 46 | "engines": { 47 | "node": ">=18" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /apps/showcase-host/rnef.config.mjs: -------------------------------------------------------------------------------- 1 | import { pluginMetroModuleFederation } from '@module-federation/metro-plugin-rnef'; 2 | import { platformAndroid } from '@rnef/platform-android'; 3 | // @ts-check 4 | import { platformIOS } from '@rnef/platform-ios'; 5 | import { pluginMetro } from '@rnef/plugin-metro'; 6 | 7 | /** @type {import('@rnef/config').Config} */ 8 | export default { 9 | bundler: pluginMetro(), 10 | platforms: { 11 | ios: platformIOS(), 12 | android: platformAndroid(), 13 | }, 14 | remoteCacheProvider: 'github-actions', 15 | plugins: [pluginMetroModuleFederation()], 16 | }; 17 | -------------------------------------------------------------------------------- /apps/showcase-host/runtime-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { FederationRuntimePlugin } from '@module-federation/runtime'; 2 | 3 | export default function (): FederationRuntimePlugin { 4 | return { 5 | name: 'custom-plugin-build', 6 | beforeLoadShare(args) { 7 | console.log('[build time inject] beforeLoadShare'); 8 | return args; 9 | }, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /apps/showcase-host/src/Fallback.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ActivityIndicator, LayoutAnimation, Text, View } from 'react-native'; 3 | 4 | export default function Fallback() { 5 | React.useEffect(() => { 6 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut, () => 7 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) 8 | ); 9 | }); 10 | 11 | return ( 12 | 20 | 21 | 22 | Async Startup in progress... 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/showcase-host/src/aura.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-host/src/aura.png -------------------------------------------------------------------------------- /apps/showcase-host/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config" 3 | } 4 | -------------------------------------------------------------------------------- /apps/showcase-mini/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /apps/showcase-mini/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native', 4 | }; 5 | -------------------------------------------------------------------------------- /apps/showcase-mini/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | **/.xcode.env.local 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | *.hprof 33 | .cxx/ 34 | *.keystore 35 | !debug.keystore 36 | .kotlin/ 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | yarn-error.log 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | **/fastlane/report.xml 52 | **/fastlane/Preview.html 53 | **/fastlane/screenshots 54 | **/fastlane/test_output 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | **/Pods/ 61 | /vendor/bundle/ 62 | 63 | # Temporary files created by Metro to check the health of the file watcher 64 | .metro-health-check* 65 | 66 | # testing 67 | /coverage 68 | 69 | # Yarn 70 | .yarn/* 71 | !.yarn/patches 72 | !.yarn/plugins 73 | !.yarn/releases 74 | !.yarn/sdks 75 | !.yarn/versions 76 | 77 | # RNEF 78 | .rnef/ 79 | 80 | dist/ 81 | -------------------------------------------------------------------------------- /apps/showcase-mini/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /apps/showcase-mini/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /apps/showcase-mini/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby ">= 2.6.10" 5 | 6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures. 7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 9 | gem 'xcodeproj', '< 1.26.0' 10 | gem 'concurrent-ruby', '< 1.3.4' 11 | 12 | # Ruby 3.4.0 has removed some libraries from the standard library. 13 | gem 'bigdecimal' 14 | gem 'logger' 15 | gem 'benchmark' 16 | gem 'mutex_m' 17 | -------------------------------------------------------------------------------- /apps/showcase-mini/__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | import ReactTestRenderer from 'react-test-renderer'; 2 | import App from '../App'; 3 | 4 | test('renders correctly', async () => { 5 | await ReactTestRenderer.act(() => { 6 | ReactTestRenderer.create(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/debug.keystore -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/java/com/mini/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mini 2 | 3 | import com.facebook.react.ReactActivity 4 | import com.facebook.react.ReactActivityDelegate 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate 7 | 8 | class MainActivity : ReactActivity() { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | override fun getMainComponentName(): String = "mini" 15 | 16 | /** 17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 19 | */ 20 | override fun createReactActivityDelegate(): ReactActivityDelegate = 21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) 22 | } 23 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/java/com/mini/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.mini 2 | 3 | import android.app.Application 4 | import com.facebook.react.PackageList 5 | import com.facebook.react.ReactApplication 6 | import com.facebook.react.ReactHost 7 | import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost 11 | import com.facebook.react.defaults.DefaultReactNativeHost 12 | 13 | class MainApplication : Application(), ReactApplication { 14 | 15 | override val reactNativeHost: ReactNativeHost = 16 | object : DefaultReactNativeHost(this) { 17 | override fun getPackages(): List = 18 | PackageList(this).packages.apply { 19 | // Packages that cannot be autolinked yet can be added manually here, for example: 20 | // add(MyReactNativePackage()) 21 | } 22 | 23 | override fun getJSMainModuleName(): String = "index" 24 | 25 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 26 | 27 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 28 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 29 | } 30 | 31 | override val reactHost: ReactHost 32 | get() = getDefaultReactHost(applicationContext, reactNativeHost) 33 | 34 | override fun onCreate() { 35 | super.onCreate() 36 | loadReactNative(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | mini 3 | 4 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | buildToolsVersion = "35.0.0" 4 | minSdkVersion = 24 5 | compileSdkVersion = 35 6 | targetSdkVersion = 35 7 | ndkVersion = "27.1.12297006" 8 | kotlinVersion = "2.1.20" 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle") 16 | classpath("com.facebook.react:react-native-gradle-plugin") 17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") 18 | } 19 | } 20 | 21 | apply plugin: "com.facebook.react.rootproject" 22 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Use this property to specify which architecture you want to build. 26 | # You can also override it from the CLI using 27 | # ./gradlew -PreactNativeArchitectures=x86_64 28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 29 | 30 | # Use this property to enable support to the new architecture. 31 | # This will allow you to use TurboModules and the Fabric render in 32 | # your application. You should enable this flag either if you want 33 | # to write custom TurboModules/Fabric components OR use libraries that 34 | # are providing them. 35 | newArchEnabled=true 36 | 37 | # Use this property to enable or disable the Hermes JS engine. 38 | # If set to false, you will be using JSC instead. 39 | hermesEnabled=true 40 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/module-federation/metro/3cfb5b11fb10ecc16e69a8a3d67dc972b1341bf1/apps/showcase-mini/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /apps/showcase-mini/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /apps/showcase-mini/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } 2 | plugins { id("com.facebook.react.settings") } 3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand(['npx', 'rnef', 'config', '-p', 'android']) } 4 | rootProject.name = 'mini' 5 | include ':app' 6 | includeBuild('../node_modules/@react-native/gradle-plugin') 7 | -------------------------------------------------------------------------------- /apps/showcase-mini/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini", 3 | "displayName": "mini" 4 | } 5 | -------------------------------------------------------------------------------- /apps/showcase-mini/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/showcase-mini/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import { AppRegistry } from 'react-native'; 6 | import App from './App'; 7 | import { name as appName } from './app.json'; 8 | 9 | AppRegistry.registerComponent(appName, () => App); 10 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Resolve react_native_pods.rb with node to allow for hoisting 2 | require Pod::Executable.execute_command('node', ['-p', 3 | 'require.resolve( 4 | "react-native/scripts/react_native_pods.rb", 5 | {paths: [process.argv[1]]}, 6 | )', __dir__]).strip 7 | 8 | platform :ios, min_ios_version_supported 9 | prepare_react_native_project! 10 | 11 | linkage = ENV['USE_FRAMEWORKS'] 12 | if linkage != nil 13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 14 | use_frameworks! :linkage => linkage.to_sym 15 | end 16 | 17 | target 'mini' do 18 | config = use_native_modules!(['npx', 'rnef', 'config', '-p', 'ios']) 19 | 20 | use_react_native!( 21 | :path => config[:reactNativePath], 22 | # An absolute path to your application root. 23 | :app_path => "#{Pod::Config.instance.installation_root}/.." 24 | ) 25 | 26 | post_install do |installer| 27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 28 | react_native_post_install( 29 | installer, 30 | config[:reactNativePath], 31 | :mac_catalyst_enabled => false, 32 | # :ccache_enabled => true 33 | ) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/mini.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/mini/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import React 3 | import React_RCTAppDelegate 4 | import ReactAppDependencyProvider 5 | 6 | @main 7 | class AppDelegate: UIResponder, UIApplicationDelegate { 8 | var window: UIWindow? 9 | 10 | var reactNativeDelegate: ReactNativeDelegate? 11 | var reactNativeFactory: RCTReactNativeFactory? 12 | 13 | func application( 14 | _ application: UIApplication, 15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil 16 | ) -> Bool { 17 | let delegate = ReactNativeDelegate() 18 | let factory = RCTReactNativeFactory(delegate: delegate) 19 | delegate.dependencyProvider = RCTAppDependencyProvider() 20 | 21 | reactNativeDelegate = delegate 22 | reactNativeFactory = factory 23 | 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | 26 | factory.startReactNative( 27 | withModuleName: "mini", 28 | in: window, 29 | launchOptions: launchOptions 30 | ) 31 | 32 | return true 33 | } 34 | } 35 | 36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { 37 | override func sourceURL(for bridge: RCTBridge) -> URL? { 38 | self.bundleURL() 39 | } 40 | 41 | override func bundleURL() -> URL? { 42 | #if DEBUG 43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") 44 | #else 45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle") 46 | #endif 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/mini/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "iphone", 5 | "scale": "2x", 6 | "size": "20x20" 7 | }, 8 | { 9 | "idiom": "iphone", 10 | "scale": "3x", 11 | "size": "20x20" 12 | }, 13 | { 14 | "idiom": "iphone", 15 | "scale": "2x", 16 | "size": "29x29" 17 | }, 18 | { 19 | "idiom": "iphone", 20 | "scale": "3x", 21 | "size": "29x29" 22 | }, 23 | { 24 | "idiom": "iphone", 25 | "scale": "2x", 26 | "size": "40x40" 27 | }, 28 | { 29 | "idiom": "iphone", 30 | "scale": "3x", 31 | "size": "40x40" 32 | }, 33 | { 34 | "idiom": "iphone", 35 | "scale": "2x", 36 | "size": "60x60" 37 | }, 38 | { 39 | "idiom": "iphone", 40 | "scale": "3x", 41 | "size": "60x60" 42 | }, 43 | { 44 | "idiom": "ios-marketing", 45 | "scale": "1x", 46 | "size": "1024x1024" 47 | } 48 | ], 49 | "info": { 50 | "author": "xcode", 51 | "version": 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/mini/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "version": 1, 4 | "author": "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/mini/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | mini 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSAllowsLocalNetworking 32 | 33 | 34 | NSLocationWhenInUseUsageDescription 35 | 36 | RCTNewArchEnabled 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | arm64 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /apps/showcase-mini/ios/mini/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 22 | 23 | 24 | NSPrivacyAccessedAPIType 25 | NSPrivacyAccessedAPICategorySystemBootTime 26 | NSPrivacyAccessedAPITypeReasons 27 | 28 | 35F9.1 29 | 30 | 31 | 32 | NSPrivacyCollectedDataTypes 33 | 34 | NSPrivacyTracking 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /apps/showcase-mini/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | }; 4 | -------------------------------------------------------------------------------- /apps/showcase-mini/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); 3 | 4 | const { withModuleFederation } = require('@module-federation/metro'); 5 | 6 | /** 7 | * Metro configuration 8 | * https://reactnative.dev/docs/metro 9 | * 10 | * @type {import('@react-native/metro-config').MetroConfig} 11 | */ 12 | const config = { 13 | resolver: { useWatchman: false }, 14 | watchFolders: [ 15 | path.resolve(__dirname, '../../node_modules'), 16 | path.resolve(__dirname, '../../packages/core'), 17 | ], 18 | }; 19 | 20 | module.exports = withModuleFederation( 21 | mergeConfig(getDefaultConfig(__dirname), config), 22 | { 23 | name: 'mini', 24 | filename: 'mini.bundle', 25 | exposes: { 26 | './button': './src/button.tsx', 27 | './confetti': './src/confetti.tsx', 28 | }, 29 | shared: { 30 | react: { 31 | singleton: true, 32 | eager: false, 33 | requiredVersion: '19.1.0', 34 | version: '19.1.0', 35 | import: false, 36 | }, 37 | 'react-native': { 38 | singleton: true, 39 | eager: false, 40 | requiredVersion: '0.80.0', 41 | version: '0.80.0', 42 | import: false, 43 | }, 44 | lodash: { 45 | singleton: false, 46 | eager: false, 47 | requiredVersion: '^4.17.21', 48 | version: '4.17.21', 49 | }, 50 | 'lottie-react-native': { 51 | singleton: true, 52 | eager: false, 53 | requiredVersion: '7.2.2', 54 | version: '7.2.2', 55 | import: false, 56 | }, 57 | }, 58 | shareStrategy: 'loaded-first', 59 | }, 60 | { 61 | flags: { 62 | unstable_patchHMRClient: true, 63 | unstable_patchInitializeCore: true, 64 | unstable_patchRuntimeRequire: true, 65 | }, 66 | } 67 | ); 68 | -------------------------------------------------------------------------------- /apps/showcase-mini/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "showcase-mini", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "rnef run:android", 7 | "ios": "rnef run:ios", 8 | "lint": "eslint .", 9 | "dev": "nodemon --config ../../nodemon.json --exec NODE_OPTIONS='--conditions=dev' pnpm start", 10 | "start": "rnef start --reset-cache --client-logs --port 8082", 11 | "test": "jest", 12 | "pods": "(cd ios && bundle install && (bundle exec pod install || bundle exec pod update))" 13 | }, 14 | "dependencies": { 15 | "lodash": "^4.17.21", 16 | "lottie-react-native": "^7.2.2", 17 | "react": "19.1.0", 18 | "react-native": "0.80.0" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.25.2", 22 | "@babel/preset-env": "^7.25.3", 23 | "@babel/runtime": "^7.25.0", 24 | "@module-federation/metro": "workspace:*", 25 | "@module-federation/metro-plugin-rnef": "workspace:*", 26 | "@module-federation/runtime": "^0.15.0", 27 | "@react-native/babel-preset": "0.80.0", 28 | "@react-native/eslint-config": "0.80.0", 29 | "@react-native/metro-config": "0.80.0", 30 | "@react-native/typescript-config": "0.80.0", 31 | "@rnef/cli": "^0.7.25", 32 | "@rnef/platform-android": "^0.7.25", 33 | "@rnef/platform-ios": "^0.7.25", 34 | "@rnef/plugin-metro": "^0.7.25", 35 | "@types/jest": "^29.5.13", 36 | "@types/lodash": "^4", 37 | "@types/react": "^19.1.0", 38 | "@types/react-test-renderer": "^19.1.0", 39 | "eslint": "^8.19.0", 40 | "jest": "^29.6.3", 41 | "nodemon": "^3.1.9", 42 | "prettier": "2.8.8", 43 | "react-test-renderer": "19.1.0", 44 | "typescript": "5.0.4" 45 | }, 46 | "engines": { 47 | "node": ">=18" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /apps/showcase-mini/rnef.config.mjs: -------------------------------------------------------------------------------- 1 | import { pluginMetroModuleFederation } from '@module-federation/metro-plugin-rnef'; 2 | import { platformAndroid } from '@rnef/platform-android'; 3 | // @ts-check 4 | import { platformIOS } from '@rnef/platform-ios'; 5 | import { pluginMetro } from '@rnef/plugin-metro'; 6 | 7 | /** @type {import('@rnef/config').Config} */ 8 | export default { 9 | bundler: pluginMetro(), 10 | platforms: { 11 | ios: platformIOS(), 12 | android: platformAndroid(), 13 | }, 14 | remoteCacheProvider: 'github-actions', 15 | plugins: [pluginMetroModuleFederation()], 16 | }; 17 | -------------------------------------------------------------------------------- /apps/showcase-mini/src/button.tsx: -------------------------------------------------------------------------------- 1 | import LottieView from 'lottie-react-native'; 2 | import React from 'react'; 3 | import { Pressable, StyleSheet } from 'react-native'; 4 | 5 | type Props = { 6 | onPress: () => void; 7 | }; 8 | 9 | export default function Button({ onPress }: Props) { 10 | const animationRef = React.useRef(null); 11 | 12 | function handlePress() { 13 | animationRef.current?.play(); 14 | onPress(); 15 | } 16 | 17 | return ( 18 | 19 | 25 | 26 | ); 27 | } 28 | 29 | const styles = StyleSheet.create({ 30 | button: { 31 | height: 50, 32 | width: 100, 33 | padding: 8, 34 | }, 35 | animation: { 36 | width: 100, 37 | height: 100, 38 | position: 'absolute', 39 | top: -50, 40 | }, 41 | }); 42 | -------------------------------------------------------------------------------- /apps/showcase-mini/src/confetti.tsx: -------------------------------------------------------------------------------- 1 | import LottieView from 'lottie-react-native'; 2 | import type { Ref } from 'react'; 3 | import { StyleSheet, View, useWindowDimensions } from 'react-native'; 4 | 5 | type Props = { 6 | ref: Ref; 7 | }; 8 | 9 | export default function Confetti({ ref }: Props) { 10 | const { width, height } = useWindowDimensions(); 11 | 12 | return ( 13 | 14 | 20 | 21 | ); 22 | } 23 | 24 | const styles = StyleSheet.create({ 25 | container: { 26 | position: 'absolute', 27 | zIndex: 1000, 28 | bottom: 0, 29 | left: 0, 30 | }, 31 | animation: { 32 | width: '100%', 33 | height: '100%', 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /apps/showcase-mini/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native/typescript-config" 3 | } 4 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nodemon.json", 3 | "verbose": true, 4 | "watch": [ 5 | "./node_modules", 6 | "../../node_modules", 7 | "../../packages/core", 8 | "./metro.config.js" 9 | ], 10 | "ext": "ts,tsx,js,json,flow", 11 | "events": { 12 | "restart": "clear && echo '[nodemon] change detected, restarting...'" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "module-federation-metro", 3 | "private": true, 4 | "license": "MIT", 5 | "contributors": [ 6 | "Jakub Romańczyk (https://github.com/jbroma)", 7 | "Kacper Wiszczuk (https://github.com/esemesek)" 8 | ], 9 | "packageManager": "pnpm@10.12.1", 10 | "repository": "https://github.com/module-federation/metro", 11 | "scripts": { 12 | "prepare": "pnpm build", 13 | "build": "turbo build", 14 | "dev": "turbo dev --filter=showcase-host --filter=showcase-mini --ui=tui", 15 | "dev:example": "turbo dev --filter=example-host --filter=example-mini --filter=example-nested-mini --ui=tui", 16 | "lint": "biome check --write", 17 | "lint:ci": "biome check", 18 | "typecheck": "turbo typecheck" 19 | }, 20 | "devDependencies": { 21 | "@biomejs/biome": "^1.9.4", 22 | "turbo": "^2.5.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Callstack and Zephyr Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/core/babel-plugin/patch-initialize-core.js: -------------------------------------------------------------------------------- 1 | // reuse `@babel/types` from `metro` 2 | const metroPath = require.resolve('metro'); 3 | const babelTypesPath = require.resolve('@babel/types', { paths: [metroPath] }); 4 | const t = require(babelTypesPath); 5 | 6 | /** 7 | * Inject require('mf:init-host') right after 'use strict' directive 8 | * in React Native's Initialize Core 9 | */ 10 | function injectInitHostRequire(path, state) { 11 | // Only process once per file 12 | if (state.hasInjected) return; 13 | 14 | let insertIndex = 0; 15 | 16 | // Find the position after 'use strict' directive 17 | for (let i = 0; i < path.node.body.length; i++) { 18 | const node = path.node.body[i]; 19 | if ( 20 | t.isExpressionStatement(node) && 21 | t.isStringLiteral(node.expression) && 22 | node.expression.value === 'use strict' 23 | ) { 24 | insertIndex = i + 1; 25 | break; 26 | } 27 | } 28 | 29 | // Create the require('mf:init-host') statement 30 | const requireStatement = t.expressionStatement( 31 | t.callExpression(t.identifier('require'), [t.stringLiteral('mf:init-host')]) 32 | ); 33 | 34 | // Insert the require statement 35 | path.node.body.splice(insertIndex, 0, requireStatement); 36 | state.hasInjected = true; 37 | } 38 | 39 | function metroPatchInitializeCorePlugin() { 40 | return { 41 | name: 'module-federation-metro-patch-initialize-core', 42 | visitor: { 43 | Program: { 44 | enter(_, state) { 45 | state.hasInjected = false; 46 | state.shouldTransform = state.file.opts.filename.includes( 47 | 'react-native/Libraries/Core/InitializeCore.js' 48 | ); 49 | }, 50 | exit(path, state) { 51 | if (!state.shouldTransform) return; 52 | injectInitHostRequire(path, state); 53 | }, 54 | }, 55 | }, 56 | }; 57 | } 58 | 59 | module.exports = metroPatchInitializeCorePlugin; 60 | -------------------------------------------------------------------------------- /packages/core/bootstrap/index.d.ts: -------------------------------------------------------------------------------- 1 | export { withAsyncStartup } from '../dist/modules/asyncStartup'; 2 | -------------------------------------------------------------------------------- /packages/core/bootstrap/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../dist/modules/asyncStartup'); 2 | -------------------------------------------------------------------------------- /packages/core/dev/commands.js: -------------------------------------------------------------------------------- 1 | require('./utils/setup'); 2 | 3 | module.exports = require('../src/commands/index'); 4 | -------------------------------------------------------------------------------- /packages/core/dev/index.js: -------------------------------------------------------------------------------- 1 | require('./utils/setup'); 2 | 3 | module.exports = require('../src/index'); 4 | -------------------------------------------------------------------------------- /packages/core/dev/utils/setup.js: -------------------------------------------------------------------------------- 1 | const path = require('node:path'); 2 | 3 | require('ts-node').register({ 4 | compilerOptions: { 5 | module: 'commonjs', 6 | moduleResolution: 'node', 7 | }, 8 | project: path.resolve(__dirname, '../../tsconfig.json'), 9 | transpileOnly: true, 10 | }); 11 | -------------------------------------------------------------------------------- /packages/core/rslib.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@rslib/core'; 2 | 3 | const externalizeMetroImports = (request: string) => { 4 | return /^metro/.test(request) ? 'node-commonjs ' + request : undefined; 5 | }; 6 | 7 | export default defineConfig({ 8 | lib: [ 9 | { 10 | format: 'esm', 11 | syntax: 'es2021', 12 | bundle: false, 13 | dts: { 14 | bundle: false, 15 | }, 16 | output: { 17 | externals: ({ request }, callback) => 18 | callback(undefined, externalizeMetroImports(request!)), 19 | }, 20 | shims: { 21 | esm: { 22 | __dirname: true, 23 | __filename: true, 24 | require: true, 25 | }, 26 | }, 27 | }, 28 | { 29 | format: 'cjs', 30 | syntax: 'es2021', 31 | bundle: false, 32 | }, 33 | ], 34 | source: { 35 | entry: { 36 | index: 'src/!(babel|modules|runtime)', 37 | }, 38 | tsconfigPath: './tsconfig.build.json', 39 | }, 40 | output: { 41 | copy: [ 42 | { from: './src/babel', to: 'babel' }, 43 | { from: './src/modules', to: 'modules' }, 44 | { from: './src/runtime', to: 'runtime' }, 45 | ], 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /packages/core/src/babel/transformer.js: -------------------------------------------------------------------------------- 1 | const babelTransformer = require('__BABEL_TRANSFORMER_PATH__'); 2 | const babelPlugins = __BABEL_PLUGINS__; 3 | 4 | function transform(config) { 5 | return babelTransformer.transform({ 6 | ...config, 7 | plugins: [...babelPlugins, ...config.plugins], 8 | }); 9 | } 10 | 11 | module.exports = { ...babelTransformer, transform }; 12 | -------------------------------------------------------------------------------- /packages/core/src/commands/bundle-host/options.ts: -------------------------------------------------------------------------------- 1 | import { getCommunityCliPlugin } from '../utils/get-community-plugin'; 2 | 3 | const communityCliPlugin = getCommunityCliPlugin(); 4 | const options = communityCliPlugin.bundleCommand.options; 5 | 6 | export default options; 7 | -------------------------------------------------------------------------------- /packages/core/src/commands/bundle-host/types.ts: -------------------------------------------------------------------------------- 1 | export type BundleFederatedHostArgs = { 2 | assetsDest?: string; 3 | assetCatalogDest?: string; 4 | entryFile: string; 5 | resetCache: boolean; 6 | resetGlobalCache: boolean; 7 | transformer?: string; 8 | minify?: boolean; 9 | config?: string; 10 | platform: string; 11 | dev: boolean; 12 | bundleOutput: string; 13 | bundleEncoding?: 'utf8' | 'utf16le' | 'ascii'; 14 | maxWorkers?: number; 15 | sourcemapOutput?: string; 16 | sourcemapSourcesRoot?: string; 17 | sourcemapUseAbsolutePath: boolean; 18 | verbose: boolean; 19 | unstableTransformProfile: 'hermes-stable' | 'hermes-canary' | 'default'; 20 | indexedRamBundle?: boolean; 21 | resolverOptions?: Array; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/core/src/commands/bundle-remote/types.ts: -------------------------------------------------------------------------------- 1 | export type BundleFederatedRemoteArgs = { 2 | entryFile: string; 3 | platform: string; 4 | dev: boolean; 5 | minify?: boolean; 6 | bundleEncoding?: 'utf8' | 'utf16le' | 'ascii'; 7 | maxWorkers?: string; 8 | sourcemapOutput?: string; 9 | sourcemapSourcesRoot?: string; 10 | sourcemapUseAbsolutePath?: boolean; 11 | assetsDest?: string; 12 | assetCatalogDest?: string; 13 | resetCache?: boolean; 14 | config?: string; 15 | output?: string; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/core/src/commands/index.ts: -------------------------------------------------------------------------------- 1 | import bundleFederatedHost, { bundleFederatedHostOptions } from './bundle-host'; 2 | import bundleFederatedRemote, { 3 | bundleFederatedRemoteOptions, 4 | } from './bundle-remote'; 5 | import loadMetroConfig from './utils/load-metro-config'; 6 | 7 | export { 8 | bundleFederatedHost, 9 | bundleFederatedHostOptions, 10 | bundleFederatedRemote, 11 | bundleFederatedRemoteOptions, 12 | loadMetroConfig, 13 | }; 14 | 15 | export default { 16 | bundleFederatedHost, 17 | bundleFederatedHostOptions, 18 | bundleFederatedRemote, 19 | bundleFederatedRemoteOptions, 20 | loadMetroConfig, 21 | }; 22 | 23 | export type { BundleFederatedHostArgs } from './bundle-host/types'; 24 | export type { BundleFederatedRemoteArgs } from './bundle-remote/types'; 25 | export type { Config } from './types'; 26 | -------------------------------------------------------------------------------- /packages/core/src/commands/types.ts: -------------------------------------------------------------------------------- 1 | export interface Config { 2 | root: string; 3 | platforms: Record; 4 | reactNativePath: string; 5 | logger?: Logger; 6 | } 7 | 8 | export interface Logger { 9 | success: (...messages: Array) => void; 10 | info: (...messages: Array) => void; 11 | warn: (...messages: Array) => void; 12 | error: (...messages: Array) => void; 13 | debug: (...messages: Array) => void; 14 | log: (...messages: Array) => void; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/commands/utils/create-module-path-remapper.ts: -------------------------------------------------------------------------------- 1 | import type { Resolution } from 'metro-resolver'; 2 | 3 | export function createModulePathRemapper() { 4 | const mappings = new Map(); 5 | const reverseMappings = new Map(); 6 | 7 | return { 8 | addMapping(originalPath: string, overridePath: string) { 9 | mappings.set(originalPath, overridePath); 10 | reverseMappings.set(overridePath, originalPath); 11 | }, 12 | removeMapping(originalPath: string) { 13 | const overridePath = mappings.get(originalPath); 14 | if (!overridePath) return; 15 | mappings.delete(originalPath); 16 | reverseMappings.delete(overridePath); 17 | }, 18 | remap(resolved: Resolution): Resolution { 19 | if (!('filePath' in resolved)) return resolved; 20 | if (!mappings.has(resolved.filePath)) return resolved; 21 | const overridePath = mappings.get(resolved.filePath)!; 22 | return { filePath: overridePath, type: resolved.type }; 23 | }, 24 | reverse(overridePath: string) { 25 | if (!reverseMappings.has(overridePath)) return overridePath; 26 | return reverseMappings.get(overridePath)!; 27 | }, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/src/commands/utils/create-resolver.ts: -------------------------------------------------------------------------------- 1 | import type Server from 'metro/src/Server'; 2 | 3 | /** 4 | * Creates a resolver utility that mirrors Metro's bundling resolution behavior. 5 | * This utility exposes Metro's internal resolver to the command context, 6 | * allowing commands to resolve module paths exactly as Metro would during bundling. 7 | * The resolver maintains consistency with Metro's resolution strategy, 8 | * including platform-specific resolution and dependency graph traversal. 9 | */ 10 | 11 | /** 12 | * Creates a resolver that matches Metro's bundling resolution behavior 13 | * @param server - The Metro server instance to use for resolution 14 | * @param platform - The target platform for resolution (e.g., 'ios', 'android', null for default) 15 | * @returns The resolver object with a resolve method that takes source and target paths 16 | */ 17 | export async function createResolver(server: Server, platform: string | null) { 18 | const bundler = server.getBundler().getBundler(); 19 | const depGraph = await bundler.getDependencyGraph(); 20 | 21 | const resolve = ({ from, to }: { from: string; to: string }) => { 22 | const config = { name: to, data: { asyncType: null, key: to, locs: [] } }; 23 | const options = { assumeFlatNodeModules: false }; 24 | const res = depGraph.resolveDependency(from, config, platform, {}, options); 25 | return res.filePath; 26 | }; 27 | 28 | return { resolve }; 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/src/commands/utils/get-community-plugin.ts: -------------------------------------------------------------------------------- 1 | import type { ConfigT } from 'metro-config'; 2 | import type Server from 'metro/src/Server'; 3 | import type { OutputOptions, RequestOptions } from 'metro/src/shared/types'; 4 | import { CLIError } from '../../utils/errors'; 5 | 6 | interface Command { 7 | name: string; 8 | description: string; 9 | func: () => Promise; 10 | options: { 11 | name: string; 12 | description: string; 13 | }[]; 14 | } 15 | 16 | interface CommunityCliPlugin { 17 | bundleCommand: Command; 18 | startCommand: Command; 19 | unstable_buildBundleWithConfig: ( 20 | args: unknown, 21 | config: ConfigT, 22 | bundleImpl: { 23 | build: ( 24 | server: Server, 25 | requestOpts: RequestOptions 26 | ) => Promise<{ code: string; map: string }>; 27 | save: ( 28 | bundle: { code: string; map: string }, 29 | options: OutputOptions, 30 | log: (msg: string) => void 31 | ) => Promise; 32 | formatName: 'bundle'; 33 | } 34 | ) => Promise; 35 | } 36 | 37 | export function getCommunityCliPlugin(reactNativePath?: string) { 38 | let communityCliPlugin: CommunityCliPlugin; 39 | try { 40 | const communityCliPluginPath = require.resolve( 41 | '@react-native/community-cli-plugin', 42 | { paths: [reactNativePath ?? require.resolve('react-native')] } 43 | ); 44 | communityCliPlugin = require(communityCliPluginPath); 45 | } catch { 46 | throw new CLIError('Community CLI plugin is not installed.'); 47 | } 48 | return communityCliPlugin; 49 | } 50 | -------------------------------------------------------------------------------- /packages/core/src/commands/utils/load-metro-config.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import type { ConfigT, InputConfigT, YargArguments } from 'metro-config'; 3 | import { loadConfig, mergeConfig, resolveConfig } from 'metro-config'; 4 | import { CLIError } from '../../utils/errors'; 5 | import type { Config } from '../types'; 6 | 7 | function getOverrideConfig(cfg: Config, config: ConfigT): InputConfigT { 8 | // create alias for path - seems like a bug in rslib 9 | const nodePath = path; 10 | const resolver: Partial = { 11 | platforms: [...Object.keys(cfg.platforms), 'native'], 12 | }; 13 | 14 | return { 15 | resolver, 16 | serializer: { 17 | getModulesRunBeforeMainModule: (entryFilePath) => [ 18 | ...(config.serializer?.getModulesRunBeforeMainModule?.(entryFilePath) || 19 | []), 20 | require.resolve( 21 | nodePath.join(cfg.reactNativePath, 'Libraries/Core/InitializeCore'), 22 | { paths: [cfg.root] } 23 | ), 24 | ], 25 | }, 26 | }; 27 | } 28 | 29 | export default async function loadMetroConfig( 30 | cfg: Config, 31 | options: YargArguments = {} 32 | ): Promise { 33 | const cwd = cfg.root; 34 | const projectConfig = await resolveConfig(options.config, cwd); 35 | 36 | if (projectConfig.isEmpty) { 37 | throw new CLIError(`No Metro config found in ${cwd}`); 38 | } 39 | 40 | const config = await loadConfig({ cwd, ...options }); 41 | 42 | const overrideConfig = getOverrideConfig(cfg, config); 43 | 44 | return mergeConfig(config, overrideConfig); 45 | } 46 | -------------------------------------------------------------------------------- /packages/core/src/commands/utils/save-bundle-and-map.ts: -------------------------------------------------------------------------------- 1 | import { promises as fs } from 'node:fs'; 2 | import util from 'node:util'; 3 | import type { MixedSourceMap } from 'metro-source-map'; 4 | import relativizeSourceMapInline from 'metro/src/lib/relativizeSourceMap'; 5 | import type { OutputOptions } from 'metro/src/shared/types'; 6 | 7 | function relativizeSerializedMap( 8 | map: string, 9 | sourceMapSourcesRoot: string 10 | ): string { 11 | const sourceMap: MixedSourceMap = JSON.parse(map); 12 | relativizeSourceMapInline(sourceMap, sourceMapSourcesRoot); 13 | return JSON.stringify(sourceMap); 14 | } 15 | 16 | export async function saveBundleAndMap( 17 | bundle: { code: string; map: string }, 18 | options: OutputOptions, 19 | log: (msg: string) => void 20 | ) { 21 | const { 22 | bundleOutput, 23 | bundleEncoding: encoding, 24 | sourcemapOutput, 25 | sourcemapSourcesRoot, 26 | } = options; 27 | 28 | const writeFns = []; 29 | 30 | writeFns.push(async () => { 31 | log(`Writing bundle output to:\n${util.styleText('dim', bundleOutput)}`); 32 | await fs.writeFile(bundleOutput, bundle.code, encoding); 33 | log('Done writing bundle output'); 34 | }); 35 | 36 | if (sourcemapOutput) { 37 | let { map } = bundle; 38 | if (sourcemapSourcesRoot != null) { 39 | log('Start relativating source map'); 40 | 41 | map = relativizeSerializedMap(map, sourcemapSourcesRoot); 42 | log('Finished relativating'); 43 | } 44 | 45 | writeFns.push(async () => { 46 | log( 47 | `Writing sourcemap output to:\n${util.styleText('dim', sourcemapOutput)}` 48 | ); 49 | await fs.writeFile(sourcemapOutput, map); 50 | log('Done writing sourcemap output'); 51 | }); 52 | } 53 | 54 | // Wait until everything is written to disk. 55 | await Promise.all(writeFns.map((cb) => cb())); 56 | } 57 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { withModuleFederation } from './plugin'; 2 | export { updateManifest } from './plugin/manifest'; 3 | -------------------------------------------------------------------------------- /packages/core/src/modules/HMRClient.ts: -------------------------------------------------------------------------------- 1 | import HMRClient from 'react-native/Libraries/Utilities/HMRClient'; 2 | 3 | let hmrOrigin: string | null = null; 4 | 5 | const originalRegisterBundle = HMRClient.registerBundle; 6 | const originalSetup = HMRClient.setup; 7 | 8 | HMRClient.setup = ( 9 | platform: string, 10 | bundleEntry: string, 11 | host: string, 12 | port: number | string, 13 | isEnabled: boolean, 14 | scheme = 'http' 15 | ) => { 16 | const serverHost = port !== null && port !== '' ? `${host}:${port}` : host; 17 | hmrOrigin = `${scheme}://${serverHost}`; 18 | 19 | return originalSetup(platform, bundleEntry, host, port, isEnabled, scheme); 20 | }; 21 | 22 | HMRClient.registerBundle = (requestUrl: string) => { 23 | // only process registerBundle calls from the same origin 24 | if (!requestUrl.includes(hmrOrigin as string)) { 25 | return; 26 | } 27 | 28 | return originalRegisterBundle(requestUrl); 29 | }; 30 | 31 | export default HMRClient; 32 | -------------------------------------------------------------------------------- /packages/core/src/modules/HMRClientShim.ts: -------------------------------------------------------------------------------- 1 | export { default } from 'react-native/Libraries/Utilities/HMRClientProdShim'; 2 | -------------------------------------------------------------------------------- /packages/core/src/modules/asyncStartup.tsx: -------------------------------------------------------------------------------- 1 | import type { Federation } from '@module-federation/runtime'; 2 | import React from 'react'; 3 | 4 | declare global { 5 | var __DEV__: boolean; 6 | var __METRO_GLOBAL_PREFIX__: string; 7 | var __FUSEBOX_HAS_FULL_CONSOLE_SUPPORT__: boolean; 8 | var __loadBundleAsync: (entry: string) => Promise; 9 | var __FEDERATION__: Federation; 10 | } 11 | 12 | type LazyComponent = { default: React.ComponentType }; 13 | 14 | function getFallbackComponent(lazyFallbackFn?: () => LazyComponent) { 15 | if (!lazyFallbackFn) return () => null; 16 | const fallback = lazyFallbackFn(); 17 | return fallback.default; 18 | } 19 | 20 | export function withAsyncStartup( 21 | lazyAppFn: () => LazyComponent, 22 | lazyFallbackFn?: () => LazyComponent 23 | ): () => () => React.JSX.Element { 24 | const AppComponent = React.lazy(async () => { 25 | await globalThis.__FEDERATION__.__NATIVE__[__METRO_GLOBAL_PREFIX__].init; 26 | return lazyAppFn(); 27 | }); 28 | 29 | const FallbackComponent = getFallbackComponent(lazyFallbackFn); 30 | 31 | return () => () => { 32 | return ( 33 | }> 34 | 35 | 36 | ); 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/src/modules/getDevServer.ts: -------------------------------------------------------------------------------- 1 | export default function getDevServer() { 2 | const scriptUrl = 3 | globalThis.__FEDERATION__.__NATIVE__[__METRO_GLOBAL_PREFIX__].origin; 4 | 5 | if (!scriptUrl) { 6 | throw new Error( 7 | `Cannot determine dev server URL for ${__METRO_GLOBAL_PREFIX__} remote` 8 | ); 9 | } 10 | 11 | return { 12 | url: scriptUrl.match(/^https?:\/\/.*?\//)![0], 13 | fullBundleUrl: scriptUrl, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/plugin/babel-transformer.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | import type { ModuleFederationConfigNormalized } from '../types'; 4 | 5 | interface CreateBabelTransformerOptions { 6 | blacklistedPaths: string[]; 7 | federationConfig: ModuleFederationConfigNormalized; 8 | originalBabelTransformerPath: string; 9 | tmpDirPath: string; 10 | enableInitializeCorePatching: boolean; 11 | enableRuntimeRequirePatching: boolean; 12 | } 13 | 14 | export function createBabelTransformer({ 15 | blacklistedPaths, 16 | federationConfig, 17 | originalBabelTransformerPath, 18 | tmpDirPath, 19 | enableInitializeCorePatching, 20 | enableRuntimeRequirePatching, 21 | }: CreateBabelTransformerOptions) { 22 | const outputPath = path.join(tmpDirPath, 'babel-transformer.js'); 23 | const templatePath = require.resolve('../babel/transformer.js'); 24 | const transformerTemplate = fs.readFileSync(templatePath, 'utf-8'); 25 | 26 | const plugins = [ 27 | [ 28 | '@module-federation/metro/babel-plugin', 29 | { 30 | blacklistedPaths, 31 | remotes: federationConfig.remotes, 32 | shared: federationConfig.shared, 33 | }, 34 | ], 35 | enableInitializeCorePatching 36 | ? '@module-federation/metro/babel-plugin/patch-initialize-core' 37 | : undefined, 38 | enableRuntimeRequirePatching 39 | ? '@module-federation/metro/babel-plugin/patch-require' 40 | : undefined, 41 | ].filter(Boolean); 42 | 43 | const babelTransformer = transformerTemplate 44 | .replaceAll('__BABEL_TRANSFORMER_PATH__', originalBabelTransformerPath) 45 | .replaceAll('__BABEL_PLUGINS__', JSON.stringify(plugins)); 46 | 47 | fs.writeFileSync(outputPath, babelTransformer, 'utf-8'); 48 | 49 | return outputPath; 50 | } 51 | -------------------------------------------------------------------------------- /packages/core/src/plugin/constants.ts: -------------------------------------------------------------------------------- 1 | // internal module names 2 | export const INIT_HOST = 'mf:init-host'; 3 | export const ASYNC_REQUIRE = 'mf:async-require'; 4 | export const REMOTE_MODULE_REGISTRY = 'mf:remote-module-registry'; 5 | export const REMOTE_HMR_SETUP = 'mf:remote-hmr'; 6 | 7 | // defaults 8 | export const DEFAULT_ENTRY_FILENAME = 'remoteEntry.bundle'; 9 | 10 | // internal React Native modules 11 | export const GET_DEV_SERVER_REGEX = 12 | /react-native\/Libraries\/Core\/Devtools\/getDevServer\.js$/; 13 | export const HMR_CLIENT_REGEX = 14 | /react-native\/Libraries\/Utilities\/HMRClient\.js$/; 15 | 16 | // other 17 | export const TMP_DIR_NAME = '.mf-metro'; 18 | export const MANIFEST_FILENAME = 'mf-manifest.json'; 19 | -------------------------------------------------------------------------------- /packages/core/src/plugin/helpers.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | import { TMP_DIR_NAME } from './constants'; 4 | 5 | export function isUsingMFCommand(command = process.argv[2]) { 6 | const allowedCommands = ['start', 'bundle-mf-host', 'bundle-mf-remote']; 7 | return allowedCommands.includes(command); 8 | } 9 | 10 | export function isUsingMFBundleCommand(command = process.argv[2]) { 11 | const allowedCommands = ['bundle-mf-host', 'bundle-mf-remote']; 12 | return allowedCommands.includes(command); 13 | } 14 | 15 | export function replaceExtension(filepath: string, extension: string) { 16 | const { dir, name } = path.parse(filepath); 17 | return path.format({ dir, name, ext: extension }); 18 | } 19 | 20 | export function removeExtension(filepath: string) { 21 | return replaceExtension(filepath, ''); 22 | } 23 | 24 | export function stubHostEntry(hostEntryPath: string) { 25 | const stub = '// host entry stub'; 26 | fs.mkdirSync(path.dirname(hostEntryPath), { recursive: true }); 27 | fs.writeFileSync(hostEntryPath, stub, 'utf-8'); 28 | } 29 | 30 | export function stubRemoteEntry(remoteEntryPath: string) { 31 | const stub = '// remote entry stub'; 32 | fs.mkdirSync(path.dirname(remoteEntryPath), { recursive: true }); 33 | fs.writeFileSync(remoteEntryPath, stub, 'utf-8'); 34 | } 35 | 36 | export function prepareTmpDir(projectRootPath: string) { 37 | const nodeModulesPath = path.resolve(projectRootPath, 'node_modules'); 38 | const tmpDirPath = path.join(nodeModulesPath, TMP_DIR_NAME); 39 | fs.rmSync(tmpDirPath, { recursive: true, force: true }); 40 | fs.mkdirSync(tmpDirPath, { recursive: true }); 41 | return tmpDirPath; 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/src/plugin/normalize-extra-options.ts: -------------------------------------------------------------------------------- 1 | import type { ModuleFederationExtraOptions } from '../types'; 2 | 3 | export function normalizeExtraOptions( 4 | extraOptions?: ModuleFederationExtraOptions 5 | ) { 6 | return { 7 | ...extraOptions, 8 | flags: { 9 | unstable_patchHMRClient: false, 10 | unstable_patchInitializeCore: false, 11 | unstable_patchRuntimeRequire: false, 12 | ...extraOptions?.flags, 13 | }, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/runtime/host-entry.js: -------------------------------------------------------------------------------- 1 | // we need to explicitly import the init-host runtime module 2 | // this is because of a metro limitation, where the module 3 | // must be used in the bundle in order to be present in the final bundle 4 | import 'mf:init-host'; 5 | import 'mf:async-require'; 6 | 7 | // replaced with the actual app entrypoint 8 | __ENTRYPOINT_IMPORT__; 9 | -------------------------------------------------------------------------------- /packages/core/src/runtime/init-host.js: -------------------------------------------------------------------------------- 1 | import { 2 | loadRemoteToRegistry, 3 | loadSharedToRegistry, 4 | } from 'mf:remote-module-registry'; 5 | import { init } from '@module-federation/runtime'; 6 | 7 | __PLUGINS__; 8 | 9 | const usedRemotes = __REMOTES__; 10 | const usedShared = __SHARED__; 11 | 12 | const name = __NAME__; 13 | const shareScopeName = 'default'; 14 | const shareStrategy = __SHARE_STRATEGY__; 15 | 16 | const instance = init({ 17 | name, 18 | remotes: usedRemotes, 19 | plugins, 20 | shared: usedShared, 21 | shareStrategy, 22 | }); 23 | 24 | globalThis.__FEDERATION__ ??= {}; 25 | globalThis.__FEDERATION__.__NATIVE__ ??= {}; 26 | globalThis.__FEDERATION__.__NATIVE__[name] ??= {}; 27 | globalThis.__FEDERATION__.__NATIVE__[name].deps ??= { 28 | shared: {}, 29 | remotes: {}, 30 | }; 31 | 32 | globalThis.__FEDERATION__.__NATIVE__[name].init = Promise.all( 33 | instance.initializeSharing(shareScopeName, { 34 | strategy: shareStrategy, 35 | from: 'build', 36 | initScope: [], 37 | }) 38 | ).then(() => 39 | Promise.all([ 40 | ...Object.keys(usedShared).map(loadSharedToRegistry), 41 | ...__EARLY_REMOTES__.map(loadRemoteToRegistry), 42 | ]) 43 | ); 44 | 45 | // IMPORTANT: load early shared deps immediately without 46 | // waiting for the async part of initializeSharing to resolve 47 | __EARLY_SHARED__.forEach(loadSharedToRegistry); 48 | -------------------------------------------------------------------------------- /packages/core/src/runtime/remote-hmr.js: -------------------------------------------------------------------------------- 1 | function parseUrl(url) { 2 | const urlPattern = /^((https?):\/\/([^:\/]+)(?::(\d+))?)\/?(.*)?$/; 3 | const match = url.match(urlPattern); 4 | 5 | if (!match) { 6 | throw new Error('Invalid URL: ' + url); 7 | } 8 | 9 | const [, origin, scheme, host, port, path] = match; 10 | return { origin, scheme, host, port, path }; 11 | } 12 | 13 | export function setup() { 14 | const HMRClient = require('react-native/Libraries/Utilities/HMRClient'); 15 | const platform = require('react-native').Platform.OS; 16 | const { scheme, host, port, path } = parseUrl( 17 | globalThis.__FEDERATION__.__NATIVE__[__METRO_GLOBAL_PREFIX__].origin 18 | ); 19 | 20 | HMRClient.default.setup(platform, path, host, port, true, scheme); 21 | } 22 | -------------------------------------------------------------------------------- /packages/core/src/runtime/remote-module.js: -------------------------------------------------------------------------------- 1 | import { getModuleFromRegistry } from 'mf:remote-module-registry'; 2 | 3 | module.exports = getModuleFromRegistry(__MODULE_ID__); 4 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface SharedConfig { 2 | singleton: boolean; 3 | eager: boolean; 4 | version: string; 5 | requiredVersion: string; 6 | import?: false; 7 | } 8 | 9 | export type Shared = Record; 10 | 11 | export interface ModuleFederationConfig { 12 | name: string; 13 | filename?: string; 14 | remotes?: Record; 15 | exposes?: Record; 16 | shared?: Shared; 17 | shareStrategy?: 'loaded-first' | 'version-first'; 18 | plugins?: string[]; 19 | } 20 | 21 | export type ModuleFederationConfigNormalized = Required; 22 | 23 | export type ModuleFederationExtraOptions = { 24 | flags?: MetroMFFlags; 25 | }; 26 | 27 | export type MetroMFFlags = { 28 | unstable_patchHMRClient?: boolean; 29 | unstable_patchInitializeCore?: boolean; 30 | unstable_patchRuntimeRequire?: boolean; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/core/src/types/metro/baseJSBundle.d.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Module, 3 | ReadOnlyGraph, 4 | SerializerOptions, 5 | } from 'metro/src/DeltaBundler/types'; 6 | 7 | declare module 'metro/src/DeltaBundler/Serializers/baseJSBundle' { 8 | interface Bundle { 9 | modules: readonly [number, string][]; 10 | post: string; 11 | pre: string; 12 | } 13 | 14 | export default function baseJSBundle( 15 | entryPoint: string, 16 | preModules: readonly Module[], 17 | graph: ReadOnlyGraph, 18 | options: SerializerOptions 19 | ): Bundle; 20 | } 21 | -------------------------------------------------------------------------------- /packages/core/src/types/metro/bundleToString.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'metro/src/lib/bundleToString' { 2 | interface Bundle { 3 | modules: readonly [number, string][]; 4 | post: string; 5 | pre: string; 6 | } 7 | 8 | interface BundleMetadata { 9 | pre: number; 10 | post: number; 11 | modules: readonly [number, number][]; 12 | } 13 | 14 | export default function bundleToString(bundle: Bundle): { 15 | code: string; 16 | metadata: BundleMetadata; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/src/types/metro/getAppendScripts.d.ts: -------------------------------------------------------------------------------- 1 | import type { Module } from 'metro/src/DeltaBundler/types'; 2 | 3 | declare module 'metro/src/lib/getAppendScripts' { 4 | interface Options { 5 | asyncRequireModulePath: string; 6 | createModuleId: (path: string) => T; 7 | getRunModuleStatement: (moduleId: T) => string; 8 | inlineSourceMap?: boolean; 9 | runBeforeMainModule: readonly string[]; 10 | runModule: boolean; 11 | shouldAddToIgnoreList: (module: Module) => boolean; 12 | sourceMapUrl?: string; 13 | sourceUrl?: string; 14 | getSourceUrl?: (module: Module) => string; 15 | } 16 | 17 | export default function getAppendScripts( 18 | entryPoint: string, 19 | modules: readonly Module[], 20 | options: Options 21 | ): readonly Module[]; 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/src/types/metro/processModules.d.ts: -------------------------------------------------------------------------------- 1 | import type { Module } from 'metro/src/DeltaBundler/types'; 2 | 3 | declare module 'metro/src/DeltaBundler/Serializers/helpers/processModules' { 4 | interface Options { 5 | filter?: (module: Module) => boolean; 6 | createModuleId: (path: string) => number; 7 | dev: boolean; 8 | includeAsyncPaths: boolean; 9 | projectRoot: string; 10 | serverRoot: string; 11 | sourceUrl?: string; 12 | } 13 | 14 | export default function processModules( 15 | modules: readonly Module[], 16 | options: Options 17 | ): readonly [Module, string][]; 18 | } 19 | -------------------------------------------------------------------------------- /packages/core/src/types/metro/relativizeSourceMap.d.ts: -------------------------------------------------------------------------------- 1 | import type { MixedSourceMap } from 'metro-source-map'; 2 | 3 | declare module 'metro/src/lib/relativizeSourceMap' { 4 | export default function relativizeSourceMap( 5 | sourceMap: MixedSourceMap, 6 | sourcesRoot: string 7 | ): void; 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/src/types/react-native.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-native/Libraries/Utilities/HMRClient' { 2 | // biome-ignore lint/complexity/noStaticOnlyClass: 3 | export default class HMRClient { 4 | static registerBundle(bundlePath: string): void; 5 | static setup( 6 | platform: string, 7 | bundleEntry: string, 8 | host: string, 9 | port: number | string, 10 | isEnabled: boolean, 11 | scheme?: string 12 | ): void; 13 | } 14 | } 15 | 16 | declare module 'react-native/Libraries/Utilities/HMRClientProdShim' { 17 | export default class HMRClientProdShim {} 18 | } 19 | 20 | declare module 'react-native/Libraries/Core/Devtools/getDevServer' { 21 | export default function getDevServer(): { 22 | url: string; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/src/types/runtime.d.ts: -------------------------------------------------------------------------------- 1 | import type runtimeCore from '@module-federation/runtime/core'; 2 | 3 | type RemoteEntryExports = runtimeCore.types.RemoteEntryExports; 4 | 5 | declare module '@module-federation/runtime' { 6 | interface Federation { 7 | __NATIVE__: { 8 | [key: string]: { 9 | deps: { 10 | shared: Record; 11 | remotes: Record; 12 | }; 13 | exports: RemoteEntryExports; 14 | init: Promise; 15 | origin: string; 16 | }; 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/utils/errors.ts: -------------------------------------------------------------------------------- 1 | const inlineString = (str = ''): string => 2 | str.replace(/(\s{2,})/gm, ' ').trim(); 3 | 4 | class EnhancedError extends Error { 5 | constructor(msg: string, originalError?: Error | string) { 6 | super(inlineString(msg)); 7 | if (originalError != null) { 8 | this.stack = 9 | typeof originalError === 'string' 10 | ? originalError 11 | : originalError.stack || ''.split('\n').slice(0, 2).join('\n'); 12 | } else { 13 | // When the "originalError" is not passed, it means that we know exactly 14 | // what went wrong and provide means to fix it. In such cases showing the 15 | // stack is an unnecessary clutter to the CLI output, hence removing it. 16 | this.stack = ''; 17 | } 18 | } 19 | } 20 | 21 | export class ConfigError extends EnhancedError {} 22 | 23 | export class CLIError extends EnhancedError {} 24 | -------------------------------------------------------------------------------- /packages/core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { CLIError, ConfigError } from './errors'; 2 | export { VirtualModuleManager } from './vm-manager'; 3 | -------------------------------------------------------------------------------- /packages/core/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["src/modules"], 4 | "compilerOptions": { 5 | "rootDir": "src", 6 | "outDir": "dist", 7 | "sourceMap": false, 8 | "declarationMap": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "rootDir": "src" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/plugin-rnc-cli/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Callstack and Zephyr Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/plugin-rnc-cli/index.js: -------------------------------------------------------------------------------- 1 | const { default: commands } = require('@module-federation/metro/commands'); 2 | 3 | const { 4 | bundleFederatedHost, 5 | bundleFederatedHostOptions, 6 | bundleFederatedRemote, 7 | bundleFederatedRemoteOptions, 8 | loadMetroConfig, 9 | } = commands; 10 | 11 | const bundleMFHostCommand = { 12 | name: 'bundle-mf-host', 13 | description: 'Bundles a Module Federation host', 14 | func: bundleFederatedHost, 15 | options: bundleFederatedHostOptions, 16 | }; 17 | 18 | const bundleMFRemoteCommand = { 19 | name: 'bundle-mf-remote', 20 | description: 21 | 'Bundles a Module Federation remote, including its container entry and all exposed modules for consumption by host applications', 22 | func: bundleFederatedRemote, 23 | options: bundleFederatedRemoteOptions, 24 | }; 25 | 26 | module.exports = { 27 | bundleMFHostCommand, 28 | bundleMFRemoteCommand, 29 | loadMetroConfig, 30 | }; 31 | -------------------------------------------------------------------------------- /packages/plugin-rnc-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@module-federation/metro-plugin-rnc-cli", 3 | "version": "0.0.1", 4 | "description": "Metro Module Federation plugin for React Native Enterprise Framework (RNEF)", 5 | "keywords": ["rnc", "cli", "module-federation", "metro", "react-native"], 6 | "type": "commonjs", 7 | "license": "MIT", 8 | "contributors": [ 9 | "Jakub Romańczyk (https://github.com/jbroma)", 10 | "Kacper Wiszczuk (https://github.com/esemesek)" 11 | ], 12 | "publishConfig": { 13 | "access": "public", 14 | "registry": "https://registry.npmjs.org/" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/module-federation/metro", 19 | "directory": "packages/plugin-rnc-cli" 20 | }, 21 | "files": ["react-native.config.js"], 22 | "main": "./index.js", 23 | "exports": "./index.js", 24 | "peerDependencies": { 25 | "@module-federation/metro": "workspace:*" 26 | }, 27 | "devDependencies": { 28 | "@module-federation/metro": "workspace:*" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/plugin-rnc-cli/react-native.config.js: -------------------------------------------------------------------------------- 1 | const { bundleMFHostCommand, bundleMFRemoteCommand } = require('./index'); 2 | 3 | module.exports = { commands: [bundleMFHostCommand, bundleMFRemoteCommand] }; 4 | -------------------------------------------------------------------------------- /packages/plugin-rnef/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Callstack and Zephyr Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/plugin-rnef/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@module-federation/metro-plugin-rnef", 3 | "version": "0.0.1", 4 | "description": "Metro Module Federation plugin for React Native Enterprise Framework (RNEF)", 5 | "keywords": ["rnef", "module-federation", "metro", "react-native"], 6 | "type": "module", 7 | "license": "MIT", 8 | "contributors": [ 9 | "Jakub Romańczyk (https://github.com/jbroma)", 10 | "Kacper Wiszczuk (https://github.com/esemesek)" 11 | ], 12 | "publishConfig": { 13 | "access": "public", 14 | "registry": "https://registry.npmjs.org/" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/module-federation/metro", 19 | "directory": "packages/plugin-rnef" 20 | }, 21 | "files": ["dist/"], 22 | "main": "./dist/index.js", 23 | "types": "./dist/index.d.ts", 24 | "exports": { 25 | "types": "./dist/index.d.ts", 26 | "require": "./dist/index.cjs", 27 | "default": "./dist/index.js" 28 | }, 29 | "scripts": { 30 | "build": "rslib build", 31 | "typecheck": "tsc --noEmit" 32 | }, 33 | "peerDependencies": { 34 | "@module-federation/metro": "workspace:*", 35 | "@rnef/tools": "^0.7.18" 36 | }, 37 | "devDependencies": { 38 | "@module-federation/metro": "workspace:*", 39 | "@rnef/config": "^0.7.18", 40 | "@rnef/tools": "^0.7.18", 41 | "@rslib/core": "^0.10.0", 42 | "@types/node": "^20.0.0", 43 | "typescript": "^5.8.3" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/plugin-rnef/rslib.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@rslib/core'; 2 | 3 | export default defineConfig({ 4 | lib: [ 5 | { format: 'esm', syntax: 'es2021', bundle: false, dts: { bundle: false } }, 6 | { format: 'cjs', syntax: 'es2021', bundle: false }, 7 | ], 8 | source: { 9 | tsconfigPath: './tsconfig.build.json', 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/plugin-rnef/src/index.ts: -------------------------------------------------------------------------------- 1 | import { pluginMetroModuleFederation } from './plugin.js'; 2 | 3 | export { pluginMetroModuleFederation }; 4 | export default pluginMetroModuleFederation; 5 | -------------------------------------------------------------------------------- /packages/plugin-rnef/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist", 6 | "sourceMap": false, 7 | "declarationMap": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/plugin-rnef/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "rootDir": "src" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /patches/lottie-react-native.patch: -------------------------------------------------------------------------------- 1 | diff --git a/package.json b/package.json 2 | index b104a6b892c04789c7ae7dca202c60f4e451cc9c..06577e1bfa6976b66e0e6ecbac2c530f02131014 100644 3 | --- a/package.json 4 | +++ b/package.json 5 | @@ -97,6 +97,13 @@ 6 | "android": { 7 | "javaPackageName": "com.airbnb.android.react.lottie" 8 | }, 9 | + "ios": { 10 | + "components": { 11 | + "LottieAnimationView": { 12 | + "className": "LottieAnimationViewComponentView" 13 | + } 14 | + } 15 | + }, 16 | "name": "lottiereactnative", 17 | "type": "components", 18 | "jsSrcsDir": "./src/specs" 19 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - apps/* 4 | 5 | autoInstallPeers: false 6 | 7 | onlyBuiltDependencies: 8 | - "@biomejs/biome" 9 | - core-js 10 | 11 | patchedDependencies: 12 | lottie-react-native: patches/lottie-react-native.patch 13 | 14 | publicHoistPattern: 15 | - "@babel/runtime" 16 | - "@react-native/gradle-plugin" 17 | - "@react-native/codegen" 18 | 19 | updateNotifier: false 20 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "preserve", 4 | "moduleResolution": "bundler", 5 | "target": "ES2021", 6 | "esModuleInterop": true, 7 | "declaration": true, 8 | "isolatedModules": true, 9 | "sourceMap": true, 10 | "declarationMap": true, 11 | "composite": false, 12 | "forceConsistentCasingInFileNames": true, 13 | "jsx": "react-native", 14 | "allowJs": false, 15 | "checkJs": false, 16 | "strict": true, 17 | "skipLibCheck": true, 18 | "noUnusedLocals": true, 19 | "resolveJsonModule": true, 20 | "allowSyntheticDefaultImports": true, 21 | "paths": { 22 | "metro/src/DeltaBundler/Serializers/baseJSBundle": [ 23 | "./packages/core/src/types/metro/baseJSBundle" 24 | ], 25 | "metro/src/lib/bundleToString": [ 26 | "./packages/core/src/types/metro/bundleToString" 27 | ], 28 | "metro/src/lib/getAppendScripts": [ 29 | "./packages/core/src/types/metro/getAppendScripts" 30 | ], 31 | "metro/src/DeltaBundler/Serializers/helpers/processModules": [ 32 | "./packages/core/src/types/metro/processModules" 33 | ], 34 | "metro/src/lib/relativizeSourceMap": [ 35 | "./packages/core/src/types/metro/relativizeSourceMap" 36 | ] 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "tasks": { 4 | "dev": { 5 | "cache": false, 6 | "persistent": true, 7 | "interruptible": true, 8 | "interactive": true 9 | }, 10 | "build": { 11 | "dependsOn": ["^build"], 12 | "cache": true, 13 | "outputs": ["dist"], 14 | "outputLogs": "errors-only" 15 | }, 16 | "typecheck": { 17 | "dependsOn": ["^typecheck"], 18 | "cache": true, 19 | "outputs": [], 20 | "outputLogs": "errors-only" 21 | } 22 | } 23 | } 24 | --------------------------------------------------------------------------------