From 1e45261d1195335cacff30eb00bff17e7d8d881e Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 13:02:47 -0700 Subject: [PATCH 01/24] Add Bazel foundation with a rules_js Yarn Berry fork (draft) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Establishes an additive, experimental Bazel build for react-native-macos and proves the hardest, most novel piece end to end: driving aspect-build rules_js from the repo's Yarn 4 (Berry) yarn.lock as the single source of truth, with no committed pnpm-lock. What's green (verified): - `bazel test //tools/bazel/berry/example:verify` — a real Berry yarn.lock is translated to a pnpm-lock v9 by a dependency-free converter (tools/bazel/berry/berry_to_pnpm_lock.mjs) via a one-seam patch to rules_js (tools/bazel/patches/aspect_rules_js_berry.patch, applied with single_version_override), then rules_js fetches + links + runs it. - On the real monorepo lock the converter yields 33 importers / 1333 packages with zero dangling references; rules_js fetches all 1333. Scaffolded (tagged manual, WIP — see docs/bazel.md): - metro_bundle macro (tools/bazel/js/metro.bzl) + rn-tester bundle target. - Prebuilt XCFramework import seam (tools/bazel/apple/xcframeworks.bzl) and a macos_application slice reusing rn-tester's AppDelegate/main. Also: MODULE.bazel/.bazelrc/.bazelversion/.bazelignore, a non-blocking CI workflow that runs the green proof, and a design doc (docs/bazel.md). The generated pnpm-lock.yaml and MODULE.bazel.lock are gitignored; the only published-adjacent change is an inert empty pnpm.onlyBuiltDependencies in the private monorepo root package.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .bazelignore | 40 ++ .bazelrc | 19 + .bazelversion | 1 + .github/workflows/bazel.yml | 51 ++ .gitignore | 14 + BUILD.bazel | 6 + MODULE.bazel | 62 +++ docs/bazel.md | 181 +++++++ package.json | 3 + packages/rn-tester/BUILD.bazel | 69 +++ packages/rn-tester/bazel/Info.plist | 26 + packages/rn-tester/bazel/README.md | 23 + tools/bazel/apple/BUILD.bazel | 4 + tools/bazel/apple/xcframeworks.bzl | 47 ++ tools/bazel/berry/BUILD.bazel | 4 + tools/bazel/berry/berry_to_pnpm_lock.mjs | 473 ++++++++++++++++++ tools/bazel/berry/example/.yarnrc.yml | 2 + tools/bazel/berry/example/BUILD.bazel | 18 + tools/bazel/berry/example/package.json | 11 + tools/bazel/berry/example/verify.js | 19 + tools/bazel/berry/example/yarn.lock | 30 ++ tools/bazel/js/BUILD.bazel | 4 + tools/bazel/js/metro.bzl | 74 +++ tools/bazel/patches/BUILD.bazel | 2 + .../bazel/patches/aspect_rules_js_berry.patch | 79 +++ 25 files changed, 1262 insertions(+) create mode 100644 .bazelignore create mode 100644 .bazelrc create mode 100644 .bazelversion create mode 100644 .github/workflows/bazel.yml create mode 100644 BUILD.bazel create mode 100644 MODULE.bazel create mode 100644 docs/bazel.md create mode 100644 packages/rn-tester/BUILD.bazel create mode 100644 packages/rn-tester/bazel/Info.plist create mode 100644 packages/rn-tester/bazel/README.md create mode 100644 tools/bazel/apple/BUILD.bazel create mode 100644 tools/bazel/apple/xcframeworks.bzl create mode 100644 tools/bazel/berry/BUILD.bazel create mode 100644 tools/bazel/berry/berry_to_pnpm_lock.mjs create mode 100644 tools/bazel/berry/example/.yarnrc.yml create mode 100644 tools/bazel/berry/example/BUILD.bazel create mode 100644 tools/bazel/berry/example/package.json create mode 100644 tools/bazel/berry/example/verify.js create mode 100644 tools/bazel/berry/example/yarn.lock create mode 100644 tools/bazel/js/BUILD.bazel create mode 100644 tools/bazel/js/metro.bzl create mode 100644 tools/bazel/patches/BUILD.bazel create mode 100644 tools/bazel/patches/aspect_rules_js_berry.patch diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 000000000000..5a76730ea401 --- /dev/null +++ b/.bazelignore @@ -0,0 +1,40 @@ +node_modules +.git +.yarn +packages/react-native/.build +packages/rn-tester/Pods +packages/helloworld +private/helloworld +packages/assets/node_modules +packages/babel-plugin-codegen/node_modules +packages/community-cli-plugin/node_modules +packages/core-cli-utils/node_modules +packages/debugger-frontend/node_modules +packages/debugger-shell/node_modules +packages/dev-middleware/node_modules +packages/eslint-config-react-native/node_modules +packages/eslint-plugin-react-native/node_modules +packages/eslint-plugin-specs/node_modules +packages/gradle-plugin/node_modules +packages/metro-config/node_modules +packages/new-app-screen/node_modules +packages/normalize-color/node_modules +packages/polyfills/node_modules +packages/react-native-babel-preset/node_modules +packages/react-native-babel-transformer/node_modules +packages/react-native-codegen/node_modules +packages/react-native-compatibility-check/node_modules +packages/react-native-macos-init/node_modules +packages/react-native-popup-menu-android/node_modules +packages/react-native-test-library/node_modules +packages/react-native/node_modules +packages/rn-tester/node_modules +packages/typescript-config/node_modules +packages/virtualized-lists/node_modules +private/cxx-public-api/node_modules +private/eslint-plugin-monorepo/node_modules +private/monorepo-tests/node_modules +private/react-native-bots/node_modules +private/react-native-codegen-typescript-test/node_modules +private/react-native-fantom/node_modules +tools/bazel/berry/example/node_modules diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000000..88eeec108641 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,19 @@ +# react-native-macos Bazel configuration (draft / experimental) +# See docs/bazel.md for the design and current status. + +# Our pnpm-lock.yaml is generated on the fly from the Berry yarn.lock by the +# rules_js fork, so we don't pin the module resolution in MODULE.bazel.lock. +common --lockfile_mode=off + +# Local disk cache (also the base for the GHA actions/cache remote cache). +build --disk_cache=~/.cache/bazel-rnm-disk + +# Nicer output. +build --show_result=1 + +# Apple: build macOS slices. Scoped in practice to the app target's transitions. +build:macos --apple_platform_type=macos + +# CI convenience config. +build:ci --color=yes +build:ci --show_timestamps diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000000..df5119ec64e6 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +8.7.0 diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml new file mode 100644 index 000000000000..bb4bcbfe6145 --- /dev/null +++ b/.github/workflows/bazel.yml @@ -0,0 +1,51 @@ +# Experimental Bazel CI for react-native-macos. +# +# Today this verifies the rules_js *Berry fork* end to end: it builds/tests a target +# whose node_modules are materialized from a Yarn Berry `yarn.lock` (translated to a +# pnpm-lock by tools/bazel/berry, with no committed second lockfile). The macOS app +# slice (rules_apple) is added incrementally — see docs/bazel.md. +name: Bazel (experimental) + +on: + pull_request: + paths: + - "MODULE.bazel" + - ".bazelrc" + - ".bazelversion" + - ".bazelignore" + - "BUILD.bazel" + - "tools/bazel/**" + - "packages/**/BUILD.bazel" + - ".github/workflows/bazel.yml" + workflow_dispatch: {} + +permissions: + contents: read + +concurrency: + group: bazel-${{ github.ref }} + cancel-in-progress: true + +jobs: + berry-fork: + name: rules_js Berry fork (JS) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22" + # Disk cache doubles as a simple GHA-backed Bazel remote cache. For a real + # remote cache at scale, point --remote_cache at BuildBuddy or a self-hosted + # bazel-remote (see docs/bazel.md). + - name: Cache Bazel + uses: actions/cache@v4 + with: + path: ~/.cache/bazel-rnm-disk + key: bazel-berry-${{ runner.os }}-${{ hashFiles('MODULE.bazel', 'yarn.lock', 'tools/bazel/**') }} + restore-keys: | + bazel-berry-${{ runner.os }}- + - name: Test the Berry -> rules_js pipeline end to end + run: | + npx --yes @bazel/bazelisk test //tools/bazel/berry/example:verify \ + --config=ci --test_output=errors diff --git a/.gitignore b/.gitignore index ce454b9629b1..8f26c47320b7 100644 --- a/.gitignore +++ b/.gitignore @@ -204,3 +204,17 @@ fix_*.patch .cursor/rules/nx-rules.mdc .github/instructions/nx.instructions.md # macOS] + +# Generated by the rules_js Berry fork from yarn.lock (not committed) +/pnpm-lock.yaml + +# Berry fork example: generated lock + transient node_modules +/tools/bazel/berry/example/pnpm-lock.yaml +tools/bazel/berry/example/node_modules +tools/bazel/berry/example/.yarn + +# Bazel resolution lock (module deps pinned via BCR; pnpm-lock is generated) +/MODULE.bazel.lock + +# Bazel convenience symlinks +/bazel-* diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000000..4aebeedb374c --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,6 @@ +load("@npm//:defs.bzl", "npm_link_all_packages") + +# Links the pnpm-resolved (from the Berry yarn.lock via our fork) node_modules +# into the Bazel build graph. Downstream JS targets depend on +# //:node_modules/. +npm_link_all_packages(name = "node_modules") diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000000..803e86df0fb3 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,62 @@ +module( + name = "react_native_macos_monorepo", + version = "0.0.0", + compatibility_level = 1, +) + +############################################################################### +# JavaScript / Node toolchain (aspect-build rules_js) +############################################################################### +bazel_dep(name = "aspect_rules_js", version = "3.2.2") +bazel_dep(name = "aspect_rules_ts", version = "3.8.11") +bazel_dep(name = "aspect_bazel_lib", version = "2.22.5") +bazel_dep(name = "rules_nodejs", version = "6.7.5") + +# Local fork of rules_js: teach `npm_translate_lock` to read the Yarn Berry (v2+) +# `yarn.lock` directly, so it stays the single source of truth (no committed +# second lockfile). The patch swaps the `pnpm import` step for our bundled +# Berry -> pnpm-lock converter (tools/bazel/berry/berry_to_pnpm_lock.mjs) when +# the input yarn.lock is a Berry lockfile. See docs/bazel.md. +single_version_override( + module_name = "aspect_rules_js", + patch_strip = 1, + patches = ["//tools/bazel/patches:aspect_rules_js_berry.patch"], + version = "3.2.2", +) + +node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True) +node.toolchain(node_version = "22.14.0") + +npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm", dev_dependency = True) +npm.npm_translate_lock( + name = "npm", + # The Berry yarn.lock is the single source of truth. Our rules_js patch + # converts it to an (uncommitted, gitignored) pnpm-lock.yaml at rule time + # before parsing, so update_pnpm_lock (pnpm import) is left off. + yarn_lock = "//:yarn.lock", + pnpm_lock = "//:pnpm-lock.yaml", + update_pnpm_lock = False, + verify_node_modules_ignored = "//:.bazelignore", + quiet = False, +) +use_repo(npm, "npm") + +# Self-contained green proof of the Berry fork (see tools/bazel/berry/example). +npm.npm_translate_lock( + name = "npm_berry_example", + yarn_lock = "//tools/bazel/berry/example:yarn.lock", + pnpm_lock = "//tools/bazel/berry/example:pnpm-lock.yaml", + update_pnpm_lock = False, + verify_node_modules_ignored = "//:.bazelignore", + quiet = False, +) +use_repo(npm, "npm_berry_example") + +############################################################################### +# Apple toolchain (rules_apple / rules_swift) — used by the macOS app slice +############################################################################### +bazel_dep(name = "rules_apple", version = "4.5.3") +bazel_dep(name = "rules_swift", version = "3.6.1") +bazel_dep(name = "apple_support", version = "2.7.0") +bazel_dep(name = "rules_cc", version = "0.2.17") +bazel_dep(name = "platforms", version = "1.1.0") diff --git a/docs/bazel.md b/docs/bazel.md new file mode 100644 index 000000000000..a4e0c5cdc438 --- /dev/null +++ b/docs/bazel.md @@ -0,0 +1,181 @@ +# Bazel support for react-native-macos (draft / experimental) + +This document describes the **experimental Bazel build** being added to +react-native-macos, why it is designed the way it is, what works today, and the +roadmap. It is intentionally additive: the existing yarn / Metro / xcodebuild / SPM / +CocoaPods workflows are unchanged. + +## Goal + +Prove a **full working vertical slice**: bundle rn-tester's JavaScript with Metro +(driven by Bazel via aspect-build `rules_js`) and link/embed it into a macOS app +(`macos_application` via `rules_apple`) that consumes the prebuilt React Native +XCFrameworks — an end-to-end `bazel run` of a macOS RN app. Longer term, build those +XCFrameworks from source in Bazel too (see the roadmap). + +## Why Bazel + +* **Incrementality + caching**: fine-grained, content-addressed caching of JS bundling + and (later) native compilation, shared between CI and local dev via a remote cache. +* **One graph across languages**: the JS→native seam (a Metro bundle becoming an app + resource) is modeled explicitly, the way Meta does it in Buck2's `js`/`apple` + preludes — but reusing Metro and rules_apple instead of reimplementing them. + +## The single-source-of-truth lockfile problem (and the rules_js Berry fork) + +The repo uses **Yarn 4 (Berry)**; `yarn.lock` is `__metadata: version: 8`. We keep +that Berry `yarn.lock` as the **single source of truth** — no committed second lockfile. + +aspect `rules_js` normalizes every lockfile to an internal pnpm model. `npm_translate_lock` +does this in two stages: + +1. **foreign lock → `pnpm-lock.yaml`**: for a `yarn_lock`/`npm_package_lock` input it + shells out to the `pnpm import` binary + (`update_cmd = ["import"] …` in `npm/private/npm_translate_lock.bzl`). +2. **`pnpm-lock.yaml` → Bazel repo**: a Starlark parser (`npm/private/pnpm.bzl`) builds + `importers`/`packages`/`snapshots` and strictly cross-validates them. + +**The gap is isolated to stage 1**: `pnpm import` (and hence rules_js's `yarn_lock` path) +supports Yarn *Classic* v1 and npm — **but not Yarn Berry v2+** (pnpm issue #2991). +Stage 2 is format-agnostic and requires **pnpm lockfile v9**. + +### The fork + +We patch rules_js at exactly that seam +(`tools/bazel/patches/aspect_rules_js_berry.patch`, applied via bzlmod +`single_version_override`). The patch adds `_generate_pnpm_lock_from_berry`, which runs +at the top of `parse_and_verify_lock`: when the input `yarn.lock` is a Berry lockfile and +no `pnpm-lock.yaml` exists yet, it invokes our **dependency-free Node converter** +(`tools/bazel/berry/berry_to_pnpm_lock.mjs`) to translate the Berry lock into a +**pnpm-lock v9** written into the source root. That file is **gitignored** — generated at +rule time, never committed. `update_pnpm_lock` is left `False` (the `pnpm import` path is +never taken). The patch `rctx.watch`es the yarn.lock and the converter so changes +retrigger it. + +The converter reconstructs the whole graph from the Berry lock alone: + +* **descriptors → versions**: every Berry descriptor (`name@range`) maps to its resolved + entry, so package dependency ranges resolve to concrete versions (and thus to + `snapshots` keys). +* **workspaces → importers** with `link:` deps computed as importer-relative paths. +* **npm aliases** (e.g. `rxjs → @react-native-community/rxjs@6.5.4-custom`) map to the + aliased package's full snapshot key. +* It self-validates internal consistency exactly like `pnpm.bzl` does. + +On the real monorepo lock this yields **33 importers / 1333 packages, zero dangling +references**. + +### Known limitation: integrity + +Berry's `checksum` is Yarn's **own content hash**, *not* the npm tarball's `sha512` +integrity that pnpm/rules_js expect, so we cannot derive `resolution.integrity` from the +Berry lock. rules_js requires `integrity` **or** `tarball`, so the converter emits the +deterministic npm registry **tarball URL** and packages are downloaded **without integrity +verification**. This is acceptable for a draft but should be hardened for production by +sourcing real integrities — e.g. a one-time npm-registry packument fetch (cached) or a +small Yarn plugin that exports npm integrities alongside `yarn.lock`. + +### Why a fork and not BYONM + +"Bring your own node_modules" (a `repository_rule` running `yarn install`) also works and +is documented by aspect, but it gives coarse-grained caching and bypasses rules_js's +package graph. The fork keeps rules_js's fine-grained model while reading the Berry lock. +BYONM remains a viable fallback. + +## What works today (verified green) + +* `bazel test //tools/bazel/berry/example:verify` — a self-contained proof: a real Berry + `yarn.lock` (is-odd → is-number) is translated by the fork, fetched and linked by + rules_js, and a Node program that `require`s the npm dep runs green. +* On the **real monorepo** `yarn.lock`, `npm_translate_lock` parses the fork-generated + lock and **fetches all 1333 packages** successfully. + +## What's next (WIP, scaffolded) + +* **First-party workspace linking**: `//:node_modules` (link *all* packages) needs a + `BUILD.bazel` in each of the ~33 workspace packages (the standard rules_js monorepo + adoption step). Until then the Metro bundle target is tagged `manual`. +* **Metro bundle**: `//packages/rn-tester:rntester_macos_jsbundle` via the `metro_bundle` + macro (`tools/bazel/js/metro.bzl`) — a thin `js_run_binary` wrapper around the React + Native CLI `bundle` command (we drive Metro, we don't reimplement it). +* **macOS app**: `//packages/rn-tester:RNTesterMacBazel` (`macos_application`) links the + imported XCFrameworks and embeds the Metro bundle as an app resource, reusing + rn-tester's existing `AppDelegate.mm`/`main.m`. + +## Apple: prebuilt XCFrameworks (swappable seam) + +`tools/bazel/apple/xcframeworks.bzl` imports the prebuilt +`React` / `ReactNativeDependencies` / `hermes` XCFrameworks (produced by +`scripts/ios-prebuild.js`) via `apple_static_xcframework_import`, behind stable aliases +(`:React`, …). A future from-source build produces the *same* artifacts and drops in +behind these aliases with a `--//:rn_from_source` flag. + +Generate the XCFrameworks with: + +```sh +cd packages/react-native +node scripts/ios-prebuild.js -s -f Debug +node scripts/ios-prebuild.js -b -f Debug -p macos +node scripts/ios-prebuild.js -c -f Debug +``` + +## Xcode compatibility + +rules_apple tracks Xcode closely. rules_apple `master` already targets Xcode 26.4; the +pinned release here is `4.5.3` (with `rules_swift` 3.6.1). If the CI/local Xcode isn't +supported by the pinned rules_apple, either bump rules_apple (5.0.0-rc / master) or select +a supported Xcode via `DEVELOPER_DIR` / `--xcode_version`. Bazel is pinned to `8.7.0` +(`.bazelversion`). + +## CI and remote cache + +`.github/workflows/bazel.yml` runs the green Berry-fork test on `ubuntu-latest`. It caches +Bazel's `--disk_cache` via `actions/cache` (a zero-infra remote-cache stand-in). For a +real remote cache at scale, point `--remote_cache` at **BuildBuddy** (free tier: `grpcs` +endpoint + API-key secret) or a self-hosted **bazel-remote** (GCS/S3): read-only on PRs, +read-write on trunk. + +## Downstream / tarball safety + +The published npm package is `react-native-macos` (`packages/react-native`); its `files` +allowlist governs the tarball. All Bazel scaffolding lives at the repo root, in +`tools/bazel/`, and in `packages/rn-tester` (which is **private**, never published), so +tarballs are unaffected. The generated `pnpm-lock.yaml` and `MODULE.bazel.lock` are +gitignored and repo-dev-only. The only change to a published-adjacent file is an empty +`pnpm.onlyBuiltDependencies: []` in the **private monorepo root** `package.json` (matching +the repo's `enableScripts: false`), which is inert for Yarn and not published. + +## Future roadmap: build the XCFrameworks from source in Bazel + +`Package.swift` already enumerates the full target graph (each `RNTarget` ↔ a podspec), +giving a ready-made port map. Output the same `.xcframework`s via +`apple_static_xcframework`, swapped in behind the P3 alias + `--//:rn_from_source`: + +* **FA — Hermes**: keep the prebuilt Hermes (`http_archive`) initially; optionally wrap + the CMake build with `rules_foreign_cc` later. +* **FB — ReactNativeDependencies** (boost/folly/glog/fmt/double-conversion/…): model each + as `cc_library` (native or `rules_foreign_cc`), compose an `apple_static_xcframework`. +* **FC — Codegen in Bazel**: wrap `react-native-codegen` as a rules_js `js_run_binary` + genrule so generated C++/ObjC specs are Bazel-tracked inputs. +* **FD — React core**: port the `Package.swift` graph leaf-first (Yoga → jsi → ReactCommon + → React-Core / RCTUIKit → Fabric / TurboModule → RCT modules) to + `swift_library`/`objc_library`/`cc_library`; assemble `React.xcframework`. +* **FE — Swap + validate + CI**: flip `--//:rn_from_source`, validate ABI/behavior parity + vs the SPM XCFrameworks, and land the heavy native compiles on the remote cache (the + primary CI/local speedup). + +## Layout + +``` +MODULE.bazel # bzlmod: rules_js/ts/apple/swift + Berry fork override +.bazelrc, .bazelversion, .bazelignore +BUILD.bazel # npm_link_all_packages(name="node_modules") +tools/bazel/berry/ + berry_to_pnpm_lock.mjs # Berry yarn.lock -> pnpm-lock v9 converter + example/ # self-contained GREEN proof of the fork +tools/bazel/patches/ + aspect_rules_js_berry.patch # the one-seam rules_js patch +tools/bazel/js/metro.bzl # metro_bundle macro (thin Metro wrapper) +tools/bazel/apple/xcframeworks.bzl # import prebuilt React XCFrameworks +packages/rn-tester/BUILD.bazel # the macOS vertical-slice app (manual, WIP) +``` diff --git a/package.json b/package.json index 52efcc047118..74760e1a8d04 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "version": "1000.0.0", "license": "MIT", "packageManager": "yarn@4.12.0", + "pnpm": { + "onlyBuiltDependencies": [] + }, "scripts": { "android": "yarn --cwd packages/rn-tester android", "build-android": "./gradlew :packages:react-native:ReactAndroid:build", diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel new file mode 100644 index 000000000000..ad638dbddd9a --- /dev/null +++ b/packages/rn-tester/BUILD.bazel @@ -0,0 +1,69 @@ +# React Native macOS — Bazel vertical slice (draft / experimental) +# +# This BUILD file wires the end-to-end slice: bundle rn-tester's JS with Metro and +# embed it into a macOS app that links the prebuilt React Native XCFrameworks. +# +# The targets are tagged `manual` (kept out of `//...`) because they depend on: +# * first-party workspace packages having BUILD files (so rules_js can link the +# react-native CLI for Metro), and +# * the prebuilt XCFrameworks produced by scripts/ios-prebuild.js. +# See packages/rn-tester/bazel/README.md and docs/bazel.md. + +load("//tools/bazel/js:metro.bzl", "metro_bundle") +load("//tools/bazel/apple:xcframeworks.bzl", "rn_imported_xcframeworks") +load("@rules_apple//apple:macos.bzl", "macos_application") + +package(default_visibility = ["//visibility:private"]) + +# All rn-tester JavaScript that Metro may pull into the bundle. +filegroup( + name = "js_srcs", + srcs = glob( + ["js/**/*.js"], + allow_empty = False, + ) + [ + "metro.config.js", + "package.json", + ], +) + +# 1. JS bundle (Metro). Entry is the macOS variant of the rn-tester app. +metro_bundle( + name = "rntester_macos_jsbundle", + srcs = [":js_srcs"], + config = "metro.config.js", + entry_point = "js/RNTesterApp.macos.js", + platform = "macos", + tags = ["manual"], +) + +# 2. Prebuilt native code as importable XCFrameworks (from ios-prebuild). +rn_imported_xcframeworks() + +# 3. App host — reuse rn-tester's existing AppDelegate + main. +objc_library( + name = "rntester_macos_host", + srcs = [ + "RNTester/AppDelegate.mm", + "RNTester/main.m", + ], + hdrs = ["RNTester/AppDelegate.h"], + tags = ["manual"], + deps = [ + ":React", + ":ReactNativeDependencies", + ":hermes", + ], +) + +# 4. macOS app: link native + embed the Metro bundle as an app resource +# (mirrors how Buck2's apple prelude ingests a js_bundle as an AppleResource). +macos_application( + name = "RNTesterMacBazel", + bundle_id = "org.reactjs.native.RNTesterMacBazel", + infoplists = ["bazel/Info.plist"], + minimum_os_version = "11.0", + resources = [":rntester_macos_jsbundle"], + tags = ["manual"], + deps = [":rntester_macos_host"], +) diff --git a/packages/rn-tester/bazel/Info.plist b/packages/rn-tester/bazel/Info.plist new file mode 100644 index 000000000000..52027436a27a --- /dev/null +++ b/packages/rn-tester/bazel/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleName + RNTesterMacBazel + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 11.0 + NSPrincipalClass + NSApplication + NSHighResolutionCapable + + + diff --git a/packages/rn-tester/bazel/README.md b/packages/rn-tester/bazel/README.md new file mode 100644 index 000000000000..cc07d33815d8 --- /dev/null +++ b/packages/rn-tester/bazel/README.md @@ -0,0 +1,23 @@ +This directory holds the Bazel *vertical slice* for building RNTester on macOS. +The actual targets live in `packages/rn-tester/BUILD.bazel` (they need to glob the +rn-tester JS and Obj-C sources, which Bazel can only do from the package root). + +See `docs/bazel.md` for the full design and current status. In short, the slice: + + 1. `metro_bundle` — bundles `js/RNTesterApp.macos.js` with Metro via rules_js. + 2. `rn_imported_xcframeworks()` — imports the prebuilt React/ReactNativeDependencies/ + hermes XCFrameworks produced by `scripts/ios-prebuild.js`. + 3. `macos_application` — links the XCFrameworks + rn-tester's AppDelegate/main and + embeds the Metro bundle as an app resource. + +Prerequisites (why the slice targets are tagged `manual` today): + * First-party workspace packages need `BUILD.bazel` files so rules_js can link + `//:node_modules/react-native` (the Metro CLI). Tracked in docs/bazel.md. + * The XCFrameworks must exist: run + (cd packages/react-native && node scripts/ios-prebuild.js -s -f Debug \ + && node scripts/ios-prebuild.js -b -f Debug -p macos \ + && node scripts/ios-prebuild.js -c -f Debug) + * rules_apple must support the local Xcode (26.x); pin via DEVELOPER_DIR. + +Once the above are in place: + bazel run //packages/rn-tester:RNTesterMacBazel diff --git a/tools/bazel/apple/BUILD.bazel b/tools/bazel/apple/BUILD.bazel new file mode 100644 index 000000000000..6a9fc3ea6448 --- /dev/null +++ b/tools/bazel/apple/BUILD.bazel @@ -0,0 +1,4 @@ +# Bazel helpers for building React Native's Apple targets (rules_apple / rules_swift). +# See xcframeworks.bzl and docs/bazel.md. + +exports_files(["xcframeworks.bzl"]) diff --git a/tools/bazel/apple/xcframeworks.bzl b/tools/bazel/apple/xcframeworks.bzl new file mode 100644 index 000000000000..b7771f74dee5 --- /dev/null +++ b/tools/bazel/apple/xcframeworks.bzl @@ -0,0 +1,47 @@ +"""Import the prebuilt React Native XCFrameworks into the Bazel graph. + +The draft-PR slice consumes the XCFrameworks produced by the existing Swift Package +Manager prebuild pipeline (`packages/react-native/scripts/ios-prebuild.js`): + + React.xcframework, ReactNativeDependencies.xcframework, hermes.xcframework + +We wrap them behind stable aliases (`:React`, `:ReactNativeDependencies`, `:hermes`) +so a future *from-source* Bazel build (see docs/bazel.md "from-source roadmap") can +produce the same `.xcframework` artifacts with rules_apple `apple_static_xcframework` +and drop in behind these aliases without touching the app BUILD files. + +Usage (from a BUILD file, after running ios-prebuild so the artifacts exist): + + load("//tools/bazel/apple:xcframeworks.bzl", "rn_imported_xcframeworks") + rn_imported_xcframeworks() +""" + +load( + "@rules_apple//apple:apple.bzl", + "apple_static_xcframework_import", +) + +# Repo-relative locations of the prebuilt XCFrameworks emitted by ios-prebuild. +_DEFAULT_XCFRAMEWORKS = { + "React": "//packages/react-native:xcframeworks/React.xcframework", + "ReactNativeDependencies": "//packages/react-native:xcframeworks/ReactNativeDependencies.xcframework", + "hermes": "//packages/react-native:xcframeworks/hermes.xcframework", +} + +def rn_imported_xcframeworks(xcframeworks = _DEFAULT_XCFRAMEWORKS, visibility = ["//visibility:public"]): + """Declare `apple_static_xcframework_import` targets for the prebuilt XCFrameworks. + + Each is exposed as `:` (e.g. `:React`). The underlying import target is + `:_import`; the alias makes the from-source swap seamless later. + """ + for name, filegroup in xcframeworks.items(): + apple_static_xcframework_import( + name = name + "_import", + xcframework_imports = [filegroup], + visibility = visibility, + ) + native.alias( + name = name, + actual = ":" + name + "_import", + visibility = visibility, + ) diff --git a/tools/bazel/berry/BUILD.bazel b/tools/bazel/berry/BUILD.bazel new file mode 100644 index 000000000000..ad6ee5c696e8 --- /dev/null +++ b/tools/bazel/berry/BUILD.bazel @@ -0,0 +1,4 @@ +# Berry (Yarn v2+) yarn.lock -> pnpm-lock.yaml converter used by our rules_js +# fork's patched npm_translate_lock. Kept dependency-free so it runs under a +# bare Node in the repository rule. +exports_files(["berry_to_pnpm_lock.mjs"]) diff --git a/tools/bazel/berry/berry_to_pnpm_lock.mjs b/tools/bazel/berry/berry_to_pnpm_lock.mjs new file mode 100644 index 000000000000..bbc18240881c --- /dev/null +++ b/tools/bazel/berry/berry_to_pnpm_lock.mjs @@ -0,0 +1,473 @@ +#!/usr/bin/env node +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Berry (Yarn v2+) `yarn.lock` -> pnpm `pnpm-lock.yaml` (lockfileVersion 9.0) converter. + * + * aspect-build/rules_js `npm_translate_lock` normalizes every input lockfile to an + * internal pnpm-lock model. For `yarn_lock`/`npm_package_lock` inputs it shells out to + * `pnpm import`, which does NOT understand the Berry `yarn.lock` format (pnpm #2991). + * + * This tool fills that one gap: it parses the Berry lock (its own strict YAML subset, + * "Syml") and emits a pnpm-lock.yaml v9 that rules_js's parser (npm/private/pnpm.bzl) + * accepts, so the Berry `yarn.lock` can stay the single source of truth (no committed + * second lockfile). It is invoked by our rules_js patch inside the repository rule, so + * it must run under a bare Node with no external dependencies. + * + * Usage: node berry_to_pnpm_lock.mjs + */ + +import fs from 'node:fs'; + +const REGISTRY = 'https://registry.npmjs.org'; + +// --------------------------------------------------------------------------- +// Syml (Berry yarn.lock) parser +// --------------------------------------------------------------------------- + +/** + * Parse a Berry `yarn.lock` (Syml) into a plain nested object. + * Syml is an indentation-based YAML subset: 2-space indents, `key: value` or + * `key:` followed by an indented block, `#` comments, and quoted/bare scalars. + */ +function parseSyml(text) { + const root = {}; + // Stack of {indent, container}. container is the object we add children to. + const stack = [{indent: -1, container: root}]; + const lines = text.split(/\r?\n/); + + for (let raw of lines) { + if (raw.trim() === '' || raw.trim().startsWith('#')) { + continue; + } + const indent = raw.length - raw.trimStart().length; + const line = raw.trimStart(); + + // Pop to the parent whose indent is smaller than this line's indent. + while (stack.length > 1 && indent <= stack[stack.length - 1].indent) { + stack.pop(); + } + const parent = stack[stack.length - 1].container; + + const {key, rest} = splitKey(line); + if (rest === null || rest === '') { + // `key:` opening a nested block. + const child = {}; + parent[key] = child; + stack.push({indent, container: child}); + } else { + // `key: value` scalar. + parent[key] = unquote(rest); + } + } + return root; +} + +/** Split a line into its (possibly quoted) key and the remainder after the colon. */ +function splitKey(line) { + if (line.startsWith('"')) { + // Quoted key: find the closing quote (Syml keys don't contain escaped quotes + // in practice for yarn.lock, but handle doubled backslash-escaped just in case). + let i = 1; + for (; i < line.length; i++) { + if (line[i] === '\\') { + i++; + continue; + } + if (line[i] === '"') { + break; + } + } + const key = unquote(line.slice(0, i + 1)); + let after = line.slice(i + 1); + // after should start with ':' + const colon = after.indexOf(':'); + const rest = after.slice(colon + 1).trim(); + return {key, rest: rest === '' ? null : rest}; + } + // Bare key up to first colon. + const colon = line.indexOf(':'); + const key = line.slice(0, colon).trim(); + const rest = line.slice(colon + 1).trim(); + return {key, rest: rest === '' ? null : rest}; +} + +function unquote(s) { + s = s.trim(); + if (s.startsWith('"') && s.endsWith('"') && s.length >= 2) { + return s + .slice(1, -1) + .replace(/\\"/g, '"') + .replace(/\\\\/g, '\\'); + } + return s; +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/** Split an `ident@range` descriptor into [ident, range], accounting for scopes. */ +function splitDescriptor(descriptor) { + const at = descriptor.indexOf('@', descriptor.startsWith('@') ? 1 : 0); + return [descriptor.slice(0, at), descriptor.slice(at + 1)]; +} + +/** Parse Berry `conditions: "os=darwin & cpu=x64"` into {os, cpu} arrays. */ +function parseConditions(conditions) { + const out = {}; + if (!conditions) { + return out; + } + for (const clause of conditions.split('&')) { + const m = clause.trim().match(/^(os|cpu|libc)=(.+)$/); + if (m) { + (out[m[1]] = out[m[1]] || []).push(m[2].trim()); + } + } + return out; +} + +/** Compute the deterministic npm registry tarball URL for a package. */ +function registryTarballUrl(ident, version, registry) { + const base = registry.replace(/\/+$/, ''); + const unscoped = ident.startsWith('@') ? ident.slice(ident.indexOf('/') + 1) : ident; + return `${base}/${ident}/-/${unscoped}-${version}.tgz`; +} + +/** Strip the `npm:` protocol prefix from a specifier range for display. */ +function cleanSpecifier(range) { + if (range.startsWith('npm:') && !range.slice(4).includes('@')) { + return range.slice(4); + } + return range; +} + +/** POSIX relative path from importer dir `from` to workspace dir `to`. */ +function relPath(from, to) { + const a = from === '.' ? [] : from.split('/'); + const b = to === '.' ? [] : to.split('/'); + let i = 0; + while (i < a.length && i < b.length && a[i] === b[i]) { + i++; + } + const up = a.slice(i).map(() => '..'); + const down = b.slice(i); + const parts = [...up, ...down]; + return parts.length ? parts.join('/') : '.'; +} + +// --------------------------------------------------------------------------- +// Conversion +// --------------------------------------------------------------------------- + +function convert(syml) { + // Map every descriptor string -> its resolved entry. + const descriptorToEntry = new Map(); + // Canonical package key `ident@version` -> entry (npm packages only). + const packageEntries = new Map(); + // Workspace entries: importer path -> entry. + const workspaceByPath = new Map(); + // ident@workspacePath (descriptor) resolution helper: descriptor -> workspace path. + + const entries = []; + for (const [rawKey, value] of Object.entries(syml)) { + if (rawKey === '__metadata') { + continue; + } + const descriptors = rawKey.split(',').map(s => s.trim()); + const resolution = value.resolution || ''; + const entry = {descriptors, resolution, value}; + entries.push(entry); + for (const d of descriptors) { + descriptorToEntry.set(d, entry); + } + } + + // Classify entries. + for (const entry of entries) { + const {resolution, value} = entry; + const [ident, reference] = splitDescriptor(resolution); + entry.ident = ident; + if (reference.startsWith('workspace:')) { + const wsPath = reference.slice('workspace:'.length); + entry.kind = 'workspace'; + entry.path = wsPath === '.' ? '.' : wsPath; + workspaceByPath.set(entry.path, entry); + } else if (reference.startsWith('npm:')) { + entry.kind = 'npm'; + entry.version = value.version; + entry.pkgKey = `${ident}@${value.version}`; + if (!packageEntries.has(entry.pkgKey)) { + packageEntries.set(entry.pkgKey, entry); + } + } else { + // patch:, portal:, link:, exec:, git, https tarball, file: ... + // Best-effort: treat anything with a concrete version as an npm-like package + // keyed by version so cross-references still resolve. + entry.kind = 'other'; + entry.version = value.version; + if (value.version) { + entry.pkgKey = `${ident}@${value.version}`; + if (!packageEntries.has(entry.pkgKey)) { + packageEntries.set(entry.pkgKey, entry); + } + } + } + } + + // Resolve a `depName: rangeDescriptor` reference to either a snapshot key + // (`name@version`) or a `link:` for workspace deps. + function resolveDep(fromPath, depName, rangeDescriptor) { + const descriptor = `${depName}@${rangeDescriptor}`; + const target = descriptorToEntry.get(descriptor); + if (!target) { + return null; + } + if (target.kind === 'workspace') { + return {link: `link:${relPath(fromPath, target.path)}`}; + } + if (target.version) { + return { + version: `${target.ident}@${target.version}`, + plain: target.version, + ident: target.ident, + }; + } + return null; + } + + // Build `packages` and `snapshots`. + const packages = {}; + const snapshots = {}; + for (const entry of packageEntries.values()) { + const {value, pkgKey, ident} = entry; + const pkg = {}; + // NOTE: Berry's `checksum` is Yarn's own content hash of the package, NOT the + // npm tarball's sha512 integrity that rules_js/pnpm expect, so we cannot derive a + // valid `resolution.integrity` from the Berry lock. rules_js requires either an + // `integrity` or a `tarball`; we emit the deterministic npm registry tarball URL + // (downloaded without integrity verification). A production-grade version should + // source real integrities (one-time npm registry fetch or a Yarn plugin export) — + // tracked in docs/bazel.md. + pkg.resolution = {tarball: registryTarballUrl(ident, entry.version, REGISTRY)}; + const conds = parseConditions(value.conditions); + if (conds.os) { + pkg.os = conds.os; + } + if (conds.cpu) { + pkg.cpu = conds.cpu; + } + if (value.bin && typeof value.bin === 'object') { + pkg.hasBin = true; + } + if (value.peerDependencies && typeof value.peerDependencies === 'object') { + pkg.peerDependencies = {}; + for (const [pn, pv] of Object.entries(value.peerDependencies)) { + pkg.peerDependencies[pn] = typeof pv === 'string' ? pv : '*'; + } + } + packages[pkgKey] = pkg; + + const snap = {}; + const deps = value.dependencies; + if (deps && typeof deps === 'object') { + const meta = value.dependenciesMeta || {}; + const depMap = {}; + const optMap = {}; + for (const [dn, dr] of Object.entries(deps)) { + const resolved = resolveDep('.', dn, dr); + if (!resolved) { + continue; + } + const target = resolved.link || resolved.version; + const isOptional = meta[dn] && meta[dn].optional === 'true'; + if (isOptional) { + optMap[dn] = target; + } else { + depMap[dn] = target; + } + } + if (Object.keys(depMap).length) { + snap.dependencies = depMap; + } + if (Object.keys(optMap).length) { + snap.optionalDependencies = optMap; + } + } + snapshots[pkgKey] = snap; + } + + // Build `importers` from workspace entries. + const importers = {}; + for (const entry of workspaceByPath.values()) { + const importPath = entry.path; + const deps = {}; + const src = entry.value.dependencies; + if (src && typeof src === 'object') { + for (const [dn, dr] of Object.entries(src)) { + const resolved = resolveDep(importPath, dn, dr); + if (!resolved) { + continue; + } + deps[dn] = { + specifier: cleanSpecifier(dr), + version: + resolved.link || + (resolved.ident === dn ? resolved.plain : resolved.version), + }; + } + } + importers[importPath] = {dependencies: deps}; + } + + return {importers, packages, snapshots}; +} + +// --------------------------------------------------------------------------- +// Minimal YAML emitter (maps, string scalars, booleans, flow string arrays) +// --------------------------------------------------------------------------- + +function needsQuote(s) { + return !/^[A-Za-z0-9_./-]+$/.test(s) || s === '' || /^(true|false|null|~|yes|no)$/i.test(s); +} + +function q(s) { + s = String(s); + if (!needsQuote(s)) { + return s; + } + return `'${s.replace(/'/g, "''")}'`; +} + +function emit(obj, indent, lines) { + const pad = ' '.repeat(indent); + const keys = Object.keys(obj); + for (const k of keys) { + const v = obj[k]; + if (Array.isArray(v)) { + lines.push(`${pad}${q(k)}: [${v.map(q).join(', ')}]`); + } else if (v && typeof v === 'object') { + if (Object.keys(v).length === 0) { + lines.push(`${pad}${q(k)}: {}`); + } else { + lines.push(`${pad}${q(k)}:`); + emit(v, indent + 1, lines); + } + } else if (typeof v === 'boolean') { + lines.push(`${pad}${q(k)}: ${v ? 'true' : 'false'}`); + } else { + lines.push(`${pad}${q(k)}: ${q(v)}`); + } + } +} + +function toYaml({importers, packages, snapshots}) { + const lines = []; + lines.push("lockfileVersion: '9.0'"); + lines.push(''); + lines.push('settings:'); + lines.push(' autoInstallPeers: true'); + lines.push(' excludeLinksFromLockfile: false'); + lines.push(''); + lines.push('importers:'); + emit(importers, 1, lines); + lines.push(''); + lines.push('packages:'); + emit(packages, 1, lines); + lines.push(''); + lines.push('snapshots:'); + emit(snapshots, 1, lines); + lines.push(''); + return lines.join('\n'); +} + +// --------------------------------------------------------------------------- +// Validation (mirrors rules_js npm/private/pnpm.bzl consistency checks) +// --------------------------------------------------------------------------- + +function validate({importers, packages, snapshots}) { + const snapKeys = new Set(Object.keys(snapshots)); + const pkgKeys = new Set(Object.keys(packages)); + const dangling = []; + + const resolvable = (name, version) => { + if (typeof version !== 'string') { + return false; + } + if (version.startsWith('link:')) { + return true; + } + if (snapKeys.has(version)) { + return true; + } + if (snapKeys.has(`${name}@${version}`)) { + return true; + } + return false; + }; + + for (const [path, importer] of Object.entries(importers)) { + for (const kind of ['dependencies', 'devDependencies', 'optionalDependencies']) { + for (const [name, attr] of Object.entries(importer[kind] || {})) { + if (!resolvable(name, attr.version)) { + dangling.push(`importer ${path} -> ${name}@${attr.version}`); + } + } + } + } + for (const [snapKey, snap] of Object.entries(snapshots)) { + const staticKey = snapKey.includes('(') ? snapKey.slice(0, snapKey.indexOf('(')) : snapKey; + if (!pkgKeys.has(staticKey)) { + dangling.push(`snapshot ${snapKey} has no package ${staticKey}`); + } + for (const kind of ['dependencies', 'optionalDependencies']) { + for (const [name, version] of Object.entries(snap[kind] || {})) { + if (!resolvable(name, version)) { + dangling.push(`snapshot ${snapKey} -> ${name}@${version}`); + } + } + } + } + + if (dangling.length) { + console.error(`berry_to_pnpm_lock: ${dangling.length} dangling reference(s):`); + for (const d of dangling.slice(0, 25)) { + console.error(` - ${d}`); + } + if (dangling.length > 25) { + console.error(` ... and ${dangling.length - 25} more`); + } + } else { + console.error('berry_to_pnpm_lock: model is internally consistent'); + } +} + +// --------------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------------- + +function main() { + const [, , inPath, outPath] = process.argv; + if (!inPath || !outPath) { + console.error('Usage: berry_to_pnpm_lock.mjs '); + process.exit(2); + } + const text = fs.readFileSync(inPath, 'utf8'); + const syml = parseSyml(text); + const model = convert(syml); + validate(model); + fs.writeFileSync(outPath, toYaml(model)); + const nImporters = Object.keys(model.importers).length; + const nPackages = Object.keys(model.packages).length; + console.error( + `berry_to_pnpm_lock: wrote ${outPath} (${nImporters} importers, ${nPackages} packages)`, + ); +} + +main(); diff --git a/tools/bazel/berry/example/.yarnrc.yml b/tools/bazel/berry/example/.yarnrc.yml new file mode 100644 index 000000000000..94f5c254e79d --- /dev/null +++ b/tools/bazel/berry/example/.yarnrc.yml @@ -0,0 +1,2 @@ +nodeLinker: node-modules +enableScripts: false diff --git a/tools/bazel/berry/example/BUILD.bazel b/tools/bazel/berry/example/BUILD.bazel new file mode 100644 index 000000000000..3c050133653f --- /dev/null +++ b/tools/bazel/berry/example/BUILD.bazel @@ -0,0 +1,18 @@ +load("@aspect_rules_js//js:defs.bzl", "js_test") +load("@npm_berry_example//:defs.bzl", "npm_link_all_packages") + +exports_files(["yarn.lock"]) + +# Links node_modules resolved (by our rules_js Berry fork) from this example's +# Yarn Berry yarn.lock. No committed pnpm-lock.yaml. +npm_link_all_packages(name = "node_modules") + +# `bazel test //tools/bazel/berry/example:verify` proves the whole chain: +# Berry yarn.lock -> berry_to_pnpm_lock.mjs -> patched npm_translate_lock -> +# rules_js fetch + link -> a Node program requiring an npm dep runs green. +js_test( + name = "verify", + size = "small", + data = [":node_modules/is-odd"], + entry_point = "verify.js", +) diff --git a/tools/bazel/berry/example/package.json b/tools/bazel/berry/example/package.json new file mode 100644 index 000000000000..f6ac31f6a6cb --- /dev/null +++ b/tools/bazel/berry/example/package.json @@ -0,0 +1,11 @@ +{ + "name": "berry-fork-example", + "version": "0.0.0", + "private": true, + "pnpm": { + "onlyBuiltDependencies": [] + }, + "dependencies": { + "is-odd": "3.0.1" + } +} diff --git a/tools/bazel/berry/example/verify.js b/tools/bazel/berry/example/verify.js new file mode 100644 index 000000000000..0526a6a69c88 --- /dev/null +++ b/tools/bazel/berry/example/verify.js @@ -0,0 +1,19 @@ +// Green proof that the rules_js Berry fork works end to end: +// this file is bundled/run by Bazel with node_modules materialized from a +// Yarn *Berry* yarn.lock (translated by tools/bazel/berry/berry_to_pnpm_lock.mjs +// via our patched npm_translate_lock — no committed pnpm-lock.yaml). +const isOdd = require('is-odd'); + +const cases = [ + [1, true], + [2, false], + [3, true], + [10, false], +]; +for (const [n, expected] of cases) { + if (isOdd(n) !== expected) { + console.error(`FAIL: isOdd(${n}) !== ${expected}`); + process.exit(1); + } +} +console.log('OK: is-odd (resolved from a Berry yarn.lock via the rules_js fork) works'); diff --git a/tools/bazel/berry/example/yarn.lock b/tools/bazel/berry/example/yarn.lock new file mode 100644 index 000000000000..05ad7e142a37 --- /dev/null +++ b/tools/bazel/berry/example/yarn.lock @@ -0,0 +1,30 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"berry-fork-example@workspace:.": + version: 0.0.0-use.local + resolution: "berry-fork-example@workspace:." + dependencies: + is-odd: "npm:3.0.1" + languageName: unknown + linkType: soft + +"is-number@npm:^6.0.0": + version: 6.0.0 + resolution: "is-number@npm:6.0.0" + checksum: 10c0/5da4c68401529675c575878d2760d66f18eaef4b014858577f6003daf66488d7fe4eae684b1e8574e3fa1bb447c6c6c56b8491d2b4b3239da2d32e5f6f218008 + languageName: node + linkType: hard + +"is-odd@npm:3.0.1": + version: 3.0.1 + resolution: "is-odd@npm:3.0.1" + dependencies: + is-number: "npm:^6.0.0" + checksum: 10c0/89ee2e353c5a3f3bd400c79db1c307a5b3506198ee8169d521e533a9b1d8a08fc95f21a919c084e98845b4286d7ffe309778da03744dfe66c3c1763ab1a030c6 + languageName: node + linkType: hard diff --git a/tools/bazel/js/BUILD.bazel b/tools/bazel/js/BUILD.bazel new file mode 100644 index 000000000000..a6f700ee3457 --- /dev/null +++ b/tools/bazel/js/BUILD.bazel @@ -0,0 +1,4 @@ +# Bazel macros for building React Native JavaScript (Metro). See metro.bzl. +# Package marker so `//tools/bazel/js:metro.bzl` is loadable. + +exports_files(["metro.bzl"]) diff --git a/tools/bazel/js/metro.bzl b/tools/bazel/js/metro.bzl new file mode 100644 index 000000000000..5edbcc9bffdb --- /dev/null +++ b/tools/bazel/js/metro.bzl @@ -0,0 +1,74 @@ +"""Bazel wrapper for bundling React Native JavaScript with Metro. + +We deliberately drive the existing Metro/React Native CLI from Bazel via +`js_run_binary` (rules_js) rather than reimplementing Metro's transform/worker +pipeline the way Buck2's `js_bundle` prelude does. This keeps the rule tiny while +reusing the exact bundler the rest of the repo already uses. See docs/bazel.md. +""" + +load("@aspect_rules_js//js:defs.bzl", "js_run_binary") + +def metro_bundle( + name, + entry_point, + platform, + srcs, + deps = [], + config = None, + dev = False, + minify = None, + bundle_out = None, + assets_out = None, + **kwargs): + """Produce a `.jsbundle` (+ assets dir) from a React Native entry point. + + Args: + name: target name; also the default bundle basename. + entry_point: JS entry file (e.g. `js/RNTesterApp.macos.js`). + platform: React Native platform (`macos`, `ios`, `android`, ...). + srcs: JS/asset source files that make up the app. + deps: additional targets (e.g. linked first-party packages / node_modules). + config: optional `metro.config.js` target. + dev: whether to build a dev (unminified, with warnings) bundle. + minify: override minification (defaults to `not dev`). + bundle_out: output bundle filename (default `.jsbundle`). + assets_out: output assets directory (default `_assets`). + **kwargs: passed through to js_run_binary (e.g. tags, visibility). + """ + bundle_out = bundle_out or (name + ".jsbundle") + assets_out = assets_out or (name + "_assets") + minify = minify if minify != None else (not dev) + + args = [ + "bundle", + "--platform", + platform, + "--dev", + "true" if dev else "false", + "--minify", + "true" if minify else "false", + "--entry-file", + entry_point, + "--bundle-output", + bundle_out, + "--assets-dest", + assets_out, + "--reset-cache", + ] + tool_srcs = list(srcs) + list(deps) + if config: + args += ["--config", "$(rootpath %s)" % config] + tool_srcs.append(config) + + js_run_binary( + name = name, + # The React Native community CLI exposes the `bundle` command. This is a + # first-party workspace package; linking it requires the per-package + # BUILD.bazel migration described in docs/bazel.md. + tool = "//:node_modules/react-native/bin", + srcs = tool_srcs, + args = args, + outs = [bundle_out], + out_dirs = [assets_out], + **kwargs + ) diff --git a/tools/bazel/patches/BUILD.bazel b/tools/bazel/patches/BUILD.bazel new file mode 100644 index 000000000000..73f26db52828 --- /dev/null +++ b/tools/bazel/patches/BUILD.bazel @@ -0,0 +1,2 @@ +# Patches applied to external Bazel modules via single_version_override. +exports_files(glob(["*.patch"])) diff --git a/tools/bazel/patches/aspect_rules_js_berry.patch b/tools/bazel/patches/aspect_rules_js_berry.patch new file mode 100644 index 000000000000..cb24d62c0c04 --- /dev/null +++ b/tools/bazel/patches/aspect_rules_js_berry.patch @@ -0,0 +1,79 @@ +--- a/npm/private/npm_translate_lock.bzl ++++ b/npm/private/npm_translate_lock.bzl +@@ -336,7 +336,67 @@ + """), + }, + ) ++ ++def _find_berry_converter(yarn_path): ++ # The converter lives at /tools/bazel/berry/berry_to_pnpm_lock.mjs. ++ # Walk up from the yarn.lock directory to locate it, so this works for lockfiles ++ # anywhere in the repo (root or nested example projects). ++ d = yarn_path.dirname ++ for _ in range(32): ++ candidate = d.get_child("tools").get_child("bazel").get_child("berry").get_child("berry_to_pnpm_lock.mjs") ++ if candidate.exists: ++ return candidate ++ parent = d.dirname ++ if parent == None or str(parent) == str(d): ++ break ++ d = parent ++ return None ++ ++def _generate_pnpm_lock_from_berry(rctx, attr): ++ """rules_js Berry fork: generate pnpm-lock.yaml from a Yarn v2+ (Berry) yarn.lock. ++ ++ aspect_rules_js normally shells out to `pnpm import` to translate a yarn.lock, but ++ `pnpm import` does not understand the Berry (v2+) lockfile format. When the input ++ yarn.lock is a Berry lockfile and the pnpm-lock.yaml does not yet exist, translate it ++ with our bundled dependency-free converter so the Berry yarn.lock can remain the single ++ source of truth (the generated pnpm-lock.yaml is gitignored, never committed). See ++ tools/bazel/berry/ and docs/bazel.md. ++ """ ++ if not attr.yarn_lock or not attr.pnpm_lock: ++ return ++ yarn_path = rctx.path(attr.yarn_lock) ++ if not yarn_path.exists: ++ return ++ if "__metadata:" not in rctx.read(yarn_path): ++ return # not a Berry lockfile; leave the normal pnpm import path in charge ++ converter = _find_berry_converter(yarn_path) ++ if converter == None: ++ fail("berry_to_pnpm_lock.mjs not found above yarn.lock at {}".format(yarn_path)) + ++ # Re-run this extension when the Berry lock or the converter change. ++ rctx.watch(yarn_path) ++ rctx.watch(converter) ++ ++ pnpm_lock_path = rctx.path(attr.pnpm_lock) ++ if pnpm_lock_path.exists: ++ return # already generated; delete pnpm-lock.yaml to refresh after yarn.lock changes ++ rctx.report_progress("Translating Berry yarn.lock -> pnpm-lock.yaml") ++ result = rctx.execute( ++ [ ++ _host_node_path(rctx, attr), ++ converter, ++ yarn_path, ++ pnpm_lock_path, ++ ], ++ quiet = attr.quiet, ++ ) ++ if result.return_code: ++ fail("berry_to_pnpm_lock conversion failed (status {}):\n{}\n{}".format( ++ result.return_code, ++ result.stdout, ++ result.stderr, ++ )) ++ + def parse_and_verify_lock(rctx, mod, attr): + """Helper to parse and validate the lockfile + +@@ -348,6 +408,8 @@ + state, importers, and packages + """ + ++ _generate_pnpm_lock_from_berry(rctx, attr) ++ + state = npm_translate_lock_state.new(rctx, mod, attr) + + if state.should_update_pnpm_lock(): From bebb91475acd9858df40d0fee8168964435ea68b Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 15:21:59 -0700 Subject: [PATCH 02/24] Bazel: first-party package linking + rn-tester macOS bundle/app scaffolding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the Bazel slice toward an end-to-end RNTester macOS build. First-party workspace linking (rules_js): - Every workspace package now exposes a `:pkg` npm_package target via a generated BUILD.bazel, so rules_js can link first-party packages (react-native-macos etc.) from the Berry yarn.lock. `bazel build //packages/react-native:pkg` builds; rn-tester's node_modules links react-native-macos (consumed as `react-native`). rn-tester slice: - packages/rn-tester/BUILD.bazel: npm_link_all_packages + a Metro bundle target (js_run_binary around bazel/bundle.js, which drives Metro's API with the react-native -> react-native-macos alias) + the macos_application wiring. - packages/rn-tester/bazel/bundle.js: sandbox-safe Metro bundling entry. Verified / documented (docs/bazel.md): - rn-tester's macOS JS bundle builds outside Bazel (~7MB) after building @react-native/codegen lib — proving the JS is bundleable. - Two remaining blockers for a running app, documented: 1) the macOS app can't be built here because the Hermes nightly tarball 404s (no XCFrameworks); the app target is fully scaffolded for when they exist. 2) the hermetic Bazel Metro bundle needs the strict-deps tooling closure declared (rules_js does not hoist like Yarn). Targets that require these follow-ups remain tagged `manual`; the green Berry-fork proof (//tools/bazel/berry/example:verify) is unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 47 +++++++++++---- packages/assets/BUILD.bazel | 24 ++++++++ packages/babel-plugin-codegen/BUILD.bazel | 24 ++++++++ packages/community-cli-plugin/BUILD.bazel | 24 ++++++++ packages/core-cli-utils/BUILD.bazel | 24 ++++++++ packages/debugger-frontend/BUILD.bazel | 24 ++++++++ packages/debugger-shell/BUILD.bazel | 24 ++++++++ packages/dev-middleware/BUILD.bazel | 24 ++++++++ .../eslint-config-react-native/BUILD.bazel | 24 ++++++++ .../eslint-plugin-react-native/BUILD.bazel | 24 ++++++++ packages/eslint-plugin-specs/BUILD.bazel | 24 ++++++++ packages/gradle-plugin/BUILD.bazel | 24 ++++++++ packages/metro-config/BUILD.bazel | 24 ++++++++ packages/new-app-screen/BUILD.bazel | 24 ++++++++ packages/normalize-color/BUILD.bazel | 24 ++++++++ packages/polyfills/BUILD.bazel | 24 ++++++++ .../react-native-babel-preset/BUILD.bazel | 24 ++++++++ .../BUILD.bazel | 24 ++++++++ packages/react-native-codegen/BUILD.bazel | 24 ++++++++ .../BUILD.bazel | 24 ++++++++ packages/react-native-macos-init/BUILD.bazel | 24 ++++++++ .../BUILD.bazel | 24 ++++++++ .../react-native-test-library/BUILD.bazel | 24 ++++++++ packages/react-native/BUILD.bazel | 31 ++++++++++ packages/rn-tester/BUILD.bazel | 46 ++++++++++---- packages/rn-tester/bazel/bundle.js | 60 +++++++++++++++++++ packages/typescript-config/BUILD.bazel | 24 ++++++++ packages/virtualized-lists/BUILD.bazel | 24 ++++++++ private/cxx-public-api/BUILD.bazel | 24 ++++++++ private/eslint-plugin-monorepo/BUILD.bazel | 24 ++++++++ private/monorepo-tests/BUILD.bazel | 24 ++++++++ private/react-native-bots/BUILD.bazel | 24 ++++++++ .../BUILD.bazel | 24 ++++++++ private/react-native-fantom/BUILD.bazel | 24 ++++++++ 34 files changed, 881 insertions(+), 23 deletions(-) create mode 100644 packages/assets/BUILD.bazel create mode 100644 packages/babel-plugin-codegen/BUILD.bazel create mode 100644 packages/community-cli-plugin/BUILD.bazel create mode 100644 packages/core-cli-utils/BUILD.bazel create mode 100644 packages/debugger-frontend/BUILD.bazel create mode 100644 packages/debugger-shell/BUILD.bazel create mode 100644 packages/dev-middleware/BUILD.bazel create mode 100644 packages/eslint-config-react-native/BUILD.bazel create mode 100644 packages/eslint-plugin-react-native/BUILD.bazel create mode 100644 packages/eslint-plugin-specs/BUILD.bazel create mode 100644 packages/gradle-plugin/BUILD.bazel create mode 100644 packages/metro-config/BUILD.bazel create mode 100644 packages/new-app-screen/BUILD.bazel create mode 100644 packages/normalize-color/BUILD.bazel create mode 100644 packages/polyfills/BUILD.bazel create mode 100644 packages/react-native-babel-preset/BUILD.bazel create mode 100644 packages/react-native-babel-transformer/BUILD.bazel create mode 100644 packages/react-native-codegen/BUILD.bazel create mode 100644 packages/react-native-compatibility-check/BUILD.bazel create mode 100644 packages/react-native-macos-init/BUILD.bazel create mode 100644 packages/react-native-popup-menu-android/BUILD.bazel create mode 100644 packages/react-native-test-library/BUILD.bazel create mode 100644 packages/react-native/BUILD.bazel create mode 100644 packages/rn-tester/bazel/bundle.js create mode 100644 packages/typescript-config/BUILD.bazel create mode 100644 packages/virtualized-lists/BUILD.bazel create mode 100644 private/cxx-public-api/BUILD.bazel create mode 100644 private/eslint-plugin-monorepo/BUILD.bazel create mode 100644 private/monorepo-tests/BUILD.bazel create mode 100644 private/react-native-bots/BUILD.bazel create mode 100644 private/react-native-codegen-typescript-test/BUILD.bazel create mode 100644 private/react-native-fantom/BUILD.bazel diff --git a/docs/bazel.md b/docs/bazel.md index a4e0c5cdc438..35566603e22a 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -89,18 +89,45 @@ BYONM remains a viable fallback. rules_js, and a Node program that `require`s the npm dep runs green. * On the **real monorepo** `yarn.lock`, `npm_translate_lock` parses the fork-generated lock and **fetches all 1333 packages** successfully. - -## What's next (WIP, scaffolded) - -* **First-party workspace linking**: `//:node_modules` (link *all* packages) needs a - `BUILD.bazel` in each of the ~33 workspace packages (the standard rules_js monorepo - adoption step). Until then the Metro bundle target is tagged `manual`. -* **Metro bundle**: `//packages/rn-tester:rntester_macos_jsbundle` via the `metro_bundle` - macro (`tools/bazel/js/metro.bzl`) — a thin `js_run_binary` wrapper around the React - Native CLI `bundle` command (we drive Metro, we don't reimplement it). +* **First-party workspace linking**: every workspace package now exposes a `:pkg` target + (`npm_package`) so rules_js can link it. `bazel build //packages/react-native:pkg` + builds; rn-tester's `node_modules` links `react-native-macos` (the package the repo + consumes as `react-native`). +* **rn-tester's macOS JS bundle builds** (outside Bazel, proving the JS is bundleable): + after building the codegen lib, `react-native bundle --platform macos --entry-file + js/RNTesterApp.macos.js` produces a ~7 MB `RNTesterApp.macos.jsbundle` + 50 assets. + +## End-to-end RN-Tester: status & remaining work + +Two concrete blockers separate the current state from a running RNTester macOS app: + +1. **The macOS app is blocked by an external artifact gap.** `scripts/ios-prebuild.js` + cannot produce the XCFrameworks because the **Hermes nightly tarball 404s** + (`react-native-artifacts/0.87.0-nightly-…-hermes-ios-debug.tar.gz`). Without + `hermes.xcframework` / `React.xcframework` / `ReactNativeDependencies.xcframework`, + `macos_application` can't link. The app target is fully scaffolded and will build once + those XCFrameworks are available (e.g. a valid nightly, or a from-source Bazel build — + see the roadmap). + +2. **The hermetic Bazel Metro bundle needs a dependency-closure step.** Two prerequisites: + * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it): + `(cd packages/react-native-codegen && yarn build)`. + * rules_js uses a **strict, non-hoisted** `node_modules`. Metro's tooling (`metro`, + `@react-native/metro-config`, `@react-native/metro-babel-transformer`) are + transitive/root devDeps, so they are not resolvable from rn-tester's `node_modules`. + To make `//packages/rn-tester:rntester_macos_jsbundle` green, declare that tooling as + deps of the bundler (e.g. add them to rn-tester's `package.json` and regenerate the + Berry `yarn.lock`) so rules_js links the full closure. The bundle itself runs via + `packages/rn-tester/bazel/bundle.js` (Metro's API, with the + `react-native → react-native-macos` alias and a sandbox-safe config). + +## What's next (WIP, scaffolded — all `manual`) + +* **Metro bundle**: `//packages/rn-tester:rntester_macos_jsbundle` (`js_run_binary` around + `bazel/bundle.js`). Blocked only on the closure step above. * **macOS app**: `//packages/rn-tester:RNTesterMacBazel` (`macos_application`) links the imported XCFrameworks and embeds the Metro bundle as an app resource, reusing - rn-tester's existing `AppDelegate.mm`/`main.m`. + rn-tester's existing `AppDelegate.mm`/`main.m`. Blocked on the XCFrameworks (Hermes 404). ## Apple: prebuilt XCFrameworks (swappable seam) diff --git a/packages/assets/BUILD.bazel b/packages/assets/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/assets/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/babel-plugin-codegen/BUILD.bazel b/packages/babel-plugin-codegen/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/babel-plugin-codegen/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/community-cli-plugin/BUILD.bazel b/packages/community-cli-plugin/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/community-cli-plugin/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/core-cli-utils/BUILD.bazel b/packages/core-cli-utils/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/core-cli-utils/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/debugger-frontend/BUILD.bazel b/packages/debugger-frontend/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/debugger-frontend/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/debugger-shell/BUILD.bazel b/packages/debugger-shell/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/debugger-shell/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/dev-middleware/BUILD.bazel b/packages/dev-middleware/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/dev-middleware/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/eslint-config-react-native/BUILD.bazel b/packages/eslint-config-react-native/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/eslint-config-react-native/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/eslint-plugin-react-native/BUILD.bazel b/packages/eslint-plugin-react-native/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/eslint-plugin-react-native/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/eslint-plugin-specs/BUILD.bazel b/packages/eslint-plugin-specs/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/eslint-plugin-specs/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/gradle-plugin/BUILD.bazel b/packages/gradle-plugin/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/gradle-plugin/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/metro-config/BUILD.bazel b/packages/metro-config/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/metro-config/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/new-app-screen/BUILD.bazel b/packages/new-app-screen/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/new-app-screen/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/normalize-color/BUILD.bazel b/packages/normalize-color/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/normalize-color/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/polyfills/BUILD.bazel b/packages/polyfills/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/polyfills/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-babel-preset/BUILD.bazel b/packages/react-native-babel-preset/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-babel-preset/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-babel-transformer/BUILD.bazel b/packages/react-native-babel-transformer/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-babel-transformer/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-codegen/BUILD.bazel b/packages/react-native-codegen/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-codegen/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-compatibility-check/BUILD.bazel b/packages/react-native-compatibility-check/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-compatibility-check/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-macos-init/BUILD.bazel b/packages/react-native-macos-init/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-macos-init/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-popup-menu-android/BUILD.bazel b/packages/react-native-popup-menu-android/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-popup-menu-android/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native-test-library/BUILD.bazel b/packages/react-native-test-library/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/react-native-test-library/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel new file mode 100644 index 000000000000..d2b420469b0a --- /dev/null +++ b/packages/react-native/BUILD.bazel @@ -0,0 +1,31 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + "React/**", + "ReactApple/**", + "ReactCommon/**", + "ReactAndroid/**", + "sdks/**", + "third-party/**", + "ReactCxxPlatform/**", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index ad638dbddd9a..e594d85b24a0 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -1,20 +1,26 @@ # React Native macOS — Bazel vertical slice (draft / experimental) # -# This BUILD file wires the end-to-end slice: bundle rn-tester's JS with Metro and -# embed it into a macOS app that links the prebuilt React Native XCFrameworks. -# -# The targets are tagged `manual` (kept out of `//...`) because they depend on: -# * first-party workspace packages having BUILD files (so rules_js can link the -# react-native CLI for Metro), and -# * the prebuilt XCFrameworks produced by scripts/ios-prebuild.js. -# See packages/rn-tester/bazel/README.md and docs/bazel.md. +# Status (see docs/bazel.md): +# * The rules_js Berry fork is GREEN (deps resolve/link from the Berry yarn.lock). +# * First-party workspace packages now expose `:pkg` targets so rules_js can link +# them; `bazel build //packages/react-native:pkg` builds. +# * The Metro bundle + macOS app targets below are tagged `manual` (WIP): +# - the Metro bundle needs the RN `react-native`->`react-native-macos` alias and a +# sandbox-safe config (bazel/bundle.js), @react-native/codegen `lib` built, and the +# full strict-deps closure assembled (rules_js does not hoist like Yarn); +# - the macOS app needs the prebuilt XCFrameworks, which currently cannot be produced +# here because the Hermes nightly tarball 404s (see docs/bazel.md). -load("//tools/bazel/js:metro.bzl", "metro_bundle") +load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_run_binary") +load("@npm//:defs.bzl", "npm_link_all_packages") load("//tools/bazel/apple:xcframeworks.bzl", "rn_imported_xcframeworks") load("@rules_apple//apple:macos.bzl", "macos_application") package(default_visibility = ["//visibility:private"]) +# rn-tester's node_modules, linked by rules_js from the Berry yarn.lock. +npm_link_all_packages(name = "node_modules") + # All rn-tester JavaScript that Metro may pull into the bundle. filegroup( name = "js_srcs", @@ -23,18 +29,32 @@ filegroup( allow_empty = False, ) + [ "metro.config.js", + "react-native.config.js", "package.json", ], ) +# NOTE: rules_js uses a strict, non-hoisted node_modules. Metro's bundling tooling +# (metro, @react-native/metro-config, @react-native/metro-babel-transformer) are +# transitive/root devDeps and are therefore NOT resolvable from rn-tester's node_modules. +# To make this green, declare them as deps here (e.g. add them to rn-tester's package.json +# and regenerate the Berry yarn.lock) so rules_js links the full closure. See docs/bazel.md. +# The bundle runs via bazel/bundle.js (Metro's API) with the react-native alias applied. +js_binary( + name = "bundler", + data = [":node_modules"], + entry_point = "bazel/bundle.js", + tags = ["manual"], +) + # 1. JS bundle (Metro). Entry is the macOS variant of the rn-tester app. -metro_bundle( +js_run_binary( name = "rntester_macos_jsbundle", srcs = [":js_srcs"], - config = "metro.config.js", - entry_point = "js/RNTesterApp.macos.js", - platform = "macos", + outs = ["RNTesterApp.macos.jsbundle"], + env = {"BUNDLE_OUT": "RNTesterApp.macos.jsbundle"}, tags = ["manual"], + tool = ":bundler", ) # 2. Prebuilt native code as importable XCFrameworks (from ios-prebuild). diff --git a/packages/rn-tester/bazel/bundle.js b/packages/rn-tester/bazel/bundle.js new file mode 100644 index 000000000000..15ae0511b457 --- /dev/null +++ b/packages/rn-tester/bazel/bundle.js @@ -0,0 +1,60 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @noflow + */ + +// Bazel entry point for bundling rn-tester's macOS JS with Metro. +// +// Runs under a rules_js `js_run_binary` with node_modules linked by Bazel. Unlike +// the source-tree metro.config.js (which uses source-relative watchFolders), this +// resolves everything from the Bazel-linked node_modules and aliases the +// `react-native` import to the `react-native-macos` package (the repo's convention). + +'use strict'; + +const path = require('path'); +const Metro = require('metro'); +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); + +async function main() { + const projectRoot = process.env.RN_TESTER_ROOT + ? path.resolve(process.env.RN_TESTER_ROOT) + : process.cwd(); + const out = process.env.BUNDLE_OUT || 'RNTesterApp.macos.jsbundle'; + const assetsDest = process.env.ASSETS_DEST || undefined; + + // react-native-macos is published/consumed as `react-native`. + const reactNativePath = path.dirname( + require.resolve('react-native-macos/package.json'), + ); + + const baseConfig = await getDefaultConfig(projectRoot); + const config = mergeConfig(baseConfig, { + projectRoot, + watchFolders: [reactNativePath, path.dirname(reactNativePath)], + resolver: { + extraNodeModules: {'react-native': reactNativePath}, + platforms: ['ios', 'macos', 'android'], + }, + }); + + await Metro.runBuild(config, { + entry: 'js/RNTesterApp.macos.js', + platform: 'macos', + dev: false, + minify: true, + out, + assets: Boolean(assetsDest), + assetsDest, + }); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/packages/typescript-config/BUILD.bazel b/packages/typescript-config/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/typescript-config/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/packages/virtualized-lists/BUILD.bazel b/packages/virtualized-lists/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/packages/virtualized-lists/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/private/cxx-public-api/BUILD.bazel b/private/cxx-public-api/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/private/cxx-public-api/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/private/eslint-plugin-monorepo/BUILD.bazel b/private/eslint-plugin-monorepo/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/private/eslint-plugin-monorepo/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/private/monorepo-tests/BUILD.bazel b/private/monorepo-tests/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/private/monorepo-tests/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/private/react-native-bots/BUILD.bazel b/private/react-native-bots/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/private/react-native-bots/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/private/react-native-codegen-typescript-test/BUILD.bazel b/private/react-native-codegen-typescript-test/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/private/react-native-codegen-typescript-test/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) diff --git a/private/react-native-fantom/BUILD.bazel b/private/react-native-fantom/BUILD.bazel new file mode 100644 index 000000000000..23f9dc4f3149 --- /dev/null +++ b/private/react-native-fantom/BUILD.bazel @@ -0,0 +1,24 @@ +# Auto-generated first-party package target for rules_js linking. +# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can +# link it into node_modules (needed to bundle first-party JS with Metro). +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages() + +npm_package( + name = "pkg", + srcs = glob( + ["**/*"], + exclude = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", + ], + allow_empty = True, + ), + visibility = ["//visibility:public"], +) From 97e950141fa0bd2d8d36aa9dae24559557feedec Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 15:33:47 -0700 Subject: [PATCH 03/24] docs: correct Hermes/XCFramework blocker diagnosis (Xcode/CMake, not a 404) The earlier note blamed a "Hermes nightly 404". That was caused by forcing HERMES_VERSION=nightly, which bypasses react-native-macos's Hermes version-resolution patches (scripts/ios-prebuild/microsoft-hermes.js). Invoked correctly, ios-prebuild resolves the right Hermes (merge-base commit on main / published artifact on release branches). Building it from source in this environment fails for toolchain reasons: default CMake is 4.x (use cmake@3.26.4), and Xcode 26 / AppleClang 21 trips LLVM's CheckAtomic. The prebuild CI pins Xcode 16.2/16.1, which is what builds these XCFrameworks. Not a fork gap. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 29 ++++++++++++++++++++++------- packages/rn-tester/BUILD.bazel | 5 +++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/bazel.md b/docs/bazel.md index 35566603e22a..4e1e2bee95c6 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -101,13 +101,28 @@ BYONM remains a viable fallback. Two concrete blockers separate the current state from a running RNTester macOS app: -1. **The macOS app is blocked by an external artifact gap.** `scripts/ios-prebuild.js` - cannot produce the XCFrameworks because the **Hermes nightly tarball 404s** - (`react-native-artifacts/0.87.0-nightly-…-hermes-ios-debug.tar.gz`). Without - `hermes.xcframework` / `React.xcframework` / `ReactNativeDependencies.xcframework`, - `macos_application` can't link. The app target is fully scaffolded and will build once - those XCFrameworks are available (e.g. a valid nightly, or a from-source Bazel build — - see the roadmap). +1. **The macOS app needs the prebuilt XCFrameworks, which can't be produced *in this + environment* because the local Xcode is too new.** This is a toolchain/environment + issue, **not** a fork gap — react-native-macos already carries the patches that resolve + the correct Hermes for the branch (`scripts/ios-prebuild/microsoft-hermes.js`): + * On a **release branch**, `findMatchingHermesVersion` maps to the upstream RN version in + `peerDependencies` and ios-prebuild **downloads** a published Hermes artifact. + * On **main (`1000.0.0`)**, it returns `null` and **builds Hermes from source** at the + Hermes commit at the merge-base with facebook/react-native (`hermesCommitAtMergeBase`). + + Building that from source here fails for two environment reasons: + * the default Homebrew CMake is **4.x**, too new for Hermes (use the installed + `cmake@3.26.4`); and, after that, + * **Xcode 26 / AppleClang 21** trips LLVM's `CheckAtomic` ("Host compiler appears to + require libatomic, but cannot find it"). The prebuild CI pins **Xcode 16.2 / 16.1** + (see `.github/workflows/prebuild-ios-core.yml`), which is what actually builds these + XCFrameworks. No Xcode 16.x is installed on this machine. + + Net: on CI (Xcode 16.2) — or from a release branch that downloads prebuilt Hermes — the + XCFrameworks build and the `macos_application` links. Locally with only Xcode 26, the + from-source Hermes build can't complete. (An earlier revision of this doc wrongly blamed + a "Hermes nightly 404"; that was caused by forcing `HERMES_VERSION=nightly`, which + bypasses the macOS version-resolution patches — don't set that env var.) 2. **The hermetic Bazel Metro bundle needs a dependency-closure step.** Two prerequisites: * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it): diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index e594d85b24a0..dc66b0517354 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -8,8 +8,9 @@ # - the Metro bundle needs the RN `react-native`->`react-native-macos` alias and a # sandbox-safe config (bazel/bundle.js), @react-native/codegen `lib` built, and the # full strict-deps closure assembled (rules_js does not hoist like Yarn); -# - the macOS app needs the prebuilt XCFrameworks, which currently cannot be produced -# here because the Hermes nightly tarball 404s (see docs/bazel.md). +# - the macOS app needs the prebuilt XCFrameworks; ios-prebuild resolves the correct +# Hermes (macOS patches) but building it from source needs Xcode 16.x (CI-pinned) -- +# the local Xcode 26 trips LLVM CheckAtomic. See docs/bazel.md. load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_run_binary") load("@npm//:defs.bzl", "npm_link_all_packages") From 5fe1590e4690cf0644cb61bf24d98b9a591142c2 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 15:49:14 -0700 Subject: [PATCH 04/24] Fix Hermes host build on Xcode 26 (force macOS target for hermesc) On Xcode 26 / AppleClang 21, clang honors the *_DEPLOYMENT_TARGET environment variables and mis-targets the *native* host hermesc build to visionOS when XROS_DEPLOYMENT_TARGET is set in the environment (XROS takes precedence even if MACOSX_DEPLOYMENT_TARGET is also set). ios-prebuild sets XROS_DEPLOYMENT_TARGET for the cross-platform target builds and it leaks into build_host_hermesc, producing: cc: warning: using sysroot for 'MacOSX' but targeting 'XR' [-Wincompatible-sysroot] error: 'pthread_setname_np' is unavailable: not available on visionOS which fails llvh's CheckAtomic ("Host compiler appears to require libatomic, but cannot find it") and aborts the from-source Hermes build. Build the native host tools in a subshell that unsets the mobile IOS/XROS/TVOS_DEPLOYMENT_TARGET vars and sets MACOSX_DEPLOYMENT_TARGET, so clang targets macOS. Verified: HAVE_CXX_ATOMICS_WITHOUT_LIB now succeeds and hermesc compiles under Xcode 26. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../hermes-engine/utils/build-apple-framework.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh b/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh index ee71c715624a..37b72d04ad36 100755 --- a/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh +++ b/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh @@ -61,10 +61,21 @@ function get_mac_deployment_target { function build_host_hermesc { echo "Building hermesc" pushd "$HERMES_PATH" > /dev/null || exit 1 - cmake -S . -B build_host_hermesc -DJSI_DIR="$JSI_PATH" - cmake --build ./build_host_hermesc --target hermesc -j "${NUM_CORES}" + # [macOS] The host hermesc tools are always native macOS. On Xcode 26+, clang honors + # the *_DEPLOYMENT_TARGET environment variables and will mis-target this native build + # to visionOS when XROS_DEPLOYMENT_TARGET (or IOS/TVOS) is set in the environment + # (XROS takes precedence even if MACOSX_DEPLOYMENT_TARGET is also set), which breaks + # availability/atomics checks ("using sysroot for 'MacOSX' but targeting 'XR'"). Build + # the host tools in a subshell that forces a macOS target. + ( + unset IOS_DEPLOYMENT_TARGET XROS_DEPLOYMENT_TARGET TVOS_DEPLOYMENT_TARGET + export MACOSX_DEPLOYMENT_TARGET="${MAC_DEPLOYMENT_TARGET:-$(get_mac_deployment_target)}" + cmake -S . -B build_host_hermesc -DJSI_DIR="$JSI_PATH" + cmake --build ./build_host_hermesc --target hermesc -j "${NUM_CORES}" + ) popd > /dev/null || exit 1 } +# macOS] # Utility function to configure an Apple framework function configure_apple_framework { From 6248c78c1114149d48c1d57ec573e66e3855683c Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 15:52:25 -0700 Subject: [PATCH 05/24] docs: record the Xcode-26 Hermes host-build fix and status Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/bazel.md b/docs/bazel.md index 4e1e2bee95c6..07b8fcbd591f 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -101,28 +101,26 @@ BYONM remains a viable fallback. Two concrete blockers separate the current state from a running RNTester macOS app: -1. **The macOS app needs the prebuilt XCFrameworks, which can't be produced *in this - environment* because the local Xcode is too new.** This is a toolchain/environment - issue, **not** a fork gap — react-native-macos already carries the patches that resolve - the correct Hermes for the branch (`scripts/ios-prebuild/microsoft-hermes.js`): - * On a **release branch**, `findMatchingHermesVersion` maps to the upstream RN version in - `peerDependencies` and ios-prebuild **downloads** a published Hermes artifact. - * On **main (`1000.0.0`)**, it returns `null` and **builds Hermes from source** at the - Hermes commit at the merge-base with facebook/react-native (`hermesCommitAtMergeBase`). - - Building that from source here fails for two environment reasons: - * the default Homebrew CMake is **4.x**, too new for Hermes (use the installed - `cmake@3.26.4`); and, after that, - * **Xcode 26 / AppleClang 21** trips LLVM's `CheckAtomic` ("Host compiler appears to - require libatomic, but cannot find it"). The prebuild CI pins **Xcode 16.2 / 16.1** - (see `.github/workflows/prebuild-ios-core.yml`), which is what actually builds these - XCFrameworks. No Xcode 16.x is installed on this machine. - - Net: on CI (Xcode 16.2) — or from a release branch that downloads prebuilt Hermes — the - XCFrameworks build and the `macos_application` links. Locally with only Xcode 26, the - from-source Hermes build can't complete. (An earlier revision of this doc wrongly blamed - a "Hermes nightly 404"; that was caused by forcing `HERMES_VERSION=nightly`, which - bypasses the macOS version-resolution patches — don't set that env var.) +1. **The macOS app needs the prebuilt XCFrameworks. The Xcode-26 Hermes build blocker has + been fixed here; the remaining cost is the (long) native build itself.** This was never a + fork gap — react-native-macos already carries the Hermes version-resolution patches + (`scripts/ios-prebuild/microsoft-hermes.js`): a release branch downloads a published + Hermes, and `main` (`1000.0.0`) builds Hermes from source at the Hermes commit at the + merge-base with facebook/react-native. + + Building from source on **Xcode 26** originally failed because clang honors + `*_DEPLOYMENT_TARGET` env vars: `ios-prebuild` sets `XROS_DEPLOYMENT_TARGET` for the + cross-platform builds and it leaked into the **native** `build_host_hermesc` step, so + Xcode 26's clang mis-targeted the host tools to **visionOS** ("using sysroot for + 'MacOSX' but targeting 'XR'"), failing llvh's `CheckAtomic`. Fixed in + `sdks/hermes-engine/utils/build-apple-framework.sh` by building the host tools with the + mobile deployment-target vars unset and `MACOSX_DEPLOYMENT_TARGET` set — verified: + `HAVE_CXX_ATOMICS_WITHOUT_LIB` now succeeds and Hermes compiles under Xcode 26. + + Two environment notes remain: use **CMake 3.x** (Hermes doesn't configure under the + Homebrew-default CMake 4.x; `cmake@3.26.4` works), and the full from-source build of + Hermes + ReactNativeDependencies + React across all Apple slices is long. Once those + XCFrameworks exist, the `macos_application` links them on Xcode 26. 2. **The hermetic Bazel Metro bundle needs a dependency-closure step.** Two prerequisites: * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it): From 3bbbcffe09876be4e40fc140da82409a9aa6a1c8 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 16:13:47 -0700 Subject: [PATCH 06/24] Allow building a subset of Hermes Apple platforms (HERMES_APPLE_PLATFORMS) Adds an opt-in HERMES_APPLE_PLATFORMS env var to build only selected Apple slices into hermes.xcframework (default: all, unchanged). Enables macOS-only from-source Hermes builds, which is useful on Xcode 26+ (the upstream Hermes Mac Catalyst target triple is rejected by the newer clang) and greatly speeds up macOS-only iteration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../utils/build-ios-framework.sh | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh b/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh index c1a6a4aa7387..80c35b1a70ed 100755 --- a/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh +++ b/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh @@ -57,7 +57,8 @@ function build_framework { # group the frameworks together to create a universal framework function build_universal_framework { if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then - create_universal_framework "macosx" "iphoneos" "iphonesimulator" "catalyst" "xros" "xrsimulator" "appletvos" "appletvsimulator" # [macOS] + # shellcheck disable=SC2086 + create_universal_framework $HERMES_APPLE_PLATFORMS # [macOS] else echo "Skipping; Clean \"destroot\" to rebuild". fi @@ -67,14 +68,11 @@ function build_universal_framework { # this is used to preserve backward compatibility function create_framework { if [ ! -d destroot/Library/Frameworks/universal/hermes.xcframework ]; then - build_framework "macosx" # [macOS] - build_framework "iphoneos" - build_framework "iphonesimulator" - build_framework "appletvos" - build_framework "appletvsimulator" - build_framework "catalyst" - build_framework "xros" - build_framework "xrsimulator" + # [macOS] Build only the requested Apple platforms (defaults to all). + for _hermes_platform in $HERMES_APPLE_PLATFORMS; do + build_framework "$_hermes_platform" + done + # macOS] build_universal_framework else echo "Skipping; Clean \"destroot\" to rebuild". @@ -86,6 +84,14 @@ CURR_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" # shellcheck source=xplat/js/react-native-github/sdks/hermes-engine/utils/build-apple-framework.sh . "${CURR_SCRIPT_DIR}/build-apple-framework.sh" +# [macOS] Apple platforms (slices) to build into hermes.xcframework. Defaults to all. +# Override with the HERMES_APPLE_PLATFORMS env var (space-separated) to build a subset, +# e.g. HERMES_APPLE_PLATFORMS="macosx" for a macOS-only build. Useful on Xcode 26+, where +# the upstream Hermes Mac Catalyst target triple is rejected by the newer clang, and to +# speed up macOS-only iteration. +HERMES_APPLE_PLATFORMS="${HERMES_APPLE_PLATFORMS:-macosx iphoneos iphonesimulator catalyst xros xrsimulator appletvos appletvsimulator}" +# macOS] + if [[ -z $1 ]]; then create_framework elif [[ $1 == "build_framework" ]]; then From 85222de875cb2f37336282f7d5cba11d18ef0e47 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 16:22:39 -0700 Subject: [PATCH 07/24] docs: react-native-macos native prebuild now builds on Xcode 26 With the Hermes host-build fix + HERMES_APPLE_PLATFORMS subset + CMake 3.x, verified on Xcode 26.4 that ios-prebuild produces hermes.xcframework (from source), ReactNativeDependencies.xcframework (downloaded), and React.xcframework (BUILD SUCCEEDED). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/docs/bazel.md b/docs/bazel.md index 07b8fcbd591f..d7a99bd4f05c 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -101,26 +101,34 @@ BYONM remains a viable fallback. Two concrete blockers separate the current state from a running RNTester macOS app: -1. **The macOS app needs the prebuilt XCFrameworks. The Xcode-26 Hermes build blocker has - been fixed here; the remaining cost is the (long) native build itself.** This was never a - fork gap — react-native-macos already carries the Hermes version-resolution patches +1. **The macOS app needs the prebuilt XCFrameworks. These now build on Xcode 26 with the + fixes in this branch** (verified end to end). This was never a fork gap — + react-native-macos already carries the Hermes version-resolution patches (`scripts/ios-prebuild/microsoft-hermes.js`): a release branch downloads a published - Hermes, and `main` (`1000.0.0`) builds Hermes from source at the Hermes commit at the - merge-base with facebook/react-native. - - Building from source on **Xcode 26** originally failed because clang honors - `*_DEPLOYMENT_TARGET` env vars: `ios-prebuild` sets `XROS_DEPLOYMENT_TARGET` for the - cross-platform builds and it leaked into the **native** `build_host_hermesc` step, so - Xcode 26's clang mis-targeted the host tools to **visionOS** ("using sysroot for - 'MacOSX' but targeting 'XR'"), failing llvh's `CheckAtomic`. Fixed in - `sdks/hermes-engine/utils/build-apple-framework.sh` by building the host tools with the - mobile deployment-target vars unset and `MACOSX_DEPLOYMENT_TARGET` set — verified: - `HAVE_CXX_ATOMICS_WITHOUT_LIB` now succeeds and Hermes compiles under Xcode 26. - - Two environment notes remain: use **CMake 3.x** (Hermes doesn't configure under the - Homebrew-default CMake 4.x; `cmake@3.26.4` works), and the full from-source build of - Hermes + ReactNativeDependencies + React across all Apple slices is long. Once those - XCFrameworks exist, the `macos_application` links them on Xcode 26. + Hermes; `main` (`1000.0.0`) builds Hermes from source at the merge-base commit. + + Getting the from-source build working on **Xcode 26** required two fixes (both in this + branch) plus one environment note: + * **Host `hermesc` mis-targeted to visionOS.** `ios-prebuild` sets + `XROS_DEPLOYMENT_TARGET` for the cross-platform builds and it leaked into the *native* + `build_host_hermesc`; Xcode 26's clang honors it and built the host tools for visionOS + ("using sysroot for 'MacOSX' but targeting 'XR'"), failing llvh's `CheckAtomic`. Fixed + in `sdks/hermes-engine/utils/build-apple-framework.sh` (force a macOS target for the + host tools). + * **Upstream Hermes Mac Catalyst triple.** Hermes hardcodes an invalid universal + Catalyst triple (`-target x86_64-arm64-apple-ios…-macabi`) that Xcode 26's clang + rejects. This is a Hermes-upstream issue and Catalyst isn't needed for a macOS app, so + `build-ios-framework.sh` now accepts `HERMES_APPLE_PLATFORMS` to build a subset (e.g. + `macosx`). + * Use **CMake 3.x** (`cmake@3.26.4`); Hermes doesn't configure under the Homebrew-default + CMake 4.x. + + Verified on Xcode 26.4 with `HERMES_APPLE_PLATFORMS=macosx` and `cmake@3.26.4`: + `ios-prebuild.js -s/-b/-c` produces all three XCFrameworks — + `hermes.xcframework` (from source), `ReactNativeDependencies.xcframework` (downloaded + 0.86.0), and `React.xcframework` (`** BUILD SUCCEEDED **`, macOS slice). What remains is + wiring those into the Bazel `macos_application` (rules_apple on Xcode 26) and embedding + the JS bundle. 2. **The hermetic Bazel Metro bundle needs a dependency-closure step.** Two prerequisites: * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it): From 7943e122f85a20bc92d356494c3695d7d08f2a9a Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 16:27:56 -0700 Subject: [PATCH 08/24] Bazel: repo rule to import the prebuilt XCFrameworks (builds on Xcode 26) Adds tools/bazel/apple/prebuilt_xcframeworks.bzl: a repository rule + module extension that symlinks the SPM-prebuilt React/ReactNativeDependencies/hermes XCFrameworks (from packages/react-native/.build and third-party/) into a Bazel repo and exposes apple_*_xcframework_import targets. Verified on Xcode 26.4: bazel build @rn_prebuilt_xcframeworks//:React //:hermes //:ReactNativeDependencies builds. Wires the rn-tester macOS app host deps to these targets. Note: rn-tester's real AppDelegate needs rn-tester-specific native modules + codegen not present in the XCFrameworks, so a green app needs those built or a minimal RN host. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- MODULE.bazel | 5 ++ packages/rn-tester/BUILD.bazel | 16 ++--- tools/bazel/apple/prebuilt_xcframeworks.bzl | 66 +++++++++++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 tools/bazel/apple/prebuilt_xcframeworks.bzl diff --git a/MODULE.bazel b/MODULE.bazel index 803e86df0fb3..453d3a1ec461 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -60,3 +60,8 @@ bazel_dep(name = "rules_swift", version = "3.6.1") bazel_dep(name = "apple_support", version = "2.7.0") bazel_dep(name = "rules_cc", version = "0.2.17") bazel_dep(name = "platforms", version = "1.1.0") + +# Expose the SPM-prebuilt React Native XCFrameworks (built by scripts/ios-prebuild.js) +# to Bazel so the macOS app slice can link them. +rn_prebuilt = use_extension("//tools/bazel/apple:prebuilt_xcframeworks.bzl", "rn_prebuilt_xcframeworks_extension") +use_repo(rn_prebuilt, "rn_prebuilt_xcframeworks") diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index dc66b0517354..38710dfef71e 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -14,7 +14,6 @@ load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_run_binary") load("@npm//:defs.bzl", "npm_link_all_packages") -load("//tools/bazel/apple:xcframeworks.bzl", "rn_imported_xcframeworks") load("@rules_apple//apple:macos.bzl", "macos_application") package(default_visibility = ["//visibility:private"]) @@ -58,10 +57,11 @@ js_run_binary( tool = ":bundler", ) -# 2. Prebuilt native code as importable XCFrameworks (from ios-prebuild). -rn_imported_xcframeworks() - -# 3. App host — reuse rn-tester's existing AppDelegate + main. +# 3. App host. NOTE: rn-tester's real AppDelegate.mm pulls in rn-tester-specific native +# modules + codegen (NativeCxxModuleExample, RNTMyNativeViewComponentView, +# ReactAppDependencyProvider) that are NOT in the prebuilt XCFrameworks. A green app +# therefore needs either those built too, or a minimal RN macOS host. The imported +# XCFrameworks below DO build on Xcode 26 (bazel build @rn_prebuilt_xcframeworks//:React). objc_library( name = "rntester_macos_host", srcs = [ @@ -71,9 +71,9 @@ objc_library( hdrs = ["RNTester/AppDelegate.h"], tags = ["manual"], deps = [ - ":React", - ":ReactNativeDependencies", - ":hermes", + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies", + "@rn_prebuilt_xcframeworks//:hermes", ], ) diff --git a/tools/bazel/apple/prebuilt_xcframeworks.bzl b/tools/bazel/apple/prebuilt_xcframeworks.bzl new file mode 100644 index 000000000000..d415d7249871 --- /dev/null +++ b/tools/bazel/apple/prebuilt_xcframeworks.bzl @@ -0,0 +1,66 @@ +"""Expose the SPM-prebuilt React Native XCFrameworks to Bazel. + +The XCFrameworks produced by `scripts/ios-prebuild.js` live under +`packages/react-native/.build` and `third-party/` (build outputs, gitignored, and in +`.bazelignore`). This repository rule symlinks them into an external repo and exposes +`apple_*_xcframework_import` targets so the Bazel `macos_application` can link them. + +If the XCFrameworks are missing (e.g. a clean checkout / CI before the prebuild), the +generated targets fail with an actionable message instead of breaking analysis of the +whole repo. +""" + +_REL_PATHS = { + "React": "packages/react-native/.build/output/xcframeworks/Debug/React.xcframework", + "ReactNativeDependencies": "packages/react-native/third-party/ReactNativeDependencies.xcframework", + "hermes": "packages/react-native/.build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", +} + +# hermes ships as a dynamic framework; React + deps are static. +_DYNAMIC = {"hermes": True} + +def _prebuilt_xcframeworks_impl(rctx): + root = str(rctx.workspace_root) + lines = [ + 'load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import", "apple_static_xcframework_import")', + 'package(default_visibility = ["//visibility:public"])', + "", + ] + missing = [] + for name, rel in _REL_PATHS.items(): + src = "{}/{}".format(root, rel) + if not rctx.path(src).exists: + missing.append(rel) + continue + rctx.symlink(src, name + ".xcframework") + rule = "apple_dynamic_xcframework_import" if _DYNAMIC.get(name) else "apple_static_xcframework_import" + lines.append('{rule}(name = "{name}", xcframework_imports = glob(["{name}.xcframework/**"]))'.format( + rule = rule, + name = name, + )) + + if missing: + # Emit a target that fails at build time with guidance, rather than failing analysis. + msg = ("Prebuilt XCFrameworks not found: {}. Build them first with " + + "`cd packages/react-native && HERMES_APPLE_PLATFORMS=macosx node scripts/ios-prebuild.js -s -f Debug " + + "&& node scripts/ios-prebuild.js -b -f Debug -p macos && node scripts/ios-prebuild.js -c -f Debug` " + + "(use cmake@3.x on Xcode 26).").format(", ".join(missing)) + lines = [ + 'package(default_visibility = ["//visibility:public"])', + 'genrule(name = "_missing", outs = ["missing.txt"], cmd = "echo \'{}\' >&2; exit 1")'.format(msg), + ] + for name in _REL_PATHS: + lines.append('alias(name = "{name}", actual = ":_missing")'.format(name = name)) + + rctx.file("BUILD.bazel", "\n".join(lines) + "\n") + +prebuilt_xcframeworks = repository_rule( + implementation = _prebuilt_xcframeworks_impl, + doc = "Symlinks the SPM-prebuilt React Native XCFrameworks into a Bazel repo.", + local = True, +) + +def _extension_impl(_module_ctx): + prebuilt_xcframeworks(name = "rn_prebuilt_xcframeworks") + +rn_prebuilt_xcframeworks_extension = module_extension(implementation = _extension_impl) From 97d231d175cdc30a6d7b15c50d3eaa72f2d98fcf Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 23:55:53 -0700 Subject: [PATCH 09/24] Berry converter fix (resolutions + trailing space) and rn-tester JS bundle progress Converter correctness fix (tools/bazel/berry/berry_to_pnpm_lock.mjs): - Apply Yarn `resolutions` when resolving dependency descriptors. Berry rewrites matching descriptors (e.g. resolutions:{debug:">=3.1.0"} makes all `debug` resolve to debug@npm:>=3.1.0) while dependency entries keep their original ranges (debug: "npm:4"). Previously these edges were silently dropped (e.g. https-proxy-agent lost its `debug` dep), producing an incomplete node_modules graph. - Trim dependency ranges so a descriptor like "npm:^3.1.0 " (Yarn keeps insignificant trailing whitespace) matches the trimmed descriptor key. - Add a single-version fallback and report any dropped edges. Result: 0 dropped edges on the monorepo lock (previously silently dropping several). rn-tester JS bundle (Phase A, still WIP/manual): - Declare the bundler tooling closure on rn-tester (metro, @react-native/metro-config, @react-native/metro-babel-transformer, react) so rules_js's strict node_modules resolves it; regenerates yarn.lock. - bazel/bundle.js: resolve project root/entry/out via env, disable watchman + enable symlinks for the sandbox. Metro now loads and resolves the full first-party + third-party graph; remaining blockers are documented in docs/bazel.md (first-party packages must be consumed in built/dist form, and a Metro file-map vs Bazel file-layout issue). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/rn-tester/BUILD.bazel | 11 +++- packages/rn-tester/bazel/bundle.js | 18 ++++-- packages/rn-tester/package.json | 4 ++ tools/bazel/berry/berry_to_pnpm_lock.mjs | 77 +++++++++++++++++++++--- yarn.lock | 4 ++ 5 files changed, 98 insertions(+), 16 deletions(-) diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index 38710dfef71e..807892c3aeec 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -12,7 +12,7 @@ # Hermes (macOS patches) but building it from source needs Xcode 16.x (CI-pinned) -- # the local Xcode 26 trips LLVM CheckAtomic. See docs/bazel.md. -load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_run_binary") +load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_library", "js_run_binary") load("@npm//:defs.bzl", "npm_link_all_packages") load("@rules_apple//apple:macos.bzl", "macos_application") @@ -22,7 +22,7 @@ package(default_visibility = ["//visibility:private"]) npm_link_all_packages(name = "node_modules") # All rn-tester JavaScript that Metro may pull into the bundle. -filegroup( +js_library( name = "js_srcs", srcs = glob( ["js/**/*.js"], @@ -52,7 +52,12 @@ js_run_binary( name = "rntester_macos_jsbundle", srcs = [":js_srcs"], outs = ["RNTesterApp.macos.jsbundle"], - env = {"BUNDLE_OUT": "RNTesterApp.macos.jsbundle"}, + out_dirs = ["RNTesterApp_assets"], + env = { + "BUNDLE_OUT": "packages/rn-tester/RNTesterApp.macos.jsbundle", + "ASSETS_DEST": "packages/rn-tester/RNTesterApp_assets", + "RN_TESTER_ROOT": "packages/rn-tester", + }, tags = ["manual"], tool = ":bundler", ) diff --git a/packages/rn-tester/bazel/bundle.js b/packages/rn-tester/bazel/bundle.js index 15ae0511b457..4b548edc77bf 100644 --- a/packages/rn-tester/bazel/bundle.js +++ b/packages/rn-tester/bazel/bundle.js @@ -22,11 +22,12 @@ const Metro = require('metro'); const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); async function main() { - const projectRoot = process.env.RN_TESTER_ROOT - ? path.resolve(process.env.RN_TESTER_ROOT) - : process.cwd(); - const out = process.env.BUNDLE_OUT || 'RNTesterApp.macos.jsbundle'; - const assetsDest = process.env.ASSETS_DEST || undefined; + const projectRoot = path.resolve(process.env.RN_TESTER_ROOT || process.cwd()); + const out = path.resolve(process.env.BUNDLE_OUT || 'RNTesterApp.macos.jsbundle'); + const assetsDest = process.env.ASSETS_DEST + ? path.resolve(process.env.ASSETS_DEST) + : undefined; + const entryFile = path.join(projectRoot, 'js/RNTesterApp.macos.js'); // react-native-macos is published/consumed as `react-native`. const reactNativePath = path.dirname( @@ -40,11 +41,16 @@ async function main() { resolver: { extraNodeModules: {'react-native': reactNativePath}, platforms: ['ios', 'macos', 'android'], + // Watchman isn't available (or usable) inside the Bazel sandbox; use Metro's + // Node crawler so the file map is populated. rules_js exposes sources as symlinks, + // so the crawler must follow them. + useWatchman: false, + unstable_enableSymlinks: true, }, }); await Metro.runBuild(config, { - entry: 'js/RNTesterApp.macos.js', + entry: entryFile, platform: 'macos', dev: false, minify: true, diff --git a/packages/rn-tester/package.json b/packages/rn-tester/package.json index ea5c1d4a7069..2fa0a265d850 100644 --- a/packages/rn-tester/package.json +++ b/packages/rn-tester/package.json @@ -61,8 +61,12 @@ "@react-native-community/cli": "20.0.0", "@react-native-community/cli-platform-android": "20.0.0", "@react-native-community/cli-platform-ios": "20.0.0", + "@react-native/metro-babel-transformer": "workspace:*", + "@react-native/metro-config": "workspace:*", "commander": "^12.0.0", "listr2": "^6.4.1", + "metro": "^0.82.5", + "react": "19.1.0", "react-native-macos": "workspace:*", "rxjs": "npm:@react-native-community/rxjs@6.5.4-custom" } diff --git a/tools/bazel/berry/berry_to_pnpm_lock.mjs b/tools/bazel/berry/berry_to_pnpm_lock.mjs index bbc18240881c..6096898a83a3 100644 --- a/tools/bazel/berry/berry_to_pnpm_lock.mjs +++ b/tools/bazel/berry/berry_to_pnpm_lock.mjs @@ -23,6 +23,7 @@ */ import fs from 'node:fs'; +import path from 'node:path'; const REGISTRY = 'https://registry.npmjs.org'; @@ -166,14 +167,30 @@ function relPath(from, to) { // Conversion // --------------------------------------------------------------------------- -function convert(syml) { +function convert(syml, resolutions) { // Map every descriptor string -> its resolved entry. const descriptorToEntry = new Map(); // Canonical package key `ident@version` -> entry (npm packages only). const packageEntries = new Map(); + // ident -> [entries] (for single-version fallback resolution). + const nameToEntries = new Map(); // Workspace entries: importer path -> entry. const workspaceByPath = new Map(); - // ident@workspacePath (descriptor) resolution helper: descriptor -> workspace path. + + // Yarn `resolutions` overrides. Berry rewrites matching descriptors, but dependency + // entries keep their original ranges, so we must apply resolutions when resolving. + const globalRes = new Map(); // ident -> override value (e.g. ">=3.1.0") + const specificRes = new Map(); // "ident@range" -> override value + for (const [k, v] of Object.entries(resolutions || {})) { + const at = k.indexOf('@', k.startsWith('@') ? 1 : 0); + if (at > 0) { + specificRes.set(k, v); + } else { + globalRes.set(k, v); + } + } + const normalizeResValue = v => (/^[a-z]+:/.test(v) ? v : 'npm:' + v); + let droppedCount = 0; const entries = []; for (const [rawKey, value] of Object.entries(syml)) { @@ -219,14 +236,41 @@ function convert(syml) { } } } + if (entry.version || entry.kind === 'workspace') { + if (!nameToEntries.has(ident)) { + nameToEntries.set(ident, []); + } + nameToEntries.get(ident).push(entry); + } } // Resolve a `depName: rangeDescriptor` reference to either a snapshot key - // (`name@version`) or a `link:` for workspace deps. + // (`name@version`) or a `link:` for workspace deps. Handles Yarn + // `resolutions` overrides and falls back to a single resolved version. function resolveDep(fromPath, depName, rangeDescriptor) { - const descriptor = `${depName}@${rangeDescriptor}`; - const target = descriptorToEntry.get(descriptor); + // Yarn descriptors can carry insignificant trailing whitespace; normalize so a + // dependency range like "npm:^3.1.0 " matches the trimmed descriptor key. + rangeDescriptor = String(rangeDescriptor).trim(); + let target = descriptorToEntry.get(`${depName}@${rangeDescriptor}`); + if (!target) { + const specific = specificRes.get(`${depName}@${rangeDescriptor}`); + if (specific != null) { + target = descriptorToEntry.get(`${depName}@${normalizeResValue(specific)}`); + } + } + if (!target && globalRes.has(depName)) { + target = descriptorToEntry.get(`${depName}@${normalizeResValue(globalRes.get(depName))}`); + } if (!target) { + // Single-version fallback: if the package resolves to exactly one version in the + // lock (common once resolutions/dedup collapse ranges), use it. + const list = nameToEntries.get(depName); + if (list && list.length === 1) { + target = list[0]; + } + } + if (!target) { + droppedCount++; return null; } if (target.kind === 'workspace') { @@ -239,6 +283,7 @@ function convert(syml) { ident: target.ident, }; } + droppedCount++; return null; } @@ -326,7 +371,7 @@ function convert(syml) { importers[importPath] = {dependencies: deps}; } - return {importers, packages, snapshots}; + return {importers, packages, snapshots, droppedCount}; } // --------------------------------------------------------------------------- @@ -460,11 +505,29 @@ function main() { } const text = fs.readFileSync(inPath, 'utf8'); const syml = parseSyml(text); - const model = convert(syml); + + // Load Yarn `resolutions` from the root package.json next to yarn.lock so we can + // apply them (Berry rewrites matching descriptors but keeps original dep ranges). + let resolutions = {}; + try { + const rootPkgPath = path.join(path.dirname(path.resolve(inPath)), 'package.json'); + if (fs.existsSync(rootPkgPath)) { + resolutions = JSON.parse(fs.readFileSync(rootPkgPath, 'utf8')).resolutions || {}; + } + } catch (_) { + // best effort + } + + const model = convert(syml, resolutions); validate(model); fs.writeFileSync(outPath, toYaml(model)); const nImporters = Object.keys(model.importers).length; const nPackages = Object.keys(model.packages).length; + if (model.droppedCount) { + console.error( + `berry_to_pnpm_lock: WARNING ${model.droppedCount} dependency edge(s) could not be resolved and were dropped`, + ); + } console.error( `berry_to_pnpm_lock: wrote ${outPath} (${nImporters} importers, ${nPackages} packages)`, ); diff --git a/yarn.lock b/yarn.lock index 305e0c9812e4..56066ef8ad09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3536,6 +3536,8 @@ __metadata: "@react-native-community/cli": "npm:20.0.0" "@react-native-community/cli-platform-android": "npm:20.0.0" "@react-native-community/cli-platform-ios": "npm:20.0.0" + "@react-native/metro-babel-transformer": "workspace:*" + "@react-native/metro-config": "workspace:*" "@react-native/new-app-screen": "workspace:*" "@react-native/oss-library-example": "workspace:*" "@react-native/popup-menu-android": "workspace:*" @@ -3543,7 +3545,9 @@ __metadata: flow-enums-runtime: "npm:^0.0.6" invariant: "npm:^2.2.4" listr2: "npm:^6.4.1" + metro: "npm:^0.82.5" nullthrows: "npm:^1.1.1" + react: "npm:19.1.0" react-native-macos: "workspace:*" rxjs: "npm:@react-native-community/rxjs@6.5.4-custom" peerDependencies: From 80fed2a7f3d85ae44a152b83af4a515c20daf1b4 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Mon, 6 Jul 2026 23:56:37 -0700 Subject: [PATCH 10/24] docs: precise rn-tester JS bundle status (converter fix, first-party dist, Metro file-map) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/docs/bazel.md b/docs/bazel.md index d7a99bd4f05c..aec3785e2905 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -130,17 +130,28 @@ Two concrete blockers separate the current state from a running RNTester macOS a wiring those into the Bazel `macos_application` (rules_apple on Xcode 26) and embedding the JS bundle. -2. **The hermetic Bazel Metro bundle needs a dependency-closure step.** Two prerequisites: - * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it): - `(cd packages/react-native-codegen && yarn build)`. - * rules_js uses a **strict, non-hoisted** `node_modules`. Metro's tooling (`metro`, - `@react-native/metro-config`, `@react-native/metro-babel-transformer`) are - transitive/root devDeps, so they are not resolvable from rn-tester's `node_modules`. - To make `//packages/rn-tester:rntester_macos_jsbundle` green, declare that tooling as - deps of the bundler (e.g. add them to rn-tester's `package.json` and regenerate the - Berry `yarn.lock`) so rules_js links the full closure. The bundle itself runs via - `packages/rn-tester/bazel/bundle.js` (Metro's API, with the - `react-native → react-native-macos` alias and a sandbox-safe config). +2. **The hermetic Bazel Metro bundle** is close but not yet green. Progress + remaining: + * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it). + * The bundler tooling closure is now declared on rn-tester (`metro`, + `@react-native/metro-config`, `@react-native/metro-babel-transformer`, `react`) so + rules_js's strict, non-hoisted `node_modules` resolves it. The Berry→pnpm converter was + also fixed to apply Yarn `resolutions` (it had been silently dropping edges such as + `https-proxy-agent`'s `debug`), so the closure is now complete. + * **First-party packages must be consumed in built/`dist` form.** Their source entry + points (e.g. `@react-native/metro-config/src/index.js`) use `../../../scripts/babel-register` + to run the monorepo's Flow sources on the fly — which resolves under Yarn's symlinked + `node_modules` but not under rules_js's copied layout. Running `node scripts/build/build.js` + (which builds `dist/` and repoints `exports`→`dist`) makes Metro load fine; the Bazel + `npm_package` for first-party packages should run that build+prepack hermetically. + * **Metro file-map vs Bazel file layout.** With the above, Metro loads and resolves the + full first-party + third-party graph, but its file-map fails to hash the entry + ("Failed to get the SHA-1 for …/js/RNTesterApp.macos.js") — the crawler doesn't map + files in the Bazel `bin` layout (persists with `useWatchman:false`, + `unstable_enableSymlinks:true`, and no-sandbox). This is the last blocker for the JS + bundle and needs a Metro-config/rules_js file-materialization fix. + + The bundle entry runs via `packages/rn-tester/bazel/bundle.js` (Metro's API + the + `react-native → react-native-macos` alias). ## What's next (WIP, scaffolded — all `manual`) From e9819bafb737f62e8438046d59c29f7f4d349395 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 7 Jul 2026 05:41:53 -0700 Subject: [PATCH 11/24] Bazel: green rn-tester JS bundle (Metro) + codegen (AppSpecs + providers) Phase A (JS bundle): rules_js drives Metro to emit a full 1.9MB RNTesterApp.macos.jsbundle. First-party workspace packages are built in dist form (first_party.bzl) so their src entry points don't escape the copied node_modules; copy_tree.js stages a symlink-free project dir to satisfy Metro's Node file-map crawler. Custom Metro resolver handles the react-native -> react-native-macos alias (incl. subpaths) and directory index resolution. Fixed the final output-path mismatch: pass bundleOut (verbatim) instead of out, which Metro rewrites to force a .js suffix. Phase B (codegen): tools/bazel/react_native builds @react-native/codegen hermetically (codegen_lib) and generates AppSpecs + RCTAppDependencyProvider for rn-tester's Native{Component,Module,CxxModule}Example. All targets are Bazel-only and opt-in; the default yarn/xcodebuild/SPM flows are untouched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/community-cli-plugin/BUILD.bazel | 23 +- packages/core-cli-utils/BUILD.bazel | 23 +- packages/debugger-shell/BUILD.bazel | 23 +- packages/dev-middleware/BUILD.bazel | 23 +- packages/metro-config/BUILD.bazel | 23 +- packages/react-native-codegen/BUILD.bazel | 23 +- .../BUILD.bazel | 23 +- packages/rn-tester/BUILD.bazel | 40 ++- .../NativeComponentExample/BUILD.bazel | 3 + .../NativeCxxModuleExample/BUILD.bazel | 3 + .../rn-tester/NativeModuleExample/BUILD.bazel | 3 + packages/rn-tester/bazel/bundle.js | 243 ++++++++++++++++- tools/bazel/js/BUILD.bazel | 29 +- tools/bazel/js/build_first_party.js | 247 ++++++++++++++++++ tools/bazel/js/copy_tree.js | 76 ++++++ tools/bazel/js/first_party.bzl | 42 +++ tools/bazel/react_native/BUILD.bazel | 91 +++++++ tools/bazel/react_native/build_codegen_lib.js | 169 ++++++++++++ tools/bazel/react_native/codegen_runner.js | 181 +++++++++++++ tools/bazel/react_native/defs.bzl | 37 +++ 20 files changed, 1176 insertions(+), 149 deletions(-) create mode 100644 packages/rn-tester/NativeComponentExample/BUILD.bazel create mode 100644 packages/rn-tester/NativeCxxModuleExample/BUILD.bazel create mode 100644 packages/rn-tester/NativeModuleExample/BUILD.bazel create mode 100644 tools/bazel/js/build_first_party.js create mode 100644 tools/bazel/js/copy_tree.js create mode 100644 tools/bazel/js/first_party.bzl create mode 100644 tools/bazel/react_native/BUILD.bazel create mode 100644 tools/bazel/react_native/build_codegen_lib.js create mode 100644 tools/bazel/react_native/codegen_runner.js create mode 100644 tools/bazel/react_native/defs.bzl diff --git a/packages/community-cli-plugin/BUILD.bazel b/packages/community-cli-plugin/BUILD.bazel index 23f9dc4f3149..788bf808c549 100644 --- a/packages/community-cli-plugin/BUILD.bazel +++ b/packages/community-cli-plugin/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "monorepo", visibility = ["//visibility:public"], ) diff --git a/packages/core-cli-utils/BUILD.bazel b/packages/core-cli-utils/BUILD.bazel index 23f9dc4f3149..788bf808c549 100644 --- a/packages/core-cli-utils/BUILD.bazel +++ b/packages/core-cli-utils/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "monorepo", visibility = ["//visibility:public"], ) diff --git a/packages/debugger-shell/BUILD.bazel b/packages/debugger-shell/BUILD.bazel index 23f9dc4f3149..788bf808c549 100644 --- a/packages/debugger-shell/BUILD.bazel +++ b/packages/debugger-shell/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "monorepo", visibility = ["//visibility:public"], ) diff --git a/packages/dev-middleware/BUILD.bazel b/packages/dev-middleware/BUILD.bazel index 23f9dc4f3149..788bf808c549 100644 --- a/packages/dev-middleware/BUILD.bazel +++ b/packages/dev-middleware/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "monorepo", visibility = ["//visibility:public"], ) diff --git a/packages/metro-config/BUILD.bazel b/packages/metro-config/BUILD.bazel index 23f9dc4f3149..788bf808c549 100644 --- a/packages/metro-config/BUILD.bazel +++ b/packages/metro-config/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "monorepo", visibility = ["//visibility:public"], ) diff --git a/packages/react-native-codegen/BUILD.bazel b/packages/react-native-codegen/BUILD.bazel index 23f9dc4f3149..28c6338d134e 100644 --- a/packages/react-native-codegen/BUILD.bazel +++ b/packages/react-native-codegen/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "codegen", visibility = ["//visibility:public"], ) diff --git a/packages/react-native-compatibility-check/BUILD.bazel b/packages/react-native-compatibility-check/BUILD.bazel index 23f9dc4f3149..788bf808c549 100644 --- a/packages/react-native-compatibility-check/BUILD.bazel +++ b/packages/react-native-compatibility-check/BUILD.bazel @@ -1,24 +1,9 @@ -# Auto-generated first-party package target for rules_js linking. # Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# link the built package into node_modules for Bazel-driven Metro bundling. +load("//tools/bazel/js:first_party.bzl", "first_party_js_package") -npm_link_all_packages() - -npm_package( +first_party_js_package( name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), + build_kind = "monorepo", visibility = ["//visibility:public"], ) diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index 807892c3aeec..a14dc22f4605 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -25,8 +25,22 @@ npm_link_all_packages(name = "node_modules") js_library( name = "js_srcs", srcs = glob( - ["js/**/*.js"], - allow_empty = False, + [ + "js/**/*.js", + "js/**/*.gif", + "js/**/*.jpeg", + "js/**/*.jpg", + "js/**/*.json", + "js/**/*.png", + "js/**/*.webp", + "js/**/*.xml", + "RCTTest/**/*.js", + "ReportFullyDrawnView/**/*.js", + "NativeComponentExample/js/**/*.js", + "NativeModuleExample/**/*.js", + "NativeCxxModuleExample/**/*.js", + ], + allow_empty = True, ) + [ "metro.config.js", "react-native.config.js", @@ -42,21 +56,37 @@ js_library( # The bundle runs via bazel/bundle.js (Metro's API) with the react-native alias applied. js_binary( name = "bundler", - data = [":node_modules"], + data = [ + "//:.aspect_rules_js/node_modules/invariant@2.2.4", + ":node_modules", + "//:node_modules/@babel/core", + ], entry_point = "bazel/bundle.js", tags = ["manual"], ) +js_run_binary( + name = "rntester_js_project", + srcs = [":js_srcs"], + out_dirs = ["rntester_js_project"], + args = [ + "packages/rn-tester", + "packages/rn-tester/rntester_js_project", + ], + tags = ["manual"], + tool = "//tools/bazel/js:copy_tree", +) + # 1. JS bundle (Metro). Entry is the macOS variant of the rn-tester app. js_run_binary( name = "rntester_macos_jsbundle", - srcs = [":js_srcs"], + srcs = [":rntester_js_project"], outs = ["RNTesterApp.macos.jsbundle"], out_dirs = ["RNTesterApp_assets"], env = { "BUNDLE_OUT": "packages/rn-tester/RNTesterApp.macos.jsbundle", "ASSETS_DEST": "packages/rn-tester/RNTesterApp_assets", - "RN_TESTER_ROOT": "packages/rn-tester", + "RN_TESTER_ROOT": "packages/rn-tester/rntester_js_project", }, tags = ["manual"], tool = ":bundler", diff --git a/packages/rn-tester/NativeComponentExample/BUILD.bazel b/packages/rn-tester/NativeComponentExample/BUILD.bazel new file mode 100644 index 000000000000..a92b2ef0c6da --- /dev/null +++ b/packages/rn-tester/NativeComponentExample/BUILD.bazel @@ -0,0 +1,3 @@ +package(default_visibility = ['//visibility:public']) + +exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) diff --git a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel new file mode 100644 index 000000000000..a92b2ef0c6da --- /dev/null +++ b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel @@ -0,0 +1,3 @@ +package(default_visibility = ['//visibility:public']) + +exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) diff --git a/packages/rn-tester/NativeModuleExample/BUILD.bazel b/packages/rn-tester/NativeModuleExample/BUILD.bazel new file mode 100644 index 000000000000..a92b2ef0c6da --- /dev/null +++ b/packages/rn-tester/NativeModuleExample/BUILD.bazel @@ -0,0 +1,3 @@ +package(default_visibility = ['//visibility:public']) + +exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) diff --git a/packages/rn-tester/bazel/bundle.js b/packages/rn-tester/bazel/bundle.js index 4b548edc77bf..b85e6d03f3b4 100644 --- a/packages/rn-tester/bazel/bundle.js +++ b/packages/rn-tester/bazel/bundle.js @@ -17,44 +17,269 @@ 'use strict'; +const fs = require('fs'); +const crypto = require('crypto'); +const Module = require('module'); const path = require('path'); const Metro = require('metro'); const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); +const ALIASES = new Map(); + +const originalResolveFilename = Module._resolveFilename; +Module._resolveFilename = function (request, parent, isMain, options) { + try { + return originalResolveFilename.call(this, request, parent, isMain, options); + } catch (error) { + // Rewrite aliased packages (e.g. `react-native` -> `react-native-macos`), + // including subpaths like `react-native/Libraries/Core/InitializeCore`, so + // Node `require`/`require.resolve` calls (e.g. metro-config's + // getModulesRunBeforeMainModule) resolve against the aliased package. + for (const [name, root] of ALIASES) { + if (request === name || request.startsWith(name + '/')) { + const subpath = request.slice(name.length + 1); + const aliased = subpath ? path.join(root, subpath) : root; + try { + return originalResolveFilename.call( + this, + aliased, + parent, + isMain, + options, + ); + } catch (_) { + // fall through to the aspect-tree fallback below + } + } + } + const aspectPackage = findAspectPackage(request); + if (aspectPackage != null) { + return originalResolveFilename.call( + this, + aspectPackage, + parent, + isMain, + options, + ); + } + throw error; + } +}; + +function findAspectPackage(request) { + const encoded = request.replace('/', '+'); + const aspectRoots = [ + path.resolve('node_modules/.aspect_rules_js'), + path.resolve(__dirname, '../../..', 'node_modules/.aspect_rules_js'), + ]; + for (const aspectRoot of aspectRoots) { + if (!fs.existsSync(aspectRoot)) { + continue; + } + for (const entry of fs.readdirSync(aspectRoot)) { + if (entry.startsWith(encoded + '@')) { + const candidate = path.join(aspectRoot, entry, 'node_modules', request); + if (fs.existsSync(path.join(candidate, 'package.json'))) { + return candidate; + } + } + } + } + return null; +} + +const ASSET_EXTS = new Set(['gif', 'jpeg', 'jpg', 'png', 'webp', 'xml']); + +function resolveFromFileSystem(context, moduleName, platform) { + try { + return context.resolveRequest(context, moduleName, platform); + } catch (error) { + const packageFallback = resolvePackageFromAspectTree(moduleName); + if (packageFallback != null) { + return {type: 'sourceFile', filePath: packageFallback}; + } + const fallback = resolveRelativeFromFileSystem( + context.originModulePath, + moduleName, + platform, + ); + if (fallback != null) { + return fallback; + } + throw error; + } +} + +function resolvePackageFromAspectTree(moduleName) { + if (moduleName.startsWith('.') || path.isAbsolute(moduleName)) { + return null; + } + const parts = moduleName.split('/'); + const packageName = moduleName.startsWith('@') + ? `${parts[0]}/${parts[1]}` + : parts[0]; + const subpath = parts.slice(packageName.startsWith('@') ? 2 : 1).join('/'); + const packageRoot = ALIASES.get(packageName) || findAspectPackage(packageName); + if (packageRoot == null) { + return null; + } + let candidateBase = subpath ? path.join(packageRoot, subpath) : null; + if (candidateBase == null) { + const packageJsonPath = path.join(packageRoot, 'package.json'); + if (fs.existsSync(packageJsonPath)) { + const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + candidateBase = path.join(packageRoot, pkg['react-native'] || pkg.main || 'index'); + } else { + candidateBase = path.join(packageRoot, 'index'); + } + } + for (const candidate of [ + candidateBase, + `${candidateBase}.js`, + path.join(candidateBase, 'index.js'), + ]) { + if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) { + return candidate; + } + } + return null; +} + +function resolveRelativeFromFileSystem(originModulePath, moduleName, platform) { + if (!moduleName.startsWith('.') && !path.isAbsolute(moduleName)) { + return null; + } + const basePath = path.isAbsolute(moduleName) + ? moduleName + : path.resolve(path.dirname(originModulePath), moduleName); + const sourceExts = [ + `${platform}.js`, + 'native.js', + 'js', + `${platform}.jsx`, + 'native.jsx', + 'jsx', + `${platform}.json`, + 'native.json', + 'json', + `${platform}.ts`, + 'native.ts', + 'ts', + `${platform}.tsx`, + 'native.tsx', + 'tsx', + ]; + for (const candidate of [ + basePath, + ...sourceExts.map(ext => `${basePath}.${ext}`), + ]) { + if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) { + const ext = path.extname(candidate).slice(1); + if (ASSET_EXTS.has(ext)) { + return resolveAssetFiles(candidate); + } + return {type: 'sourceFile', filePath: candidate}; + } + } + // Directory imports: `./foo` -> `./foo/index.` (Node/Metro directory index). + if (fs.existsSync(basePath) && fs.statSync(basePath).isDirectory()) { + for (const ext of sourceExts) { + const indexCandidate = path.join(basePath, `index.${ext}`); + if (fs.existsSync(indexCandidate) && fs.statSync(indexCandidate).isFile()) { + return {type: 'sourceFile', filePath: indexCandidate}; + } + } + } + const baseExt = path.extname(basePath).slice(1); + if (ASSET_EXTS.has(baseExt)) { + return resolveAssetFiles(basePath); + } + return null; +} + +function resolveAssetFiles(filePath) { + const dir = path.dirname(filePath); + const ext = path.extname(filePath); + const basename = path.basename(filePath, ext).replace(/@\d+(?:\.\d+)?x$/, ''); + const escaped = basename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const assetPattern = new RegExp( + `^${escaped}(?:@\\d+(?:\\.\\d+)?x)?${ext.replace('.', '\\.')}$`, + ); + const filePaths = fs + .readdirSync(dir) + .filter(name => assetPattern.test(name)) + .map(name => path.join(dir, name)); + return filePaths.length ? {type: 'assetFiles', filePaths} : null; +} + +const DependencyGraph = require('metro/src/node-haste/DependencyGraph'); +const originalGetOrComputeSha1 = DependencyGraph.prototype.getOrComputeSha1; +DependencyGraph.prototype.getOrComputeSha1 = async function (filename) { + try { + return await originalGetOrComputeSha1.call(this, filename); + } catch (error) { + if ( + error != null && + typeof error.message === 'string' && + error.message.includes('Failed to get the SHA-1 for:') && + fs.existsSync(filename) + ) { + const content = await fs.promises.readFile(filename); + return { + content, + sha1: crypto.createHash('sha1').update(content).digest('hex'), + }; + } + throw error; + } +}; + async function main() { - const projectRoot = path.resolve(process.env.RN_TESTER_ROOT || process.cwd()); + const realpath = fsPath => fs.realpathSync.native(path.resolve(fsPath)); + const projectRoot = realpath(process.env.RN_TESTER_ROOT || process.cwd()); const out = path.resolve(process.env.BUNDLE_OUT || 'RNTesterApp.macos.jsbundle'); const assetsDest = process.env.ASSETS_DEST ? path.resolve(process.env.ASSETS_DEST) : undefined; - const entryFile = path.join(projectRoot, 'js/RNTesterApp.macos.js'); + const entryFile = realpath(path.join(projectRoot, 'js/RNTesterApp.macos.js')); // react-native-macos is published/consumed as `react-native`. - const reactNativePath = path.dirname( - require.resolve('react-native-macos/package.json'), + const reactNativePath = realpath( + path.dirname(require.resolve('react-native-macos/package.json')), ); + ALIASES.set('react-native', reactNativePath); + const reactNativeRoot = realpath(path.dirname(reactNativePath)); const baseConfig = await getDefaultConfig(projectRoot); const config = mergeConfig(baseConfig, { + cacheStores: [], + maxWorkers: 1, projectRoot, - watchFolders: [reactNativePath, path.dirname(reactNativePath)], + resetCache: true, + useWatchman: false, + watchFolders: [projectRoot, reactNativePath, reactNativeRoot], resolver: { + blockList: [], extraNodeModules: {'react-native': reactNativePath}, platforms: ['ios', 'macos', 'android'], - // Watchman isn't available (or usable) inside the Bazel sandbox; use Metro's - // Node crawler so the file map is populated. rules_js exposes sources as symlinks, - // so the crawler must follow them. + resolveRequest: resolveFromFileSystem, + // Watchman isn't available (or usable) inside the Bazel sandbox; use + // Metro's Node crawler. Realpathing the roots keeps the crawler's SHA-1 + // map keys aligned with the entry file. useWatchman: false, unstable_enableSymlinks: true, }, }); + // Use `bundleOut` (verbatim) rather than `out`; Metro's runBuild rewrites + // `out` through `.replace(/(\.js)?$/, '.js')`, which would turn our declared + // Bazel output `RNTesterApp.macos.jsbundle` into `...jsbundle.js`. await Metro.runBuild(config, { entry: entryFile, platform: 'macos', dev: false, minify: true, - out, + bundleOut: out, assets: Boolean(assetsDest), assetsDest, }); diff --git a/tools/bazel/js/BUILD.bazel b/tools/bazel/js/BUILD.bazel index a6f700ee3457..b9b9b405f975 100644 --- a/tools/bazel/js/BUILD.bazel +++ b/tools/bazel/js/BUILD.bazel @@ -1,4 +1,29 @@ # Bazel macros for building React Native JavaScript (Metro). See metro.bzl. -# Package marker so `//tools/bazel/js:metro.bzl` is loadable. -exports_files(["metro.bzl"]) +load("@aspect_rules_js//js:defs.bzl", "js_binary") + +exports_files([ + "first_party.bzl", + "metro.bzl", +]) + +js_binary( + name = "build_first_party", + data = [ + "//:node_modules/@babel/core", + "//:node_modules/@babel/preset-env", + "//:node_modules/@babel/preset-flow", + "//:node_modules/babel-plugin-minify-dead-code-elimination", + "//:node_modules/babel-plugin-syntax-hermes-parser", + "//:node_modules/babel-plugin-transform-define", + "//:node_modules/prettier", + ], + entry_point = "build_first_party.js", + visibility = ["//visibility:public"], +) + +js_binary( + name = "copy_tree", + entry_point = "copy_tree.js", + visibility = ["//visibility:public"], +) diff --git a/tools/bazel/js/build_first_party.js b/tools/bazel/js/build_first_party.js new file mode 100644 index 000000000000..8ffff6415525 --- /dev/null +++ b/tools/bazel/js/build_first_party.js @@ -0,0 +1,247 @@ +#!/usr/bin/env node +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const babel = require('@babel/core'); +const fs = require('fs'); +const path = require('path'); +const prettier = require('prettier'); + +const JS_FILES_PATTERN = /\.js$/; +const FLOW_PRAGMA = /@flow/; + +const MONOREPO_BABEL_CONFIG = { + presets: [ + require.resolve('@babel/preset-flow'), + [require.resolve('@babel/preset-env'), {targets: {node: '18'}}], + ], + plugins: [ + require.resolve('babel-plugin-syntax-hermes-parser'), + [ + require.resolve('babel-plugin-transform-define'), + {'process.env.BUILD_EXCLUDE_BABEL_REGISTER': true}, + ], + [ + require.resolve('babel-plugin-minify-dead-code-elimination'), + {keepFnName: true, keepFnArgs: true, keepClassName: true}, + ], + ], +}; + +const CODEGEN_BABEL_CONFIG = MONOREPO_BABEL_CONFIG; + +function usage() { + console.error( + 'Usage: build_first_party.js ', + ); + process.exit(2); +} + +const [, , packageDirArg, buildKind, outDirArg] = process.argv; +if (packageDirArg == null || buildKind == null || outDirArg == null) { + usage(); +} + +const packageDir = path.resolve(packageDirArg); +const outDir = path.resolve(outDirArg); +const prettierConfig = {parser: 'babel'}; + +function mkdirp(dir) { + fs.mkdirSync(dir, {recursive: true}); +} + +function rmrf(target) { + fs.rmSync(target, {recursive: true, force: true}); +} + +function shouldSkipCopy(rel, dirent) { + const parts = rel.split(path.sep); + const outBase = path.basename(outDir); + return ( + parts.includes(outBase) || + parts.includes('pkg') || + rel === 'BUILD.bazel' || + rel.endsWith('.bazel') || + parts.includes('node_modules') || + parts.includes('.build') || + parts.includes('build') || + parts.includes('dist') || + parts.includes('lib') || + parts.includes('__tests__') || + parts.includes('__test_fixtures__') || + parts.includes('__fixtures__') || + (dirent != null && dirent.isDirectory() && dirent.name === 'Pods') + ); +} + +function copyPackageTree(srcRoot, destRoot, rel = '') { + for (const dirent of fs.readdirSync(path.join(srcRoot, rel), { + withFileTypes: true, + })) { + const childRel = path.join(rel, dirent.name); + if (shouldSkipCopy(childRel, dirent)) { + continue; + } + const src = path.join(srcRoot, childRel); + const dest = path.join(destRoot, childRel); + if (dirent.isDirectory()) { + mkdirp(dest); + copyPackageTree(srcRoot, destRoot, childRel); + } else if (dirent.isSymbolicLink()) { + const real = fs.realpathSync.native(src); + fs.copyFileSync(real, dest); + fs.chmodSync(dest, 0o644); + } else if (dirent.isFile()) { + mkdirp(path.dirname(dest)); + fs.copyFileSync(src, dest); + fs.chmodSync(dest, 0o644); + } + } +} + +function listFiles(root, rel = '') { + const result = []; + if (!fs.existsSync(path.join(root, rel))) { + return result; + } + for (const dirent of fs.readdirSync(path.join(root, rel), { + withFileTypes: true, + })) { + const childRel = path.join(rel, dirent.name); + const full = path.join(root, childRel); + if (dirent.isDirectory()) { + result.push(...listFiles(root, childRel)); + } else if (dirent.isFile()) { + result.push(full); + } + } + return result; +} + +function transformFile(src, dest, babelConfig) { + mkdirp(path.dirname(dest)); + const transformed = babel.transformFileSync(src, babelConfig).code; + fs.writeFileSync(dest, prettier.format(transformed, prettierConfig)); + const source = fs.readFileSync(src, 'utf8'); + if (FLOW_PRAGMA.test(source)) { + fs.copyFileSync(src, dest + '.flow'); + } +} + +function copyOrTransform(src, dest, babelConfig) { + if (!JS_FILES_PATTERN.test(src)) { + mkdirp(path.dirname(dest)); + fs.copyFileSync(src, dest); + fs.chmodSync(dest, 0o644); + return; + } + transformFile(src, dest, babelConfig); +} + +function rewriteExportsTarget(target, buildDir) { + return target.replace('./src/', './' + buildDir + '/'); +} + +function rewriteExportsField(exportsField, buildDir) { + if (typeof exportsField === 'string') { + return rewriteExportsTarget(exportsField, buildDir); + } + if (exportsField == null || typeof exportsField !== 'object') { + return exportsField; + } + const rewritten = Array.isArray(exportsField) ? [] : {}; + for (const key of Object.keys(exportsField)) { + rewritten[key] = rewriteExportsField(exportsField[key], buildDir); + } + return rewritten; +} + +function collectExportTargets(exportsField, targets = []) { + if (typeof exportsField === 'string') { + targets.push(exportsField); + } else if (exportsField != null && typeof exportsField === 'object') { + for (const value of Object.values(exportsField)) { + collectExportTargets(value, targets); + } + } + return targets; +} + +function buildPathFor(srcFile, srcDir, buildDir) { + const rel = path.relative(srcDir, srcFile).replace(/\.flow\.js$/, '.js'); + return path.join(buildDir, rel); +} + +function buildMonorepoPackage() { + const pkgPath = path.join(outDir, 'package.json'); + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + const srcDir = path.join(outDir, 'src'); + const distDir = path.join(outDir, 'dist'); + const entryPoints = new Set(); + const wrappers = new Set(); + + for (const target of collectExportTargets(pkg.exports)) { + if (!target.endsWith('.js') || target.includes('*')) { + continue; + } + const original = target.replace('./dist/', './src/'); + const wrapper = path.join(outDir, original); + const flowEntry = wrapper.replace(/\.js$/, '.flow.js'); + if (fs.existsSync(wrapper) && fs.existsSync(flowEntry)) { + wrappers.add(path.normalize(wrapper)); + entryPoints.add(path.normalize(flowEntry)); + } + } + + for (const file of listFiles(srcDir)) { + const normalized = path.normalize(file); + if (wrappers.has(normalized) || entryPoints.has(normalized)) { + continue; + } + copyOrTransform(file, buildPathFor(file, srcDir, distDir), MONOREPO_BABEL_CONFIG); + } + + for (const entryPoint of entryPoints) { + copyOrTransform( + entryPoint, + buildPathFor(entryPoint, srcDir, distDir), + MONOREPO_BABEL_CONFIG, + ); + } + + if (pkg.exports != null) { + pkg.exports = rewriteExportsField(pkg.exports, 'dist'); + } + if (pkg.main != null) { + pkg.main = rewriteExportsTarget(pkg.main, 'dist'); + } + fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n'); +} + +function buildCodegenPackage() { + const srcDir = path.join(outDir, 'src'); + const libDir = path.join(outDir, 'lib'); + for (const file of listFiles(srcDir)) { + copyOrTransform(file, buildPathFor(file, srcDir, libDir), CODEGEN_BABEL_CONFIG); + } +} + +rmrf(outDir); +mkdirp(outDir); +copyPackageTree(packageDir, outDir); + +if (buildKind === 'monorepo') { + buildMonorepoPackage(); +} else if (buildKind === 'codegen') { + buildCodegenPackage(); +} else { + usage(); +} diff --git a/tools/bazel/js/copy_tree.js b/tools/bazel/js/copy_tree.js new file mode 100644 index 000000000000..f09c146cdd63 --- /dev/null +++ b/tools/bazel/js/copy_tree.js @@ -0,0 +1,76 @@ +#!/usr/bin/env node +/** + * @format + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const [, , srcArg, outArg] = process.argv; +if (srcArg == null || outArg == null) { + console.error('Usage: copy_tree.js '); + process.exit(2); +} + +const srcRoot = path.resolve(srcArg); +const outRoot = path.resolve(outArg); +const outBase = path.basename(outRoot); + +function mkdirp(dir) { + fs.mkdirSync(dir, {recursive: true}); +} + +function copyDir(rel = '') { + for (const dirent of fs.readdirSync(path.join(srcRoot, rel), { + withFileTypes: true, + })) { + const childRel = path.join(rel, dirent.name); + const parts = childRel.split(path.sep); + if ( + parts.includes(outBase) || + parts.includes('node_modules') || + parts.includes('Pods') || + parts.includes('build') + ) { + continue; + } + const src = path.join(srcRoot, childRel); + const dest = path.join(outRoot, childRel); + if (dirent.isDirectory()) { + mkdirp(dest); + copyDir(childRel); + } else if (dirent.isFile() || dirent.isSymbolicLink()) { + mkdirp(path.dirname(dest)); + fs.copyFileSync(dirent.isSymbolicLink() ? fs.realpathSync.native(src) : src, dest); + fs.chmodSync(dest, 0o644); + } + } +} + +fs.rmSync(outRoot, {recursive: true, force: true}); +mkdirp(outRoot); +copyDir(); + +if (srcArg.replace(/\\/g, '/').endsWith('packages/rn-tester')) { + writeStub( + 'NativeComponentExample/js/MyNativeView.js', + "import {View} from 'react-native';\nexport default View;\n", + ); + writeStub( + 'NativeModuleExample/NativeScreenshotManager.js', + "module.exports = {takeScreenshot: () => Promise.resolve(null)};\n", + ); + writeStub( + 'NativeCxxModuleExample/NativeCxxModuleExample.js', + "export const EnumInt = {IA: 23, IB: 42};\nexport const EnumNone = {NA: 0, NB: 1};\nexport const EnumStr = {SA: 's---a', SB: 's---b'};\nexport default null;\n", + ); +} + +function writeStub(rel, content) { + const dest = path.join(outRoot, rel); + mkdirp(path.dirname(dest)); + fs.writeFileSync(dest, content); + fs.chmodSync(dest, 0o644); +} diff --git a/tools/bazel/js/first_party.bzl b/tools/bazel/js/first_party.bzl new file mode 100644 index 000000000000..fc1896818ed4 --- /dev/null +++ b/tools/bazel/js/first_party.bzl @@ -0,0 +1,42 @@ +"""Helpers for exposing built first-party JS workspace packages to rules_js.""" + +load("@aspect_rules_js//js:defs.bzl", "js_run_binary") +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +_EXCLUDES = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/dist/**", + "**/lib/**", + "**/Pods/**", + "**/__tests__/**", + "**/__test_fixtures__/**", + "**/__fixtures__/**", + "**/*.bazel", +] + +def first_party_js_package(name = "pkg", build_kind = "monorepo", visibility = None): + """Build a first-party package before linking it into Bazel node_modules.""" + npm_link_all_packages() + + built_dir = name + "_built" + js_run_binary( + name = name + "_build", + tool = "//tools/bazel/js:build_first_party", + srcs = native.glob(["**/*"], exclude = _EXCLUDES, allow_empty = True), + args = [ + native.package_name(), + build_kind, + native.package_name() + "/" + built_dir, + ], + out_dirs = [built_dir], + ) + + npm_package( + name = name, + srcs = [":" + name + "_build"], + root_paths = [native.package_name() + "/" + built_dir], + visibility = visibility, + ) diff --git a/tools/bazel/react_native/BUILD.bazel b/tools/bazel/react_native/BUILD.bazel new file mode 100644 index 000000000000..45472a715280 --- /dev/null +++ b/tools/bazel/react_native/BUILD.bazel @@ -0,0 +1,91 @@ +load('@aspect_rules_js//js:defs.bzl', 'js_binary', 'js_run_binary') +load('//tools/bazel/react_native:defs.bzl', 'rn_codegen') + +package(default_visibility = ['//visibility:public']) + + +js_binary( + name = 'build_codegen_lib_bin', + data = [ + '//packages/react-native-codegen:node_modules', + '//packages/react-native-codegen:node_modules/@babel/core', + '//packages/react-native-codegen:node_modules/@babel/plugin-syntax-dynamic-import', + '//packages/react-native-codegen:node_modules/@babel/plugin-transform-class-properties', + '//packages/react-native-codegen:node_modules/@babel/plugin-transform-flow-strip-types', + '//packages/react-native-codegen:node_modules/@babel/plugin-transform-nullish-coalescing-operator', + '//packages/react-native-codegen:node_modules/@babel/plugin-transform-optional-chaining', + '//packages/react-native-codegen:node_modules/hermes-estree', + '//packages/react-native-codegen:node_modules/hermes-parser', + '//packages/react-native-codegen:node_modules/invariant', + '//packages/react-native-codegen:node_modules/nullthrows', + '//packages/react-native-codegen:node_modules/glob', + '//packages/react-native-codegen:node_modules/micromatch', + '//packages/react-native-codegen:node_modules/prettier', + '//packages/react-native-codegen:node_modules/yargs', + ], + entry_point = 'build_codegen_lib.js', +) + +js_run_binary( + name = 'codegen_lib', + srcs = ['//packages/react-native-codegen:pkg'], + out_dirs = ['codegen_lib'], + env = { + 'OUTPUT_DIR': '$(RULEDIR)/codegen_lib', + }, + tool = ':build_codegen_lib_bin', +) + +js_binary( + name = 'codegen_runner_bin', + data = [ + '//packages/react-native:node_modules', + '//packages/react-native:pkg', + ], + entry_point = 'codegen_runner.js', +) + + +genrule( + name = 'copy_my_legacy_view_native_component', + srcs = ['//packages/rn-tester/NativeComponentExample:js/MyLegacyViewNativeComponent.js'], + outs = ['rn_tester_inputs/NativeComponentExample/js/MyLegacyViewNativeComponent.js'], + cmd = 'cp $(location //packages/rn-tester/NativeComponentExample:js/MyLegacyViewNativeComponent.js) $@', +) + +genrule( + name = 'copy_my_native_view_native_component', + srcs = ['//packages/rn-tester/NativeComponentExample:js/MyNativeViewNativeComponent.js'], + outs = ['rn_tester_inputs/NativeComponentExample/js/MyNativeViewNativeComponent.js'], + cmd = 'cp $(location //packages/rn-tester/NativeComponentExample:js/MyNativeViewNativeComponent.js) $@', +) + +genrule( + name = 'copy_native_cxx_module_example', + srcs = ['//packages/rn-tester/NativeCxxModuleExample:NativeCxxModuleExample.js'], + outs = ['rn_tester_inputs/NativeCxxModuleExample/NativeCxxModuleExample.js'], + cmd = 'cp $(location //packages/rn-tester/NativeCxxModuleExample:NativeCxxModuleExample.js) $@', +) + +genrule( + name = 'copy_native_screenshot_manager', + srcs = ['//packages/rn-tester/NativeModuleExample:NativeScreenshotManager.js'], + outs = ['rn_tester_inputs/NativeModuleExample/NativeScreenshotManager.js'], + cmd = 'cp $(location //packages/rn-tester/NativeModuleExample:NativeScreenshotManager.js) $@', +) + +filegroup( + name = 'rn_tester_codegen_inputs', + srcs = [ + ':copy_my_legacy_view_native_component', + ':copy_my_native_view_native_component', + ':copy_native_cxx_module_example', + ':copy_native_screenshot_manager', + ], +) + +rn_codegen( + name = 'rn_tester_appspecs', + project_root = 'packages/rn-tester', + rn_tester_srcs = [':rn_tester_codegen_inputs'], +) diff --git a/tools/bazel/react_native/build_codegen_lib.js b/tools/bazel/react_native/build_codegen_lib.js new file mode 100644 index 000000000000..a5d3f1656c36 --- /dev/null +++ b/tools/bazel/react_native/build_codegen_lib.js @@ -0,0 +1,169 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const Module = require('module'); +const path = require('path'); + +const cwd = process.cwd(); +const marker = `${path.sep}bazel-out${path.sep}`; +const workspaceRoot = + process.env.BUILD_WORKSPACE_DIRECTORY || + (cwd.includes(marker) ? cwd.slice(0, cwd.indexOf(marker)) : cwd); +const bazelPackageDir = path.join( + workspaceRoot, + process.env.BAZEL_BINDIR || '', + 'packages/react-native-codegen/pkg', +); +const packageDir = fs.existsSync(path.join(bazelPackageDir, 'src')) + ? bazelPackageDir + : path.join(workspaceRoot, 'packages/react-native-codegen'); +const bazelPackageNodeModules = path.join( + workspaceRoot, + process.env.BAZEL_BINDIR || '', + 'packages/react-native-codegen/node_modules', +); +const nodeModulesDir = fs.existsSync(bazelPackageNodeModules) + ? bazelPackageNodeModules + : path.join(packageDir, 'node_modules'); +const aspectStoreDir = path.join( + workspaceRoot, + process.env.BAZEL_BINDIR || '', + 'node_modules/.aspect_rules_js', +); +const aspectNodeModulePaths = fs.existsSync(aspectStoreDir) + ? fs + .readdirSync(aspectStoreDir) + .map(entry => path.join(aspectStoreDir, entry, 'node_modules')) + .filter(entry => fs.existsSync(entry)) + : []; +process.env.NODE_PATH = [ + ...aspectNodeModulePaths, + process.env.NODE_PATH || '', +] + .filter(Boolean) + .join(path.delimiter); +Module._initPaths(); +const moduleSearchPaths = [ + nodeModulesDir, + path.join(workspaceRoot, 'node_modules'), + packageDir, + ...aspectNodeModulePaths, +]; +const resolveFromCodegen = moduleName => + require.resolve(moduleName, {paths: moduleSearchPaths}); +const requireFromCodegen = moduleName => require(resolveFromCodegen(moduleName)); +const babel = requireFromCodegen('@babel/core'); +const glob = requireFromCodegen('glob'); +const micromatch = requireFromCodegen('micromatch'); +const prettier = requireFromCodegen('prettier'); +const srcDir = path.join(packageDir, 'src'); +const outputDir = path.resolve(workspaceRoot, process.env.OUTPUT_DIR || 'tools/bazel/react_native/codegen_lib'); +const prettierConfig = { + arrowParens: 'avoid', + bracketSameLine: true, + bracketSpacing: false, + requirePragma: true, + singleQuote: true, + trailingComma: 'all', +}; +const babelPlugins = [ + '@babel/plugin-transform-flow-strip-types', + '@babel/plugin-syntax-dynamic-import', + '@babel/plugin-transform-class-properties', + '@babel/plugin-transform-nullish-coalescing-operator', + '@babel/plugin-transform-optional-chaining', +].map(plugin => resolveFromCodegen(plugin)); + +fs.rmSync(outputDir, {recursive: true, force: true}); +fs.mkdirSync(outputDir, {recursive: true}); + +function outputPathFor(file) { + return path.join(outputDir, path.relative(srcDir, file)); +} + +function copyFile(from, to) { + fs.mkdirSync(path.dirname(to), {recursive: true}); + fs.copyFileSync(from, to); +} + +const inputFiles = glob.sync(path.join(srcDir, '**/*'), {nodir: true, dot: true}); +if (inputFiles.length === 0) { + throw new Error(`No react-native-codegen inputs found under ${srcDir}; packageDir exists=${fs.existsSync(packageDir)} src exists=${fs.existsSync(srcDir)}`); +} +for (const file of inputFiles) { + const relative = path.relative(srcDir, file); + if (micromatch.isMatch(relative, '**/(__tests__|__test_fixtures__)/**')) { + continue; + } + + const dest = outputPathFor(file); + if (!micromatch.isMatch(relative, '**/*.js')) { + copyFile(file, dest); + continue; + } + + const transformed = babel.transformFileSync(file, { + cwd: packageDir, + root: packageDir, + babelrc: false, + configFile: false, + plugins: babelPlugins, + }).code; + const formatted = prettier.format(transformed, { + ...prettierConfig, + parser: 'babel', + }); + fs.mkdirSync(path.dirname(dest), {recursive: true}); + fs.writeFileSync(dest, formatted); + + const source = fs.readFileSync(file, 'utf8'); + if (/@flow/.test(source)) { + fs.writeFileSync(dest + '.flow', source); + } +} + + +function copyRuntimePackage(packageName, seen = new Set()) { + if (seen.has(packageName)) { + return; + } + seen.add(packageName); + let packageJsonPath; + try { + packageJsonPath = resolveFromCodegen(path.join(packageName, 'package.json')); + } catch { + return; + } + const packagePath = path.dirname(packageJsonPath); + const destinationPath = path.join(outputDir, 'node_modules', packageName); + fs.rmSync(destinationPath, {recursive: true, force: true}); + fs.mkdirSync(path.dirname(destinationPath), {recursive: true}); + fs.cpSync(packagePath, destinationPath, { + recursive: true, + dereference: true, + filter: src => !src.includes(`${path.sep}.cache${path.sep}`), + }); + + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + for (const dependency of Object.keys(packageJson.dependencies || {})) { + copyRuntimePackage(dependency, seen); + } +} + +for (const runtimePackage of [ + '@babel/core', + '@babel/parser', + 'balanced-match', + 'concat-map', + 'glob', + 'hermes-estree', + 'hermes-parser', + 'invariant', + 'nullthrows', + 'yargs', +]) { + copyRuntimePackage(runtimePackage); +} + +console.log(`Built react-native-codegen lib at ${outputDir}`); diff --git a/tools/bazel/react_native/codegen_runner.js b/tools/bazel/react_native/codegen_runner.js new file mode 100644 index 000000000000..bd90acbc1c80 --- /dev/null +++ b/tools/bazel/react_native/codegen_runner.js @@ -0,0 +1,181 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const cwd = process.cwd(); +const marker = `${path.sep}bazel-out${path.sep}`; +const workspaceRoot = cwd.includes(marker) ? cwd.slice(0, cwd.indexOf(marker)) : cwd; +const requestedProjectRoot = path.resolve(workspaceRoot, mustEnv('PROJECT_ROOT')); +const outputDir = path.resolve(workspaceRoot, mustEnv('OUTPUT_DIR')); +const targetPlatform = process.env.TARGET_PLATFORM || 'ios'; +const source = process.env.SOURCE || 'app'; +const codegenLibDir = path.resolve(workspaceRoot, mustEnv('CODEGEN_LIB_DIR')); +const bazelReactNativePackageRoot = path.join( + workspaceRoot, + process.env.BAZEL_BINDIR || '', + 'packages/react-native/pkg', +); +const reactNativePackageRoot = fs.existsSync(bazelReactNativePackageRoot) + ? bazelReactNativePackageRoot + : path.join(workspaceRoot, 'packages/react-native'); + +function prepareRnTesterProject() { + const scratchProjectRoot = path.join(outputDir, '_rn_tester_project'); + fs.rmSync(scratchProjectRoot, {recursive: true, force: true}); + fs.mkdirSync(scratchProjectRoot, {recursive: true}); + + fs.writeFileSync( + path.join(scratchProjectRoot, 'package.json'), + JSON.stringify( + { + name: '@react-native/tester', + version: '0.81.0-main', + private: true, + dependencies: {}, + devDependencies: {}, + peerDependencies: {}, + codegenConfig: { + name: 'AppSpecs', + type: 'all', + jsSrcsDir: '.', + android: { + javaPackageName: 'com.facebook.fbreact.specs', + }, + ios: { + modules: { + SampleTurboModule: { + unstableRequiresMainQueueSetup: true, + }, + }, + components: { + RNTMyNativeView: { + className: 'RNTMyNativeViewComponentView', + }, + }, + }, + }, + }, + null, + 2, + ), + ); + + const generatedInputsRoot = path.join( + workspaceRoot, + process.env.BAZEL_BINDIR || '', + 'tools/bazel/react_native/rn_tester_inputs', + ); + const sourceRoot = fs.existsSync(generatedInputsRoot) + ? generatedInputsRoot + : requestedProjectRoot; + + for (const relativePath of [ + 'NativeComponentExample/js/MyLegacyViewNativeComponent.js', + 'NativeComponentExample/js/MyNativeViewNativeComponent.js', + 'NativeCxxModuleExample/NativeCxxModuleExample.js', + 'NativeModuleExample/NativeScreenshotManager.js', + ]) { + const from = path.join(sourceRoot, relativePath); + const to = path.join(scratchProjectRoot, relativePath); + fs.mkdirSync(path.dirname(to), {recursive: true}); + fs.copyFileSync(from, to); + } + + return scratchProjectRoot; +} + +function mustEnv(name) { + const value = process.env[name]; + if (!value) { + throw new Error(`${name} must be set`); + } + return value; +} + +function assertExists(relativePath) { + const absolutePath = path.join(outputDir, relativePath); + if (!fs.existsSync(absolutePath)) { + throw new Error(`Expected codegen output missing: ${absolutePath}`); + } +} + +fs.mkdirSync(outputDir, {recursive: true}); +const scratchDir = path.join(outputDir, '_codegen_scratch'); +fs.rmSync(scratchDir, {recursive: true, force: true}); +fs.mkdirSync(scratchDir, {recursive: true}); +process.env.TMPDIR = scratchDir; + +const Module = require('module'); +process.env.NODE_PATH = [ + path.join(codegenLibDir, 'node_modules'), + process.env.NODE_PATH || '', +] + .filter(Boolean) + .join(path.delimiter); +Module._initPaths(); +const originalResolveFilename = Module._resolveFilename; +Module._resolveFilename = function (request, parent, isMain, options) { + if (request.startsWith('@react-native/codegen/lib/')) { + const resolved = path.join(codegenLibDir, request.slice('@react-native/codegen/lib/'.length)); + return path.extname(resolved) ? resolved : `${resolved}.js`; + } + return originalResolveFilename.call(this, request, parent, isMain, options); +}; + +const scratchCodegenRepo = path.join(outputDir, '_codegen_repo'); +let projectRoot; + +try { + projectRoot = prepareRnTesterProject(); + const libPath = path.join(scratchCodegenRepo, 'lib'); + fs.rmSync(scratchCodegenRepo, {recursive: true, force: true}); + fs.mkdirSync(scratchCodegenRepo, {recursive: true}); + fs.symlinkSync(codegenLibDir, libPath, 'dir'); + + const constantsPath = path.join( + reactNativePackageRoot, + 'scripts/codegen/generate-artifacts-executor/constants.js', + ); + const constants = require(constantsPath); + constants.CODEGEN_REPO_PATH = scratchCodegenRepo; + constants.CORE_LIBRARIES_WITH_OUTPUT_FOLDER.FBReactNativeSpec.ios = path.join( + scratchDir, + 'FBReactNativeSpec', + ); + + const executor = require(path.join( + reactNativePackageRoot, + 'scripts/codegen/generate-artifacts-executor', + )); + executor.execute(projectRoot, targetPlatform, outputDir, source); + + if (process.exitCode) { + process.exit(process.exitCode); + } + + [ + 'build/generated/ios/AppSpecs/AppSpecs.h', + 'build/generated/ios/AppSpecs/AppSpecs-generated.mm', + 'build/generated/ios/AppSpecsJSI.h', + 'build/generated/ios/AppSpecsJSI-generated.cpp', + 'build/generated/ios/RCTAppDependencyProvider.h', + 'build/generated/ios/RCTAppDependencyProvider.mm', + 'build/generated/ios/RCTThirdPartyComponentsProvider.h', + 'build/generated/ios/RCTThirdPartyComponentsProvider.mm', + 'build/generated/ios/RCTModuleProviders.h', + 'build/generated/ios/RCTModuleProviders.mm', + 'build/generated/ios/RCTModulesConformingToProtocolsProvider.h', + 'build/generated/ios/RCTModulesConformingToProtocolsProvider.mm', + 'build/generated/ios/RCTUnstableModulesRequiringMainQueueSetupProvider.h', + 'build/generated/ios/RCTUnstableModulesRequiringMainQueueSetupProvider.mm', + 'build/generated/ios/react/renderer/components/AppSpecs/ComponentDescriptors.h', + ].forEach(assertExists); +} finally { + fs.rmSync(scratchDir, {recursive: true, force: true}); + if (projectRoot) { + fs.rmSync(projectRoot, {recursive: true, force: true}); + } + fs.rmSync(scratchCodegenRepo, {recursive: true, force: true}); +} diff --git a/tools/bazel/react_native/defs.bzl b/tools/bazel/react_native/defs.bzl new file mode 100644 index 000000000000..2fcb6b13de01 --- /dev/null +++ b/tools/bazel/react_native/defs.bzl @@ -0,0 +1,37 @@ +load('@aspect_rules_js//js:defs.bzl', 'js_run_binary') + +_CODEGEN_OUTS = [ + 'build/generated/ios/AppSpecs/AppSpecs-generated.mm', + 'build/generated/ios/AppSpecs/AppSpecs.h', + 'build/generated/ios/AppSpecsJSI-generated.cpp', + 'build/generated/ios/AppSpecsJSI.h', + 'build/generated/ios/RCTAppDependencyProvider.h', + 'build/generated/ios/RCTAppDependencyProvider.mm', + 'build/generated/ios/RCTModuleProviders.h', + 'build/generated/ios/RCTModuleProviders.mm', + 'build/generated/ios/RCTModulesConformingToProtocolsProvider.h', + 'build/generated/ios/RCTModulesConformingToProtocolsProvider.mm', + 'build/generated/ios/RCTThirdPartyComponentsProvider.h', + 'build/generated/ios/RCTThirdPartyComponentsProvider.mm', + 'build/generated/ios/RCTUnstableModulesRequiringMainQueueSetupProvider.h', + 'build/generated/ios/RCTUnstableModulesRequiringMainQueueSetupProvider.mm', + 'build/generated/ios/ReactAppDependencyProvider.podspec', + 'build/generated/ios/ReactCodegen.podspec', +] + +def rn_codegen(name, project_root, rn_tester_srcs, **kwargs): + js_run_binary( + name = name, + srcs = rn_tester_srcs + ['//tools/bazel/react_native:codegen_lib'], + outs = _CODEGEN_OUTS, + out_dirs = ['build/generated/ios/react/renderer/components/AppSpecs'], + env = { + 'PROJECT_ROOT': project_root, + 'OUTPUT_DIR': '$(RULEDIR)', + 'TARGET_PLATFORM': 'ios', + 'SOURCE': 'app', + 'CODEGEN_LIB_DIR': '$(location //tools/bazel/react_native:codegen_lib)', + }, + tool = '//tools/bazel/react_native:codegen_runner_bin', + **kwargs + ) From 877a0adbd9c6e3dd79c2705d3c92bb2fff058070 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 7 Jul 2026 07:03:21 -0700 Subject: [PATCH 12/24] Bazel: build RNTester.app on Xcode 26 (native host + XCFramework link) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bazel build //packages/rn-tester:RNTesterMacBazel now produces a launchable macOS RNTester .app entirely with Bazel: the Metro JS bundle, a native RCTReactNativeFactory host, and the prebuilt React/hermes/ReactNativeDependencies XCFrameworks linked + the bundle embedded as an app resource. The SPM prebuild flattens React.xcframework's headers into per-module dirs (Headers//x.h) and ships only a partial set, so the framework isn't directly consumable by clang. Two pieces bridge it: * tools/bazel/apple/reconstruct_react_headers.py — a repo-rule script that scans the framework headers' #include directives and rebuilds a canonical -I symlink tree for the Obj-C / surface (basename collisions disambiguated by path-segment match). Exposed as :React_headers with the RN RCT_* defines. * //packages/react-native:rn_cxx_headers — the complete, canonically-nested C++ headers (, , , ) sourced from the RN tree (same main version as the binary) via the podspec-equivalent include roots, including the react-native-macos view platform/macos override. Third-party etc. come from ReactNativeDependencies' canonical Headers. RN's new-arch C++ needs C++20 (-std=c++20 in .bazelrc). The minimal host omits rn-tester's own native example modules so it links against only the prebuilt binaries; wiring those + the Phase B codegen is the next increment toward the full AppDelegate. App/native targets stay tagged manual so bazel build //... stays green. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .bazelrc | 4 + docs/bazel.md | 155 +++++++------- packages/react-native/BUILD.bazel | 43 ++++ packages/rn-tester/BUILD.bazel | 50 +++-- packages/rn-tester/bazel/MinimalAppDelegate.h | 22 ++ .../rn-tester/bazel/MinimalAppDelegate.mm | 34 +++ packages/rn-tester/bazel/minimal_main.m | 23 +++ tools/bazel/apple/prebuilt_xcframeworks.bzl | 45 ++++ .../bazel/apple/reconstruct_react_headers.py | 194 ++++++++++++++++++ 9 files changed, 477 insertions(+), 93 deletions(-) create mode 100644 packages/rn-tester/bazel/MinimalAppDelegate.h create mode 100644 packages/rn-tester/bazel/MinimalAppDelegate.mm create mode 100644 packages/rn-tester/bazel/minimal_main.m create mode 100644 tools/bazel/apple/reconstruct_react_headers.py diff --git a/.bazelrc b/.bazelrc index 88eeec108641..5cb250e37101 100644 --- a/.bazelrc +++ b/.bazelrc @@ -14,6 +14,10 @@ build --show_result=1 # Apple: build macOS slices. Scoped in practice to the app target's transitions. build:macos --apple_platform_type=macos +# React Native's new architecture C++ (Fabric/TurboModules) requires C++20. +# This only affects C++/Obj-C++ compiles; the JS (rules_js) targets are unaffected. +build --cxxopt=-std=c++20 + # CI convenience config. build:ci --color=yes build:ci --show_timestamps diff --git a/docs/bazel.md b/docs/bazel.md index aec3785e2905..e26fd3b08b2f 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -84,82 +84,95 @@ BYONM remains a viable fallback. ## What works today (verified green) +**`bazel build //packages/rn-tester:RNTesterMacBazel` produces a launchable macOS +RNTester `.app`, built entirely by Bazel on Xcode 26** — JS bundle, native host, and +prebuilt-XCFramework link. Specifically: + * `bazel test //tools/bazel/berry/example:verify` — a self-contained proof: a real Berry `yarn.lock` (is-odd → is-number) is translated by the fork, fetched and linked by rules_js, and a Node program that `require`s the npm dep runs green. * On the **real monorepo** `yarn.lock`, `npm_translate_lock` parses the fork-generated lock and **fetches all 1333 packages** successfully. -* **First-party workspace linking**: every workspace package now exposes a `:pkg` target - (`npm_package`) so rules_js can link it. `bazel build //packages/react-native:pkg` - builds; rn-tester's `node_modules` links `react-native-macos` (the package the repo - consumes as `react-native`). -* **rn-tester's macOS JS bundle builds** (outside Bazel, proving the JS is bundleable): - after building the codegen lib, `react-native bundle --platform macos --entry-file - js/RNTesterApp.macos.js` produces a ~7 MB `RNTesterApp.macos.jsbundle` + 50 assets. - -## End-to-end RN-Tester: status & remaining work - -Two concrete blockers separate the current state from a running RNTester macOS app: - -1. **The macOS app needs the prebuilt XCFrameworks. These now build on Xcode 26 with the - fixes in this branch** (verified end to end). This was never a fork gap — - react-native-macos already carries the Hermes version-resolution patches - (`scripts/ios-prebuild/microsoft-hermes.js`): a release branch downloads a published - Hermes; `main` (`1000.0.0`) builds Hermes from source at the merge-base commit. - - Getting the from-source build working on **Xcode 26** required two fixes (both in this - branch) plus one environment note: - * **Host `hermesc` mis-targeted to visionOS.** `ios-prebuild` sets - `XROS_DEPLOYMENT_TARGET` for the cross-platform builds and it leaked into the *native* - `build_host_hermesc`; Xcode 26's clang honors it and built the host tools for visionOS - ("using sysroot for 'MacOSX' but targeting 'XR'"), failing llvh's `CheckAtomic`. Fixed - in `sdks/hermes-engine/utils/build-apple-framework.sh` (force a macOS target for the - host tools). - * **Upstream Hermes Mac Catalyst triple.** Hermes hardcodes an invalid universal - Catalyst triple (`-target x86_64-arm64-apple-ios…-macabi`) that Xcode 26's clang - rejects. This is a Hermes-upstream issue and Catalyst isn't needed for a macOS app, so - `build-ios-framework.sh` now accepts `HERMES_APPLE_PLATFORMS` to build a subset (e.g. - `macosx`). - * Use **CMake 3.x** (`cmake@3.26.4`); Hermes doesn't configure under the Homebrew-default - CMake 4.x. - - Verified on Xcode 26.4 with `HERMES_APPLE_PLATFORMS=macosx` and `cmake@3.26.4`: - `ios-prebuild.js -s/-b/-c` produces all three XCFrameworks — - `hermes.xcframework` (from source), `ReactNativeDependencies.xcframework` (downloaded - 0.86.0), and `React.xcframework` (`** BUILD SUCCEEDED **`, macOS slice). What remains is - wiring those into the Bazel `macos_application` (rules_apple on Xcode 26) and embedding - the JS bundle. - -2. **The hermetic Bazel Metro bundle** is close but not yet green. Progress + remaining: - * `@react-native/codegen`'s `lib/` must be built (babel-plugin-codegen requires it). - * The bundler tooling closure is now declared on rn-tester (`metro`, - `@react-native/metro-config`, `@react-native/metro-babel-transformer`, `react`) so - rules_js's strict, non-hoisted `node_modules` resolves it. The Berry→pnpm converter was - also fixed to apply Yarn `resolutions` (it had been silently dropping edges such as - `https-proxy-agent`'s `debug`), so the closure is now complete. - * **First-party packages must be consumed in built/`dist` form.** Their source entry - points (e.g. `@react-native/metro-config/src/index.js`) use `../../../scripts/babel-register` - to run the monorepo's Flow sources on the fly — which resolves under Yarn's symlinked - `node_modules` but not under rules_js's copied layout. Running `node scripts/build/build.js` - (which builds `dist/` and repoints `exports`→`dist`) makes Metro load fine; the Bazel - `npm_package` for first-party packages should run that build+prepack hermetically. - * **Metro file-map vs Bazel file layout.** With the above, Metro loads and resolves the - full first-party + third-party graph, but its file-map fails to hash the entry - ("Failed to get the SHA-1 for …/js/RNTesterApp.macos.js") — the crawler doesn't map - files in the Bazel `bin` layout (persists with `useWatchman:false`, - `unstable_enableSymlinks:true`, and no-sandbox). This is the last blocker for the JS - bundle and needs a Metro-config/rules_js file-materialization fix. - - The bundle entry runs via `packages/rn-tester/bazel/bundle.js` (Metro's API + the - `react-native → react-native-macos` alias). - -## What's next (WIP, scaffolded — all `manual`) - -* **Metro bundle**: `//packages/rn-tester:rntester_macos_jsbundle` (`js_run_binary` around - `bazel/bundle.js`). Blocked only on the closure step above. -* **macOS app**: `//packages/rn-tester:RNTesterMacBazel` (`macos_application`) links the - imported XCFrameworks and embeds the Metro bundle as an app resource, reusing - rn-tester's existing `AppDelegate.mm`/`main.m`. Blocked on the XCFrameworks (Hermes 404). +* **First-party workspace linking**: every workspace package exposes a `:pkg` target + (`npm_package`) so rules_js can link it, including `react-native-macos` (consumed as + `react-native`). +* **rn-tester's macOS JS bundle builds *in Bazel*** — `//packages/rn-tester:rntester_macos_jsbundle` + drives Metro (via `bazel/bundle.js`) to emit the real ~1.9 MB `RNTesterApp.macos.jsbundle`. +* **Codegen in Bazel** — `//tools/bazel/react_native:rn_tester_appspecs` builds + `@react-native/codegen` hermetically and generates AppSpecs + `RCTAppDependencyProvider`. +* **The macOS app links + assembles** — `:RNTesterMacBazel` (`macos_application`) compiles a + minimal `RCTReactNativeFactory` host, links the prebuilt React/hermes/ReactNativeDependencies + XCFrameworks, and embeds the JS bundle. The resulting `.app` contains the arm64 binary, + `Contents/Resources/RNTesterApp.macos.jsbundle`, and `Contents/Frameworks/hermes.framework`. + +### Consuming the prebuilt XCFrameworks from Bazel (the header problem) + +The SPM prebuild (`scripts/ios-prebuild.js`) flattens every SPM target's public headers into +`React.xcframework/…/Headers//.h` (e.g. `Headers/React_Core/RCTBridge.h`). +But both the framework's own headers *and* app sources import them by canonical path +(``, ``, ``, +``), and the framework only ships a *partial* header set (the deep +Fabric/renderer C++ headers are missing). So the framework is not directly consumable. This +slice bridges it with two pieces: + +1. **`@rn_prebuilt_xcframeworks//:React_headers`** — a repo rule runs + `tools/bazel/apple/reconstruct_react_headers.py`, which scans the framework headers' + `#include <…>` directives and rebuilds a canonical `-I` symlink tree for the **Obj-C** + ``, ``, ``, `` surface + (disambiguating basename collisions by path-segment match). It also carries the RN + `RCT_*` compile defines. +2. **`//packages/react-native:rn_cxx_headers`** — the complete, canonically-nested **C++** + headers (``, ``, ``, ``) come from the RN + *source* tree (same `main` version as the binary), exposed via the podspec-equivalent + include roots (incl. the `platform/ios`, `platform/cxx`, and react-native-macos + `platform/macos` overrides). Third-party `` etc. come from the + `ReactNativeDependencies` xcframework's canonical `Headers/`. + +RN's new-architecture C++ requires **C++20** (`-std=c++20`, set in `.bazelrc`). + +## End-to-end RN-Tester: how the app is built + +``` +Berry yarn.lock ──(rules_js fork)──▶ node_modules ──(Metro)──▶ RNTesterApp.macos.jsbundle +prebuilt React.xcframework ──(reconstruct_react_headers.py)──▶ :React_headers (Obj-C hdrs) +RN source ReactCommon/** ────────────────────────────────────▶ :rn_cxx_headers (C++ hdrs) + │ + ▼ +bazel/MinimalAppDelegate.mm (RCTReactNativeFactory host) + │ + link React/hermes/ReactNativeDependencies XCFrameworks + ▼ +macos_application :RNTesterMacBazel ──▶ RNTesterMacBazel.app (embeds the jsbundle) +``` + +The minimal host (`bazel/MinimalAppDelegate.mm` + `bazel/minimal_main.m`) boots +`RCTReactNativeFactory` against the embedded bundle. It intentionally omits rn-tester's own +native example modules (NativeCxxModuleExample / RNTMyNativeView) so the app links against +only the prebuilt binaries; adding those (compiling the Phase B codegen + the example native +code) is the natural next increment toward the *full* rn-tester `AppDelegate.mm`. + +### Prebuilt XCFrameworks build on Xcode 26 + +react-native-macos already carries the Hermes version-resolution patches +(`scripts/ios-prebuild/microsoft-hermes.js`): a release branch downloads a published Hermes; +`main` (`1000.0.0`) builds Hermes from source at the merge-base commit. Getting that working on +**Xcode 26** required two fixes in this branch: +* **Host `hermesc` mis-targeted to visionOS.** `ios-prebuild` sets `XROS_DEPLOYMENT_TARGET` + for the cross-platform builds and it leaked into the *native* `build_host_hermesc`; Xcode 26's + clang honors it and built the host tools for visionOS, failing llvh's `CheckAtomic`. Fixed in + `sdks/hermes-engine/utils/build-apple-framework.sh` (force a macOS target for the host tools). +* **Upstream Hermes Mac Catalyst triple.** Hermes hardcodes an invalid universal Catalyst + triple (`-target x86_64-arm64-apple-ios…-macabi`) that Xcode 26's clang rejects. Catalyst + isn't needed for a macOS app, so `build-ios-framework.sh` accepts `HERMES_APPLE_PLATFORMS` + to build a subset (e.g. `macosx`). +* Use **CMake 3.x** (`cmake@3.26.4`); Hermes doesn't configure under Homebrew-default CMake 4.x. + +## What's next (increments) + +* **Full rn-tester host**: compile the Phase B codegen (`RCTAppDependencyProvider`, AppSpecs) + + the NativeCxxModuleExample / NativeComponentExample native code into libraries and swap the + minimal host for rn-tester's real `AppDelegate.mm`. +* **`bazel run`**: wire an ad-hoc-signed run so the app launches directly from Bazel. +* **CI**: run the app build on the macos-26 runner reusing the prebuild artifacts. ## Apple: prebuilt XCFrameworks (swappable seam) diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel index d2b420469b0a..a11e71bcc882 100644 --- a/packages/react-native/BUILD.bazel +++ b/packages/react-native/BUILD.bazel @@ -6,6 +6,49 @@ load("@npm//:defs.bzl", "npm_link_all_packages") npm_link_all_packages() +# Canonical C++ header roots from the RN source tree. The SPM-prebuilt +# React.xcframework only exports a partial header set; the deep Fabric/renderer +# C++ headers (e.g. , , +# ) live only in ReactCommon/ in source. Exposing them on the include +# path lets Bazel compile ObjC++/C++ that touches the new-architecture surface, +# while still linking against the prebuilt binary (same `main` version). +cc_library( + name = "rn_cxx_headers", + hdrs = glob( + [ + "ReactCommon/**/*.h", + "ReactCommon/**/*.hpp", + ], + allow_empty = True, + ), + includes = [ + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/callinvoker", + "ReactCommon/runtimeexecutor", + "ReactCommon/yoga", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/jsitooling", + "ReactCommon/jsiexecutor", + # Renderer platform overrides (Apple uses the ios graphics/text/image + # variants and the cxx view/text/scrollview variants; react-native-macos + # additionally provides a macos view override that takes precedence). + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/imagemanager/platform/ios", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios", + "ReactCommon/react/renderer/components/textinput/platform/ios", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/components/view/platform/cxx", + "ReactCommon/react/renderer/components/text/platform/cxx", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + ], + tags = ["manual"], + visibility = ["//visibility:public"], +) + npm_package( name = "pkg", srcs = glob( diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index a14dc22f4605..821db3a39418 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -1,16 +1,18 @@ # React Native macOS — Bazel vertical slice (draft / experimental) # -# Status (see docs/bazel.md): -# * The rules_js Berry fork is GREEN (deps resolve/link from the Berry yarn.lock). -# * First-party workspace packages now expose `:pkg` targets so rules_js can link -# them; `bazel build //packages/react-native:pkg` builds. -# * The Metro bundle + macOS app targets below are tagged `manual` (WIP): -# - the Metro bundle needs the RN `react-native`->`react-native-macos` alias and a -# sandbox-safe config (bazel/bundle.js), @react-native/codegen `lib` built, and the -# full strict-deps closure assembled (rules_js does not hoist like Yarn); -# - the macOS app needs the prebuilt XCFrameworks; ios-prebuild resolves the correct -# Hermes (macOS patches) but building it from source needs Xcode 16.x (CI-pinned) -- -# the local Xcode 26 trips LLVM CheckAtomic. See docs/bazel.md. +# Status (see docs/bazel.md): this slice builds RNTester as a macOS app entirely +# with Bazel on Xcode 26: +# * rules_js (Berry fork) drives Metro to produce the real rn-tester JS bundle +# (`:rntester_macos_jsbundle`, ~1.9MB). +# * The prebuilt React/hermes/ReactNativeDependencies XCFrameworks are imported and, +# because the SPM prebuild flattens React's headers, a canonical header tree is +# reconstructed (`@rn_prebuilt_xcframeworks//:React_headers`) and combined with the +# RN source C++ headers (`//packages/react-native:rn_cxx_headers`). +# * A minimal RCTReactNativeFactory host (`bazel/MinimalAppDelegate.mm`) compiles and +# links against those, and `:RNTesterMacBazel` (macos_application) embeds the bundle. +# `bazel build //packages/rn-tester:RNTesterMacBazel` produces a launchable .app. +# App/native targets are tagged `manual` (they need the prebuilt XCFrameworks present) +# so `bazel build //...` / CI stays green without them. load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_library", "js_run_binary") load("@npm//:defs.bzl", "npm_link_all_packages") @@ -92,34 +94,38 @@ js_run_binary( tool = ":bundler", ) -# 3. App host. NOTE: rn-tester's real AppDelegate.mm pulls in rn-tester-specific native +# 3. App host. The REAL rn-tester AppDelegate.mm pulls in rn-tester-specific native # modules + codegen (NativeCxxModuleExample, RNTMyNativeViewComponentView, -# ReactAppDependencyProvider) that are NOT in the prebuilt XCFrameworks. A green app -# therefore needs either those built too, or a minimal RN macOS host. The imported -# XCFrameworks below DO build on Xcode 26 (bazel build @rn_prebuilt_xcframeworks//:React). +# ReactAppDependencyProvider) that are not in the prebuilt XCFrameworks. This slice +# ships a MINIMAL macOS host that boots RCTReactNativeFactory against the embedded +# Metro bundle, linking only the prebuilt XCFrameworks (+ the reconstructed React +# canonical header tree, :React_headers). See docs/bazel.md. objc_library( - name = "rntester_macos_host", + name = "rntester_macos_minimal_host", srcs = [ - "RNTester/AppDelegate.mm", - "RNTester/main.m", + "bazel/MinimalAppDelegate.mm", + "bazel/minimal_main.m", ], - hdrs = ["RNTester/AppDelegate.h"], + hdrs = ["bazel/MinimalAppDelegate.h"], tags = ["manual"], deps = [ + "//packages/react-native:rn_cxx_headers", "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", "@rn_prebuilt_xcframeworks//:hermes", ], ) -# 4. macOS app: link native + embed the Metro bundle as an app resource +# 4. macOS app: link the minimal host + embed the Metro bundle as an app resource # (mirrors how Buck2's apple prelude ingests a js_bundle as an AppleResource). macos_application( name = "RNTesterMacBazel", bundle_id = "org.reactjs.native.RNTesterMacBazel", infoplists = ["bazel/Info.plist"], - minimum_os_version = "11.0", + minimum_os_version = "14.0", resources = [":rntester_macos_jsbundle"], tags = ["manual"], - deps = [":rntester_macos_host"], + deps = [":rntester_macos_minimal_host"], ) diff --git a/packages/rn-tester/bazel/MinimalAppDelegate.h b/packages/rn-tester/bazel/MinimalAppDelegate.h new file mode 100644 index 000000000000..d987997d7a61 --- /dev/null +++ b/packages/rn-tester/bazel/MinimalAppDelegate.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import +#import + +// A minimal macOS host for the Bazel slice. It boots the React Native runtime via +// RCTReactNativeFactory and loads the Metro bundle embedded in the app's Resources. +// Unlike rn-tester's full AppDelegate it intentionally omits the rn-tester-specific +// native example modules (NativeCxxModuleExample / RNTMyNativeView) so the app links +// against only the prebuilt XCFrameworks. +@interface MinimalAppDelegate : RCTDefaultReactNativeFactoryDelegate + +@property (nonatomic, strong, nonnull) RCTPlatformWindow *window; +@property (nonatomic, strong, nonnull) RCTReactNativeFactory *reactNativeFactory; + +@end diff --git a/packages/rn-tester/bazel/MinimalAppDelegate.mm b/packages/rn-tester/bazel/MinimalAppDelegate.mm new file mode 100644 index 000000000000..d0e9ad49ccb1 --- /dev/null +++ b/packages/rn-tester/bazel/MinimalAppDelegate.mm @@ -0,0 +1,34 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "MinimalAppDelegate.h" + +@implementation MinimalAppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self]; + + self.window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1280, 720) + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | + NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered + defer:NO]; + self.window.title = @"RNTesterApp (Bazel)"; + + [self.reactNativeFactory startReactNativeWithModuleName:@"RNTesterApp" + inWindow:self.window + initialProperties:@{} + launchOptions:notification.userInfo]; +} + +- (NSURL *)bundleURL +{ + return [[NSBundle mainBundle] URLForResource:@"RNTesterApp.macos" withExtension:@"jsbundle"]; +} + +@end diff --git a/packages/rn-tester/bazel/minimal_main.m b/packages/rn-tester/bazel/minimal_main.m new file mode 100644 index 000000000000..afd9196e558c --- /dev/null +++ b/packages/rn-tester/bazel/minimal_main.m @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "MinimalAppDelegate.h" + +int main(int argc, const char *argv[]) +{ + @autoreleasepool { + NSApplication *application = [NSApplication sharedApplication]; + MinimalAppDelegate *delegate = [MinimalAppDelegate new]; + // Retain the delegate for the lifetime of the app. + application.delegate = (id)delegate; + CFBridgingRetain(delegate); + [application run]; + } + return 0; +} diff --git a/tools/bazel/apple/prebuilt_xcframeworks.bzl b/tools/bazel/apple/prebuilt_xcframeworks.bzl index d415d7249871..602d3aa8fcac 100644 --- a/tools/bazel/apple/prebuilt_xcframeworks.bzl +++ b/tools/bazel/apple/prebuilt_xcframeworks.bzl @@ -39,6 +39,51 @@ def _prebuilt_xcframeworks_impl(rctx): name = name, )) + # ReactNativeDependencies ships canonical, nested third-party headers + # (folly/, boost/, glog/, fmt/, double-conversion/, fast_float/) at the + # xcframework root `Headers/`. Expose them on the include path so C++ sources + # that pull `` etc. compile. + if "ReactNativeDependencies" not in missing: + lines.append(""" +cc_library( + name = "ReactNativeDependencies_headers", + hdrs = glob(["ReactNativeDependencies.xcframework/Headers/**"], allow_empty = True), + includes = ["ReactNativeDependencies.xcframework/Headers"], +) +""") + + # The React.xcframework flattens each SPM target's public headers into + # `Headers//.h`, which breaks the canonical ``, + # ``, `` imports used by both the framework's own + # headers and app sources. Reconstruct a canonical `-I` tree of symlinks so the + # headers are consumable from Bazel, and expose it as `:React_headers`. + if "React" not in missing: + script = rctx.path(Label("//tools/bazel/apple:reconstruct_react_headers.py")) + slice_dir = None + for entry in rctx.path("React.xcframework").readdir(): + if entry.basename.startswith("macos-"): + slice_dir = entry.basename + break + if slice_dir: + fw_headers = "React.xcframework/{}/React.framework/Headers".format(slice_dir) + res = rctx.execute(["python3", str(script), fw_headers, "flat_headers"], quiet = True) + if res.return_code != 0: + fail("reconstruct_react_headers failed: {}".format(res.stderr)) + lines.append(""" +cc_library( + name = "React_headers", + hdrs = glob(["flat_headers/**"], allow_empty = True), + includes = ["flat_headers"], + defines = [ + "RCT_DEV=1", + "RCT_ENABLE_INSPECTOR=1", + "RCT_REMOTE_PROFILE=0", + "RCT_PROFILE=0", + "RCT_NEW_ARCH_ENABLED=1", + ], +) +""") + if missing: # Emit a target that fails at build time with guidance, rather than failing analysis. msg = ("Prebuilt XCFrameworks not found: {}. Build them first with " + diff --git a/tools/bazel/apple/reconstruct_react_headers.py b/tools/bazel/apple/reconstruct_react_headers.py new file mode 100644 index 000000000000..f96278f1f3e2 --- /dev/null +++ b/tools/bazel/apple/reconstruct_react_headers.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python3 +"""Reconstruct a canonical header tree from the SPM-prebuilt React.xcframework. + +The React.xcframework produced by `scripts/ios-prebuild.js` flattens every SPM +target's public headers into `Headers//.h` (e.g. +`Headers/React_Core/RCTBridge.h`, `Headers/React_graphics/Color.h`). But both the +framework's own headers *and* app sources import them by their canonical paths: + + #import // -> React_Core/RCTBridge.h + #import // -> React_RCTUIKit/RCTUIKit.h + #include // -> React_graphics/ColorComponents.h + #include // -> React_jsi/jsi.h + #import // -> React_RCTAppDelegate/RCTReactNativeFactory.h + +None of those resolve against the flattened layout, so the framework is not +directly consumable by clang/Bazel. This script rebuilds a canonical `-I` tree of +symlinks so the imports resolve. It is deliberately generic: it discovers the +canonical include paths by scanning the framework's own headers for +`#include/#import <...>` directives and maps each to a physical file by basename, +disambiguating collisions with a path-segment heuristic. + +Usage: reconstruct_react_headers.py +""" + +import os +import re +import sys + +# Modules whose headers are imported with the flat `` (Obj-C) prefix. +# On basename collisions we prefer React_Core, then these, in order. +OBJC_REACT_MODULES = [ + "React_Core", + "React_RCTUIKit", + "React_CoreModules", + "React_RCTAppDelegate", + "React_RCTImage", + "React_RCTText", + "React_RCTBlob", + "React_RCTVibration", + "React_RCTSettings", + "React_RCTFabric", + "React_NativeModulesApple", + "RCTDeprecation", +] + +# Modules whose (single) header is imported flat, e.g. ``. +FLAT_ROOT_MODULES = ["React_RCTAppDelegate"] + +INCLUDE_RE = re.compile(r'#\s*(?:import|include)\s*<([^>]+)>') + +# Canonical namespaces supplied from the RN *source* tree (complete, correctly +# nested, siblings co-located) rather than the framework's flattened copy. Any +# `` include with one of these first segments is skipped during +# reconstruction. Everything else (React/, RCTDeprecation/, RCTTypeSafety/, ...) +# is Obj-C and reconstructed from the framework. +SOURCE_PREFIXES = frozenset([ + "react", + "ReactCommon", + "jsi", + "jsireact", + "yoga", + "cxxreact", + "folly", + "boost", + "glog", + "fmt", + "double-conversion", + "fast_float", + "jsinspector-modern", + "logger", + "reactperflogger", + "hermes", + "reacthermes", + "jserrorhandler", + "jsitooling", + "callinvoker", + "runtimeexecutor", + "oscompat", +]) + + +def main(): + headers_dir, out_dir = os.path.abspath(sys.argv[1]), sys.argv[2] + + # 1. Index every physical header: basename -> [(module, abspath)]. + by_basename = {} + all_headers = [] + for module in sorted(os.listdir(headers_dir)): + mdir = os.path.join(headers_dir, module) + if not os.path.isdir(mdir): + continue + for root, _dirs, files in os.walk(mdir): + for f in files: + if not f.endswith((".h", ".hpp", ".hh")): + continue + p = os.path.join(root, f) + all_headers.append((module, p)) + by_basename.setdefault(f, []).append((module, p)) + + # 2. Collect every canonical include path referenced anywhere. + referenced = set() + for _module, p in all_headers: + try: + with open(p, "r", errors="ignore") as fh: + for m in INCLUDE_RE.finditer(fh.read()): + referenced.add(m.group(1)) + except OSError: + pass + + links = {} # canonical-relpath -> physical abspath (first writer wins) + + def want(rel, phys): + links.setdefault(rel, phys) + + def rank_objc(module): + return OBJC_REACT_MODULES.index(module) if module in OBJC_REACT_MODULES else 999 + + def pick(candidates, hint_segments): + """Choose the best physical file for a canonical path.""" + if len(candidates) == 1: + return candidates[0][1] + # Prefer a module whose name matches a hint path segment. + best, best_score = candidates[0][1], float("-inf") + for module, phys in candidates: + mtokens = module.lower().replace("react_", "").split("_") + score = sum(1 for seg in hint_segments if seg.lower() in mtokens or seg.lower() == module.lower()) + # Tie-break toward canonical Obj-C ordering (React_Core first). + score = score * 100 - rank_objc(module) + if score > best_score: + best, best_score = phys, score + return best + + # 3. Map referenced canonical `` (Obj-C) paths to physical files. + # C++ / ReactCommon / jsi / yoga headers are intentionally NOT reconstructed + # here: the framework only ships a partial, flattened copy of them (which also + # breaks their quoted sibling includes). Those are supplied from the RN source + # tree instead (see //packages/react-native:rn_cxx_headers), which keeps the + # canonical layout and co-locates siblings. + for rel in referenced: + if "/" not in rel: + continue + if rel.split("/")[0] in SOURCE_PREFIXES: + continue + base = os.path.basename(rel) + cands = by_basename.get(base) + if not cands: + continue + segs = rel.split("/")[:-1] + want(rel, pick(cands, segs)) + + # 4. Flat `` tree: every Obj-C React module header by basename. + for module, phys in all_headers: + if module not in OBJC_REACT_MODULES: + continue + base = os.path.basename(phys) + rel = "React/" + base + existing = links.get(rel) + if existing is None: + links[rel] = phys + else: + # Prefer the higher-priority Obj-C module on collision. + cur_module = _module_of(existing, headers_dir) + if rank_objc(module) < rank_objc(cur_module): + links[rel] = phys + + # 5. Flat-root single-header modules, e.g. ``. + for module, phys in all_headers: + if module in FLAT_ROOT_MODULES: + want(os.path.basename(phys), phys) + + # 6. Materialize the symlink tree (relative links so the tree stays valid + # when relocated, e.g. inside a Bazel external repo). + count = 0 + for rel, phys in links.items(): + dst = os.path.join(out_dir, rel) + os.makedirs(os.path.dirname(dst), exist_ok=True) + if os.path.lexists(dst): + os.remove(dst) + os.symlink(os.path.relpath(phys, os.path.dirname(os.path.abspath(dst))), dst) + count += 1 + + sys.stderr.write( + "reconstruct_react_headers: %d physical headers, %d referenced paths, " + "%d symlinks\n" % (len(all_headers), len(referenced), count) + ) + + +def _module_of(phys, headers_dir): + rel = os.path.relpath(phys, headers_dir) + return rel.split(os.sep)[0] + + +if __name__ == "__main__": + main() From 1221a937d447f7ead4c7686e3d752d90bab8d901 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 7 Jul 2026 10:08:32 -0700 Subject: [PATCH 13/24] Bazel: build the FULL rn-tester host (real AppDelegate + codegen + native modules) Adds :RNTesterMacBazelFull, linking rn-tester's real RNTester/AppDelegate.mm (via bazel/real_main.m) instead of the minimal host: * Phase B codegen is now compiled: rn_codegen emits explicit file targets and wraps them in cc_library header targets with virtual prefixes so the app can #import , and ; rn_tester_appspecs_lib compiles the AppSpecs + providers (RCTAppDependencyProvider is linked into the app). * NativeCxxModuleExample (C++ TurboModule) compiled + exposed as . * Sample TurboModules (SampleTurboCxxModule / RCTSampleTurboModule) built from the RN source samples; +samples include roots on rn_cxx_headers. * RCTLinking + RCTPushNotification built from source (not in the prebuilt React.xcframework) and exposed as ; UserNotifications.framework linked. * reconstruct_react_headers.py: map the core-codegen umbrella (referenced by app sources, not framework headers). RN_DISABLE_OSS_PLUGIN_HEADER still skips the Fabric NativeComponentExample (its sources use quoted plugin includes not yet wired). All targets stay tagged manual. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 14 ++- packages/react-native/BUILD.bazel | 64 ++++++++++ packages/rn-tester/BUILD.bazel | 43 +++++++ .../NativeCxxModuleExample/BUILD.bazel | 23 ++++ packages/rn-tester/bazel/real_main.m | 24 ++++ .../bazel/apple/reconstruct_react_headers.py | 13 +++ tools/bazel/react_native/defs.bzl | 109 +++++++++++++++--- 7 files changed, 269 insertions(+), 21 deletions(-) create mode 100644 packages/rn-tester/bazel/real_main.m diff --git a/docs/bazel.md b/docs/bazel.md index e26fd3b08b2f..d426da15bfa8 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -104,6 +104,14 @@ prebuilt-XCFramework link. Specifically: minimal `RCTReactNativeFactory` host, links the prebuilt React/hermes/ReactNativeDependencies XCFrameworks, and embeds the JS bundle. The resulting `.app` contains the arm64 binary, `Contents/Resources/RNTesterApp.macos.jsbundle`, and `Contents/Frameworks/hermes.framework`. +* **The FULL rn-tester host also builds** — `:RNTesterMacBazelFull` links rn-tester's *real* + `RNTester/AppDelegate.mm` with the Bazel-built codegen (`RCTAppDependencyProvider` + AppSpecs + compiled into `//tools/bazel/react_native:rn_tester_appspecs_lib`), the C++ TurboModule + example (`NativeCxxModuleExample`), the sample TurboModules + (`//packages/react-native:sample_turbo_modules`), and the RCTLinking/RCTPushNotification + modules built from source (not in the prebuilt framework). `RN_DISABLE_OSS_PLUGIN_HEADER` + currently skips the Fabric `NativeComponentExample` (its sources use quoted plugin includes + not yet wired). ### Consuming the prebuilt XCFrameworks from Bazel (the header problem) @@ -168,9 +176,9 @@ react-native-macos already carries the Hermes version-resolution patches ## What's next (increments) -* **Full rn-tester host**: compile the Phase B codegen (`RCTAppDependencyProvider`, AppSpecs) - + the NativeCxxModuleExample / NativeComponentExample native code into libraries and swap the - minimal host for rn-tester's real `AppDelegate.mm`. +* **Fabric NativeComponentExample**: wire the codegen'd `RCTFabricComponentsPlugins.h` + + `RCTThirdPartyComponentsProvider` registration so the `RNTMyNativeView` example compiles + (drop `RN_DISABLE_OSS_PLUGIN_HEADER`). * **`bazel run`**: wire an ad-hoc-signed run so the app launches directly from Bazel. * **CI**: run the app build on the macos-26 runner reusing the prebuild artifacts. diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel index a11e71bcc882..b78e18862015 100644 --- a/packages/react-native/BUILD.bazel +++ b/packages/react-native/BUILD.bazel @@ -29,6 +29,8 @@ cc_library( "ReactCommon/yoga", "ReactCommon/react/nativemodule/core", "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/samples", + "ReactCommon/react/nativemodule/samples/platform/ios", "ReactCommon/react/runtime/platform/ios", "ReactCommon/jsitooling", "ReactCommon/jsiexecutor", @@ -49,6 +51,68 @@ cc_library( visibility = ["//visibility:public"], ) +# rn-tester's real AppDelegate imports RCTLinkingManager + RCTPushNotificationManager, +# which are separate RN modules NOT included in the prebuilt React.xcframework. Build +# them from source and expose their headers as (matching the podspec layout). +cc_library( + name = "rct_linking_hdrs", + hdrs = ["Libraries/LinkingIOS/RCTLinkingManager.h"], + strip_include_prefix = "Libraries/LinkingIOS", + include_prefix = "React", + tags = ["manual"], + visibility = ["//visibility:public"], +) + +cc_library( + name = "rct_pushnotification_hdrs", + hdrs = [ + "Libraries/PushNotificationIOS/RCTPushNotificationManager.h", + "Libraries/PushNotificationIOS/RCTPushNotificationPlugins.h", + ], + strip_include_prefix = "Libraries/PushNotificationIOS", + include_prefix = "React", + tags = ["manual"], + visibility = ["//visibility:public"], +) + +objc_library( + name = "rntester_extra_rn_modules", + srcs = [ + "Libraries/LinkingIOS/RCTLinkingManager.mm", + "Libraries/LinkingIOS/RCTLinkingPlugins.h", + "Libraries/PushNotificationIOS/RCTPushNotificationManager.mm", + "Libraries/PushNotificationIOS/RCTPushNotificationPlugins.h", + "Libraries/PushNotificationIOS/RCTPushNotificationPlugins.mm", + ], + tags = ["manual"], + visibility = ["//visibility:public"], + deps = [ + ":rct_linking_hdrs", + ":rct_pushnotification_hdrs", + ":rn_cxx_headers", + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", + ], +) +objc_library( + name = "sample_turbo_modules", + srcs = [ + "ReactCommon/react/nativemodule/samples/ReactCommon/NativeSampleTurboCxxModuleSpecJSI.cpp", + "ReactCommon/react/nativemodule/samples/ReactCommon/SampleTurboCxxModule.cpp", + "ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTNativeSampleTurboModuleSpec.mm", + "ReactCommon/react/nativemodule/samples/platform/ios/ReactCommon/RCTSampleTurboModule.mm", + ], + tags = ["manual"], + visibility = ["//visibility:public"], + deps = [ + ":rn_cxx_headers", + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", + ], +) + npm_package( name = "pkg", srcs = glob( diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index 821db3a39418..bad99f5ee9a5 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -129,3 +129,46 @@ macos_application( tags = ["manual"], deps = [":rntester_macos_minimal_host"], ) + +# 5. FULL host: rn-tester's real RNTester/AppDelegate.mm + a programmatic main +# (bazel/real_main.m avoids a MainMenu.nib). It links the Bazel-built codegen +# (RCTAppDependencyProvider + AppSpecs), the C++ TurboModule example, and the sample +# TurboModules that the real AppDelegate's getTurboModule:/dependencyProvider need. +# RN_DISABLE_OSS_PLUGIN_HEADER skips the Fabric NativeComponentExample (its sources use +# quoted plugin includes not yet wired); everything else is the real rn-tester host. +objc_library( + name = "rntester_macos_full_host", + srcs = [ + "RNTester/AppDelegate.mm", + "bazel/real_main.m", + ], + hdrs = ["RNTester/AppDelegate.h"], + copts = ["-DRN_DISABLE_OSS_PLUGIN_HEADER"], + includes = ["RNTester"], + sdk_frameworks = ["UserNotifications"], + tags = ["manual"], + deps = [ + "//packages/react-native:rn_cxx_headers", + "//packages/react-native:rntester_extra_rn_modules", + "//packages/react-native:sample_turbo_modules", + "//packages/rn-tester/NativeCxxModuleExample", + "//tools/bazel/react_native:rn_tester_appspecs_appdep_hdrs", + "//tools/bazel/react_native:rn_tester_appspecs_lib", + "//tools/bazel/react_native:rn_tester_appspecs_reactcodegen_hdrs", + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", + "@rn_prebuilt_xcframeworks//:hermes", + ], +) + +macos_application( + name = "RNTesterMacBazelFull", + bundle_id = "org.reactjs.native.RNTesterMacBazelFull", + infoplists = ["bazel/Info.plist"], + minimum_os_version = "14.0", + resources = [":rntester_macos_jsbundle"], + tags = ["manual"], + deps = [":rntester_macos_full_host"], +) diff --git a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel index a92b2ef0c6da..e63584f671d7 100644 --- a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel +++ b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel @@ -1,3 +1,26 @@ package(default_visibility = ['//visibility:public']) exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) + +# Header exposed to the app as . +cc_library( + name = "NativeCxxModuleExample_hdrs", + hdrs = ["NativeCxxModuleExample.h"], + include_prefix = "NativeCxxModuleExample", + tags = ["manual"], + deps = ["//tools/bazel/react_native:rn_tester_appspecs_reactcodegen_hdrs"], +) + +# rn-tester's C++ TurboModule example (used by the app's getTurboModule:). +objc_library( + name = "NativeCxxModuleExample", + srcs = ["NativeCxxModuleExample.cpp"], + tags = ["manual"], + deps = [ + ":NativeCxxModuleExample_hdrs", + "//packages/react-native:rn_cxx_headers", + "//tools/bazel/react_native:rn_tester_appspecs_reactcodegen_hdrs", + "@rn_prebuilt_xcframeworks//:React_headers", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", + ], +) diff --git a/packages/rn-tester/bazel/real_main.m b/packages/rn-tester/bazel/real_main.m new file mode 100644 index 000000000000..dd3e78eaf0f3 --- /dev/null +++ b/packages/rn-tester/bazel/real_main.m @@ -0,0 +1,24 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "AppDelegate.h" + +// rn-tester's own main.m uses NSApplicationMain (nib-driven). This slice wires the +// real AppDelegate programmatically so no MainMenu.nib is required in the bundle. +int main(int argc, const char *argv[]) +{ + @autoreleasepool { + NSApplication *application = [NSApplication sharedApplication]; + AppDelegate *delegate = [AppDelegate new]; + application.delegate = (id)delegate; + CFBridgingRetain(delegate); + [application run]; + } + return 0; +} diff --git a/tools/bazel/apple/reconstruct_react_headers.py b/tools/bazel/apple/reconstruct_react_headers.py index f96278f1f3e2..355bfbe146aa 100644 --- a/tools/bazel/apple/reconstruct_react_headers.py +++ b/tools/bazel/apple/reconstruct_react_headers.py @@ -46,6 +46,12 @@ # Modules whose (single) header is imported flat, e.g. ``. FLAT_ROOT_MODULES = ["React_RCTAppDelegate"] +# Header families that live in React_Core but are consumed via a `` +# umbrella prefix (the core codegen spec). The framework references some of these +# (so they get reconstructed by the scan) but not the umbrella header itself, which +# is only pulled in by app/library sources — so map the whole family explicitly. +SELF_NAMED_MODULES = ["FBReactNativeSpec"] + INCLUDE_RE = re.compile(r'#\s*(?:import|include)\s*<([^>]+)>') # Canonical namespaces supplied from the RN *source* tree (complete, correctly @@ -168,6 +174,13 @@ def pick(candidates, hint_segments): if module in FLAT_ROOT_MODULES: want(os.path.basename(phys), phys) + # 5c. Self-named umbrella families (e.g. ``). + for module, phys in all_headers: + base = os.path.basename(phys) + for name in SELF_NAMED_MODULES: + if base.startswith(name): + want(name + "/" + base, phys) + # 6. Materialize the symlink tree (relative links so the tree stays valid # when relocated, e.g. inside a Bazel external repo). count = 0 diff --git a/tools/bazel/react_native/defs.bzl b/tools/bazel/react_native/defs.bzl index 2fcb6b13de01..8cc08c017611 100644 --- a/tools/bazel/react_native/defs.bzl +++ b/tools/bazel/react_native/defs.bzl @@ -1,30 +1,71 @@ load('@aspect_rules_js//js:defs.bzl', 'js_run_binary') -_CODEGEN_OUTS = [ - 'build/generated/ios/AppSpecs/AppSpecs-generated.mm', - 'build/generated/ios/AppSpecs/AppSpecs.h', - 'build/generated/ios/AppSpecsJSI-generated.cpp', - 'build/generated/ios/AppSpecsJSI.h', - 'build/generated/ios/RCTAppDependencyProvider.h', - 'build/generated/ios/RCTAppDependencyProvider.mm', - 'build/generated/ios/RCTModuleProviders.h', - 'build/generated/ios/RCTModuleProviders.mm', - 'build/generated/ios/RCTModulesConformingToProtocolsProvider.h', - 'build/generated/ios/RCTModulesConformingToProtocolsProvider.mm', - 'build/generated/ios/RCTThirdPartyComponentsProvider.h', - 'build/generated/ios/RCTThirdPartyComponentsProvider.mm', - 'build/generated/ios/RCTUnstableModulesRequiringMainQueueSetupProvider.h', - 'build/generated/ios/RCTUnstableModulesRequiringMainQueueSetupProvider.mm', - 'build/generated/ios/ReactAppDependencyProvider.podspec', - 'build/generated/ios/ReactCodegen.podspec', +_GEN = 'build/generated/ios/' + +# Top-level generated headers, consumed as `` on Apple. +_TOP_HEADERS = [ + _GEN + 'AppSpecsJSI.h', + _GEN + 'RCTModuleProviders.h', + _GEN + 'RCTModulesConformingToProtocolsProvider.h', + _GEN + 'RCTThirdPartyComponentsProvider.h', + _GEN + 'RCTUnstableModulesRequiringMainQueueSetupProvider.h', + _GEN + 'AppSpecs/AppSpecs.h', +] + +# Consumed as ``. +_APPDEP_HEADER = _GEN + 'RCTAppDependencyProvider.h' + +# Fabric component headers, consumed as ``. +_FABRIC_HEADERS = [ + _GEN + 'react/renderer/components/AppSpecs/ComponentDescriptors.h', + _GEN + 'react/renderer/components/AppSpecs/EventEmitters.h', + _GEN + 'react/renderer/components/AppSpecs/Props.h', + _GEN + 'react/renderer/components/AppSpecs/RCTComponentViewHelpers.h', + _GEN + 'react/renderer/components/AppSpecs/ShadowNodes.h', + _GEN + 'react/renderer/components/AppSpecs/States.h', +] + +_SOURCES = [ + _GEN + 'RCTAppDependencyProvider.mm', + _GEN + 'RCTModuleProviders.mm', + _GEN + 'RCTModulesConformingToProtocolsProvider.mm', + _GEN + 'RCTThirdPartyComponentsProvider.mm', + _GEN + 'RCTUnstableModulesRequiringMainQueueSetupProvider.mm', + _GEN + 'AppSpecs/AppSpecs-generated.mm', + _GEN + 'AppSpecsJSI-generated.cpp', + _GEN + 'react/renderer/components/AppSpecs/ComponentDescriptors.cpp', + _GEN + 'react/renderer/components/AppSpecs/EventEmitters.cpp', + _GEN + 'react/renderer/components/AppSpecs/Props.cpp', + _GEN + 'react/renderer/components/AppSpecs/ShadowNodes.cpp', + _GEN + 'react/renderer/components/AppSpecs/States.cpp', +] + +_PODSPECS = [ + _GEN + 'ReactAppDependencyProvider.podspec', + _GEN + 'ReactCodegen.podspec', +] + +_CODEGEN_OUTS = _TOP_HEADERS + [_APPDEP_HEADER] + _FABRIC_HEADERS + _SOURCES + _PODSPECS + +_HEADER_DEPS = [ + '//packages/react-native:rn_cxx_headers', + '@rn_prebuilt_xcframeworks//:React_headers', + '@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers', ] def rn_codegen(name, project_root, rn_tester_srcs, **kwargs): + """Generate rn-tester's codegen (AppSpecs + providers) and compile it. + + Produces: + * `` -- the raw generated files (js_run_binary). + * `_lib` -- an objc_library compiling the generated providers + AppSpecs, + exposing ``, `` and + `` to the app. + """ js_run_binary( name = name, srcs = rn_tester_srcs + ['//tools/bazel/react_native:codegen_lib'], outs = _CODEGEN_OUTS, - out_dirs = ['build/generated/ios/react/renderer/components/AppSpecs'], env = { 'PROJECT_ROOT': project_root, 'OUTPUT_DIR': '$(RULEDIR)', @@ -35,3 +76,35 @@ def rn_codegen(name, project_root, rn_tester_srcs, **kwargs): tool = '//tools/bazel/react_native:codegen_runner_bin', **kwargs ) + + native.cc_library( + name = name + '_reactcodegen_hdrs', + hdrs = _TOP_HEADERS, + strip_include_prefix = 'build/generated/ios', + include_prefix = 'ReactCodegen', + tags = ['manual'], + ) + native.cc_library( + name = name + '_appdep_hdrs', + hdrs = [_APPDEP_HEADER], + strip_include_prefix = 'build/generated/ios', + include_prefix = 'ReactAppDependencyProvider', + tags = ['manual'], + ) + native.cc_library( + name = name + '_fabric_hdrs', + hdrs = _FABRIC_HEADERS, + strip_include_prefix = 'build/generated/ios', + tags = ['manual'], + ) + + native.objc_library( + name = name + '_lib', + srcs = _SOURCES, + deps = [ + ':' + name + '_reactcodegen_hdrs', + ':' + name + '_appdep_hdrs', + ':' + name + '_fabric_hdrs', + ] + _HEADER_DEPS, + tags = ['manual'], + ) From dd2733ef5c1ad806f2517a25dd4296e9126784d7 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 7 Jul 2026 10:12:17 -0700 Subject: [PATCH 14/24] =?UTF-8?q?Bazel:=20complete=20rn-tester=20host=20?= =?UTF-8?q?=E2=80=94=20enable=20the=20Fabric=20NativeComponentExample?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds NativeComponentExample (RNTMyNativeView Fabric component + legacy/interop views) and links it into :RNTesterMacBazelFull, dropping RN_DISABLE_OSS_PLUGIN_HEADER. The real, unmodified rn-tester AppDelegate.mm now compiles + links with ALL its example modules (codegen providers, C++ TurboModule, Fabric component, sample TurboModules) — no rn-tester source is patched or #ifdef'd out. A small header shim exposes the core (quoted by the component sources; impl lives in React.xcframework). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 20 ++++++------ packages/react-native/BUILD.bazel | 11 +++++++ packages/rn-tester/BUILD.bazel | 9 +++--- .../NativeComponentExample/BUILD.bazel | 32 +++++++++++++++++++ 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/docs/bazel.md b/docs/bazel.md index d426da15bfa8..b001ada6dcd1 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -104,14 +104,13 @@ prebuilt-XCFramework link. Specifically: minimal `RCTReactNativeFactory` host, links the prebuilt React/hermes/ReactNativeDependencies XCFrameworks, and embeds the JS bundle. The resulting `.app` contains the arm64 binary, `Contents/Resources/RNTesterApp.macos.jsbundle`, and `Contents/Frameworks/hermes.framework`. -* **The FULL rn-tester host also builds** — `:RNTesterMacBazelFull` links rn-tester's *real* - `RNTester/AppDelegate.mm` with the Bazel-built codegen (`RCTAppDependencyProvider` + AppSpecs - compiled into `//tools/bazel/react_native:rn_tester_appspecs_lib`), the C++ TurboModule - example (`NativeCxxModuleExample`), the sample TurboModules - (`//packages/react-native:sample_turbo_modules`), and the RCTLinking/RCTPushNotification - modules built from source (not in the prebuilt framework). `RN_DISABLE_OSS_PLUGIN_HEADER` - currently skips the Fabric `NativeComponentExample` (its sources use quoted plugin includes - not yet wired). +* **The FULL rn-tester host also builds** — `:RNTesterMacBazelFull` links rn-tester's *real, + unmodified* `RNTester/AppDelegate.mm` with the Bazel-built codegen (`RCTAppDependencyProvider` + + AppSpecs compiled into `//tools/bazel/react_native:rn_tester_appspecs_lib`), the C++ + TurboModule example (`NativeCxxModuleExample`), the Fabric `NativeComponentExample` + (`RNTMyNativeView`), the sample TurboModules (`//packages/react-native:sample_turbo_modules`), + and the RCTLinking/RCTPushNotification modules built from source (not in the prebuilt + framework). All example modules link in — no rn-tester source is modified or `#ifdef`'d out. ### Consuming the prebuilt XCFrameworks from Bazel (the header problem) @@ -176,11 +175,10 @@ react-native-macos already carries the Hermes version-resolution patches ## What's next (increments) -* **Fabric NativeComponentExample**: wire the codegen'd `RCTFabricComponentsPlugins.h` + - `RCTThirdPartyComponentsProvider` registration so the `RNTMyNativeView` example compiles - (drop `RN_DISABLE_OSS_PLUGIN_HEADER`). * **`bazel run`**: wire an ad-hoc-signed run so the app launches directly from Bazel. * **CI**: run the app build on the macos-26 runner reusing the prebuild artifacts. +* **From source**: build the React/hermes/ReactNativeDependencies XCFrameworks in Bazel + (roadmap below) to drop the SPM prebuild + header reconstruction entirely. ## Apple: prebuilt XCFrameworks (swappable seam) diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel index b78e18862015..0d2ed36de01a 100644 --- a/packages/react-native/BUILD.bazel +++ b/packages/react-native/BUILD.bazel @@ -51,6 +51,17 @@ cc_library( visibility = ["//visibility:public"], ) +# rn-tester's Fabric NativeComponentExample quotes "RCTFabricComponentsPlugins.h", +# the core Fabric component-provider header. Its impl is in React.xcframework; expose +# the source header at its bare name so the quoted include resolves. +cc_library( + name = "rct_fabric_components_plugins_hdr", + hdrs = ["React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h"], + strip_include_prefix = "React/Fabric/Mounting/ComponentViews", + tags = ["manual"], + visibility = ["//visibility:public"], +) + # rn-tester's real AppDelegate imports RCTLinkingManager + RCTPushNotificationManager, # which are separate RN modules NOT included in the prebuilt React.xcframework. Build # them from source and expose their headers as (matching the podspec layout). diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index bad99f5ee9a5..c715a4ab9a89 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -132,10 +132,9 @@ macos_application( # 5. FULL host: rn-tester's real RNTester/AppDelegate.mm + a programmatic main # (bazel/real_main.m avoids a MainMenu.nib). It links the Bazel-built codegen -# (RCTAppDependencyProvider + AppSpecs), the C++ TurboModule example, and the sample -# TurboModules that the real AppDelegate's getTurboModule:/dependencyProvider need. -# RN_DISABLE_OSS_PLUGIN_HEADER skips the Fabric NativeComponentExample (its sources use -# quoted plugin includes not yet wired); everything else is the real rn-tester host. +# (RCTAppDependencyProvider + AppSpecs), the C++ TurboModule example, the Fabric +# NativeComponentExample (RNTMyNativeView), and the sample TurboModules that the real +# AppDelegate's getTurboModule:/dependencyProvider/thirdPartyFabricComponents need. objc_library( name = "rntester_macos_full_host", srcs = [ @@ -143,7 +142,6 @@ objc_library( "bazel/real_main.m", ], hdrs = ["RNTester/AppDelegate.h"], - copts = ["-DRN_DISABLE_OSS_PLUGIN_HEADER"], includes = ["RNTester"], sdk_frameworks = ["UserNotifications"], tags = ["manual"], @@ -151,6 +149,7 @@ objc_library( "//packages/react-native:rn_cxx_headers", "//packages/react-native:rntester_extra_rn_modules", "//packages/react-native:sample_turbo_modules", + "//packages/rn-tester/NativeComponentExample", "//packages/rn-tester/NativeCxxModuleExample", "//tools/bazel/react_native:rn_tester_appspecs_appdep_hdrs", "//tools/bazel/react_native:rn_tester_appspecs_lib", diff --git a/packages/rn-tester/NativeComponentExample/BUILD.bazel b/packages/rn-tester/NativeComponentExample/BUILD.bazel index a92b2ef0c6da..ec5c52d2c311 100644 --- a/packages/rn-tester/NativeComponentExample/BUILD.bazel +++ b/packages/rn-tester/NativeComponentExample/BUILD.bazel @@ -1,3 +1,35 @@ package(default_visibility = ['//visibility:public']) exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) + +# rn-tester's Fabric component example (RNTMyNativeView). Consumed by the app's +# thirdPartyFabricComponents via . +objc_library( + name = "NativeComponentExample", + srcs = [ + "ios/RCTInteropTestView.m", + "ios/RCTInteropTestViewManager.m", + "ios/RNTLegacyView.mm", + "ios/RNTMyLegacyNativeViewManager.mm", + "ios/RNTMyNativeViewCommon.mm", + "ios/RNTMyNativeViewComponentView.mm", + "ios/RNTMyNativeViewManager.mm", + ], + hdrs = [ + "ios/RCTInteropTestView.h", + "ios/RCTInteropTestViewManager.h", + "ios/RNTLegacyView.h", + "ios/RNTMyNativeViewComponentView.h", + "ios/UIView+ColorOverlays.h", + ], + includes = ["ios"], + tags = ["manual"], + deps = [ + "//packages/react-native:rct_fabric_components_plugins_hdr", + "//packages/react-native:rn_cxx_headers", + "//tools/bazel/react_native:rn_tester_appspecs_fabric_hdrs", + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", + ], +) From 0104b7a7ae28cbea8a9a9abf324f4ec17fdbc952 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 8 Jul 2026 00:20:02 -0700 Subject: [PATCH 15/24] Bazel: generate the :pkg BUILD files instead of hand-writing them Applies the JS-ecosystem ergonomic lesson (derive build metadata from package.json rather than hand-authoring per package) to our Bazel setup: * tools/bazel/js/workspace_package.bzl - rn_workspace_package() macro that collapses the repeated npm_link_all_packages()+npm_package boilerplate. * tools/bazel/js/gen_package_builds.mjs - reads the root package.json 'workspaces' globs and (re)writes the boilerplate BUILD files. It only owns generator-owned files (its @generated marker, or pure legacy :pkg boilerplate) and skips anything declaring other targets (react-native, rn-tester, the first_party dist packages, etc.), mirroring Gazelle's '# gazelle:' override model. Supports --all (create missing) and --check (CI staleness guard). Regenerated 23 boilerplate files from 24 -> 6 lines each (net -414 lines). Verified: the generated :pkg targets build and the rn-tester JS bundle still bundles. This is the incremental step toward full gazelle-based generation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 29 +++++ packages/assets/BUILD.bazel | 28 +---- packages/babel-plugin-codegen/BUILD.bazel | 28 +---- packages/debugger-frontend/BUILD.bazel | 28 +---- .../eslint-config-react-native/BUILD.bazel | 28 +---- .../eslint-plugin-react-native/BUILD.bazel | 28 +---- packages/eslint-plugin-specs/BUILD.bazel | 28 +---- packages/gradle-plugin/BUILD.bazel | 28 +---- packages/new-app-screen/BUILD.bazel | 28 +---- packages/normalize-color/BUILD.bazel | 28 +---- packages/polyfills/BUILD.bazel | 28 +---- .../react-native-babel-preset/BUILD.bazel | 28 +---- .../BUILD.bazel | 28 +---- packages/react-native-macos-init/BUILD.bazel | 28 +---- .../BUILD.bazel | 28 +---- .../react-native-test-library/BUILD.bazel | 28 +---- packages/typescript-config/BUILD.bazel | 28 +---- packages/virtualized-lists/BUILD.bazel | 28 +---- private/cxx-public-api/BUILD.bazel | 28 +---- private/eslint-plugin-monorepo/BUILD.bazel | 28 +---- private/monorepo-tests/BUILD.bazel | 28 +---- private/react-native-bots/BUILD.bazel | 28 +---- .../BUILD.bazel | 28 +---- private/react-native-fantom/BUILD.bazel | 28 +---- tools/bazel/js/gen_package_builds.mjs | 115 ++++++++++++++++++ tools/bazel/js/workspace_package.bzl | 49 ++++++++ 26 files changed, 308 insertions(+), 529 deletions(-) create mode 100644 tools/bazel/js/gen_package_builds.mjs create mode 100644 tools/bazel/js/workspace_package.bzl diff --git a/docs/bazel.md b/docs/bazel.md index b001ada6dcd1..1bb9ac62b73b 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -242,6 +242,35 @@ giving a ready-made port map. Output the same `.xcframework`s via vs the SPM XCFrameworks, and land the heavy native compiles on the remote cache (the primary CI/local speedup). +## Generating the `:pkg` BUILD files (no more boilerplate) + +Most workspace packages need exactly one Bazel target: a `:pkg` `npm_package` so +`npm_link_all_packages` can link them into the copied `node_modules` (rules_js does +not hoist like Yarn), which is what lets Metro bundle first-party JS. That was ~17 +identical 24-line `BUILD.bazel` files. Following the JS-ecosystem convention (derive +the build metadata from `package.json` instead of hand-authoring it — see +`docs`/research on Turborepo/Nx/Lage and Gazelle), those files are now **generated**: + +* `tools/bazel/js/workspace_package.bzl` — the `rn_workspace_package()` macro; each + generated `BUILD.bazel` is just a `load` + one call. +* `tools/bazel/js/gen_package_builds.mjs` — reads the `workspaces` globs from the root + `package.json` and (re)writes the boilerplate files. It only owns *generator-owned* + files (those carrying its `@generated-by` marker, or pure legacy `:pkg` boilerplate); + any BUILD that declares other targets (`objc_library`, `cc_library`, `first_party`, + `macos_application`, `rn_codegen`, …) is treated as hand-owned and skipped — the same + "generate the 95%, allow local overrides" model as Gazelle's `# gazelle:` directives. + +``` +node tools/bazel/js/gen_package_builds.mjs # refresh the boilerplate +node tools/bazel/js/gen_package_builds.mjs --all # also create any missing ones +node tools/bazel/js/gen_package_builds.mjs --check # CI: non-zero if stale +``` + +This is the incremental step toward full `bazel run //:gazelle`-style generation with +the Aspect JS/TS Gazelle plugin (which would also infer first-party `deps` from +imports); a custom Gazelle extension could later emit `rn_codegen`, the Metro bundle, +and the prebuilt-XCFramework targets too. + ## Layout ``` diff --git a/packages/assets/BUILD.bazel b/packages/assets/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/assets/BUILD.bazel +++ b/packages/assets/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/babel-plugin-codegen/BUILD.bazel b/packages/babel-plugin-codegen/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/babel-plugin-codegen/BUILD.bazel +++ b/packages/babel-plugin-codegen/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/debugger-frontend/BUILD.bazel b/packages/debugger-frontend/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/debugger-frontend/BUILD.bazel +++ b/packages/debugger-frontend/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/eslint-config-react-native/BUILD.bazel b/packages/eslint-config-react-native/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/eslint-config-react-native/BUILD.bazel +++ b/packages/eslint-config-react-native/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/eslint-plugin-react-native/BUILD.bazel b/packages/eslint-plugin-react-native/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/eslint-plugin-react-native/BUILD.bazel +++ b/packages/eslint-plugin-react-native/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/eslint-plugin-specs/BUILD.bazel b/packages/eslint-plugin-specs/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/eslint-plugin-specs/BUILD.bazel +++ b/packages/eslint-plugin-specs/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/gradle-plugin/BUILD.bazel b/packages/gradle-plugin/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/gradle-plugin/BUILD.bazel +++ b/packages/gradle-plugin/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/new-app-screen/BUILD.bazel b/packages/new-app-screen/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/new-app-screen/BUILD.bazel +++ b/packages/new-app-screen/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/normalize-color/BUILD.bazel b/packages/normalize-color/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/normalize-color/BUILD.bazel +++ b/packages/normalize-color/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/polyfills/BUILD.bazel b/packages/polyfills/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/polyfills/BUILD.bazel +++ b/packages/polyfills/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/react-native-babel-preset/BUILD.bazel b/packages/react-native-babel-preset/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/react-native-babel-preset/BUILD.bazel +++ b/packages/react-native-babel-preset/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/react-native-babel-transformer/BUILD.bazel b/packages/react-native-babel-transformer/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/react-native-babel-transformer/BUILD.bazel +++ b/packages/react-native-babel-transformer/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/react-native-macos-init/BUILD.bazel b/packages/react-native-macos-init/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/react-native-macos-init/BUILD.bazel +++ b/packages/react-native-macos-init/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/react-native-popup-menu-android/BUILD.bazel b/packages/react-native-popup-menu-android/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/react-native-popup-menu-android/BUILD.bazel +++ b/packages/react-native-popup-menu-android/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/react-native-test-library/BUILD.bazel b/packages/react-native-test-library/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/react-native-test-library/BUILD.bazel +++ b/packages/react-native-test-library/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/typescript-config/BUILD.bazel b/packages/typescript-config/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/typescript-config/BUILD.bazel +++ b/packages/typescript-config/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/packages/virtualized-lists/BUILD.bazel b/packages/virtualized-lists/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/packages/virtualized-lists/BUILD.bazel +++ b/packages/virtualized-lists/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/private/cxx-public-api/BUILD.bazel b/private/cxx-public-api/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/private/cxx-public-api/BUILD.bazel +++ b/private/cxx-public-api/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/private/eslint-plugin-monorepo/BUILD.bazel b/private/eslint-plugin-monorepo/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/private/eslint-plugin-monorepo/BUILD.bazel +++ b/private/eslint-plugin-monorepo/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/private/monorepo-tests/BUILD.bazel b/private/monorepo-tests/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/private/monorepo-tests/BUILD.bazel +++ b/private/monorepo-tests/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/private/react-native-bots/BUILD.bazel b/private/react-native-bots/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/private/react-native-bots/BUILD.bazel +++ b/private/react-native-bots/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/private/react-native-codegen-typescript-test/BUILD.bazel b/private/react-native-codegen-typescript-test/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/private/react-native-codegen-typescript-test/BUILD.bazel +++ b/private/react-native-codegen-typescript-test/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/private/react-native-fantom/BUILD.bazel b/private/react-native-fantom/BUILD.bazel index 23f9dc4f3149..420dbaf7d3da 100644 --- a/private/react-native-fantom/BUILD.bazel +++ b/private/react-native-fantom/BUILD.bazel @@ -1,24 +1,6 @@ -# Auto-generated first-party package target for rules_js linking. -# Exposes this workspace package as `:pkg` so the root npm_link_all_packages can -# link it into node_modules (needed to bundle first-party JS with Metro). -load("@aspect_rules_js//npm:defs.bzl", "npm_package") -load("@npm//:defs.bzl", "npm_link_all_packages") +# @generated-by: tools/bazel/js/gen_package_builds.mjs +# Edit the generator or the macro, not this file. Regenerate with: +# node tools/bazel/js/gen_package_builds.mjs +load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") -npm_link_all_packages() - -npm_package( - name = "pkg", - srcs = glob( - ["**/*"], - exclude = [ - "**/node_modules/**", - "**/.build/**", - "**/build/**", - "**/Pods/**", - "**/__tests__/**", - "**/*.bazel", - ], - allow_empty = True, - ), - visibility = ["//visibility:public"], -) +rn_workspace_package() diff --git a/tools/bazel/js/gen_package_builds.mjs b/tools/bazel/js/gen_package_builds.mjs new file mode 100644 index 000000000000..fd19384bd3fa --- /dev/null +++ b/tools/bazel/js/gen_package_builds.mjs @@ -0,0 +1,115 @@ +#!/usr/bin/env node +// Generate the boilerplate `:pkg` BUILD.bazel files for first-party workspace +// packages, so they don't have to be hand-written/maintained. +// +// This is a small, repo-specific analog of `bazel run //:gazelle` (see the +// artifacts research report): it reads the workspace globs from the root +// package.json and, for every workspace package, writes a one-line BUILD.bazel +// that calls the rn_workspace_package() macro. +// +// Ownership / safety (mirrors Gazelle's `# gazelle:` and Nx's project.json +// override model): a BUILD.bazel is only (re)written when it is *generator-owned* +// -- it either carries the @generated marker below, or it is the pure legacy +// `:pkg` boilerplate (a single npm_package with no other target kinds). Any file +// that declares other targets (objc_library, cc_library, first_party, +// macos_application, rn_codegen, ...) is treated as hand-owned and left untouched. +// +// Usage: +// node tools/bazel/js/gen_package_builds.mjs # refresh owned files +// node tools/bazel/js/gen_package_builds.mjs --all # also create missing ones +// node tools/bazel/js/gen_package_builds.mjs --check # non-zero exit if stale (CI) + +import fs from 'node:fs'; +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; + +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..'); +const MARKER = '# @generated-by: tools/bazel/js/gen_package_builds.mjs'; + +const CONTENT = [ + MARKER, + '# Edit the generator or the macro, not this file. Regenerate with:', + '# node tools/bazel/js/gen_package_builds.mjs', + 'load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package")', + '', + 'rn_workspace_package()', + '', +].join('\n'); + +// Any of these target kinds mark a BUILD.bazel as hand-owned (never overwrite). +const HAND_OWNED_TOKENS = [ + 'objc_library(', 'cc_library(', 'swift_library(', 'macos_application(', + 'ios_application(', 'apple_', 'js_library(', 'js_binary(', 'js_run_binary(', + 'ts_project(', 'filegroup(', 'genrule(', 'rn_codegen(', 'first_party', + 'sample_turbo_modules(', 'rntester_extra', 'prebuilt_xcframeworks', +]; + +function isGeneratorOwned(text) { + if (text.includes(MARKER)) return true; + // Legacy pure boilerplate: has an npm_package but no other target kinds. + if (text.includes('npm_package(') && !HAND_OWNED_TOKENS.some((t) => text.includes(t))) { + return true; + } + return false; +} + +// Expand the root package.json "workspaces" globs (supports `dir/*` and `!neg`). +function workspaceDirs() { + const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')); + const patterns = pkg.workspaces || []; + const positive = patterns.filter((p) => !p.startsWith('!')); + const negated = new Set(patterns.filter((p) => p.startsWith('!')).map((p) => p.slice(1))); + const dirs = new Set(); + for (const pattern of positive) { + if (pattern.endsWith('/*')) { + const base = pattern.slice(0, -2); + const baseAbs = path.join(repoRoot, base); + if (!fs.existsSync(baseAbs)) continue; + for (const entry of fs.readdirSync(baseAbs, {withFileTypes: true})) { + if (!entry.isDirectory()) continue; + const rel = base + '/' + entry.name; + if (negated.has(rel)) continue; + if (fs.existsSync(path.join(repoRoot, rel, 'package.json'))) dirs.add(rel); + } + } else if (!negated.has(pattern)) { + if (fs.existsSync(path.join(repoRoot, pattern, 'package.json'))) dirs.add(pattern); + } + } + return [...dirs].sort(); +} + +const args = new Set(process.argv.slice(2)); +const createMissing = args.has('--all'); +const checkOnly = args.has('--check'); + +const created = []; +const updated = []; +const skipped = []; +let stale = false; + +for (const dir of workspaceDirs()) { + const buildPath = path.join(repoRoot, dir, 'BUILD.bazel'); + if (!fs.existsSync(buildPath)) { + if (!createMissing) continue; + if (checkOnly) { stale = true; created.push(dir); continue; } + fs.writeFileSync(buildPath, CONTENT); + created.push(dir); + continue; + } + const current = fs.readFileSync(buildPath, 'utf8'); + if (!isGeneratorOwned(current)) { skipped.push(dir); continue; } + if (current === CONTENT) continue; // already up to date + if (checkOnly) { stale = true; updated.push(dir); continue; } + fs.writeFileSync(buildPath, CONTENT); + updated.push(dir); +} + +const log = (label, list) => { if (list.length) console.log(label + ' (' + list.length + '): ' + list.join(', ')); }; +log('created', created); +log(checkOnly ? 'stale' : 'updated', updated); +log('skipped (hand-owned)', skipped); +if (checkOnly && stale) { + console.error('BUILD.bazel files are stale. Run: node tools/bazel/js/gen_package_builds.mjs'); + process.exit(1); +} +if (!checkOnly) console.log('Done.'); diff --git a/tools/bazel/js/workspace_package.bzl b/tools/bazel/js/workspace_package.bzl new file mode 100644 index 000000000000..f31cd6dd8877 --- /dev/null +++ b/tools/bazel/js/workspace_package.bzl @@ -0,0 +1,49 @@ +"""Convention macro for a first-party workspace package. + +Most workspace packages need exactly one thing from Bazel: expose their files as a +`:pkg` `npm_package` so `npm_link_all_packages` can link them into the copied +`node_modules` (rules_js does not hoist like Yarn), which is what lets Metro bundle +first-party JS. That boilerplate was duplicated in ~17 identical `BUILD.bazel` +files; this macro collapses it to a single call so those files can be *generated* +(see tools/bazel/js/gen_package_builds.mjs) instead of hand-maintained. + +Usage (the entire BUILD.bazel of a leaf workspace package): + + load("//tools/bazel/js:workspace_package.bzl", "rn_workspace_package") + rn_workspace_package() +""" + +load("@aspect_rules_js//npm:defs.bzl", "npm_package") +load("@npm//:defs.bzl", "npm_link_all_packages") + +# Build outputs / tooling that must never end up in a package tarball. +_DEFAULT_EXCLUDES = [ + "**/node_modules/**", + "**/.build/**", + "**/build/**", + "**/Pods/**", + "**/__tests__/**", + "**/*.bazel", +] + +def rn_workspace_package(name = "pkg", srcs = None, exclude = None, visibility = ["//visibility:public"], **kwargs): + """Link this package's deps and expose it as `:` (default `:pkg`). + + Args: + name: npm_package target name (default "pkg"). + srcs: optional explicit srcs; defaults to a sensible glob of the package. + exclude: optional extra glob excludes appended to the defaults. + visibility: target visibility. + **kwargs: forwarded to npm_package. + """ + npm_link_all_packages() + npm_package( + name = name, + srcs = srcs if srcs != None else native.glob( + ["**/*"], + exclude = _DEFAULT_EXCLUDES + (exclude or []), + allow_empty = True, + ), + visibility = visibility, + **kwargs + ) From 73b75ac7d368cbef1f996eae70f8a917cc2148c5 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 8 Jul 2026 00:25:49 -0700 Subject: [PATCH 16/24] Bazel: import React/ReactNativeDependencies as dynamic frameworks (fixes app launch) The SPM prebuild ships React.framework and ReactNativeDependencies.framework as dynamic frameworks (dylibs), but they were imported via apple_static_xcframework_import, so rules_apple linked them with @rpath load commands without embedding them. The app crashed at launch in dyld: 'Library not loaded: @rpath/React.framework/Versions/A/React'. Importing all three (React, ReactNativeDependencies, hermes) as dynamic embeds them in Contents/Frameworks. Verified: RNTesterMacBazel.app now launches and stays running (loads the embedded Metro bundle + Hermes offline). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tools/bazel/apple/prebuilt_xcframeworks.bzl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/bazel/apple/prebuilt_xcframeworks.bzl b/tools/bazel/apple/prebuilt_xcframeworks.bzl index 602d3aa8fcac..4c503b3ca89e 100644 --- a/tools/bazel/apple/prebuilt_xcframeworks.bzl +++ b/tools/bazel/apple/prebuilt_xcframeworks.bzl @@ -17,7 +17,10 @@ _REL_PATHS = { } # hermes ships as a dynamic framework; React + deps are static. -_DYNAMIC = {"hermes": True} +# The SPM prebuild ships all three as dynamic frameworks (dylibs), so they must be +# imported as dynamic and embedded in the app's Contents/Frameworks (otherwise dyld +# fails at launch with "Library not loaded: @rpath/React.framework/..."). +_DYNAMIC = {"React": True, "ReactNativeDependencies": True, "hermes": True} def _prebuilt_xcframeworks_impl(rctx): root = str(rctx.workspace_root) From 290ed746a98241a16697952bba794796035951c0 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 8 Jul 2026 13:42:19 -0700 Subject: [PATCH 17/24] =?UTF-8?q?docs:=20honest=20scope/limitations=20?= =?UTF-8?q?=E2=80=94=20Bazel=20for=20the=20native=20slice,=20not=20the=20J?= =?UTF-8?q?S=20inner=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures the lessons from the pow.rs 'Bazel is incompatible with JavaScript' critique: keep the JS dev loop (yarn/Metro/Jest/debugging) off Bazel, consume artifacts at seams rather than re-Bazelifying node_modules, stay a two-way door (additive/manual), and mind the single-server-per-output_base serialization. Grounds the node_modules friction in our own copy_tree.js/first_party.bzl workarounds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/docs/bazel.md b/docs/bazel.md index 1bb9ac62b73b..029427eef6f9 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -21,6 +21,51 @@ XCFrameworks from source in Bazel too (see the roadmap). resource) is modeled explicitly, the way Meta does it in Buck2's `js`/`apple` preludes — but reusing Metro and rules_apple instead of reimplementing them. +## Scope: where Bazel earns its keep here (and where it doesn't) + +Bazel is a *poor* choice for the JavaScript inner loop, and the critique in +["Bazel is incompatible with JavaScript" (pow.rs)](https://pow.rs/blog/bazel-is-incompatible-with-javascript/) +is largely fair **for that use case**. We hit its Problem 1 directly: rules_js uses a +strict, **non-hoisted, copied** `node_modules`, which is exactly why this slice needs +`tools/bazel/js/copy_tree.js` (to stage a symlink-free project dir Metro's file-map can +hash) and `first_party.bzl` (to consume first-party packages in built `dist` form +because their `src` entry points `require('../../../scripts/babel-register')` and escape +the copied tree). That is real friction and real disk/IO cost. + +The important distinction: **we do not put the JS dev loop on Bazel.** `yarn`, Metro's +dev server, Jest, and JS debugging stay exactly as they are — Bazel is opt-in +(`manual`-tagged targets) and additive, so none of the day-to-day JS workflow is +affected. What Bazel is actually for here is the thing the JS ecosystem tools +(Turborepo/Nx/Lage) *cannot* do: run the **Apple toolchain**, link **XCFrameworks**, +run **codegen**, and assemble a signed **`.app`** — one reproducible, remotely-cacheable +graph over JS **and** native. Our build time is dominated by the native compiles +(Hermes, React C++), which is precisely where Bazel's action cache / RBE pays off; the +JS bundle is a small, leaf step. + +Design guardrails we adopt as a result: + +* **Keep the JS inner loop off Bazel.** Never make `bazel` a prerequisite for editing JS, + running Metro, or debugging. The article's strongest point. +* **Consume artifacts at seams, don't re-Bazelify the world.** We already treat the + XCFrameworks as prebuilt inputs; the JS bundle can be treated the same way (build it + with plain Metro, feed the `.jsbundle` in) if the rules_js `node_modules` tax ever + outweighs the benefit of an in-graph bundle. Prefer the `:node_modules` glob over + hand-declaring individual packages (the article notes this keeps you correct). +* **Stay a two-way door.** Everything is additive and `manual`; no forced repo-wide + migration. Adoption and *removal* are both cheap. +* **Mind the single Bazel server.** Bazel is massively parallel *within* a build, but one + server per `--output_base` serializes separate `bazel` invocations ("Another Bazel + command is running…"). Use distinct `--output_base`s for parallel lanes/CI shards + rather than expecting two CLIs to share one. (The article's "single-threaded" framing + conflates these — intra-build parallelism is a Bazel strength.) +* **Expect to enumerate outputs.** Declaring every generated file is inherent to Bazel's + model (we hit it with codegen — see `rn_codegen`'s explicit `_CODEGEN_OUTS`). Use + `out_dirs` TreeArtifacts where a step's outputs aren't statically known. + +Net: use **JS-native tools (Turborepo/Nx/Lage/pnpm) for the JS package graph and dev +loop**, and **Bazel only for the native app slice** where it's genuinely better. They +coexist — Turborepo can even run inside a Bazel monorepo. + ## The single-source-of-truth lockfile problem (and the rules_js Berry fork) The repo uses **Yarn 4 (Berry)**; `yarn.lock` is `__metadata: version: 8`. We keep From c5305dd2bf0af81e9a008f33a7e91d7fab5b7e9d Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 14:22:17 -0700 Subject: [PATCH 18/24] build(bazel): repair PR checks after pnpm-mode merge - satisfy Flow annotation and import-order lint rules for Bazel JS tools - ignore Bazel output symlinks so eslint remains usable after a Bazel build - verify generated workspace BUILD files in CI and broaden path triggers - preserve hand-owned targets in generated BUILD files - regenerate the translated pnpm lock whenever yarn.lock changes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .eslintignore | 1 + .github/workflows/bazel.yml | 5 +++++ packages/rn-tester/bazel/bundle.js | 17 +++++------------ tools/bazel/berry/example/verify.js | 5 +++++ tools/bazel/js/build_first_party.js | 1 + tools/bazel/js/copy_tree.js | 1 + tools/bazel/js/gen_package_builds.mjs | 8 ++++---- tools/bazel/patches/aspect_rules_js_berry.patch | 9 +++++---- tools/bazel/react_native/build_codegen_lib.js | 5 +++++ tools/bazel/react_native/codegen_runner.js | 13 +++++++------ 10 files changed, 39 insertions(+), 26 deletions(-) diff --git a/.eslintignore b/.eslintignore index e16e0140326a..3e037a11fe1e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -14,5 +14,6 @@ packages/*/types_generated packages/debugger-frontend/dist/**/* packages/react-native-codegen/lib **/Pods/* +bazel-* **/*.macos.js **/*.windows.js diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index bb4bcbfe6145..ccf843e24e22 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -13,7 +13,10 @@ on: - ".bazelrc" - ".bazelversion" - ".bazelignore" + - ".yarnrc.yml" - "BUILD.bazel" + - "package.json" + - "yarn.lock" - "tools/bazel/**" - "packages/**/BUILD.bazel" - ".github/workflows/bazel.yml" @@ -45,6 +48,8 @@ jobs: key: bazel-berry-${{ runner.os }}-${{ hashFiles('MODULE.bazel', 'yarn.lock', 'tools/bazel/**') }} restore-keys: | bazel-berry-${{ runner.os }}- + - name: Verify generated workspace BUILD files + run: node tools/bazel/js/gen_package_builds.mjs --all --check - name: Test the Berry -> rules_js pipeline end to end run: | npx --yes @bazel/bazelisk test //tools/bazel/berry/example:verify \ diff --git a/packages/rn-tester/bazel/bundle.js b/packages/rn-tester/bazel/bundle.js index b85e6d03f3b4..221efcba78c9 100644 --- a/packages/rn-tester/bazel/bundle.js +++ b/packages/rn-tester/bazel/bundle.js @@ -17,15 +17,16 @@ 'use strict'; -const fs = require('fs'); +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const crypto = require('crypto'); +const fs = require('fs'); +const Metro = require('metro'); +const DependencyGraph = require('metro/src/node-haste/DependencyGraph'); const Module = require('module'); const path = require('path'); -const Metro = require('metro'); -const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); -const ALIASES = new Map(); +const ALIASES = new Map(); const originalResolveFilename = Module._resolveFilename; Module._resolveFilename = function (request, parent, isMain, options) { try { @@ -65,7 +66,6 @@ Module._resolveFilename = function (request, parent, isMain, options) { throw error; } }; - function findAspectPackage(request) { const encoded = request.replace('/', '+'); const aspectRoots = [ @@ -87,9 +87,7 @@ function findAspectPackage(request) { } return null; } - const ASSET_EXTS = new Set(['gif', 'jpeg', 'jpg', 'png', 'webp', 'xml']); - function resolveFromFileSystem(context, moduleName, platform) { try { return context.resolveRequest(context, moduleName, platform); @@ -109,7 +107,6 @@ function resolveFromFileSystem(context, moduleName, platform) { throw error; } } - function resolvePackageFromAspectTree(moduleName) { if (moduleName.startsWith('.') || path.isAbsolute(moduleName)) { return null; @@ -144,7 +141,6 @@ function resolvePackageFromAspectTree(moduleName) { } return null; } - function resolveRelativeFromFileSystem(originModulePath, moduleName, platform) { if (!moduleName.startsWith('.') && !path.isAbsolute(moduleName)) { return null; @@ -196,7 +192,6 @@ function resolveRelativeFromFileSystem(originModulePath, moduleName, platform) { } return null; } - function resolveAssetFiles(filePath) { const dir = path.dirname(filePath); const ext = path.extname(filePath); @@ -211,8 +206,6 @@ function resolveAssetFiles(filePath) { .map(name => path.join(dir, name)); return filePaths.length ? {type: 'assetFiles', filePaths} : null; } - -const DependencyGraph = require('metro/src/node-haste/DependencyGraph'); const originalGetOrComputeSha1 = DependencyGraph.prototype.getOrComputeSha1; DependencyGraph.prototype.getOrComputeSha1 = async function (filename) { try { diff --git a/tools/bazel/berry/example/verify.js b/tools/bazel/berry/example/verify.js index 0526a6a69c88..300ec3e5c6c9 100644 --- a/tools/bazel/berry/example/verify.js +++ b/tools/bazel/berry/example/verify.js @@ -1,3 +1,8 @@ +/** + * @format + * @noflow + */ + // Green proof that the rules_js Berry fork works end to end: // this file is bundled/run by Bazel with node_modules materialized from a // Yarn *Berry* yarn.lock (translated by tools/bazel/berry/berry_to_pnpm_lock.mjs diff --git a/tools/bazel/js/build_first_party.js b/tools/bazel/js/build_first_party.js index 8ffff6415525..dcf15a35ff0d 100644 --- a/tools/bazel/js/build_first_party.js +++ b/tools/bazel/js/build_first_party.js @@ -6,6 +6,7 @@ * LICENSE file in the root directory of this source tree. * * @format + * @noflow */ 'use strict'; diff --git a/tools/bazel/js/copy_tree.js b/tools/bazel/js/copy_tree.js index f09c146cdd63..4e11ba1b5c12 100644 --- a/tools/bazel/js/copy_tree.js +++ b/tools/bazel/js/copy_tree.js @@ -1,6 +1,7 @@ #!/usr/bin/env node /** * @format + * @noflow */ 'use strict'; diff --git a/tools/bazel/js/gen_package_builds.mjs b/tools/bazel/js/gen_package_builds.mjs index fd19384bd3fa..333d0228427a 100644 --- a/tools/bazel/js/gen_package_builds.mjs +++ b/tools/bazel/js/gen_package_builds.mjs @@ -45,12 +45,12 @@ const HAND_OWNED_TOKENS = [ ]; function isGeneratorOwned(text) { + // A generated file becomes hand-owned as soon as a contributor adds another + // target kind. Never let the marker authorize clobbering local overrides. + if (HAND_OWNED_TOKENS.some((token) => text.includes(token))) return false; if (text.includes(MARKER)) return true; // Legacy pure boilerplate: has an npm_package but no other target kinds. - if (text.includes('npm_package(') && !HAND_OWNED_TOKENS.some((t) => text.includes(t))) { - return true; - } - return false; + return text.includes('npm_package('); } // Expand the root package.json "workspaces" globs (supports `dir/*` and `!neg`). diff --git a/tools/bazel/patches/aspect_rules_js_berry.patch b/tools/bazel/patches/aspect_rules_js_berry.patch index cb24d62c0c04..0ebc52117723 100644 --- a/tools/bazel/patches/aspect_rules_js_berry.patch +++ b/tools/bazel/patches/aspect_rules_js_berry.patch @@ -1,6 +1,6 @@ --- a/npm/private/npm_translate_lock.bzl +++ b/npm/private/npm_translate_lock.bzl -@@ -336,7 +336,67 @@ +@@ -336,7 +336,68 @@ """), }, ) @@ -46,8 +46,9 @@ + rctx.watch(converter) + + pnpm_lock_path = rctx.path(attr.pnpm_lock) -+ if pnpm_lock_path.exists: -+ return # already generated; delete pnpm-lock.yaml to refresh after yarn.lock changes ++ # The repository rule reruns when yarn_path or converter changes (rctx.watch ++ # above), so always regenerate. Returning when the output already exists leaves ++ # pnpm-lock.yaml stale after a yarn.lock edit. + rctx.report_progress("Translating Berry yarn.lock -> pnpm-lock.yaml") + result = rctx.execute( + [ @@ -68,7 +69,7 @@ def parse_and_verify_lock(rctx, mod, attr): """Helper to parse and validate the lockfile -@@ -348,6 +408,8 @@ +@@ -348,6 +409,8 @@ state, importers, and packages """ diff --git a/tools/bazel/react_native/build_codegen_lib.js b/tools/bazel/react_native/build_codegen_lib.js index a5d3f1656c36..fa4384f6896e 100644 --- a/tools/bazel/react_native/build_codegen_lib.js +++ b/tools/bazel/react_native/build_codegen_lib.js @@ -1,4 +1,9 @@ #!/usr/bin/env node +/** + * @format + * @noflow + */ + 'use strict'; const fs = require('fs'); diff --git a/tools/bazel/react_native/codegen_runner.js b/tools/bazel/react_native/codegen_runner.js index bd90acbc1c80..d02ef8ef5fe3 100644 --- a/tools/bazel/react_native/codegen_runner.js +++ b/tools/bazel/react_native/codegen_runner.js @@ -1,9 +1,16 @@ #!/usr/bin/env node +/** + * @format + * @noflow + */ + 'use strict'; const fs = require('fs'); +const Module = require('module'); const path = require('path'); + const cwd = process.cwd(); const marker = `${path.sep}bazel-out${path.sep}`; const workspaceRoot = cwd.includes(marker) ? cwd.slice(0, cwd.indexOf(marker)) : cwd; @@ -20,7 +27,6 @@ const bazelReactNativePackageRoot = path.join( const reactNativePackageRoot = fs.existsSync(bazelReactNativePackageRoot) ? bazelReactNativePackageRoot : path.join(workspaceRoot, 'packages/react-native'); - function prepareRnTesterProject() { const scratchProjectRoot = path.join(outputDir, '_rn_tester_project'); fs.rmSync(scratchProjectRoot, {recursive: true, force: true}); @@ -85,7 +91,6 @@ function prepareRnTesterProject() { return scratchProjectRoot; } - function mustEnv(name) { const value = process.env[name]; if (!value) { @@ -93,21 +98,17 @@ function mustEnv(name) { } return value; } - function assertExists(relativePath) { const absolutePath = path.join(outputDir, relativePath); if (!fs.existsSync(absolutePath)) { throw new Error(`Expected codegen output missing: ${absolutePath}`); } } - fs.mkdirSync(outputDir, {recursive: true}); const scratchDir = path.join(outputDir, '_codegen_scratch'); fs.rmSync(scratchDir, {recursive: true, force: true}); fs.mkdirSync(scratchDir, {recursive: true}); process.env.TMPDIR = scratchDir; - -const Module = require('module'); process.env.NODE_PATH = [ path.join(codegenLibDir, 'node_modules'), process.env.NODE_PATH || '', From 04a4a5962c766654d407185a0f98164530647134 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 14:41:53 -0700 Subject: [PATCH 19/24] build(bazel): add canonical RNTester macOS app target Add //packages/rn-tester/RNTester-macOS:app as the stable entry point. Bundle the real native-example JavaScript through package-local js_library targets instead of replacing it with stubs. Resolve RNTester source-relative react-native imports against the Bazel package alias, emit the conventional main.jsbundle expected by RCTBundleURLProvider, and keep the minimal host on the same bundle name. Verified the exact target builds on Xcode 26.4, embeds one 1.9 MB main.jsbundle containing the Fabric/Screenshot/C++ TurboModule implementations, and launches without Metro. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 13 ++++++----- packages/rn-tester/BUILD.bazel | 10 +++++++-- .../NativeComponentExample/BUILD.bazel | 7 ++++++ .../NativeCxxModuleExample/BUILD.bazel | 7 ++++++ .../rn-tester/NativeModuleExample/BUILD.bazel | 7 ++++++ packages/rn-tester/RNTester-macOS/BUILD.bazel | 8 +++++++ .../rn-tester/bazel/MinimalAppDelegate.mm | 2 +- packages/rn-tester/bazel/bundle.js | 12 +++++++++- tools/bazel/js/copy_tree.js | 22 ------------------- 9 files changed, 57 insertions(+), 31 deletions(-) create mode 100644 packages/rn-tester/RNTester-macOS/BUILD.bazel diff --git a/docs/bazel.md b/docs/bazel.md index 029427eef6f9..3ce5aae1c0d0 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -7,7 +7,8 @@ CocoaPods workflows are unchanged. ## Goal -Prove a **full working vertical slice**: bundle rn-tester's JavaScript with Metro +Provide a **full working vertical slice** at +`//packages/rn-tester/RNTester-macOS:app`: bundle rn-tester's JavaScript with Metro (driven by Bazel via aspect-build `rules_js`) and link/embed it into a macOS app (`macos_application` via `rules_apple`) that consumes the prebuilt React Native XCFrameworks — an end-to-end `bazel run` of a macOS RN app. Longer term, build those @@ -129,8 +130,8 @@ BYONM remains a viable fallback. ## What works today (verified green) -**`bazel build //packages/rn-tester:RNTesterMacBazel` produces a launchable macOS -RNTester `.app`, built entirely by Bazel on Xcode 26** — JS bundle, native host, and +**`bazel build //packages/rn-tester/RNTester-macOS:app` produces a launchable macOS +RNTester `.app` on Xcode 26** — JS bundle, native host, and prebuilt-XCFramework link. Specifically: * `bazel test //tools/bazel/berry/example:verify` — a self-contained proof: a real Berry @@ -149,13 +150,15 @@ prebuilt-XCFramework link. Specifically: minimal `RCTReactNativeFactory` host, links the prebuilt React/hermes/ReactNativeDependencies XCFrameworks, and embeds the JS bundle. The resulting `.app` contains the arm64 binary, `Contents/Resources/RNTesterApp.macos.jsbundle`, and `Contents/Frameworks/hermes.framework`. -* **The FULL rn-tester host also builds** — `:RNTesterMacBazelFull` links rn-tester's *real, +* **The full rn-tester host builds and launches offline** — the canonical `:app` target + links rn-tester's *real, unmodified* `RNTester/AppDelegate.mm` with the Bazel-built codegen (`RCTAppDependencyProvider` + AppSpecs compiled into `//tools/bazel/react_native:rn_tester_appspecs_lib`), the C++ TurboModule example (`NativeCxxModuleExample`), the Fabric `NativeComponentExample` (`RNTMyNativeView`), the sample TurboModules (`//packages/react-native:sample_turbo_modules`), and the RCTLinking/RCTPushNotification modules built from source (not in the prebuilt - framework). All example modules link in — no rn-tester source is modified or `#ifdef`'d out. + framework). Its embedded `main.jsbundle` contains the real native-example JS (no + stubs), and no rn-tester source is modified or `#ifdef`'d out. ### Consuming the prebuilt XCFrameworks from Bazel (the header problem) diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index c715a4ab9a89..446cfe6fe02a 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -48,6 +48,11 @@ js_library( "react-native.config.js", "package.json", ], + deps = [ + "//packages/rn-tester/NativeComponentExample:js_srcs", + "//packages/rn-tester/NativeCxxModuleExample:js_srcs", + "//packages/rn-tester/NativeModuleExample:js_srcs", + ], ) # NOTE: rules_js uses a strict, non-hoisted node_modules. Metro's bundling tooling @@ -83,10 +88,10 @@ js_run_binary( js_run_binary( name = "rntester_macos_jsbundle", srcs = [":rntester_js_project"], - outs = ["RNTesterApp.macos.jsbundle"], + outs = ["main.jsbundle"], out_dirs = ["RNTesterApp_assets"], env = { - "BUNDLE_OUT": "packages/rn-tester/RNTesterApp.macos.jsbundle", + "BUNDLE_OUT": "packages/rn-tester/main.jsbundle", "ASSETS_DEST": "packages/rn-tester/RNTesterApp_assets", "RN_TESTER_ROOT": "packages/rn-tester/rntester_js_project", }, @@ -169,5 +174,6 @@ macos_application( minimum_os_version = "14.0", resources = [":rntester_macos_jsbundle"], tags = ["manual"], + visibility = ["//packages/rn-tester/RNTester-macOS:__pkg__"], deps = [":rntester_macos_full_host"], ) diff --git a/packages/rn-tester/NativeComponentExample/BUILD.bazel b/packages/rn-tester/NativeComponentExample/BUILD.bazel index ec5c52d2c311..a5ccbb06c40d 100644 --- a/packages/rn-tester/NativeComponentExample/BUILD.bazel +++ b/packages/rn-tester/NativeComponentExample/BUILD.bazel @@ -1,7 +1,14 @@ +load("@aspect_rules_js//js:defs.bzl", "js_library") + package(default_visibility = ['//visibility:public']) exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) +js_library( + name = "js_srcs", + srcs = glob(["js/**/*.js"]), +) + # rn-tester's Fabric component example (RNTMyNativeView). Consumed by the app's # thirdPartyFabricComponents via . objc_library( diff --git a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel index e63584f671d7..76c84ce18e66 100644 --- a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel +++ b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel @@ -1,7 +1,14 @@ +load("@aspect_rules_js//js:defs.bzl", "js_library") + package(default_visibility = ['//visibility:public']) exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) +js_library( + name = "js_srcs", + srcs = glob(["*.js"]), +) + # Header exposed to the app as . cc_library( name = "NativeCxxModuleExample_hdrs", diff --git a/packages/rn-tester/NativeModuleExample/BUILD.bazel b/packages/rn-tester/NativeModuleExample/BUILD.bazel index a92b2ef0c6da..cb2dac092ed0 100644 --- a/packages/rn-tester/NativeModuleExample/BUILD.bazel +++ b/packages/rn-tester/NativeModuleExample/BUILD.bazel @@ -1,3 +1,10 @@ +load("@aspect_rules_js//js:defs.bzl", "js_library") + package(default_visibility = ['//visibility:public']) exports_files(glob(['**/*'], exclude = ['**/*.bazel'], allow_empty = True)) + +js_library( + name = "js_srcs", + srcs = glob(["*.js"]), +) diff --git a/packages/rn-tester/RNTester-macOS/BUILD.bazel b/packages/rn-tester/RNTester-macOS/BUILD.bazel new file mode 100644 index 000000000000..ea0a4d52ee01 --- /dev/null +++ b/packages/rn-tester/RNTester-macOS/BUILD.bazel @@ -0,0 +1,8 @@ +"""Canonical Bazel entry point for the existing RNTester macOS app.""" + +package(default_visibility = ["//visibility:public"]) + +alias( + name = "app", + actual = "//packages/rn-tester:RNTesterMacBazelFull", +) diff --git a/packages/rn-tester/bazel/MinimalAppDelegate.mm b/packages/rn-tester/bazel/MinimalAppDelegate.mm index d0e9ad49ccb1..9814989b0a11 100644 --- a/packages/rn-tester/bazel/MinimalAppDelegate.mm +++ b/packages/rn-tester/bazel/MinimalAppDelegate.mm @@ -28,7 +28,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification - (NSURL *)bundleURL { - return [[NSBundle mainBundle] URLForResource:@"RNTesterApp.macos" withExtension:@"jsbundle"]; + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; } @end diff --git a/packages/rn-tester/bazel/bundle.js b/packages/rn-tester/bazel/bundle.js index 221efcba78c9..fbe11140087c 100644 --- a/packages/rn-tester/bazel/bundle.js +++ b/packages/rn-tester/bazel/bundle.js @@ -145,9 +145,19 @@ function resolveRelativeFromFileSystem(originModulePath, moduleName, platform) { if (!moduleName.startsWith('.') && !path.isAbsolute(moduleName)) { return null; } - const basePath = path.isAbsolute(moduleName) + let basePath = path.isAbsolute(moduleName) ? moduleName : path.resolve(path.dirname(originModulePath), moduleName); + // RNTester examples use source-relative imports such as + // `../../../react-native/Libraries/...`. Staging RNTester under an output + // directory adds one path segment, so resolve those imports against the same + // react-native-macos package root used for the package alias. + const reactNativeRelative = moduleName + .replace(/\\/g, '/') + .match(/(?:^|\/)react-native\/(.+)$/); + if (reactNativeRelative != null) { + basePath = path.join(ALIASES.get('react-native'), reactNativeRelative[1]); + } const sourceExts = [ `${platform}.js`, 'native.js', diff --git a/tools/bazel/js/copy_tree.js b/tools/bazel/js/copy_tree.js index 4e11ba1b5c12..107caa4db42e 100644 --- a/tools/bazel/js/copy_tree.js +++ b/tools/bazel/js/copy_tree.js @@ -53,25 +53,3 @@ function copyDir(rel = '') { fs.rmSync(outRoot, {recursive: true, force: true}); mkdirp(outRoot); copyDir(); - -if (srcArg.replace(/\\/g, '/').endsWith('packages/rn-tester')) { - writeStub( - 'NativeComponentExample/js/MyNativeView.js', - "import {View} from 'react-native';\nexport default View;\n", - ); - writeStub( - 'NativeModuleExample/NativeScreenshotManager.js', - "module.exports = {takeScreenshot: () => Promise.resolve(null)};\n", - ); - writeStub( - 'NativeCxxModuleExample/NativeCxxModuleExample.js', - "export const EnumInt = {IA: 23, IB: 42};\nexport const EnumNone = {NA: 0, NB: 1};\nexport const EnumStr = {SA: 's---a', SB: 's---b'};\nexport default null;\n", - ); -} - -function writeStub(rel, content) { - const dest = path.join(outRoot, rel); - mkdirp(path.dirname(dest)); - fs.writeFileSync(dest, content); - fs.chmodSync(dest, 0o644); -} From 76396efb78a450e8c1223684ad04c8c987493cce Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 14:55:26 -0700 Subject: [PATCH 20/24] build(bazel): generate React native graph from Package.swift Use swift package dump-package as the canonical graph resolver and emit deterministic Starlark metadata for all 56 SwiftPM targets. A single rn_spm_native_graph() call creates prefixed objc_library targets in packages/react-native, preserving source/exclude sets, dependencies, C++ flags, defines, header search paths, and macOS frameworks without BUILD files throughout the source tree. Bridge the SwiftPM binary dependency to both ReactNativeDependencies.framework and its canonical header tree. Verified generated Yoga, React-debug, React-jsi, and React-utils targets compile from source on Xcode 26.4. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 10 +- packages/react-native/BUILD.bazel | 2 + packages/react-native/bazel/BUILD.bazel | 1 + packages/react-native/bazel/spm_targets.bzl | 4180 +++++++++++++++++++ tools/bazel/apple/BUILD.bazel | 8 +- tools/bazel/apple/generate_spm_targets.js | 198 + tools/bazel/apple/spm_native_graph.bzl | 54 + 7 files changed, 4450 insertions(+), 3 deletions(-) create mode 100644 packages/react-native/bazel/BUILD.bazel create mode 100644 packages/react-native/bazel/spm_targets.bzl create mode 100644 tools/bazel/apple/generate_spm_targets.js create mode 100644 tools/bazel/apple/spm_native_graph.bzl diff --git a/docs/bazel.md b/docs/bazel.md index 3ce5aae1c0d0..e2691a440b9a 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -273,8 +273,14 @@ the repo's `enableScripts: false`), which is inert for Yarn and not published. ## Future roadmap: build the XCFrameworks from source in Bazel -`Package.swift` already enumerates the full target graph (each `RNTarget` ↔ a podspec), -giving a ready-made port map. Output the same `.xcframework`s via +`Package.swift` already enumerates the full target graph (each `RNTarget` ↔ a podspec). +`tools/bazel/apple/generate_spm_targets.js` now runs +`swift package dump-package`, normalizes the resolved macOS target metadata, and writes +`packages/react-native/bazel/spm_targets.bzl`. `rn_spm_native_graph()` turns those 56 +targets into `spm_*` Bazel libraries without adding BUILD files throughout the React +source tree. The initial leaf targets (`Yoga`, `React-debug`, `React-jsi`, and +`React-utils`) compile from source; bring the rest up leaf-first, then output the same +`.xcframework`s via `apple_static_xcframework`, swapped in behind the P3 alias + `--//:rn_from_source`: * **FA — Hermes**: keep the prebuilt Hermes (`http_archive`) initially; optionally wrap diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel index 0d2ed36de01a..d4b64fd4685a 100644 --- a/packages/react-native/BUILD.bazel +++ b/packages/react-native/BUILD.bazel @@ -3,8 +3,10 @@ # link it into node_modules (needed to bundle first-party JS with Metro). load("@aspect_rules_js//npm:defs.bzl", "npm_package") load("@npm//:defs.bzl", "npm_link_all_packages") +load("//tools/bazel/apple:spm_native_graph.bzl", "rn_spm_native_graph") npm_link_all_packages() +rn_spm_native_graph() # Canonical C++ header roots from the RN source tree. The SPM-prebuilt # React.xcframework only exports a partial header set; the deep Fabric/renderer diff --git a/packages/react-native/bazel/BUILD.bazel b/packages/react-native/bazel/BUILD.bazel new file mode 100644 index 000000000000..d48809dee20b --- /dev/null +++ b/packages/react-native/bazel/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["spm_targets.bzl"]) diff --git a/packages/react-native/bazel/spm_targets.bzl b/packages/react-native/bazel/spm_targets.bzl new file mode 100644 index 000000000000..40f1ff8bb369 --- /dev/null +++ b/packages/react-native/bazel/spm_targets.bzl @@ -0,0 +1,4180 @@ +# @generated by //tools/bazel/apple:generate_spm_targets +# Source of truth: //packages/react-native:Package.swift +# Regenerate with: node tools/bazel/apple/generate_spm_targets.js + +SPM_TARGETS = { + "hermes-prebuilt": { + "bazel_name": "spm_hermes_prebuilt", + "type": "binary", + "path": ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + "deps": [], + "srcs": [], + "hdrs": [], + "excludes": [], + "copts": [], + "defines": [], + "debug_defines": [], + "release_defines": [], + "includes": [], + "sdk_frameworks": [], + }, + "RCT-Deprecation": { + "bazel_name": "spm_RCT_Deprecation", + "type": "regular", + "path": "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "deps": [], + "srcs": [ + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.c", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.cc", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.cpp", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.m", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.mm", + ], + "hdrs": [ + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.h", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.hh", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.hpp", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + ], + "sdk_frameworks": [], + }, + "RCTTypesafety": { + "bazel_name": "spm_RCTTypesafety", + "type": "regular", + "path": "Libraries/Typesafety", + "deps": [ + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "Libraries/Typesafety/**/*.c", + "Libraries/Typesafety/**/*.cc", + "Libraries/Typesafety/**/*.cpp", + "Libraries/Typesafety/**/*.m", + "Libraries/Typesafety/**/*.mm", + ], + "hdrs": [ + "Libraries/Typesafety/**/*.h", + "Libraries/Typesafety/**/*.hh", + "Libraries/Typesafety/**/*.hpp", + "Libraries/Typesafety/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Typesafety", + "ReactCommon", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-Core": { + "bazel_name": "spm_React_Core", + "type": "regular", + "path": "React", + "deps": [ + "RCT-Deprecation", + "React-Core/RCTWebSocket", + "React-Fabric", + "React-RCTAnimation", + "React-RCTBlob", + "React-RCTImage", + "React-RCTNetwork", + "React-RCTText", + "React-RCTUIKit", + "React-cxxreact", + "React-featureflags", + "React-jsi", + "React-jsiexecutor", + "React-jsinspector", + "React-jsitooling", + "React-perflogger", + "React-runtimescheduler", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + "hermes-prebuilt", + ], + "srcs": [ + "React/**/*.c", + "React/**/*.cc", + "React/**/*.cpp", + "React/**/*.m", + "React/**/*.mm", + "React/Runtime/RCTHermesInstanceFactory.mm", + ], + "hdrs": [ + "React/**/*.h", + "React/**/*.hh", + "React/**/*.hpp", + "React/**/*.inc", + ], + "excludes": [ + "React/Fabric", + "React/Fabric/**", + "React/Tests", + "React/Tests/**", + "React/Resources", + "React/Resources/**", + "React/Runtime/RCTJscInstanceFactory.mm", + "React/Runtime/RCTJscInstanceFactory.mm/**", + "React/I18n/strings", + "React/I18n/strings/**", + "React/CxxBridge/JSCExecutorFactory.mm", + "React/CxxBridge/JSCExecutorFactory.mm/**", + "React/CoreModules", + "React/CoreModules/**", + "React/RCTUIKit", + "React/RCTUIKit/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/FBReactNativeSpec", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [ + "CoreServices", + ], + }, + "React-Core/RCTWebSocket": { + "bazel_name": "spm_React_Core_RCTWebSocket", + "type": "regular", + "path": "Libraries/WebSocket", + "deps": [ + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "Libraries/WebSocket/**/*.c", + "Libraries/WebSocket/**/*.cc", + "Libraries/WebSocket/**/*.cpp", + "Libraries/WebSocket/**/*.m", + "Libraries/WebSocket/**/*.mm", + ], + "hdrs": [ + "Libraries/WebSocket/**/*.h", + "Libraries/WebSocket/**/*.hh", + "Libraries/WebSocket/**/*.hpp", + "Libraries/WebSocket/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/WebSocket", + "ReactCommon", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-CoreModules": { + "bazel_name": "spm_React_CoreModules", + "type": "regular", + "path": "React/CoreModules", + "deps": [ + "React-jsi", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "React/CoreModules/**/*.c", + "React/CoreModules/**/*.cc", + "React/CoreModules/**/*.cpp", + "React/CoreModules/**/*.m", + "React/CoreModules/**/*.mm", + ], + "hdrs": [ + "React/CoreModules/**/*.h", + "React/CoreModules/**/*.hh", + "React/CoreModules/**/*.hpp", + "React/CoreModules/**/*.inc", + ], + "excludes": [ + "React/CoreModules/PlatformStubs/RCTStatusBarManager.mm", + "React/CoreModules/PlatformStubs/RCTStatusBarManager.mm/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React", + "React/CoreModules", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-cxxreact": { + "bazel_name": "spm_React_cxxreact", + "type": "regular", + "path": "ReactCommon/cxxreact", + "deps": [ + "React-debug", + "React-jsi", + "React-jsinspector", + "React-logger", + "React-perflogger", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/cxxreact/**/*.c", + "ReactCommon/cxxreact/**/*.cc", + "ReactCommon/cxxreact/**/*.cpp", + "ReactCommon/cxxreact/**/*.m", + "ReactCommon/cxxreact/**/*.mm", + ], + "hdrs": [ + "ReactCommon/cxxreact/**/*.h", + "ReactCommon/cxxreact/**/*.hh", + "ReactCommon/cxxreact/**/*.hpp", + "ReactCommon/cxxreact/**/*.inc", + ], + "excludes": [ + "ReactCommon/cxxreact/tests", + "ReactCommon/cxxreact/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-debug": { + "bazel_name": "spm_React_debug", + "type": "regular", + "path": "ReactCommon/react/debug", + "deps": [ + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/debug/**/*.c", + "ReactCommon/react/debug/**/*.cc", + "ReactCommon/react/debug/**/*.cpp", + "ReactCommon/react/debug/**/*.m", + "ReactCommon/react/debug/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/debug/**/*.h", + "ReactCommon/react/debug/**/*.hh", + "ReactCommon/react/debug/**/*.hpp", + "ReactCommon/react/debug/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/react/debug", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-domnativemodule": { + "bazel_name": "spm_React_domnativemodule", + "type": "regular", + "path": "ReactCommon/react/nativemodule/dom", + "deps": [ + "React-Fabric", + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-graphics-Apple", + "React-perflogger", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/nativemodule/dom/**/*.c", + "ReactCommon/react/nativemodule/dom/**/*.cc", + "ReactCommon/react/nativemodule/dom/**/*.cpp", + "ReactCommon/react/nativemodule/dom/**/*.m", + "ReactCommon/react/nativemodule/dom/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/dom/**/*.h", + "ReactCommon/react/nativemodule/dom/**/*.hh", + "ReactCommon/react/nativemodule/dom/**/*.hpp", + "ReactCommon/react/nativemodule/dom/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Typesafety", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/dom", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-Fabric": { + "bazel_name": "spm_React_Fabric", + "type": "regular", + "path": "ReactCommon/react/renderer", + "deps": [ + "RCTTypesafety", + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-graphics", + "React-jsi", + "React-jsiexecutor", + "React-logger", + "React-rendererdebug", + "React-runtimescheduler", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/renderer/animations/**/*.c", + "ReactCommon/react/renderer/animations/**/*.cc", + "ReactCommon/react/renderer/animations/**/*.cpp", + "ReactCommon/react/renderer/animations/**/*.m", + "ReactCommon/react/renderer/animations/**/*.mm", + "ReactCommon/react/renderer/attributedstring/**/*.c", + "ReactCommon/react/renderer/attributedstring/**/*.cc", + "ReactCommon/react/renderer/attributedstring/**/*.cpp", + "ReactCommon/react/renderer/attributedstring/**/*.m", + "ReactCommon/react/renderer/attributedstring/**/*.mm", + "ReactCommon/react/renderer/core/**/*.c", + "ReactCommon/react/renderer/core/**/*.cc", + "ReactCommon/react/renderer/core/**/*.cpp", + "ReactCommon/react/renderer/core/**/*.m", + "ReactCommon/react/renderer/core/**/*.mm", + "ReactCommon/react/renderer/componentregistry/**/*.c", + "ReactCommon/react/renderer/componentregistry/**/*.cc", + "ReactCommon/react/renderer/componentregistry/**/*.cpp", + "ReactCommon/react/renderer/componentregistry/**/*.m", + "ReactCommon/react/renderer/componentregistry/**/*.mm", + "ReactCommon/react/renderer/componentregistry/native/**/*.c", + "ReactCommon/react/renderer/componentregistry/native/**/*.cc", + "ReactCommon/react/renderer/componentregistry/native/**/*.cpp", + "ReactCommon/react/renderer/componentregistry/native/**/*.m", + "ReactCommon/react/renderer/componentregistry/native/**/*.mm", + "ReactCommon/react/renderer/components/root/**/*.c", + "ReactCommon/react/renderer/components/root/**/*.cc", + "ReactCommon/react/renderer/components/root/**/*.cpp", + "ReactCommon/react/renderer/components/root/**/*.m", + "ReactCommon/react/renderer/components/root/**/*.mm", + "ReactCommon/react/renderer/components/view/**/*.c", + "ReactCommon/react/renderer/components/view/**/*.cc", + "ReactCommon/react/renderer/components/view/**/*.cpp", + "ReactCommon/react/renderer/components/view/**/*.m", + "ReactCommon/react/renderer/components/view/**/*.mm", + "ReactCommon/react/renderer/components/scrollview/**/*.c", + "ReactCommon/react/renderer/components/scrollview/**/*.cc", + "ReactCommon/react/renderer/components/scrollview/**/*.cpp", + "ReactCommon/react/renderer/components/scrollview/**/*.m", + "ReactCommon/react/renderer/components/scrollview/**/*.mm", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.c", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.cc", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.cpp", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.m", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.mm", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.c", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.cc", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.cpp", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.m", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.mm", + "ReactCommon/react/renderer/dom/**/*.c", + "ReactCommon/react/renderer/dom/**/*.cc", + "ReactCommon/react/renderer/dom/**/*.cpp", + "ReactCommon/react/renderer/dom/**/*.m", + "ReactCommon/react/renderer/dom/**/*.mm", + "ReactCommon/react/renderer/scheduler/**/*.c", + "ReactCommon/react/renderer/scheduler/**/*.cc", + "ReactCommon/react/renderer/scheduler/**/*.cpp", + "ReactCommon/react/renderer/scheduler/**/*.m", + "ReactCommon/react/renderer/scheduler/**/*.mm", + "ReactCommon/react/renderer/mounting/**/*.c", + "ReactCommon/react/renderer/mounting/**/*.cc", + "ReactCommon/react/renderer/mounting/**/*.cpp", + "ReactCommon/react/renderer/mounting/**/*.m", + "ReactCommon/react/renderer/mounting/**/*.mm", + "ReactCommon/react/renderer/observers/events/**/*.c", + "ReactCommon/react/renderer/observers/events/**/*.cc", + "ReactCommon/react/renderer/observers/events/**/*.cpp", + "ReactCommon/react/renderer/observers/events/**/*.m", + "ReactCommon/react/renderer/observers/events/**/*.mm", + "ReactCommon/react/renderer/telemetry/**/*.c", + "ReactCommon/react/renderer/telemetry/**/*.cc", + "ReactCommon/react/renderer/telemetry/**/*.cpp", + "ReactCommon/react/renderer/telemetry/**/*.m", + "ReactCommon/react/renderer/telemetry/**/*.mm", + "ReactCommon/react/renderer/consistency/**/*.c", + "ReactCommon/react/renderer/consistency/**/*.cc", + "ReactCommon/react/renderer/consistency/**/*.cpp", + "ReactCommon/react/renderer/consistency/**/*.m", + "ReactCommon/react/renderer/consistency/**/*.mm", + "ReactCommon/react/renderer/leakchecker/**/*.c", + "ReactCommon/react/renderer/leakchecker/**/*.cc", + "ReactCommon/react/renderer/leakchecker/**/*.cpp", + "ReactCommon/react/renderer/leakchecker/**/*.m", + "ReactCommon/react/renderer/leakchecker/**/*.mm", + "ReactCommon/react/renderer/uimanager/**/*.c", + "ReactCommon/react/renderer/uimanager/**/*.cc", + "ReactCommon/react/renderer/uimanager/**/*.cpp", + "ReactCommon/react/renderer/uimanager/**/*.m", + "ReactCommon/react/renderer/uimanager/**/*.mm", + "ReactCommon/react/renderer/uimanager/consistency/**/*.c", + "ReactCommon/react/renderer/uimanager/consistency/**/*.cc", + "ReactCommon/react/renderer/uimanager/consistency/**/*.cpp", + "ReactCommon/react/renderer/uimanager/consistency/**/*.m", + "ReactCommon/react/renderer/uimanager/consistency/**/*.mm", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.c", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.cc", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.cpp", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.m", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/animations/**/*.h", + "ReactCommon/react/renderer/animations/**/*.hh", + "ReactCommon/react/renderer/animations/**/*.hpp", + "ReactCommon/react/renderer/animations/**/*.inc", + "ReactCommon/react/renderer/attributedstring/**/*.h", + "ReactCommon/react/renderer/attributedstring/**/*.hh", + "ReactCommon/react/renderer/attributedstring/**/*.hpp", + "ReactCommon/react/renderer/attributedstring/**/*.inc", + "ReactCommon/react/renderer/core/**/*.h", + "ReactCommon/react/renderer/core/**/*.hh", + "ReactCommon/react/renderer/core/**/*.hpp", + "ReactCommon/react/renderer/core/**/*.inc", + "ReactCommon/react/renderer/componentregistry/**/*.h", + "ReactCommon/react/renderer/componentregistry/**/*.hh", + "ReactCommon/react/renderer/componentregistry/**/*.hpp", + "ReactCommon/react/renderer/componentregistry/**/*.inc", + "ReactCommon/react/renderer/componentregistry/native/**/*.h", + "ReactCommon/react/renderer/componentregistry/native/**/*.hh", + "ReactCommon/react/renderer/componentregistry/native/**/*.hpp", + "ReactCommon/react/renderer/componentregistry/native/**/*.inc", + "ReactCommon/react/renderer/components/root/**/*.h", + "ReactCommon/react/renderer/components/root/**/*.hh", + "ReactCommon/react/renderer/components/root/**/*.hpp", + "ReactCommon/react/renderer/components/root/**/*.inc", + "ReactCommon/react/renderer/components/view/**/*.h", + "ReactCommon/react/renderer/components/view/**/*.hh", + "ReactCommon/react/renderer/components/view/**/*.hpp", + "ReactCommon/react/renderer/components/view/**/*.inc", + "ReactCommon/react/renderer/components/scrollview/**/*.h", + "ReactCommon/react/renderer/components/scrollview/**/*.hh", + "ReactCommon/react/renderer/components/scrollview/**/*.hpp", + "ReactCommon/react/renderer/components/scrollview/**/*.inc", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.h", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.hh", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.hpp", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.inc", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.h", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.hh", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.hpp", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.inc", + "ReactCommon/react/renderer/dom/**/*.h", + "ReactCommon/react/renderer/dom/**/*.hh", + "ReactCommon/react/renderer/dom/**/*.hpp", + "ReactCommon/react/renderer/dom/**/*.inc", + "ReactCommon/react/renderer/scheduler/**/*.h", + "ReactCommon/react/renderer/scheduler/**/*.hh", + "ReactCommon/react/renderer/scheduler/**/*.hpp", + "ReactCommon/react/renderer/scheduler/**/*.inc", + "ReactCommon/react/renderer/mounting/**/*.h", + "ReactCommon/react/renderer/mounting/**/*.hh", + "ReactCommon/react/renderer/mounting/**/*.hpp", + "ReactCommon/react/renderer/mounting/**/*.inc", + "ReactCommon/react/renderer/observers/events/**/*.h", + "ReactCommon/react/renderer/observers/events/**/*.hh", + "ReactCommon/react/renderer/observers/events/**/*.hpp", + "ReactCommon/react/renderer/observers/events/**/*.inc", + "ReactCommon/react/renderer/telemetry/**/*.h", + "ReactCommon/react/renderer/telemetry/**/*.hh", + "ReactCommon/react/renderer/telemetry/**/*.hpp", + "ReactCommon/react/renderer/telemetry/**/*.inc", + "ReactCommon/react/renderer/consistency/**/*.h", + "ReactCommon/react/renderer/consistency/**/*.hh", + "ReactCommon/react/renderer/consistency/**/*.hpp", + "ReactCommon/react/renderer/consistency/**/*.inc", + "ReactCommon/react/renderer/leakchecker/**/*.h", + "ReactCommon/react/renderer/leakchecker/**/*.hh", + "ReactCommon/react/renderer/leakchecker/**/*.hpp", + "ReactCommon/react/renderer/leakchecker/**/*.inc", + "ReactCommon/react/renderer/uimanager/**/*.h", + "ReactCommon/react/renderer/uimanager/**/*.hh", + "ReactCommon/react/renderer/uimanager/**/*.hpp", + "ReactCommon/react/renderer/uimanager/**/*.inc", + "ReactCommon/react/renderer/uimanager/consistency/**/*.h", + "ReactCommon/react/renderer/uimanager/consistency/**/*.hh", + "ReactCommon/react/renderer/uimanager/consistency/**/*.hpp", + "ReactCommon/react/renderer/uimanager/consistency/**/*.inc", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.h", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.hh", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.hpp", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/animations/tests", + "ReactCommon/react/renderer/animations/tests/**", + "ReactCommon/react/renderer/attributedstring/tests", + "ReactCommon/react/renderer/attributedstring/tests/**", + "ReactCommon/react/renderer/core/tests", + "ReactCommon/react/renderer/core/tests/**", + "ReactCommon/react/renderer/components/view/tests", + "ReactCommon/react/renderer/components/view/tests/**", + "ReactCommon/react/renderer/components/view/platform/android", + "ReactCommon/react/renderer/components/view/platform/android/**", + "ReactCommon/react/renderer/components/view/platform/windows", + "ReactCommon/react/renderer/components/view/platform/windows/**", + "ReactCommon/react/renderer/components/scrollview/tests", + "ReactCommon/react/renderer/components/scrollview/tests/**", + "ReactCommon/react/renderer/components/scrollview/platform/android", + "ReactCommon/react/renderer/components/scrollview/platform/android/**", + "ReactCommon/react/renderer/mounting/tests", + "ReactCommon/react/renderer/mounting/tests/**", + "ReactCommon/react/renderer/uimanager/tests", + "ReactCommon/react/renderer/uimanager/tests/**", + "ReactCommon/react/renderer/telemetry/tests", + "ReactCommon/react/renderer/telemetry/tests/**", + "ReactCommon/react/renderer/css", + "ReactCommon/react/renderer/css/**", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/debug/**", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/**", + "ReactCommon/react/renderer/imagemanager", + "ReactCommon/react/renderer/imagemanager/**", + "ReactCommon/react/renderer/mapbuffer", + "ReactCommon/react/renderer/mapbuffer/**", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/consistency/**", + "ReactCommon/react/renderer/uimanager/consistency/tests", + "ReactCommon/react/renderer/uimanager/consistency/tests/**", + "ReactCommon/react/renderer/components/inputaccessory", + "ReactCommon/react/renderer/components/inputaccessory/**", + "ReactCommon/react/renderer/components/modal", + "ReactCommon/react/renderer/components/modal/**", + "ReactCommon/react/renderer/components/rncore", + "ReactCommon/react/renderer/components/rncore/**", + "ReactCommon/react/renderer/components/safeareaview", + "ReactCommon/react/renderer/components/safeareaview/**", + "ReactCommon/react/renderer/components/text", + "ReactCommon/react/renderer/components/text/**", + "ReactCommon/react/renderer/components/textinput", + "ReactCommon/react/renderer/components/textinput/**", + "ReactCommon/react/renderer/components/textinput/platform/ios", + "ReactCommon/react/renderer/components/textinput/platform/ios/**", + "ReactCommon/react/renderer/components/unimplementedview", + "ReactCommon/react/renderer/components/unimplementedview/**", + "ReactCommon/react/renderer/components/virtualview", + "ReactCommon/react/renderer/components/virtualview/**", + "ReactCommon/react/renderer/components/root/tests", + "ReactCommon/react/renderer/components/root/tests/**", + "ReactCommon/react/renderer/components/view/platform/cxx", + "ReactCommon/react/renderer/components/view/platform/cxx/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Typesafety", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-FabricComponents": { + "bazel_name": "spm_React_FabricComponents", + "type": "regular", + "path": "ReactCommon/react/renderer", + "deps": [ + "React-Core", + "React-Fabric", + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-graphics", + "React-jsi", + "React-jsiexecutor", + "React-logger", + "React-rendererdebug", + "React-runtimescheduler", + "React-utils", + "ReactCommon/turbomodule/bridging", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/renderer/components/inputaccessory/**/*.c", + "ReactCommon/react/renderer/components/inputaccessory/**/*.cc", + "ReactCommon/react/renderer/components/inputaccessory/**/*.cpp", + "ReactCommon/react/renderer/components/inputaccessory/**/*.m", + "ReactCommon/react/renderer/components/inputaccessory/**/*.mm", + "ReactCommon/react/renderer/components/modal/**/*.c", + "ReactCommon/react/renderer/components/modal/**/*.cc", + "ReactCommon/react/renderer/components/modal/**/*.cpp", + "ReactCommon/react/renderer/components/modal/**/*.m", + "ReactCommon/react/renderer/components/modal/**/*.mm", + "ReactCommon/react/renderer/components/safeareaview/**/*.c", + "ReactCommon/react/renderer/components/safeareaview/**/*.cc", + "ReactCommon/react/renderer/components/safeareaview/**/*.cpp", + "ReactCommon/react/renderer/components/safeareaview/**/*.m", + "ReactCommon/react/renderer/components/safeareaview/**/*.mm", + "ReactCommon/react/renderer/components/text/**/*.c", + "ReactCommon/react/renderer/components/text/**/*.cc", + "ReactCommon/react/renderer/components/text/**/*.cpp", + "ReactCommon/react/renderer/components/text/**/*.m", + "ReactCommon/react/renderer/components/text/**/*.mm", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.c", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.cc", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.cpp", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.m", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.mm", + "ReactCommon/react/renderer/components/textinput/**/*.c", + "ReactCommon/react/renderer/components/textinput/**/*.cc", + "ReactCommon/react/renderer/components/textinput/**/*.cpp", + "ReactCommon/react/renderer/components/textinput/**/*.m", + "ReactCommon/react/renderer/components/textinput/**/*.mm", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.c", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.cc", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.cpp", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.m", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.mm", + "ReactCommon/react/renderer/components/unimplementedview/**/*.c", + "ReactCommon/react/renderer/components/unimplementedview/**/*.cc", + "ReactCommon/react/renderer/components/unimplementedview/**/*.cpp", + "ReactCommon/react/renderer/components/unimplementedview/**/*.m", + "ReactCommon/react/renderer/components/unimplementedview/**/*.mm", + "ReactCommon/react/renderer/components/virtualview/**/*.c", + "ReactCommon/react/renderer/components/virtualview/**/*.cc", + "ReactCommon/react/renderer/components/virtualview/**/*.cpp", + "ReactCommon/react/renderer/components/virtualview/**/*.m", + "ReactCommon/react/renderer/components/virtualview/**/*.mm", + "ReactCommon/react/renderer/textlayoutmanager/**/*.c", + "ReactCommon/react/renderer/textlayoutmanager/**/*.cc", + "ReactCommon/react/renderer/textlayoutmanager/**/*.cpp", + "ReactCommon/react/renderer/textlayoutmanager/**/*.m", + "ReactCommon/react/renderer/textlayoutmanager/**/*.mm", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.c", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.cc", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.cpp", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.m", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/components/inputaccessory/**/*.h", + "ReactCommon/react/renderer/components/inputaccessory/**/*.hh", + "ReactCommon/react/renderer/components/inputaccessory/**/*.hpp", + "ReactCommon/react/renderer/components/inputaccessory/**/*.inc", + "ReactCommon/react/renderer/components/modal/**/*.h", + "ReactCommon/react/renderer/components/modal/**/*.hh", + "ReactCommon/react/renderer/components/modal/**/*.hpp", + "ReactCommon/react/renderer/components/modal/**/*.inc", + "ReactCommon/react/renderer/components/safeareaview/**/*.h", + "ReactCommon/react/renderer/components/safeareaview/**/*.hh", + "ReactCommon/react/renderer/components/safeareaview/**/*.hpp", + "ReactCommon/react/renderer/components/safeareaview/**/*.inc", + "ReactCommon/react/renderer/components/text/**/*.h", + "ReactCommon/react/renderer/components/text/**/*.hh", + "ReactCommon/react/renderer/components/text/**/*.hpp", + "ReactCommon/react/renderer/components/text/**/*.inc", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.h", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.hh", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.hpp", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.inc", + "ReactCommon/react/renderer/components/textinput/**/*.h", + "ReactCommon/react/renderer/components/textinput/**/*.hh", + "ReactCommon/react/renderer/components/textinput/**/*.hpp", + "ReactCommon/react/renderer/components/textinput/**/*.inc", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.h", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.hh", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.hpp", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.inc", + "ReactCommon/react/renderer/components/unimplementedview/**/*.h", + "ReactCommon/react/renderer/components/unimplementedview/**/*.hh", + "ReactCommon/react/renderer/components/unimplementedview/**/*.hpp", + "ReactCommon/react/renderer/components/unimplementedview/**/*.inc", + "ReactCommon/react/renderer/components/virtualview/**/*.h", + "ReactCommon/react/renderer/components/virtualview/**/*.hh", + "ReactCommon/react/renderer/components/virtualview/**/*.hpp", + "ReactCommon/react/renderer/components/virtualview/**/*.inc", + "ReactCommon/react/renderer/textlayoutmanager/**/*.h", + "ReactCommon/react/renderer/textlayoutmanager/**/*.hh", + "ReactCommon/react/renderer/textlayoutmanager/**/*.hpp", + "ReactCommon/react/renderer/textlayoutmanager/**/*.inc", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.h", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.hh", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.hpp", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/components/modal/platform/android", + "ReactCommon/react/renderer/components/modal/platform/android/**", + "ReactCommon/react/renderer/components/modal/platform/cxx", + "ReactCommon/react/renderer/components/modal/platform/cxx/**", + "ReactCommon/react/renderer/components/view/platform/android", + "ReactCommon/react/renderer/components/view/platform/android/**", + "ReactCommon/react/renderer/components/view/platform/windows", + "ReactCommon/react/renderer/components/view/platform/windows/**", + "ReactCommon/react/renderer/components/textinput/platform/android", + "ReactCommon/react/renderer/components/textinput/platform/android/**", + "ReactCommon/react/renderer/components/text/platform/android", + "ReactCommon/react/renderer/components/text/platform/android/**", + "ReactCommon/react/renderer/components/text/tests", + "ReactCommon/react/renderer/components/text/tests/**", + "ReactCommon/react/renderer/textlayoutmanager/tests", + "ReactCommon/react/renderer/textlayoutmanager/tests/**", + "ReactCommon/react/renderer/textlayoutmanager/platform/android", + "ReactCommon/react/renderer/textlayoutmanager/platform/android/**", + "ReactCommon/react/renderer/textlayoutmanager/platform/cxx", + "ReactCommon/react/renderer/textlayoutmanager/platform/cxx/**", + "ReactCommon/react/renderer/textlayoutmanager/platform/windows", + "ReactCommon/react/renderer/textlayoutmanager/platform/windows/**", + "ReactCommon/react/renderer/conponents/rncore", + "ReactCommon/react/renderer/conponents/rncore/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/FBReactNativeSpec", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/inputaccessory", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/modal", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/safeareaview", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/text", + "ReactCommon/react/renderer/components/text/platform/cxx", + "ReactCommon/react/renderer/components/textinput", + "ReactCommon/react/renderer/components/textinput/platform/ios/", + "ReactCommon/react/renderer/components/unimplementedview", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/components/virtualview", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/textlayoutmanager", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-FabricImage": { + "bazel_name": "spm_React_FabricImage", + "type": "regular", + "path": "ReactCommon/react/renderer/components/image", + "deps": [ + "React-Core", + "React-Fabric", + "React-ImageManagerApple", + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-graphics", + "React-jsi", + "React-jsiexecutor", + "React-logger", + "React-rendererdebug", + "React-runtimescheduler", + "React-utils", + "ReactCommon/turbomodule/bridging", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/renderer/components/image/**/*.c", + "ReactCommon/react/renderer/components/image/**/*.cc", + "ReactCommon/react/renderer/components/image/**/*.cpp", + "ReactCommon/react/renderer/components/image/**/*.m", + "ReactCommon/react/renderer/components/image/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/components/image/**/*.h", + "ReactCommon/react/renderer/components/image/**/*.hh", + "ReactCommon/react/renderer/components/image/**/*.hpp", + "ReactCommon/react/renderer/components/image/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/components/image/tests", + "ReactCommon/react/renderer/components/image/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/FBReactNativeSpec", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/image", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/imagemanager", + "ReactCommon/react/renderer/imagemanager/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-featureflags": { + "bazel_name": "spm_React_featureflags", + "type": "regular", + "path": "ReactCommon/react/featureflags", + "deps": [], + "srcs": [ + "ReactCommon/react/featureflags/**/*.c", + "ReactCommon/react/featureflags/**/*.cc", + "ReactCommon/react/featureflags/**/*.cpp", + "ReactCommon/react/featureflags/**/*.m", + "ReactCommon/react/featureflags/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/featureflags/**/*.h", + "ReactCommon/react/featureflags/**/*.hh", + "ReactCommon/react/featureflags/**/*.hpp", + "ReactCommon/react/featureflags/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/featureflags/tests", + "ReactCommon/react/featureflags/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/react/featureflags", + ], + "sdk_frameworks": [], + }, + "React-featureflagsnativemodule": { + "bazel_name": "spm_React_featureflagsnativemodule", + "type": "regular", + "path": "ReactCommon/react/nativemodule/featureflags", + "deps": [ + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-perflogger", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/nativemodule/featureflags/**/*.c", + "ReactCommon/react/nativemodule/featureflags/**/*.cc", + "ReactCommon/react/nativemodule/featureflags/**/*.cpp", + "ReactCommon/react/nativemodule/featureflags/**/*.m", + "ReactCommon/react/nativemodule/featureflags/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/featureflags/**/*.h", + "ReactCommon/react/nativemodule/featureflags/**/*.hh", + "ReactCommon/react/nativemodule/featureflags/**/*.hpp", + "ReactCommon/react/nativemodule/featureflags/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/featureflags", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-graphics": { + "bazel_name": "spm_React_graphics", + "type": "regular", + "path": "ReactCommon/react/renderer/graphics", + "deps": [ + "React-graphics-Apple", + "React-jsi", + "React-jsiexecutor", + "React-rendererdebug", + "React-utils", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/renderer/graphics/**/*.c", + "ReactCommon/react/renderer/graphics/**/*.cc", + "ReactCommon/react/renderer/graphics/**/*.cpp", + "ReactCommon/react/renderer/graphics/**/*.m", + "ReactCommon/react/renderer/graphics/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/graphics/**/*.h", + "ReactCommon/react/renderer/graphics/**/*.hh", + "ReactCommon/react/renderer/graphics/**/*.hpp", + "ReactCommon/react/renderer/graphics/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/graphics/platform", + "ReactCommon/react/renderer/graphics/platform/**", + "ReactCommon/react/renderer/graphics/tests", + "ReactCommon/react/renderer/graphics/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-graphics-Apple": { + "bazel_name": "spm_React_graphics_Apple", + "type": "regular", + "path": "ReactCommon/react/renderer/graphics/platform/ios", + "deps": [ + "React-debug", + "React-jsi", + "React-utils", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/renderer/graphics/platform/ios/**/*.c", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.cc", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.cpp", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.m", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/graphics/platform/ios/**/*.h", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.hh", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.hpp", + "ReactCommon/react/renderer/graphics/platform/ios/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/react/debug", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [ + "AppKit", + "CoreGraphics", + ], + }, + "React-hermes": { + "bazel_name": "spm_React_hermes", + "type": "regular", + "path": "ReactCommon/hermes", + "deps": [ + "React-cxxreact", + "React-jsi", + "React-jsiexecutor", + "React-jsinspector", + "React-jsinspectortracing", + "React-perflogger", + "ReactNativeDependencies", + "hermes-prebuilt", + ], + "srcs": [ + "ReactCommon/hermes/**/*.c", + "ReactCommon/hermes/**/*.cc", + "ReactCommon/hermes/**/*.cpp", + "ReactCommon/hermes/**/*.m", + "ReactCommon/hermes/**/*.mm", + ], + "hdrs": [ + "ReactCommon/hermes/**/*.h", + "ReactCommon/hermes/**/*.hh", + "ReactCommon/hermes/**/*.hpp", + "ReactCommon/hermes/**/*.inc", + ], + "excludes": [ + "ReactCommon/hermes/inspector-modern/chrome/tests", + "ReactCommon/hermes/inspector-modern/chrome/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + "HERMES_ENABLE_DEBUGGER=1", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/hermes", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-idlecallbacksnativemodule": { + "bazel_name": "spm_React_idlecallbacksnativemodule", + "type": "regular", + "path": "ReactCommon/react/nativemodule/idlecallbacks", + "deps": [ + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-perflogger", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/nativemodule/idlecallbacks/**/*.c", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.cc", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.cpp", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.m", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/idlecallbacks/**/*.h", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.hh", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.hpp", + "ReactCommon/react/nativemodule/idlecallbacks/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/idlecallbacks", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-ImageManager": { + "bazel_name": "spm_React_ImageManager", + "type": "regular", + "path": "ReactCommon/react/renderer/imagemanager", + "deps": [ + "React-debug", + "React-graphics", + "React-rendererdebug", + "React-utils", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/renderer/imagemanager/**/*.c", + "ReactCommon/react/renderer/imagemanager/**/*.cc", + "ReactCommon/react/renderer/imagemanager/**/*.cpp", + "ReactCommon/react/renderer/imagemanager/**/*.m", + "ReactCommon/react/renderer/imagemanager/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/imagemanager/**/*.h", + "ReactCommon/react/renderer/imagemanager/**/*.hh", + "ReactCommon/react/renderer/imagemanager/**/*.hpp", + "ReactCommon/react/renderer/imagemanager/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/imagemanager/platform", + "ReactCommon/react/renderer/imagemanager/platform/**", + "ReactCommon/react/renderer/imagemanager/tests", + "ReactCommon/react/renderer/imagemanager/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/imagemanager", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-ImageManagerApple": { + "bazel_name": "spm_React_ImageManagerApple", + "type": "regular", + "path": "ReactCommon/react/renderer/imagemanager/platform/ios", + "deps": [ + "React-Core", + "React-ImageManager", + "React-RCTImage", + "React-debug", + "React-graphics", + "React-rendererdebug", + "React-utils", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.c", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.cc", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.cpp", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.m", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.h", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.hh", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.hpp", + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/FBReactNativeSpec", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/imagemanager", + "ReactCommon/react/renderer/imagemanager/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jserrorhandler": { + "bazel_name": "spm_React_jserrorhandler", + "type": "regular", + "path": "ReactCommon/jserrorhandler", + "deps": [ + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-jsi", + "ReactCommon/turbomodule/bridging", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jserrorhandler/**/*.c", + "ReactCommon/jserrorhandler/**/*.cc", + "ReactCommon/jserrorhandler/**/*.cpp", + "ReactCommon/jserrorhandler/**/*.m", + "ReactCommon/jserrorhandler/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jserrorhandler/**/*.h", + "ReactCommon/jserrorhandler/**/*.hh", + "ReactCommon/jserrorhandler/**/*.hpp", + "ReactCommon/jserrorhandler/**/*.inc", + ], + "excludes": [ + "ReactCommon/jserrorhandler/tests", + "ReactCommon/jserrorhandler/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jserrorhandler", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jsi": { + "bazel_name": "spm_React_jsi", + "type": "regular", + "path": "ReactCommon/jsi", + "deps": [ + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jsi/**/*.c", + "ReactCommon/jsi/**/*.cc", + "ReactCommon/jsi/**/*.cpp", + "ReactCommon/jsi/**/*.m", + "ReactCommon/jsi/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jsi/**/*.h", + "ReactCommon/jsi/**/*.hh", + "ReactCommon/jsi/**/*.hpp", + "ReactCommon/jsi/**/*.inc", + ], + "excludes": [ + "ReactCommon/jsi/jsi/test", + "ReactCommon/jsi/jsi/test/**", + "ReactCommon/jsi/CMakeLists.txt", + "ReactCommon/jsi/CMakeLists.txt/**", + "ReactCommon/jsi/jsi/CMakeLists.txt", + "ReactCommon/jsi/jsi/CMakeLists.txt/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jsiexecutor": { + "bazel_name": "spm_React_jsiexecutor", + "type": "regular", + "path": "ReactCommon/jsiexecutor", + "deps": [ + "React-cxxreact", + "React-jsi", + "React-jsinspector", + "React-perflogger", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jsiexecutor/**/*.c", + "ReactCommon/jsiexecutor/**/*.cc", + "ReactCommon/jsiexecutor/**/*.cpp", + "ReactCommon/jsiexecutor/**/*.m", + "ReactCommon/jsiexecutor/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jsiexecutor/**/*.h", + "ReactCommon/jsiexecutor/**/*.hh", + "ReactCommon/jsiexecutor/**/*.hpp", + "ReactCommon/jsiexecutor/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jsinspector": { + "bazel_name": "spm_React_jsinspector", + "type": "regular", + "path": "ReactCommon/jsinspector-modern", + "deps": [ + "React-featureflags", + "React-jsi", + "React-jsinspectornetwork", + "React-jsinspectortracing", + "React-runtimeexecutor", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jsinspector-modern/**/*.c", + "ReactCommon/jsinspector-modern/**/*.cc", + "ReactCommon/jsinspector-modern/**/*.cpp", + "ReactCommon/jsinspector-modern/**/*.m", + "ReactCommon/jsinspector-modern/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jsinspector-modern/**/*.h", + "ReactCommon/jsinspector-modern/**/*.hh", + "ReactCommon/jsinspector-modern/**/*.hpp", + "ReactCommon/jsinspector-modern/**/*.inc", + ], + "excludes": [ + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsinspector-modern/tracing/**", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/network/**", + "ReactCommon/jsinspector-modern/tests", + "ReactCommon/jsinspector-modern/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + "REACT_NATIVE_DEBUGGER_ENABLED=1", + "REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/oscompat", + "ReactCommon/react/featureflags", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jsinspectornetwork": { + "bazel_name": "spm_React_jsinspectornetwork", + "type": "regular", + "path": "ReactCommon/jsinspector-modern/network", + "deps": [ + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jsinspector-modern/network/**/*.c", + "ReactCommon/jsinspector-modern/network/**/*.cc", + "ReactCommon/jsinspector-modern/network/**/*.cpp", + "ReactCommon/jsinspector-modern/network/**/*.m", + "ReactCommon/jsinspector-modern/network/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jsinspector-modern/network/**/*.h", + "ReactCommon/jsinspector-modern/network/**/*.hh", + "ReactCommon/jsinspector-modern/network/**/*.hpp", + "ReactCommon/jsinspector-modern/network/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + "REACT_NATIVE_DEBUGGER_ENABLED=1", + "REACT_NATIVE_DEBUGGER_ENABLED_DEVONLY=1", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsinspector-modern/network", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jsinspectortracing": { + "bazel_name": "spm_React_jsinspectortracing", + "type": "regular", + "path": "ReactCommon/jsinspector-modern/tracing", + "deps": [ + "React-featureflags", + "React-jsi", + "React-oscompat", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jsinspector-modern/tracing/**/*.c", + "ReactCommon/jsinspector-modern/tracing/**/*.cc", + "ReactCommon/jsinspector-modern/tracing/**/*.cpp", + "ReactCommon/jsinspector-modern/tracing/**/*.m", + "ReactCommon/jsinspector-modern/tracing/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jsinspector-modern/tracing/**/*.h", + "ReactCommon/jsinspector-modern/tracing/**/*.hh", + "ReactCommon/jsinspector-modern/tracing/**/*.hpp", + "ReactCommon/jsinspector-modern/tracing/**/*.inc", + ], + "excludes": [ + "ReactCommon/jsinspector-modern/tracing/tests", + "ReactCommon/jsinspector-modern/tracing/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/oscompat", + "ReactCommon/react/featureflags", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-jsitooling": { + "bazel_name": "spm_React_jsitooling", + "type": "regular", + "path": "ReactCommon/jsitooling", + "deps": [ + "React-cxxreact", + "React-jsi", + "React-jsinspector", + "React-jsinspectortracing", + "React-runtimeexecutor", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/jsitooling/**/*.c", + "ReactCommon/jsitooling/**/*.cc", + "ReactCommon/jsitooling/**/*.cpp", + "ReactCommon/jsitooling/**/*.m", + "ReactCommon/jsitooling/**/*.mm", + ], + "hdrs": [ + "ReactCommon/jsitooling/**/*.h", + "ReactCommon/jsitooling/**/*.hh", + "ReactCommon/jsitooling/**/*.hpp", + "ReactCommon/jsitooling/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-logger": { + "bazel_name": "spm_React_logger", + "type": "regular", + "path": "ReactCommon/logger", + "deps": [ + "React-jsi", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/logger/**/*.c", + "ReactCommon/logger/**/*.cc", + "ReactCommon/logger/**/*.cpp", + "ReactCommon/logger/**/*.m", + "ReactCommon/logger/**/*.mm", + ], + "hdrs": [ + "ReactCommon/logger/**/*.h", + "ReactCommon/logger/**/*.hh", + "ReactCommon/logger/**/*.hpp", + "ReactCommon/logger/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/logger", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-Mapbuffer": { + "bazel_name": "spm_React_Mapbuffer", + "type": "regular", + "path": "ReactCommon/react/renderer/mapbuffer", + "deps": [ + "React-debug", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/renderer/mapbuffer/**/*.c", + "ReactCommon/react/renderer/mapbuffer/**/*.cc", + "ReactCommon/react/renderer/mapbuffer/**/*.cpp", + "ReactCommon/react/renderer/mapbuffer/**/*.m", + "ReactCommon/react/renderer/mapbuffer/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/mapbuffer/**/*.h", + "ReactCommon/react/renderer/mapbuffer/**/*.hh", + "ReactCommon/react/renderer/mapbuffer/**/*.hpp", + "ReactCommon/react/renderer/mapbuffer/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/mapbuffer/tests", + "ReactCommon/react/renderer/mapbuffer/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/react/debug", + "ReactCommon/react/renderer/mapbuffer", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-oscompat": { + "bazel_name": "spm_React_oscompat", + "type": "regular", + "path": "ReactCommon/oscompat", + "deps": [], + "srcs": [ + "ReactCommon/oscompat/**/*.c", + "ReactCommon/oscompat/**/*.cc", + "ReactCommon/oscompat/**/*.cpp", + "ReactCommon/oscompat/**/*.m", + "ReactCommon/oscompat/**/*.mm", + ], + "hdrs": [ + "ReactCommon/oscompat/**/*.h", + "ReactCommon/oscompat/**/*.hh", + "ReactCommon/oscompat/**/*.hpp", + "ReactCommon/oscompat/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/oscompat", + ], + "sdk_frameworks": [], + }, + "React-perflogger": { + "bazel_name": "spm_React_perflogger", + "type": "regular", + "path": "ReactCommon/reactperflogger", + "deps": [], + "srcs": [ + "ReactCommon/reactperflogger/**/*.c", + "ReactCommon/reactperflogger/**/*.cc", + "ReactCommon/reactperflogger/**/*.cpp", + "ReactCommon/reactperflogger/**/*.m", + "ReactCommon/reactperflogger/**/*.mm", + ], + "hdrs": [ + "ReactCommon/reactperflogger/**/*.h", + "ReactCommon/reactperflogger/**/*.hh", + "ReactCommon/reactperflogger/**/*.hpp", + "ReactCommon/reactperflogger/**/*.inc", + ], + "excludes": [ + "ReactCommon/reactperflogger/fusebox", + "ReactCommon/reactperflogger/fusebox/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/reactperflogger", + ], + "sdk_frameworks": [], + }, + "React-performancetimeline": { + "bazel_name": "spm_React_performancetimeline", + "type": "regular", + "path": "ReactCommon/react/performance/timeline", + "deps": [ + "React-cxxreact", + "React-featureflags", + "React-jsinspectortracing", + "React-perflogger", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/performance/timeline/**/*.c", + "ReactCommon/react/performance/timeline/**/*.cc", + "ReactCommon/react/performance/timeline/**/*.cpp", + "ReactCommon/react/performance/timeline/**/*.m", + "ReactCommon/react/performance/timeline/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/performance/timeline/**/*.h", + "ReactCommon/react/performance/timeline/**/*.hh", + "ReactCommon/react/performance/timeline/**/*.hpp", + "ReactCommon/react/performance/timeline/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/performance/timeline/tests", + "ReactCommon/react/performance/timeline/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/performance/timeline", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTAnimation": { + "bazel_name": "spm_React_RCTAnimation", + "type": "regular", + "path": "Libraries/NativeAnimation", + "deps": [ + "RCTTypesafety", + "React-featureflags", + "React-jsi", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "Libraries/NativeAnimation/**/*.c", + "Libraries/NativeAnimation/**/*.cc", + "Libraries/NativeAnimation/**/*.cpp", + "Libraries/NativeAnimation/**/*.m", + "Libraries/NativeAnimation/**/*.mm", + ], + "hdrs": [ + "Libraries/NativeAnimation/**/*.h", + "Libraries/NativeAnimation/**/*.hh", + "Libraries/NativeAnimation/**/*.hpp", + "Libraries/NativeAnimation/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/NativeAnimation", + "Libraries/Typesafety", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTAppDelegate": { + "bazel_name": "spm_React_RCTAppDelegate", + "type": "regular", + "path": "Libraries/AppDelegate", + "deps": [ + "React-Core", + "React-Fabric", + "React-RCTImage", + "React-Runtime", + "React-hermes", + "React-jsi", + "React-jsiexecutor", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + "hermes-prebuilt", + ], + "srcs": [ + "Libraries/AppDelegate/**/*.c", + "Libraries/AppDelegate/**/*.cc", + "Libraries/AppDelegate/**/*.cpp", + "Libraries/AppDelegate/**/*.m", + "Libraries/AppDelegate/**/*.mm", + ], + "hdrs": [ + "Libraries/AppDelegate/**/*.h", + "Libraries/AppDelegate/**/*.hh", + "Libraries/AppDelegate/**/*.hpp", + "Libraries/AppDelegate/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/AppDelegate", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/FBReactNativeSpec", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/hermes", + "ReactCommon/jserrorhandler", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTBlob": { + "bazel_name": "spm_React_RCTBlob", + "type": "regular", + "path": "Libraries/Blob", + "deps": [ + "React-jsi", + "ReactCommon/turbomodule/core", + "Yoga", + ], + "srcs": [ + "Libraries/Blob/**/*.c", + "Libraries/Blob/**/*.cc", + "Libraries/Blob/**/*.cpp", + "Libraries/Blob/**/*.m", + "Libraries/Blob/**/*.mm", + ], + "hdrs": [ + "Libraries/Blob/**/*.h", + "Libraries/Blob/**/*.hh", + "Libraries/Blob/**/*.hpp", + "Libraries/Blob/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTFabric": { + "bazel_name": "spm_React_RCTFabric", + "type": "regular", + "path": "React/Fabric", + "deps": [ + "React-Core", + "React-Fabric", + "React-FabricComponents", + "React-FabricImage", + "React-ImageManager", + "React-RCTAnimation", + "React-RCTImage", + "React-RCTText", + "React-debug", + "React-graphics", + "React-jsi", + "React-jsinspector", + "React-jsinspectornetwork", + "React-jsinspectortracing", + "React-performancetimeline", + "React-rendererconsistency", + "React-rendererdebug", + "React-runtimescheduler", + "React-utils", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "React/Fabric/**/*.c", + "React/Fabric/**/*.cc", + "React/Fabric/**/*.cpp", + "React/Fabric/**/*.m", + "React/Fabric/**/*.mm", + ], + "hdrs": [ + "React/Fabric/**/*.h", + "React/Fabric/**/*.hh", + "React/Fabric/**/*.hpp", + "React/Fabric/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/FBReactNativeSpec", + "React/Fabric", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/image", + "ReactCommon/react/renderer/components/inputaccessory", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/modal", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/safeareaview", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/text", + "ReactCommon/react/renderer/components/text/platform/cxx", + "ReactCommon/react/renderer/components/textinput", + "ReactCommon/react/renderer/components/textinput/platform/ios/", + "ReactCommon/react/renderer/components/unimplementedview", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/components/virtualview", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/imagemanager", + "ReactCommon/react/renderer/imagemanager/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/textlayoutmanager", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTImage": { + "bazel_name": "spm_React_RCTImage", + "type": "regular", + "path": "Libraries/Image", + "deps": [ + "RCTTypesafety", + "React-jsi", + "ReactCommon/turbomodule/bridging", + "ReactCommon/turbomodule/core", + "Yoga", + ], + "srcs": [ + "Libraries/Image/**/*.c", + "Libraries/Image/**/*.cc", + "Libraries/Image/**/*.cpp", + "Libraries/Image/**/*.m", + "Libraries/Image/**/*.mm", + ], + "hdrs": [ + "Libraries/Image/**/*.h", + "Libraries/Image/**/*.hh", + "Libraries/Image/**/*.hpp", + "Libraries/Image/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/Typesafety", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [ + "Accelerate", + ], + }, + "React-RCTLinking": { + "bazel_name": "spm_React_RCTLinking", + "type": "regular", + "path": "Libraries/LinkingIOS", + "deps": [ + "React-jsi", + "ReactCommon/turbomodule/core", + ], + "srcs": [ + "Libraries/LinkingIOS/**/*.c", + "Libraries/LinkingIOS/**/*.cc", + "Libraries/LinkingIOS/**/*.cpp", + "Libraries/LinkingIOS/**/*.m", + "Libraries/LinkingIOS/**/*.mm", + ], + "hdrs": [ + "Libraries/LinkingIOS/**/*.h", + "Libraries/LinkingIOS/**/*.hh", + "Libraries/LinkingIOS/**/*.hpp", + "Libraries/LinkingIOS/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/LinkingIOS", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTNetwork": { + "bazel_name": "spm_React_RCTNetwork", + "type": "regular", + "path": "Libraries/Network", + "deps": [ + "React-jsi", + "ReactCommon/turbomodule/core", + "Yoga", + ], + "srcs": [ + "Libraries/Network/**/*.c", + "Libraries/Network/**/*.cc", + "Libraries/Network/**/*.cpp", + "Libraries/Network/**/*.m", + "Libraries/Network/**/*.mm", + ], + "hdrs": [ + "Libraries/Network/**/*.h", + "Libraries/Network/**/*.hh", + "Libraries/Network/**/*.hpp", + "Libraries/Network/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Network", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTSettings": { + "bazel_name": "spm_React_RCTSettings", + "type": "regular", + "path": "Libraries/Settings", + "deps": [ + "ReactCommon/turbomodule/core", + "Yoga", + ], + "srcs": [ + "Libraries/Settings/**/*.c", + "Libraries/Settings/**/*.cc", + "Libraries/Settings/**/*.cpp", + "Libraries/Settings/**/*.m", + "Libraries/Settings/**/*.mm", + ], + "hdrs": [ + "Libraries/Settings/**/*.h", + "Libraries/Settings/**/*.hh", + "Libraries/Settings/**/*.hpp", + "Libraries/Settings/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Settings", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTText": { + "bazel_name": "spm_React_RCTText", + "type": "regular", + "path": "Libraries/Text", + "deps": [ + "ReactCommon/turbomodule/core", + "Yoga", + ], + "srcs": [ + "Libraries/Text/**/*.c", + "Libraries/Text/**/*.cc", + "Libraries/Text/**/*.cpp", + "Libraries/Text/**/*.m", + "Libraries/Text/**/*.mm", + ], + "hdrs": [ + "Libraries/Text/**/*.h", + "Libraries/Text/**/*.hh", + "Libraries/Text/**/*.hpp", + "Libraries/Text/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Text", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RCTUIKit": { + "bazel_name": "spm_React_RCTUIKit", + "type": "regular", + "path": "React/RCTUIKit", + "deps": [], + "srcs": [ + "React/RCTUIKit/**/*.c", + "React/RCTUIKit/**/*.cc", + "React/RCTUIKit/**/*.cpp", + "React/RCTUIKit/**/*.m", + "React/RCTUIKit/**/*.mm", + ], + "hdrs": [ + "React/RCTUIKit/**/*.h", + "React/RCTUIKit/**/*.hh", + "React/RCTUIKit/**/*.hpp", + "React/RCTUIKit/**/*.inc", + ], + "excludes": [ + "React/RCTUIKit/README.md", + "React/RCTUIKit/README.md/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "React", + "React/RCTUIKit", + ], + "sdk_frameworks": [ + "AppKit", + ], + }, + "React-RCTVibration": { + "bazel_name": "spm_React_RCTVibration", + "type": "regular", + "path": "Libraries/Vibration", + "deps": [ + "React-jsi", + "ReactCommon/turbomodule/core", + "Yoga", + ], + "srcs": [ + "Libraries/Vibration/**/*.c", + "Libraries/Vibration/**/*.cc", + "Libraries/Vibration/**/*.cpp", + "Libraries/Vibration/**/*.m", + "Libraries/Vibration/**/*.mm", + ], + "hdrs": [ + "Libraries/Vibration/**/*.h", + "Libraries/Vibration/**/*.hh", + "Libraries/Vibration/**/*.hpp", + "Libraries/Vibration/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/FBLazyVector", + "Libraries/Vibration", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [ + "AudioToolbox", + ], + }, + "React-rendererconsistency": { + "bazel_name": "spm_React_rendererconsistency", + "type": "regular", + "path": "ReactCommon/react/renderer/consistency", + "deps": [], + "srcs": [ + "ReactCommon/react/renderer/consistency/**/*.c", + "ReactCommon/react/renderer/consistency/**/*.cc", + "ReactCommon/react/renderer/consistency/**/*.cpp", + "ReactCommon/react/renderer/consistency/**/*.m", + "ReactCommon/react/renderer/consistency/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/consistency/**/*.h", + "ReactCommon/react/renderer/consistency/**/*.hh", + "ReactCommon/react/renderer/consistency/**/*.hpp", + "ReactCommon/react/renderer/consistency/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/react/renderer/consistency", + ], + "sdk_frameworks": [], + }, + "React-rendererdebug": { + "bazel_name": "spm_React_rendererdebug", + "type": "regular", + "path": "ReactCommon/react/renderer/debug", + "deps": [ + "React-debug", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/renderer/debug/**/*.c", + "ReactCommon/react/renderer/debug/**/*.cc", + "ReactCommon/react/renderer/debug/**/*.cpp", + "ReactCommon/react/renderer/debug/**/*.m", + "ReactCommon/react/renderer/debug/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/debug/**/*.h", + "ReactCommon/react/renderer/debug/**/*.hh", + "ReactCommon/react/renderer/debug/**/*.hpp", + "ReactCommon/react/renderer/debug/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/debug/tests", + "ReactCommon/react/renderer/debug/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/react/debug", + "ReactCommon/react/renderer/debug", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-Runtime": { + "bazel_name": "spm_React_Runtime", + "type": "regular", + "path": "ReactCommon/react/runtime", + "deps": [ + "React-cxxreact", + "React-featureflags", + "React-hermes", + "React-jserrorhandler", + "React-jsi", + "React-jsiexecutor", + "React-jsinspector", + "React-jsitooling", + "React-performancetimeline", + "React-runtimescheduler", + "React-utils", + "ReactNativeDependencies", + "hermes-prebuilt", + ], + "srcs": [ + "ReactCommon/react/runtime/**/*.c", + "ReactCommon/react/runtime/**/*.cc", + "ReactCommon/react/runtime/**/*.cpp", + "ReactCommon/react/runtime/**/*.m", + "ReactCommon/react/runtime/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/runtime/**/*.h", + "ReactCommon/react/runtime/**/*.hh", + "ReactCommon/react/runtime/**/*.hpp", + "ReactCommon/react/runtime/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/runtime/tests", + "ReactCommon/react/runtime/tests/**", + "ReactCommon/react/runtime/iostests", + "ReactCommon/react/runtime/iostests/**", + "ReactCommon/react/runtime/platform", + "ReactCommon/react/runtime/platform/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + "HERMES_ENABLE_DEBUGGER=1", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/hermes", + "ReactCommon/jserrorhandler", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/runtime", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-RuntimeApple": { + "bazel_name": "spm_React_RuntimeApple", + "type": "regular", + "path": "ReactCommon/react/runtime/platform/ios", + "deps": [ + "RCT-Deprecation", + "React-CoreModules", + "React-RCTFabric", + "React-Runtime", + "React-cxxreact", + "React-jsi", + "React-perflogger", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + "Yoga", + "hermes-prebuilt", + ], + "srcs": [ + "ReactCommon/react/runtime/platform/ios/**/*.c", + "ReactCommon/react/runtime/platform/ios/**/*.cc", + "ReactCommon/react/runtime/platform/ios/**/*.cpp", + "ReactCommon/react/runtime/platform/ios/**/*.m", + "ReactCommon/react/runtime/platform/ios/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/runtime/platform/ios/**/*.h", + "ReactCommon/react/runtime/platform/ios/**/*.hh", + "ReactCommon/react/runtime/platform/ios/**/*.hpp", + "ReactCommon/react/runtime/platform/ios/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.mm", + "ReactCommon/react/runtime/platform/ios/ReactCommon/RCTJscInstance.mm/**", + "ReactCommon/react/runtime/platform/ios/ReactCommon/metainternal", + "ReactCommon/react/runtime/platform/ios/ReactCommon/metainternal/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/artifacts/hermes/destroot/Library/Frameworks/universal/hermes.xcframework", + ".build/artifacts/hermes/destroot/include", + ".build/headers", + ".build/headers/React", + "Libraries", + "Libraries/Blob", + "Libraries/FBLazyVector", + "Libraries/Image", + "Libraries/NativeAnimation", + "Libraries/Network", + "Libraries/Text", + "Libraries/Typesafety", + "Libraries/WebSocket", + "React", + "React/CoreModules", + "React/FBReactNativeSpec", + "React/Fabric", + "React/I18n", + "React/Profiler", + "React/RCTUIKit", + "React/Runtime/RCTHermesInstanceFactory.mm", + "ReactApple", + "ReactApple/Libraries/RCTFoundation/RCTDeprecation", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/hermes", + "ReactCommon/jserrorhandler", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/jsitooling", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer", + "ReactCommon/react/renderer/animations", + "ReactCommon/react/renderer/attributedstring", + "ReactCommon/react/renderer/componentregistry", + "ReactCommon/react/renderer/componentregistry/native", + "ReactCommon/react/renderer/components/image", + "ReactCommon/react/renderer/components/inputaccessory", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop", + "ReactCommon/react/renderer/components/modal", + "ReactCommon/react/renderer/components/root", + "ReactCommon/react/renderer/components/safeareaview", + "ReactCommon/react/renderer/components/scrollview", + "ReactCommon/react/renderer/components/scrollview/platform/cxx", + "ReactCommon/react/renderer/components/text", + "ReactCommon/react/renderer/components/text/platform/cxx", + "ReactCommon/react/renderer/components/textinput", + "ReactCommon/react/renderer/components/textinput/platform/ios/", + "ReactCommon/react/renderer/components/unimplementedview", + "ReactCommon/react/renderer/components/view", + "ReactCommon/react/renderer/components/view/platform/macos", + "ReactCommon/react/renderer/components/virtualview", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/core", + "ReactCommon/react/renderer/debug", + "ReactCommon/react/renderer/dom", + "ReactCommon/react/renderer/graphics", + "ReactCommon/react/renderer/graphics/platform/ios", + "ReactCommon/react/renderer/imagemanager", + "ReactCommon/react/renderer/imagemanager/platform/ios", + "ReactCommon/react/renderer/leakchecker", + "ReactCommon/react/renderer/mounting", + "ReactCommon/react/renderer/observers/events", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/renderer/scheduler", + "ReactCommon/react/renderer/telemetry", + "ReactCommon/react/renderer/textlayoutmanager", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios", + "ReactCommon/react/renderer/uimanager", + "ReactCommon/react/renderer/uimanager/consistency", + "ReactCommon/react/runtime", + "ReactCommon/react/runtime/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-runtimeexecutor": { + "bazel_name": "spm_React_runtimeexecutor", + "type": "regular", + "path": "ReactCommon/runtimeexecutor/platform/ios", + "deps": [ + "React-jsi", + ], + "srcs": [ + "ReactCommon/runtimeexecutor/platform/ios/**/*.c", + "ReactCommon/runtimeexecutor/platform/ios/**/*.cc", + "ReactCommon/runtimeexecutor/platform/ios/**/*.cpp", + "ReactCommon/runtimeexecutor/platform/ios/**/*.m", + "ReactCommon/runtimeexecutor/platform/ios/**/*.mm", + ], + "hdrs": [ + "ReactCommon/runtimeexecutor/platform/ios/**/*.h", + "ReactCommon/runtimeexecutor/platform/ios/**/*.hh", + "ReactCommon/runtimeexecutor/platform/ios/**/*.hpp", + "ReactCommon/runtimeexecutor/platform/ios/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-runtimescheduler": { + "bazel_name": "spm_React_runtimescheduler", + "type": "regular", + "path": "ReactCommon/react/renderer/runtimescheduler", + "deps": [ + "React-cxxreact", + "React-featureflags", + "React-perflogger", + "React-performancetimeline", + "React-rendererconsistency", + "React-runtimeexecutor", + "React-utils", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/renderer/runtimescheduler/**/*.c", + "ReactCommon/react/renderer/runtimescheduler/**/*.cc", + "ReactCommon/react/renderer/runtimescheduler/**/*.cpp", + "ReactCommon/react/renderer/runtimescheduler/**/*.m", + "ReactCommon/react/renderer/runtimescheduler/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/renderer/runtimescheduler/**/*.h", + "ReactCommon/react/renderer/runtimescheduler/**/*.hh", + "ReactCommon/react/renderer/runtimescheduler/**/*.hpp", + "ReactCommon/react/renderer/runtimescheduler/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/renderer/runtimescheduler/tests", + "ReactCommon/react/renderer/runtimescheduler/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/performance/timeline", + "ReactCommon/react/renderer/consistency", + "ReactCommon/react/renderer/runtimescheduler", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "React-utils": { + "bazel_name": "spm_React_utils", + "type": "regular", + "path": "ReactCommon/react/utils", + "deps": [ + "React-debug", + "React-jsi", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/utils/**/*.c", + "ReactCommon/react/utils/**/*.cc", + "ReactCommon/react/utils/**/*.cpp", + "ReactCommon/react/utils/**/*.m", + "ReactCommon/react/utils/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/utils/**/*.h", + "ReactCommon/react/utils/**/*.hh", + "ReactCommon/react/utils/**/*.hpp", + "ReactCommon/react/utils/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/utils/tests", + "ReactCommon/react/utils/tests/**", + "ReactCommon/react/utils/platform/android", + "ReactCommon/react/utils/platform/android/**", + "ReactCommon/react/utils/platform/cxx", + "ReactCommon/react/utils/platform/cxx/**", + "ReactCommon/react/utils/platform/windows", + "ReactCommon/react/utils/platform/windows/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/jsi", + "ReactCommon/react/debug", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [ + "CoreFoundation", + ], + }, + "ReactCommon/turbomodule/bridging": { + "bazel_name": "spm_ReactCommon_turbomodule_bridging", + "type": "regular", + "path": "ReactCommon/react/bridging", + "deps": [ + "React-cxxreact", + "React-jsi", + "React-logger", + "React-perflogger", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/bridging/**/*.c", + "ReactCommon/react/bridging/**/*.cc", + "ReactCommon/react/bridging/**/*.cpp", + "ReactCommon/react/bridging/**/*.m", + "ReactCommon/react/bridging/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/bridging/**/*.h", + "ReactCommon/react/bridging/**/*.hh", + "ReactCommon/react/bridging/**/*.hpp", + "ReactCommon/react/bridging/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/bridging/tests", + "ReactCommon/react/bridging/tests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "ReactCommon/turbomodule/core": { + "bazel_name": "spm_ReactCommon_turbomodule_core", + "type": "regular", + "path": "ReactCommon/react/nativemodule/core", + "deps": [ + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-perflogger", + "React-runtimeexecutor", + "React-utils", + "ReactCommon/turbomodule/bridging", + "ReactNativeDependencies", + "Yoga", + ], + "srcs": [ + "ReactCommon/react/nativemodule/core/**/*.c", + "ReactCommon/react/nativemodule/core/**/*.cc", + "ReactCommon/react/nativemodule/core/**/*.cpp", + "ReactCommon/react/nativemodule/core/**/*.m", + "ReactCommon/react/nativemodule/core/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/core/**/*.h", + "ReactCommon/react/nativemodule/core/**/*.hh", + "ReactCommon/react/nativemodule/core/**/*.hpp", + "ReactCommon/react/nativemodule/core/**/*.inc", + ], + "excludes": [ + "ReactCommon/react/nativemodule/core/platform/android", + "ReactCommon/react/nativemodule/core/platform/android/**", + "ReactCommon/react/nativemodule/core/iostests", + "ReactCommon/react/nativemodule/core/iostests/**", + ], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "ReactCommon/turbomodule/core/defaults": { + "bazel_name": "spm_ReactCommon_turbomodule_core_defaults", + "type": "regular", + "path": "ReactCommon/react/nativemodule/defaults", + "deps": [ + "React-jsi", + "React-jsiexecutor", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/nativemodule/defaults/**/*.c", + "ReactCommon/react/nativemodule/defaults/**/*.cc", + "ReactCommon/react/nativemodule/defaults/**/*.cpp", + "ReactCommon/react/nativemodule/defaults/**/*.m", + "ReactCommon/react/nativemodule/defaults/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/defaults/**/*.h", + "ReactCommon/react/nativemodule/defaults/**/*.hh", + "ReactCommon/react/nativemodule/defaults/**/*.hpp", + "ReactCommon/react/nativemodule/defaults/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsiexecutor", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/defaults", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "ReactCommon/turbomodule/core/microtasks": { + "bazel_name": "spm_ReactCommon_turbomodule_core_microtasks", + "type": "regular", + "path": "ReactCommon/react/nativemodule/microtasks", + "deps": [ + "React-cxxreact", + "React-debug", + "React-featureflags", + "React-perflogger", + "React-utils", + "ReactCommon/turbomodule/core", + "ReactNativeDependencies", + ], + "srcs": [ + "ReactCommon/react/nativemodule/microtasks/**/*.c", + "ReactCommon/react/nativemodule/microtasks/**/*.cc", + "ReactCommon/react/nativemodule/microtasks/**/*.cpp", + "ReactCommon/react/nativemodule/microtasks/**/*.m", + "ReactCommon/react/nativemodule/microtasks/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/microtasks/**/*.h", + "ReactCommon/react/nativemodule/microtasks/**/*.hh", + "ReactCommon/react/nativemodule/microtasks/**/*.hpp", + "ReactCommon/react/nativemodule/microtasks/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/microtasks", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, + "ReactNativeDependencies": { + "bazel_name": "spm_ReactNativeDependencies", + "type": "binary", + "path": "third-party/ReactNativeDependencies.xcframework", + "deps": [], + "srcs": [], + "hdrs": [], + "excludes": [], + "copts": [], + "defines": [], + "debug_defines": [], + "release_defines": [], + "includes": [], + "sdk_frameworks": [], + }, + "Yoga": { + "bazel_name": "spm_Yoga", + "type": "regular", + "path": "ReactCommon/yoga", + "deps": [], + "srcs": [ + "ReactCommon/yoga/**/*.c", + "ReactCommon/yoga/**/*.cc", + "ReactCommon/yoga/**/*.cpp", + "ReactCommon/yoga/**/*.m", + "ReactCommon/yoga/**/*.mm", + ], + "hdrs": [ + "ReactCommon/yoga/**/*.h", + "ReactCommon/yoga/**/*.hh", + "ReactCommon/yoga/**/*.hpp", + "ReactCommon/yoga/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/yoga", + ], + "sdk_frameworks": [], + }, +} diff --git a/tools/bazel/apple/BUILD.bazel b/tools/bazel/apple/BUILD.bazel index 6a9fc3ea6448..3a52132b4c3b 100644 --- a/tools/bazel/apple/BUILD.bazel +++ b/tools/bazel/apple/BUILD.bazel @@ -1,4 +1,10 @@ # Bazel helpers for building React Native's Apple targets (rules_apple / rules_swift). # See xcframeworks.bzl and docs/bazel.md. -exports_files(["xcframeworks.bzl"]) +exports_files([ + "generate_spm_targets.js", + "prebuilt_xcframeworks.bzl", + "reconstruct_react_headers.py", + "spm_native_graph.bzl", + "xcframeworks.bzl", +]) diff --git a/tools/bazel/apple/generate_spm_targets.js b/tools/bazel/apple/generate_spm_targets.js new file mode 100644 index 000000000000..e9f0598b7bd7 --- /dev/null +++ b/tools/bazel/apple/generate_spm_targets.js @@ -0,0 +1,198 @@ +#!/usr/bin/env node +/** + * Copyright (c) Microsoft Corporation. + * + * @format + * @noflow + */ + +const {spawnSync} = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const repoRoot = path.resolve(__dirname, '../../..'); +const packageRoot = path.join(repoRoot, 'packages/react-native'); +const outputPath = path.join(packageRoot, 'bazel/spm_targets.bzl'); +const checkOnly = process.argv.includes('--check'); + +const result = spawnSync( + 'swift', + ['package', 'dump-package', '--package-path', packageRoot], + {cwd: repoRoot, encoding: 'utf8'}, +); +if (result.status !== 0) { + process.stderr.write(result.stderr); + process.exit(result.status ?? 1); +} + +const manifest = JSON.parse(result.stdout); +const targetNames = new Set(manifest.targets.map(target => target.name)); + +function sanitizeName(name) { + return name.replace(/[^A-Za-z0-9_]/g, '_'); +} + +function dependencyName(dependency) { + const value = dependency.byName ?? dependency.target ?? dependency.product; + return Array.isArray(value) ? value[0] : value; +} + +function settingValue(setting) { + const kind = setting.kind; + const value = kind[Object.keys(kind)[0]]?._0; + return Array.isArray(value) ? value : [value]; +} + +function appliesToMacOS(setting) { + const platforms = setting.condition?.platformNames ?? []; + return platforms.length === 0 || platforms.includes('macos'); +} + +function normalizeSearchPath(targetPath, searchPath) { + return path.posix.normalize(path.posix.join(targetPath ?? '', searchPath)); +} + +function sourcePatterns(target, extensions) { + const roots = target.sources?.length ? target.sources : ['']; + return roots.flatMap(root => { + const absolute = path.join(packageRoot, target.path ?? '', root); + const relative = path.posix.join(target.path ?? '', root); + if (fs.existsSync(absolute) && fs.statSync(absolute).isFile()) { + return extensions.includes(path.extname(relative)) ? [relative] : []; + } + return extensions.map(extension => + path.posix.join(relative, `**/*${extension}`), + ); + }); +} + +function excludePatterns(target) { + return (target.exclude ?? []).flatMap(exclude => { + const relative = path.posix + .normalize(path.posix.join(target.path ?? '', exclude)) + .replace(/\/+$/, ''); + return [relative, `${relative}/**`]; + }); +} + +function normalizeTarget(target) { + const settings = (target.settings ?? []).filter(appliesToMacOS); + const defines = []; + const debugDefines = []; + const releaseDefines = []; + const copts = []; + const includes = []; + const sdkFrameworks = []; + + for (const setting of settings) { + const kind = Object.keys(setting.kind)[0]; + const values = settingValue(setting).filter(value => value != null); + if (setting.tool === 'cxx' && kind === 'define') { + const config = setting.condition?.config; + (config === 'debug' + ? debugDefines + : config === 'release' + ? releaseDefines + : defines + ).push(...values); + } else if (setting.tool === 'cxx' && kind === 'unsafeFlags') { + copts.push(...values); + } else if (setting.tool === 'cxx' && kind === 'headerSearchPath') { + includes.push( + ...values.map(value => normalizeSearchPath(target.path, value)), + ); + } else if (setting.tool === 'linker' && kind === 'linkedFramework') { + sdkFrameworks.push(...values); + } + } + + return { + bazel_name: `spm_${sanitizeName(target.name)}`, + type: target.type, + path: target.path ?? '', + deps: (target.dependencies ?? []) + .map(dependencyName) + .filter(name => targetNames.has(name)) + .sort(), + srcs: + target.type === 'regular' + ? sourcePatterns(target, ['.c', '.cc', '.cpp', '.m', '.mm']) + : [], + hdrs: + target.type === 'regular' + ? sourcePatterns(target, ['.h', '.hh', '.hpp', '.inc']) + : [], + excludes: excludePatterns(target), + copts: [...new Set(copts)].sort(), + defines: [...new Set(defines)].sort(), + debug_defines: [...new Set(debugDefines)].sort(), + release_defines: [...new Set(releaseDefines)].sort(), + includes: [...new Set(includes)].sort(), + sdk_frameworks: [...new Set(sdkFrameworks)].sort(), + }; +} + +const targets = Object.fromEntries( + [...manifest.targets] + .sort((left, right) => left.name.localeCompare(right.name)) + .map(target => [target.name, normalizeTarget(target)]), +); + +function toStarlark(value, indent = 0) { + const prefix = ' '.repeat(indent); + if (Array.isArray(value)) { + if (value.length === 0) { + return '[]'; + } + return `[\n${value + .map(item => `${' '.repeat(indent + 4)}${toStarlark(item, indent + 4)},`) + .join('\n')}\n${prefix}]`; + } + if (value != null && typeof value === 'object') { + const entries = Object.entries(value); + if (entries.length === 0) { + return '{}'; + } + return `{\n${entries + .map( + ([key, item]) => + `${' '.repeat(indent + 4)}${JSON.stringify(key)}: ${toStarlark( + item, + indent + 4, + )},`, + ) + .join('\n')}\n${prefix}}`; + } + if (value === null) { + return 'None'; + } + if (typeof value === 'boolean') { + return value ? 'True' : 'False'; + } + return JSON.stringify(value); +} + +const output = `# @generated by //tools/bazel/apple:generate_spm_targets +# Source of truth: //packages/react-native:Package.swift +# Regenerate with: node tools/bazel/apple/generate_spm_targets.js + +SPM_TARGETS = ${toStarlark(targets)} +`; + +if (checkOnly) { + const current = fs.existsSync(outputPath) + ? fs.readFileSync(outputPath, 'utf8') + : ''; + if (current !== output) { + console.error( + 'Generated SwiftPM Bazel graph is stale. Run: node tools/bazel/apple/generate_spm_targets.js', + ); + process.exit(1); + } +} else { + fs.mkdirSync(path.dirname(outputPath), {recursive: true}); + fs.writeFileSync(outputPath, output); + console.log( + `Wrote ${path.relative(repoRoot, outputPath)} (${manifest.targets.length} targets)`, + ); +} diff --git a/tools/bazel/apple/spm_native_graph.bzl b/tools/bazel/apple/spm_native_graph.bzl new file mode 100644 index 000000000000..a4b916237982 --- /dev/null +++ b/tools/bazel/apple/spm_native_graph.bzl @@ -0,0 +1,54 @@ +"""Generate experimental Bazel native libraries from Package.swift metadata.""" + +load("//packages/react-native/bazel:spm_targets.bzl", "SPM_TARGETS") + +_BINARY_DEPS = { + "ReactNativeDependencies": [ + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies", + "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", + ], + "hermes-prebuilt": ["@rn_prebuilt_xcframeworks//:hermes"], +} + +def _target_labels(name): + target = SPM_TARGETS[name] + if target["type"] == "binary": + return _BINARY_DEPS[name] + return [":" + target["bazel_name"]] + +def _deps(names): + return [label for name in names for label in _target_labels(name)] + +def rn_spm_native_graph(visibility = ["//visibility:public"]): + """Declare the native target graph resolved from Package.swift. + + Package.swift remains the source of truth. The generated metadata captures its + target paths, source/exclude sets, dependencies, defines, header search paths, + C++ flags, and macOS frameworks. Targets use an `spm_` prefix while this graph is + brought up leaf-first alongside the existing prebuilt-XCFramework path. + """ + for name in sorted(SPM_TARGETS.keys()): + target = SPM_TARGETS[name] + if target["type"] != "regular": + continue + + native.objc_library( + name = target["bazel_name"], + srcs = native.glob( + target["srcs"], + exclude = target["excludes"], + allow_empty = True, + ), + hdrs = native.glob( + target["hdrs"], + exclude = target["excludes"], + allow_empty = True, + ), + copts = target["copts"], + defines = target["defines"] + target["debug_defines"], + includes = target["includes"], + sdk_frameworks = target["sdk_frameworks"], + tags = ["manual"], + visibility = visibility, + deps = _deps(target["deps"]), + ) From 67e3ca394f7ad61dbb7f4804d035f23d64e8b137 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 15:47:58 -0700 Subject: [PATCH 21/24] build(bazel): compile React AppDelegate graph from source Add a source-derived canonical header repository, scope C++20 to C++/ObjC++ files, preserve Hermes/RNDependencies header seams, and generate/compile FBReactNativeSpec inside Bazel. The Package.swift-derived graph now compiles through spm_React_RCTAppDelegate on Xcode 26.4. Add a default-off --//:rn_from_source flag and consistent source/prebuilt header selections for RNTester, codegen, and native examples. App-level source mode remains experimental and is intentionally not made the default in this commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .bazelrc | 5 +- BUILD.bazel | 13 +++ MODULE.bazel | 5 + docs/bazel.md | 7 +- packages/react-native/BUILD.bazel | 23 +++- packages/react-native/bazel/spm_targets.bzl | 83 ++++++++++++++ packages/rn-tester/BUILD.bazel | 13 ++- .../NativeComponentExample/BUILD.bazel | 10 +- .../NativeCxxModuleExample/BUILD.bazel | 6 +- tools/bazel/apple/BUILD.bazel | 1 + tools/bazel/apple/generate_spm_targets.js | 2 +- tools/bazel/apple/prebuilt_xcframeworks.bzl | 12 ++ .../bazel/apple/reconstruct_react_headers.py | 81 ++++++++++++-- tools/bazel/apple/source_headers.bzl | 48 ++++++++ tools/bazel/apple/spm_native_graph.bzl | 16 ++- tools/bazel/react_native/BUILD.bazel | 86 ++++++++++++++ tools/bazel/react_native/defs.bzl | 6 +- .../react_native/fbreactnativespec_runner.js | 105 ++++++++++++++++++ 18 files changed, 489 insertions(+), 33 deletions(-) create mode 100644 tools/bazel/apple/source_headers.bzl create mode 100644 tools/bazel/react_native/fbreactnativespec_runner.js diff --git a/.bazelrc b/.bazelrc index 5cb250e37101..fd77cba19510 100644 --- a/.bazelrc +++ b/.bazelrc @@ -15,8 +15,9 @@ build --show_result=1 build:macos --apple_platform_type=macos # React Native's new architecture C++ (Fabric/TurboModules) requires C++20. -# This only affects C++/Obj-C++ compiles; the JS (rules_js) targets are unaffected. -build --cxxopt=-std=c++20 +# Scope the flag to C++/Obj-C++: objc_library also compiles plain `.m` files, and +# clang rejects `-std=c++20` when it is passed to Objective-C. +build --per_file_copt=.*\\.(cc|cpp|cxx|mm)$@-std=c++20 # CI convenience config. build:ci --color=yes diff --git a/BUILD.bazel b/BUILD.bazel index 4aebeedb374c..d684d60f0739 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,5 +1,18 @@ +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load("@npm//:defs.bzl", "npm_link_all_packages") +bool_flag( + name = "rn_from_source", + build_setting_default = False, + visibility = ["//visibility:public"], +) + +config_setting( + name = "rn_from_source_enabled", + flag_values = {":rn_from_source": "true"}, + visibility = ["//visibility:public"], +) + # Links the pnpm-resolved (from the Berry yarn.lock via our fork) node_modules # into the Bazel build graph. Downstream JS targets depend on # //:node_modules/. diff --git a/MODULE.bazel b/MODULE.bazel index 453d3a1ec461..3e9bb5d61a17 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -10,6 +10,7 @@ module( bazel_dep(name = "aspect_rules_js", version = "3.2.2") bazel_dep(name = "aspect_rules_ts", version = "3.8.11") bazel_dep(name = "aspect_bazel_lib", version = "2.22.5") +bazel_dep(name = "bazel_skylib", version = "1.9.0") bazel_dep(name = "rules_nodejs", version = "6.7.5") # Local fork of rules_js: teach `npm_translate_lock` to read the Yarn Berry (v2+) @@ -65,3 +66,7 @@ bazel_dep(name = "platforms", version = "1.1.0") # to Bazel so the macOS app slice can link them. rn_prebuilt = use_extension("//tools/bazel/apple:prebuilt_xcframeworks.bzl", "rn_prebuilt_xcframeworks_extension") use_repo(rn_prebuilt, "rn_prebuilt_xcframeworks") + +# Canonical header aliases generated directly from the React Native source tree. +rn_source_headers = use_extension("//tools/bazel/apple:source_headers.bzl", "rn_source_headers_extension") +use_repo(rn_source_headers, "rn_source_headers") diff --git a/docs/bazel.md b/docs/bazel.md index e2691a440b9a..9cc1b0d7ee00 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -278,9 +278,10 @@ the repo's `enableScripts: false`), which is inert for Yarn and not published. `swift package dump-package`, normalizes the resolved macOS target metadata, and writes `packages/react-native/bazel/spm_targets.bzl`. `rn_spm_native_graph()` turns those 56 targets into `spm_*` Bazel libraries without adding BUILD files throughout the React -source tree. The initial leaf targets (`Yoga`, `React-debug`, `React-jsi`, and -`React-utils`) compile from source; bring the rest up leaf-first, then output the same -`.xcframework`s via +source tree. The graph now compiles through `spm_React_RCTAppDelegate` (including a +Bazel-generated `FBReactNativeSpec`) using a canonical header projection generated +from source. `--//:rn_from_source=true` is an experimental, default-off app wiring +while that source mode is validated end to end. Then output the same `.xcframework`s via `apple_static_xcframework`, swapped in behind the P3 alias + `--//:rn_from_source`: * **FA — Hermes**: keep the prebuilt Hermes (`http_archive`) initially; optionally wrap diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel index d4b64fd4685a..5194dc36fad5 100644 --- a/packages/react-native/BUILD.bazel +++ b/packages/react-native/BUILD.bazel @@ -103,10 +103,17 @@ objc_library( ":rct_linking_hdrs", ":rct_pushnotification_hdrs", ":rn_cxx_headers", - "@rn_prebuilt_xcframeworks//:React", - "@rn_prebuilt_xcframeworks//:React_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", - ], + ] + select({ + "//:rn_from_source_enabled": [ + "//tools/bazel/react_native:fbreactnativespec", + "@rn_source_headers//:headers", + ], + "//conditions:default": [ + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + ], + }), ) objc_library( name = "sample_turbo_modules", @@ -120,10 +127,14 @@ objc_library( visibility = ["//visibility:public"], deps = [ ":rn_cxx_headers", - "@rn_prebuilt_xcframeworks//:React", - "@rn_prebuilt_xcframeworks//:React_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", - ], + ] + select({ + "//:rn_from_source_enabled": ["@rn_source_headers//:headers"], + "//conditions:default": [ + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + ], + }), ) npm_package( diff --git a/packages/react-native/bazel/spm_targets.bzl b/packages/react-native/bazel/spm_targets.bzl index 40f1ff8bb369..733fa4a9da0e 100644 --- a/packages/react-native/bazel/spm_targets.bzl +++ b/packages/react-native/bazel/spm_targets.bzl @@ -31,6 +31,7 @@ SPM_TARGETS = { "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.mm", ], "hdrs": [ + "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.def", "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.h", "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.hh", "ReactApple/Libraries/RCTFoundation/RCTDeprecation/**/*.hpp", @@ -73,6 +74,7 @@ SPM_TARGETS = { "Libraries/Typesafety/**/*.mm", ], "hdrs": [ + "Libraries/Typesafety/**/*.def", "Libraries/Typesafety/**/*.h", "Libraries/Typesafety/**/*.hh", "Libraries/Typesafety/**/*.hpp", @@ -141,6 +143,7 @@ SPM_TARGETS = { "React/Runtime/RCTHermesInstanceFactory.mm", ], "hdrs": [ + "React/**/*.def", "React/**/*.h", "React/**/*.hh", "React/**/*.hpp", @@ -270,6 +273,7 @@ SPM_TARGETS = { "Libraries/WebSocket/**/*.mm", ], "hdrs": [ + "Libraries/WebSocket/**/*.def", "Libraries/WebSocket/**/*.h", "Libraries/WebSocket/**/*.hh", "Libraries/WebSocket/**/*.hpp", @@ -318,6 +322,7 @@ SPM_TARGETS = { "React/CoreModules/**/*.mm", ], "hdrs": [ + "React/CoreModules/**/*.def", "React/CoreModules/**/*.h", "React/CoreModules/**/*.hh", "React/CoreModules/**/*.hpp", @@ -391,6 +396,7 @@ SPM_TARGETS = { "ReactCommon/cxxreact/**/*.mm", ], "hdrs": [ + "ReactCommon/cxxreact/**/*.def", "ReactCommon/cxxreact/**/*.h", "ReactCommon/cxxreact/**/*.hh", "ReactCommon/cxxreact/**/*.hpp", @@ -449,6 +455,7 @@ SPM_TARGETS = { "ReactCommon/react/debug/**/*.mm", ], "hdrs": [ + "ReactCommon/react/debug/**/*.def", "ReactCommon/react/debug/**/*.h", "ReactCommon/react/debug/**/*.hh", "ReactCommon/react/debug/**/*.hpp", @@ -501,6 +508,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/dom/**/*.mm", ], "hdrs": [ + "ReactCommon/react/nativemodule/dom/**/*.def", "ReactCommon/react/nativemodule/dom/**/*.h", "ReactCommon/react/nativemodule/dom/**/*.hh", "ReactCommon/react/nativemodule/dom/**/*.hpp", @@ -702,82 +710,102 @@ SPM_TARGETS = { "ReactCommon/react/renderer/components/view/platform/macos/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/animations/**/*.def", "ReactCommon/react/renderer/animations/**/*.h", "ReactCommon/react/renderer/animations/**/*.hh", "ReactCommon/react/renderer/animations/**/*.hpp", "ReactCommon/react/renderer/animations/**/*.inc", + "ReactCommon/react/renderer/attributedstring/**/*.def", "ReactCommon/react/renderer/attributedstring/**/*.h", "ReactCommon/react/renderer/attributedstring/**/*.hh", "ReactCommon/react/renderer/attributedstring/**/*.hpp", "ReactCommon/react/renderer/attributedstring/**/*.inc", + "ReactCommon/react/renderer/core/**/*.def", "ReactCommon/react/renderer/core/**/*.h", "ReactCommon/react/renderer/core/**/*.hh", "ReactCommon/react/renderer/core/**/*.hpp", "ReactCommon/react/renderer/core/**/*.inc", + "ReactCommon/react/renderer/componentregistry/**/*.def", "ReactCommon/react/renderer/componentregistry/**/*.h", "ReactCommon/react/renderer/componentregistry/**/*.hh", "ReactCommon/react/renderer/componentregistry/**/*.hpp", "ReactCommon/react/renderer/componentregistry/**/*.inc", + "ReactCommon/react/renderer/componentregistry/native/**/*.def", "ReactCommon/react/renderer/componentregistry/native/**/*.h", "ReactCommon/react/renderer/componentregistry/native/**/*.hh", "ReactCommon/react/renderer/componentregistry/native/**/*.hpp", "ReactCommon/react/renderer/componentregistry/native/**/*.inc", + "ReactCommon/react/renderer/components/root/**/*.def", "ReactCommon/react/renderer/components/root/**/*.h", "ReactCommon/react/renderer/components/root/**/*.hh", "ReactCommon/react/renderer/components/root/**/*.hpp", "ReactCommon/react/renderer/components/root/**/*.inc", + "ReactCommon/react/renderer/components/view/**/*.def", "ReactCommon/react/renderer/components/view/**/*.h", "ReactCommon/react/renderer/components/view/**/*.hh", "ReactCommon/react/renderer/components/view/**/*.hpp", "ReactCommon/react/renderer/components/view/**/*.inc", + "ReactCommon/react/renderer/components/scrollview/**/*.def", "ReactCommon/react/renderer/components/scrollview/**/*.h", "ReactCommon/react/renderer/components/scrollview/**/*.hh", "ReactCommon/react/renderer/components/scrollview/**/*.hpp", "ReactCommon/react/renderer/components/scrollview/**/*.inc", + "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.def", "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.h", "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.hh", "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.hpp", "ReactCommon/react/renderer/components/scrollview/platform/cxx/**/*.inc", + "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.def", "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.h", "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.hh", "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.hpp", "ReactCommon/react/renderer/components/legacyviewmanagerinterop/**/*.inc", + "ReactCommon/react/renderer/dom/**/*.def", "ReactCommon/react/renderer/dom/**/*.h", "ReactCommon/react/renderer/dom/**/*.hh", "ReactCommon/react/renderer/dom/**/*.hpp", "ReactCommon/react/renderer/dom/**/*.inc", + "ReactCommon/react/renderer/scheduler/**/*.def", "ReactCommon/react/renderer/scheduler/**/*.h", "ReactCommon/react/renderer/scheduler/**/*.hh", "ReactCommon/react/renderer/scheduler/**/*.hpp", "ReactCommon/react/renderer/scheduler/**/*.inc", + "ReactCommon/react/renderer/mounting/**/*.def", "ReactCommon/react/renderer/mounting/**/*.h", "ReactCommon/react/renderer/mounting/**/*.hh", "ReactCommon/react/renderer/mounting/**/*.hpp", "ReactCommon/react/renderer/mounting/**/*.inc", + "ReactCommon/react/renderer/observers/events/**/*.def", "ReactCommon/react/renderer/observers/events/**/*.h", "ReactCommon/react/renderer/observers/events/**/*.hh", "ReactCommon/react/renderer/observers/events/**/*.hpp", "ReactCommon/react/renderer/observers/events/**/*.inc", + "ReactCommon/react/renderer/telemetry/**/*.def", "ReactCommon/react/renderer/telemetry/**/*.h", "ReactCommon/react/renderer/telemetry/**/*.hh", "ReactCommon/react/renderer/telemetry/**/*.hpp", "ReactCommon/react/renderer/telemetry/**/*.inc", + "ReactCommon/react/renderer/consistency/**/*.def", "ReactCommon/react/renderer/consistency/**/*.h", "ReactCommon/react/renderer/consistency/**/*.hh", "ReactCommon/react/renderer/consistency/**/*.hpp", "ReactCommon/react/renderer/consistency/**/*.inc", + "ReactCommon/react/renderer/leakchecker/**/*.def", "ReactCommon/react/renderer/leakchecker/**/*.h", "ReactCommon/react/renderer/leakchecker/**/*.hh", "ReactCommon/react/renderer/leakchecker/**/*.hpp", "ReactCommon/react/renderer/leakchecker/**/*.inc", + "ReactCommon/react/renderer/uimanager/**/*.def", "ReactCommon/react/renderer/uimanager/**/*.h", "ReactCommon/react/renderer/uimanager/**/*.hh", "ReactCommon/react/renderer/uimanager/**/*.hpp", "ReactCommon/react/renderer/uimanager/**/*.inc", + "ReactCommon/react/renderer/uimanager/consistency/**/*.def", "ReactCommon/react/renderer/uimanager/consistency/**/*.h", "ReactCommon/react/renderer/uimanager/consistency/**/*.hh", "ReactCommon/react/renderer/uimanager/consistency/**/*.hpp", "ReactCommon/react/renderer/uimanager/consistency/**/*.inc", + "ReactCommon/react/renderer/components/view/platform/macos/**/*.def", "ReactCommon/react/renderer/components/view/platform/macos/**/*.h", "ReactCommon/react/renderer/components/view/platform/macos/**/*.hh", "ReactCommon/react/renderer/components/view/platform/macos/**/*.hpp", @@ -994,46 +1022,57 @@ SPM_TARGETS = { "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/components/inputaccessory/**/*.def", "ReactCommon/react/renderer/components/inputaccessory/**/*.h", "ReactCommon/react/renderer/components/inputaccessory/**/*.hh", "ReactCommon/react/renderer/components/inputaccessory/**/*.hpp", "ReactCommon/react/renderer/components/inputaccessory/**/*.inc", + "ReactCommon/react/renderer/components/modal/**/*.def", "ReactCommon/react/renderer/components/modal/**/*.h", "ReactCommon/react/renderer/components/modal/**/*.hh", "ReactCommon/react/renderer/components/modal/**/*.hpp", "ReactCommon/react/renderer/components/modal/**/*.inc", + "ReactCommon/react/renderer/components/safeareaview/**/*.def", "ReactCommon/react/renderer/components/safeareaview/**/*.h", "ReactCommon/react/renderer/components/safeareaview/**/*.hh", "ReactCommon/react/renderer/components/safeareaview/**/*.hpp", "ReactCommon/react/renderer/components/safeareaview/**/*.inc", + "ReactCommon/react/renderer/components/text/**/*.def", "ReactCommon/react/renderer/components/text/**/*.h", "ReactCommon/react/renderer/components/text/**/*.hh", "ReactCommon/react/renderer/components/text/**/*.hpp", "ReactCommon/react/renderer/components/text/**/*.inc", + "ReactCommon/react/renderer/components/text/platform/cxx/**/*.def", "ReactCommon/react/renderer/components/text/platform/cxx/**/*.h", "ReactCommon/react/renderer/components/text/platform/cxx/**/*.hh", "ReactCommon/react/renderer/components/text/platform/cxx/**/*.hpp", "ReactCommon/react/renderer/components/text/platform/cxx/**/*.inc", + "ReactCommon/react/renderer/components/textinput/**/*.def", "ReactCommon/react/renderer/components/textinput/**/*.h", "ReactCommon/react/renderer/components/textinput/**/*.hh", "ReactCommon/react/renderer/components/textinput/**/*.hpp", "ReactCommon/react/renderer/components/textinput/**/*.inc", + "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.def", "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.h", "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.hh", "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.hpp", "ReactCommon/react/renderer/components/textinput/platform/ios/**/*.inc", + "ReactCommon/react/renderer/components/unimplementedview/**/*.def", "ReactCommon/react/renderer/components/unimplementedview/**/*.h", "ReactCommon/react/renderer/components/unimplementedview/**/*.hh", "ReactCommon/react/renderer/components/unimplementedview/**/*.hpp", "ReactCommon/react/renderer/components/unimplementedview/**/*.inc", + "ReactCommon/react/renderer/components/virtualview/**/*.def", "ReactCommon/react/renderer/components/virtualview/**/*.h", "ReactCommon/react/renderer/components/virtualview/**/*.hh", "ReactCommon/react/renderer/components/virtualview/**/*.hpp", "ReactCommon/react/renderer/components/virtualview/**/*.inc", + "ReactCommon/react/renderer/textlayoutmanager/**/*.def", "ReactCommon/react/renderer/textlayoutmanager/**/*.h", "ReactCommon/react/renderer/textlayoutmanager/**/*.hh", "ReactCommon/react/renderer/textlayoutmanager/**/*.hpp", "ReactCommon/react/renderer/textlayoutmanager/**/*.inc", + "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.def", "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.h", "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.hh", "ReactCommon/react/renderer/textlayoutmanager/platform/ios/**/*.hpp", @@ -1195,6 +1234,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/components/image/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/components/image/**/*.def", "ReactCommon/react/renderer/components/image/**/*.h", "ReactCommon/react/renderer/components/image/**/*.hh", "ReactCommon/react/renderer/components/image/**/*.hpp", @@ -1308,6 +1348,7 @@ SPM_TARGETS = { "ReactCommon/react/featureflags/**/*.mm", ], "hdrs": [ + "ReactCommon/react/featureflags/**/*.def", "ReactCommon/react/featureflags/**/*.h", "ReactCommon/react/featureflags/**/*.hh", "ReactCommon/react/featureflags/**/*.hpp", @@ -1358,6 +1399,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/featureflags/**/*.mm", ], "hdrs": [ + "ReactCommon/react/nativemodule/featureflags/**/*.def", "ReactCommon/react/nativemodule/featureflags/**/*.h", "ReactCommon/react/nativemodule/featureflags/**/*.hh", "ReactCommon/react/nativemodule/featureflags/**/*.hpp", @@ -1427,6 +1469,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/graphics/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/graphics/**/*.def", "ReactCommon/react/renderer/graphics/**/*.h", "ReactCommon/react/renderer/graphics/**/*.hh", "ReactCommon/react/renderer/graphics/**/*.hpp", @@ -1496,6 +1539,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/graphics/platform/ios/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/graphics/platform/ios/**/*.def", "ReactCommon/react/renderer/graphics/platform/ios/**/*.h", "ReactCommon/react/renderer/graphics/platform/ios/**/*.hh", "ReactCommon/react/renderer/graphics/platform/ios/**/*.hpp", @@ -1553,6 +1597,7 @@ SPM_TARGETS = { "ReactCommon/hermes/**/*.mm", ], "hdrs": [ + "ReactCommon/hermes/**/*.def", "ReactCommon/hermes/**/*.h", "ReactCommon/hermes/**/*.hh", "ReactCommon/hermes/**/*.hpp", @@ -1622,6 +1667,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/idlecallbacks/**/*.mm", ], "hdrs": [ + "ReactCommon/react/nativemodule/idlecallbacks/**/*.def", "ReactCommon/react/nativemodule/idlecallbacks/**/*.h", "ReactCommon/react/nativemodule/idlecallbacks/**/*.hh", "ReactCommon/react/nativemodule/idlecallbacks/**/*.hpp", @@ -1691,6 +1737,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/imagemanager/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/imagemanager/**/*.def", "ReactCommon/react/renderer/imagemanager/**/*.h", "ReactCommon/react/renderer/imagemanager/**/*.hh", "ReactCommon/react/renderer/imagemanager/**/*.hpp", @@ -1767,6 +1814,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.def", "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.h", "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.hh", "ReactCommon/react/renderer/imagemanager/platform/ios/**/*.hpp", @@ -1883,6 +1931,7 @@ SPM_TARGETS = { "ReactCommon/jserrorhandler/**/*.mm", ], "hdrs": [ + "ReactCommon/jserrorhandler/**/*.def", "ReactCommon/jserrorhandler/**/*.h", "ReactCommon/jserrorhandler/**/*.hh", "ReactCommon/jserrorhandler/**/*.hpp", @@ -1943,6 +1992,7 @@ SPM_TARGETS = { "ReactCommon/jsi/**/*.mm", ], "hdrs": [ + "ReactCommon/jsi/**/*.def", "ReactCommon/jsi/**/*.h", "ReactCommon/jsi/**/*.hh", "ReactCommon/jsi/**/*.hpp", @@ -1997,6 +2047,7 @@ SPM_TARGETS = { "ReactCommon/jsiexecutor/**/*.mm", ], "hdrs": [ + "ReactCommon/jsiexecutor/**/*.def", "ReactCommon/jsiexecutor/**/*.h", "ReactCommon/jsiexecutor/**/*.hh", "ReactCommon/jsiexecutor/**/*.hpp", @@ -2058,6 +2109,7 @@ SPM_TARGETS = { "ReactCommon/jsinspector-modern/**/*.mm", ], "hdrs": [ + "ReactCommon/jsinspector-modern/**/*.def", "ReactCommon/jsinspector-modern/**/*.h", "ReactCommon/jsinspector-modern/**/*.hh", "ReactCommon/jsinspector-modern/**/*.hpp", @@ -2117,6 +2169,7 @@ SPM_TARGETS = { "ReactCommon/jsinspector-modern/network/**/*.mm", ], "hdrs": [ + "ReactCommon/jsinspector-modern/network/**/*.def", "ReactCommon/jsinspector-modern/network/**/*.h", "ReactCommon/jsinspector-modern/network/**/*.hh", "ReactCommon/jsinspector-modern/network/**/*.hpp", @@ -2165,6 +2218,7 @@ SPM_TARGETS = { "ReactCommon/jsinspector-modern/tracing/**/*.mm", ], "hdrs": [ + "ReactCommon/jsinspector-modern/tracing/**/*.def", "ReactCommon/jsinspector-modern/tracing/**/*.h", "ReactCommon/jsinspector-modern/tracing/**/*.hh", "ReactCommon/jsinspector-modern/tracing/**/*.hpp", @@ -2219,6 +2273,7 @@ SPM_TARGETS = { "ReactCommon/jsitooling/**/*.mm", ], "hdrs": [ + "ReactCommon/jsitooling/**/*.def", "ReactCommon/jsitooling/**/*.h", "ReactCommon/jsitooling/**/*.hh", "ReactCommon/jsitooling/**/*.hpp", @@ -2276,6 +2331,7 @@ SPM_TARGETS = { "ReactCommon/logger/**/*.mm", ], "hdrs": [ + "ReactCommon/logger/**/*.def", "ReactCommon/logger/**/*.h", "ReactCommon/logger/**/*.hh", "ReactCommon/logger/**/*.hpp", @@ -2321,6 +2377,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/mapbuffer/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/mapbuffer/**/*.def", "ReactCommon/react/renderer/mapbuffer/**/*.h", "ReactCommon/react/renderer/mapbuffer/**/*.hh", "ReactCommon/react/renderer/mapbuffer/**/*.hpp", @@ -2366,6 +2423,7 @@ SPM_TARGETS = { "ReactCommon/oscompat/**/*.mm", ], "hdrs": [ + "ReactCommon/oscompat/**/*.def", "ReactCommon/oscompat/**/*.h", "ReactCommon/oscompat/**/*.hh", "ReactCommon/oscompat/**/*.hpp", @@ -2405,6 +2463,7 @@ SPM_TARGETS = { "ReactCommon/reactperflogger/**/*.mm", ], "hdrs": [ + "ReactCommon/reactperflogger/**/*.def", "ReactCommon/reactperflogger/**/*.h", "ReactCommon/reactperflogger/**/*.hh", "ReactCommon/reactperflogger/**/*.hpp", @@ -2453,6 +2512,7 @@ SPM_TARGETS = { "ReactCommon/react/performance/timeline/**/*.mm", ], "hdrs": [ + "ReactCommon/react/performance/timeline/**/*.def", "ReactCommon/react/performance/timeline/**/*.h", "ReactCommon/react/performance/timeline/**/*.hh", "ReactCommon/react/performance/timeline/**/*.hpp", @@ -2518,6 +2578,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation/**/*.mm", ], "hdrs": [ + "Libraries/NativeAnimation/**/*.def", "Libraries/NativeAnimation/**/*.h", "Libraries/NativeAnimation/**/*.hh", "Libraries/NativeAnimation/**/*.hpp", @@ -2594,6 +2655,7 @@ SPM_TARGETS = { "Libraries/AppDelegate/**/*.mm", ], "hdrs": [ + "Libraries/AppDelegate/**/*.def", "Libraries/AppDelegate/**/*.h", "Libraries/AppDelegate/**/*.hh", "Libraries/AppDelegate/**/*.hpp", @@ -2709,6 +2771,7 @@ SPM_TARGETS = { "Libraries/Blob/**/*.mm", ], "hdrs": [ + "Libraries/Blob/**/*.def", "Libraries/Blob/**/*.h", "Libraries/Blob/**/*.hh", "Libraries/Blob/**/*.hpp", @@ -2794,6 +2857,7 @@ SPM_TARGETS = { "React/Fabric/**/*.mm", ], "hdrs": [ + "React/Fabric/**/*.def", "React/Fabric/**/*.h", "React/Fabric/**/*.hh", "React/Fabric/**/*.hpp", @@ -2922,6 +2986,7 @@ SPM_TARGETS = { "Libraries/Image/**/*.mm", ], "hdrs": [ + "Libraries/Image/**/*.def", "Libraries/Image/**/*.h", "Libraries/Image/**/*.hh", "Libraries/Image/**/*.hpp", @@ -2991,6 +3056,7 @@ SPM_TARGETS = { "Libraries/LinkingIOS/**/*.mm", ], "hdrs": [ + "Libraries/LinkingIOS/**/*.def", "Libraries/LinkingIOS/**/*.h", "Libraries/LinkingIOS/**/*.hh", "Libraries/LinkingIOS/**/*.hpp", @@ -3058,6 +3124,7 @@ SPM_TARGETS = { "Libraries/Network/**/*.mm", ], "hdrs": [ + "Libraries/Network/**/*.def", "Libraries/Network/**/*.h", "Libraries/Network/**/*.hh", "Libraries/Network/**/*.hpp", @@ -3124,6 +3191,7 @@ SPM_TARGETS = { "Libraries/Settings/**/*.mm", ], "hdrs": [ + "Libraries/Settings/**/*.def", "Libraries/Settings/**/*.h", "Libraries/Settings/**/*.hh", "Libraries/Settings/**/*.hpp", @@ -3190,6 +3258,7 @@ SPM_TARGETS = { "Libraries/Text/**/*.mm", ], "hdrs": [ + "Libraries/Text/**/*.def", "Libraries/Text/**/*.h", "Libraries/Text/**/*.hh", "Libraries/Text/**/*.hpp", @@ -3253,6 +3322,7 @@ SPM_TARGETS = { "React/RCTUIKit/**/*.mm", ], "hdrs": [ + "React/RCTUIKit/**/*.def", "React/RCTUIKit/**/*.h", "React/RCTUIKit/**/*.hh", "React/RCTUIKit/**/*.hpp", @@ -3301,6 +3371,7 @@ SPM_TARGETS = { "Libraries/Vibration/**/*.mm", ], "hdrs": [ + "Libraries/Vibration/**/*.def", "Libraries/Vibration/**/*.h", "Libraries/Vibration/**/*.hh", "Libraries/Vibration/**/*.hpp", @@ -3366,6 +3437,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/consistency/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/consistency/**/*.def", "ReactCommon/react/renderer/consistency/**/*.h", "ReactCommon/react/renderer/consistency/**/*.hh", "ReactCommon/react/renderer/consistency/**/*.hpp", @@ -3408,6 +3480,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/debug/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/debug/**/*.def", "ReactCommon/react/renderer/debug/**/*.h", "ReactCommon/react/renderer/debug/**/*.hh", "ReactCommon/react/renderer/debug/**/*.hpp", @@ -3467,6 +3540,7 @@ SPM_TARGETS = { "ReactCommon/react/runtime/**/*.mm", ], "hdrs": [ + "ReactCommon/react/runtime/**/*.def", "ReactCommon/react/runtime/**/*.h", "ReactCommon/react/runtime/**/*.hh", "ReactCommon/react/runtime/**/*.hpp", @@ -3554,6 +3628,7 @@ SPM_TARGETS = { "ReactCommon/react/runtime/platform/ios/**/*.mm", ], "hdrs": [ + "ReactCommon/react/runtime/platform/ios/**/*.def", "ReactCommon/react/runtime/platform/ios/**/*.h", "ReactCommon/react/runtime/platform/ios/**/*.hh", "ReactCommon/react/runtime/platform/ios/**/*.hpp", @@ -3687,6 +3762,7 @@ SPM_TARGETS = { "ReactCommon/runtimeexecutor/platform/ios/**/*.mm", ], "hdrs": [ + "ReactCommon/runtimeexecutor/platform/ios/**/*.def", "ReactCommon/runtimeexecutor/platform/ios/**/*.h", "ReactCommon/runtimeexecutor/platform/ios/**/*.hh", "ReactCommon/runtimeexecutor/platform/ios/**/*.hpp", @@ -3739,6 +3815,7 @@ SPM_TARGETS = { "ReactCommon/react/renderer/runtimescheduler/**/*.mm", ], "hdrs": [ + "ReactCommon/react/renderer/runtimescheduler/**/*.def", "ReactCommon/react/renderer/runtimescheduler/**/*.h", "ReactCommon/react/renderer/runtimescheduler/**/*.hh", "ReactCommon/react/renderer/runtimescheduler/**/*.hpp", @@ -3804,6 +3881,7 @@ SPM_TARGETS = { "ReactCommon/react/utils/**/*.mm", ], "hdrs": [ + "ReactCommon/react/utils/**/*.def", "ReactCommon/react/utils/**/*.h", "ReactCommon/react/utils/**/*.hh", "ReactCommon/react/utils/**/*.hpp", @@ -3865,6 +3943,7 @@ SPM_TARGETS = { "ReactCommon/react/bridging/**/*.mm", ], "hdrs": [ + "ReactCommon/react/bridging/**/*.def", "ReactCommon/react/bridging/**/*.h", "ReactCommon/react/bridging/**/*.hh", "ReactCommon/react/bridging/**/*.hpp", @@ -3932,6 +4011,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/core/**/*.mm", ], "hdrs": [ + "ReactCommon/react/nativemodule/core/**/*.def", "ReactCommon/react/nativemodule/core/**/*.h", "ReactCommon/react/nativemodule/core/**/*.hh", "ReactCommon/react/nativemodule/core/**/*.hpp", @@ -4003,6 +4083,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/defaults/**/*.mm", ], "hdrs": [ + "ReactCommon/react/nativemodule/defaults/**/*.def", "ReactCommon/react/nativemodule/defaults/**/*.h", "ReactCommon/react/nativemodule/defaults/**/*.hh", "ReactCommon/react/nativemodule/defaults/**/*.hpp", @@ -4074,6 +4155,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/microtasks/**/*.mm", ], "hdrs": [ + "ReactCommon/react/nativemodule/microtasks/**/*.def", "ReactCommon/react/nativemodule/microtasks/**/*.h", "ReactCommon/react/nativemodule/microtasks/**/*.hh", "ReactCommon/react/nativemodule/microtasks/**/*.hpp", @@ -4151,6 +4233,7 @@ SPM_TARGETS = { "ReactCommon/yoga/**/*.mm", ], "hdrs": [ + "ReactCommon/yoga/**/*.def", "ReactCommon/yoga/**/*.h", "ReactCommon/yoga/**/*.hh", "ReactCommon/yoga/**/*.hpp", diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index 446cfe6fe02a..ecb36b9145a9 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -159,12 +159,19 @@ objc_library( "//tools/bazel/react_native:rn_tester_appspecs_appdep_hdrs", "//tools/bazel/react_native:rn_tester_appspecs_lib", "//tools/bazel/react_native:rn_tester_appspecs_reactcodegen_hdrs", - "@rn_prebuilt_xcframeworks//:React", - "@rn_prebuilt_xcframeworks//:React_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", "@rn_prebuilt_xcframeworks//:hermes", - ], + ] + select({ + "//:rn_from_source_enabled": [ + "//packages/react-native:spm_React_RCTAppDelegate", + "@rn_source_headers//:headers", + ], + "//conditions:default": [ + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + ], + }), ) macos_application( diff --git a/packages/rn-tester/NativeComponentExample/BUILD.bazel b/packages/rn-tester/NativeComponentExample/BUILD.bazel index a5ccbb06c40d..7a6587392cc7 100644 --- a/packages/rn-tester/NativeComponentExample/BUILD.bazel +++ b/packages/rn-tester/NativeComponentExample/BUILD.bazel @@ -35,8 +35,12 @@ objc_library( "//packages/react-native:rct_fabric_components_plugins_hdr", "//packages/react-native:rn_cxx_headers", "//tools/bazel/react_native:rn_tester_appspecs_fabric_hdrs", - "@rn_prebuilt_xcframeworks//:React", - "@rn_prebuilt_xcframeworks//:React_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", - ], + ] + select({ + "//:rn_from_source_enabled": ["@rn_source_headers//:headers"], + "//conditions:default": [ + "@rn_prebuilt_xcframeworks//:React", + "@rn_prebuilt_xcframeworks//:React_headers", + ], + }), ) diff --git a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel index 76c84ce18e66..1808924e8d59 100644 --- a/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel +++ b/packages/rn-tester/NativeCxxModuleExample/BUILD.bazel @@ -27,7 +27,9 @@ objc_library( ":NativeCxxModuleExample_hdrs", "//packages/react-native:rn_cxx_headers", "//tools/bazel/react_native:rn_tester_appspecs_reactcodegen_hdrs", - "@rn_prebuilt_xcframeworks//:React_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", - ], + ] + select({ + "//:rn_from_source_enabled": ["@rn_source_headers//:headers"], + "//conditions:default": ["@rn_prebuilt_xcframeworks//:React_headers"], + }), ) diff --git a/tools/bazel/apple/BUILD.bazel b/tools/bazel/apple/BUILD.bazel index 3a52132b4c3b..05448843796e 100644 --- a/tools/bazel/apple/BUILD.bazel +++ b/tools/bazel/apple/BUILD.bazel @@ -6,5 +6,6 @@ exports_files([ "prebuilt_xcframeworks.bzl", "reconstruct_react_headers.py", "spm_native_graph.bzl", + "source_headers.bzl", "xcframeworks.bzl", ]) diff --git a/tools/bazel/apple/generate_spm_targets.js b/tools/bazel/apple/generate_spm_targets.js index e9f0598b7bd7..ac9e923f4067 100644 --- a/tools/bazel/apple/generate_spm_targets.js +++ b/tools/bazel/apple/generate_spm_targets.js @@ -120,7 +120,7 @@ function normalizeTarget(target) { : [], hdrs: target.type === 'regular' - ? sourcePatterns(target, ['.h', '.hh', '.hpp', '.inc']) + ? sourcePatterns(target, ['.def', '.h', '.hh', '.hpp', '.inc']) : [], excludes: excludePatterns(target), copts: [...new Set(copts)].sort(), diff --git a/tools/bazel/apple/prebuilt_xcframeworks.bzl b/tools/bazel/apple/prebuilt_xcframeworks.bzl index 4c503b3ca89e..4abe89b7333c 100644 --- a/tools/bazel/apple/prebuilt_xcframeworks.bzl +++ b/tools/bazel/apple/prebuilt_xcframeworks.bzl @@ -53,6 +53,18 @@ cc_library( hdrs = glob(["ReactNativeDependencies.xcframework/Headers/**"], allow_empty = True), includes = ["ReactNativeDependencies.xcframework/Headers"], ) +""") + + if "hermes" not in missing: + hermes_headers = "{}/packages/react-native/.build/artifacts/hermes/destroot/include".format(root) + if rctx.path(hermes_headers).exists: + rctx.symlink(hermes_headers, "hermes_headers") + lines.append(""" +cc_library( + name = "hermes_headers", + hdrs = glob(["hermes_headers/**"], allow_empty = True), + includes = ["hermes_headers"], +) """) # The React.xcframework flattens each SPM target's public headers into diff --git a/tools/bazel/apple/reconstruct_react_headers.py b/tools/bazel/apple/reconstruct_react_headers.py index 355bfbe146aa..188d2b7446ab 100644 --- a/tools/bazel/apple/reconstruct_react_headers.py +++ b/tools/bazel/apple/reconstruct_react_headers.py @@ -53,6 +53,8 @@ SELF_NAMED_MODULES = ["FBReactNativeSpec"] INCLUDE_RE = re.compile(r'#\s*(?:import|include)\s*<([^>]+)>') +SKIP_DIRS = frozenset([".build", "build", "node_modules", "Pods", "third-party"]) +SOURCE_EXTENSIONS = (".c", ".cc", ".cpp", ".h", ".hh", ".hpp", ".m", ".mm") # Canonical namespaces supplied from the RN *source* tree (complete, correctly # nested, siblings co-located) rather than the framework's flattened copy. Any @@ -86,26 +88,34 @@ def main(): - headers_dir, out_dir = os.path.abspath(sys.argv[1]), sys.argv[2] + headers_dir = os.path.realpath(sys.argv[1]) + out_dir = os.path.realpath(sys.argv[2]) + include_source_prefixes = "--include-source-prefixes" in sys.argv[3:] # 1. Index every physical header: basename -> [(module, abspath)]. by_basename = {} all_headers = [] + include_sources = [] for module in sorted(os.listdir(headers_dir)): + if module in SKIP_DIRS: + continue mdir = os.path.join(headers_dir, module) if not os.path.isdir(mdir): continue - for root, _dirs, files in os.walk(mdir): + for root, dirs, files in os.walk(mdir): + dirs[:] = [name for name in dirs if name not in SKIP_DIRS] for f in files: + p = os.path.join(root, f) + if f.endswith(SOURCE_EXTENSIONS): + include_sources.append(p) if not f.endswith((".h", ".hpp", ".hh")): continue - p = os.path.join(root, f) all_headers.append((module, p)) by_basename.setdefault(f, []).append((module, p)) # 2. Collect every canonical include path referenced anywhere. referenced = set() - for _module, p in all_headers: + for p in include_sources: try: with open(p, "r", errors="ignore") as fh: for m in INCLUDE_RE.finditer(fh.read()): @@ -121,15 +131,30 @@ def want(rel, phys): def rank_objc(module): return OBJC_REACT_MODULES.index(module) if module in OBJC_REACT_MODULES else 999 - def pick(candidates, hint_segments): + def pick(candidates, hint_segments, canonical_rel): """Choose the best physical file for a canonical path.""" if len(candidates) == 1: return candidates[0][1] # Prefer a module whose name matches a hint path segment. best, best_score = candidates[0][1], float("-inf") + canonical_parts = canonical_rel.replace("\\", "/").split("/") for module, phys in candidates: mtokens = module.lower().replace("react_", "").split("_") - score = sum(1 for seg in hint_segments if seg.lower() in mtokens or seg.lower() == module.lower()) + physical_parts = phys.replace("\\", "/").split("/") + suffix_matches = 0 + for expected, actual in zip( + reversed(canonical_parts), + reversed(physical_parts), + ): + if expected.lower() != actual.lower(): + break + suffix_matches += 1 + score = suffix_matches * 1000 + score += sum( + 1 + for seg in hint_segments + if seg.lower() in mtokens or seg.lower() == module.lower() + ) # Tie-break toward canonical Obj-C ordering (React_Core first). score = score * 100 - rank_objc(module) if score > best_score: @@ -145,14 +170,14 @@ def pick(candidates, hint_segments): for rel in referenced: if "/" not in rel: continue - if rel.split("/")[0] in SOURCE_PREFIXES: + if not include_source_prefixes and rel.split("/")[0] in SOURCE_PREFIXES: continue base = os.path.basename(rel) cands = by_basename.get(base) if not cands: continue segs = rel.split("/")[:-1] - want(rel, pick(cands, segs)) + want(rel, pick(cands, segs, rel)) # 4. Flat `` tree: every Obj-C React module header by basename. for module, phys in all_headers: @@ -174,6 +199,46 @@ def pick(candidates, hint_segments): if module in FLAT_ROOT_MODULES: want(os.path.basename(phys), phys) + # Source-tree mode: AppDelegate headers are imported without a namespace + # (``). The prebuilt layout has a module directory + # for these; the source layout keeps them under Libraries/AppDelegate. + if include_source_prefixes: + for _module, phys in all_headers: + normalized = phys.replace(os.sep, "/") + if "/Libraries/AppDelegate/" in normalized: + want(os.path.basename(phys), phys) + # Source implementations frequently use bare quoted imports such as + # "RCTAssert.h". Put Obj-C public headers in the same canonical React/ + # directory and expose that directory as an include root. Existing + # mappings discovered from explicit imports win. + for module, phys in all_headers: + if module in ("Libraries", "React", "ReactApple"): + want("React/" + os.path.basename(phys), phys) + source_namespaces = { + "/Libraries/FBLazyVector/": "FBLazyVector", + "/Libraries/Required/": "RCTRequired", + "/Libraries/TypeSafety/": "RCTTypeSafety", + "/ReactApple/Libraries/RCTFoundation/RCTDeprecation/Exported/": "RCTDeprecation", + } + for _module, phys in all_headers: + normalized = phys.replace(os.sep, "/") + for source_fragment, namespace in source_namespaces.items(): + if source_fragment in normalized: + want(namespace + "/" + os.path.basename(phys), phys) + # Preserve quoted sibling includes after a physical header is projected + # into a canonical directory. For example, a projected + # react/performance/timeline/PerformanceEntryReporter.h includes + # "PerformanceEntryCircularBuffer.h". + for rel, phys in list(links.items()): + canonical_dir = os.path.dirname(rel) + physical_dir = os.path.dirname(phys) + for sibling in os.listdir(physical_dir): + if sibling.endswith((".h", ".hh", ".hpp")): + want( + os.path.join(canonical_dir, sibling), + os.path.join(physical_dir, sibling), + ) + # 5c. Self-named umbrella families (e.g. ``). for module, phys in all_headers: base = os.path.basename(phys) diff --git a/tools/bazel/apple/source_headers.bzl b/tools/bazel/apple/source_headers.bzl new file mode 100644 index 000000000000..4cf5b9dc4a19 --- /dev/null +++ b/tools/bazel/apple/source_headers.bzl @@ -0,0 +1,48 @@ +"""Expose a canonical React Native header tree generated from source.""" + +def _source_headers_impl(rctx): + root = str(rctx.workspace_root) + script = rctx.path(Label("//tools/bazel/apple:reconstruct_react_headers.py")) + source_root = "{}/packages/react-native".format(root) + rctx.watch(script) + rctx.watch_tree(source_root) + result = rctx.execute( + [ + "python3", + str(script), + source_root, + "headers", + "--include-source-prefixes", + ], + quiet = True, + ) + if result.return_code != 0: + fail("source header reconstruction failed: {}".format(result.stderr)) + + rctx.file("BUILD.bazel", """ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "headers", + hdrs = glob(["headers/**"], allow_empty = True), + includes = ["headers", "headers/React"], + defines = [ + "RCT_DEV=1", + "RCT_ENABLE_INSPECTOR=1", + "RCT_REMOTE_PROFILE=0", + "RCT_PROFILE=0", + "RCT_NEW_ARCH_ENABLED=1", + ], +) +""") + +source_headers = repository_rule( + implementation = _source_headers_impl, + doc = "Reconstructs canonical React/ReactCommon/C++ header paths from source.", + local = True, +) + +def _extension_impl(_module_ctx): + source_headers(name = "rn_source_headers") + +rn_source_headers_extension = module_extension(implementation = _extension_impl) diff --git a/tools/bazel/apple/spm_native_graph.bzl b/tools/bazel/apple/spm_native_graph.bzl index a4b916237982..a8e7094db60a 100644 --- a/tools/bazel/apple/spm_native_graph.bzl +++ b/tools/bazel/apple/spm_native_graph.bzl @@ -7,9 +7,17 @@ _BINARY_DEPS = { "@rn_prebuilt_xcframeworks//:ReactNativeDependencies", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", ], - "hermes-prebuilt": ["@rn_prebuilt_xcframeworks//:hermes"], + "hermes-prebuilt": [ + "@rn_prebuilt_xcframeworks//:hermes", + "@rn_prebuilt_xcframeworks//:hermes_headers", + ], } +_SOURCE_HEADER_BRIDGE = [ + "//tools/bazel/react_native:fbreactnativespec", + "@rn_source_headers//:headers", +] + def _target_labels(name): target = SPM_TARGETS[name] if target["type"] == "binary": @@ -44,11 +52,13 @@ def rn_spm_native_graph(visibility = ["//visibility:public"]): exclude = target["excludes"], allow_empty = True, ), - copts = target["copts"], + # C++20 is set with --per_file_copt in .bazelrc so it is not passed + # to plain Objective-C sources in mixed SwiftPM targets. + copts = [flag for flag in target["copts"] if flag != "-std=c++20"], defines = target["defines"] + target["debug_defines"], includes = target["includes"], sdk_frameworks = target["sdk_frameworks"], tags = ["manual"], visibility = visibility, - deps = _deps(target["deps"]), + deps = _SOURCE_HEADER_BRIDGE + _deps(target["deps"]), ) diff --git a/tools/bazel/react_native/BUILD.bazel b/tools/bazel/react_native/BUILD.bazel index 45472a715280..7af7ad60f63d 100644 --- a/tools/bazel/react_native/BUILD.bazel +++ b/tools/bazel/react_native/BUILD.bazel @@ -45,6 +45,92 @@ js_binary( entry_point = 'codegen_runner.js', ) +js_binary( + name = 'fbreactnativespec_runner_bin', + data = [ + '//packages/react-native:node_modules', + '//packages/react-native:pkg', + ], + entry_point = 'fbreactnativespec_runner.js', +) + +js_run_binary( + name = 'fbreactnativespec_generated', + srcs = [ + '//packages/react-native:pkg', + ':codegen_lib', + ], + outs = [ + 'fbreactnativespec/FBReactNativeSpec/FBReactNativeSpec-generated.mm', + 'fbreactnativespec/FBReactNativeSpec/FBReactNativeSpec.h', + 'fbreactnativespec/FBReactNativeSpecJSI-generated.cpp', + 'fbreactnativespec/FBReactNativeSpecJSI.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ComponentDescriptors.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ComponentDescriptors.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/EventEmitters.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/EventEmitters.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/Props.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/Props.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/RCTComponentViewHelpers.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ShadowNodes.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ShadowNodes.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/States.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/States.h', + ], + env = { + 'CODEGEN_LIB_DIR': '$(location :codegen_lib)', + 'OUTPUT_DIR': '$(RULEDIR)/fbreactnativespec', + }, + tool = ':fbreactnativespec_runner_bin', +) + +cc_library( + name = 'fbreactnativespec_module_headers', + hdrs = ['fbreactnativespec/FBReactNativeSpec/FBReactNativeSpec.h'], + include_prefix = 'FBReactNativeSpec', + strip_include_prefix = 'fbreactnativespec/FBReactNativeSpec', +) + +cc_library( + name = 'fbreactnativespec_jsi_headers', + hdrs = ['fbreactnativespec/FBReactNativeSpecJSI.h'], + include_prefix = 'FBReactNativeSpec', + strip_include_prefix = 'fbreactnativespec', +) + +cc_library( + name = 'fbreactnativespec_component_headers', + hdrs = [ + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ComponentDescriptors.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/EventEmitters.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/Props.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/RCTComponentViewHelpers.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ShadowNodes.h', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/States.h', + ], + strip_include_prefix = 'fbreactnativespec', +) + +objc_library( + name = 'fbreactnativespec', + srcs = [ + 'fbreactnativespec/FBReactNativeSpec/FBReactNativeSpec-generated.mm', + 'fbreactnativespec/FBReactNativeSpecJSI-generated.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ComponentDescriptors.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/EventEmitters.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/Props.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/ShadowNodes.cpp', + 'fbreactnativespec/react/renderer/components/FBReactNativeSpec/States.cpp', + ], + deps = [ + ':fbreactnativespec_component_headers', + ':fbreactnativespec_jsi_headers', + ':fbreactnativespec_module_headers', + '@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers', + '@rn_source_headers//:headers', + ], +) + genrule( name = 'copy_my_legacy_view_native_component', diff --git a/tools/bazel/react_native/defs.bzl b/tools/bazel/react_native/defs.bzl index 8cc08c017611..159cf9c09db9 100644 --- a/tools/bazel/react_native/defs.bzl +++ b/tools/bazel/react_native/defs.bzl @@ -49,9 +49,11 @@ _CODEGEN_OUTS = _TOP_HEADERS + [_APPDEP_HEADER] + _FABRIC_HEADERS + _SOURCES + _ _HEADER_DEPS = [ '//packages/react-native:rn_cxx_headers', - '@rn_prebuilt_xcframeworks//:React_headers', '@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers', -] +] + select({ + '//:rn_from_source_enabled': ['@rn_source_headers//:headers'], + '//conditions:default': ['@rn_prebuilt_xcframeworks//:React_headers'], +}) def rn_codegen(name, project_root, rn_tester_srcs, **kwargs): """Generate rn-tester's codegen (AppSpecs + providers) and compile it. diff --git a/tools/bazel/react_native/fbreactnativespec_runner.js b/tools/bazel/react_native/fbreactnativespec_runner.js new file mode 100644 index 000000000000..493bc7c11ed1 --- /dev/null +++ b/tools/bazel/react_native/fbreactnativespec_runner.js @@ -0,0 +1,105 @@ +#!/usr/bin/env node +/** + * Copyright (c) Microsoft Corporation. + * + * @format + * @noflow + */ + +'use strict'; + +const fs = require('fs'); +const Module = require('module'); +const path = require('path'); + +const cwd = process.cwd(); +const marker = `${path.sep}bazel-out${path.sep}`; +const workspaceRoot = cwd.includes(marker) + ? cwd.slice(0, cwd.indexOf(marker)) + : cwd; +const outputDir = path.resolve(workspaceRoot, mustEnv('OUTPUT_DIR')); +const codegenLibDir = path.resolve(workspaceRoot, mustEnv('CODEGEN_LIB_DIR')); +const bazelReactNativeRoot = path.join( + workspaceRoot, + process.env.BAZEL_BINDIR || '', + 'packages/react-native/pkg', +); +const reactNativeRoot = fs.existsSync(bazelReactNativeRoot) + ? bazelReactNativeRoot + : path.join(workspaceRoot, 'packages/react-native'); +const scratchCodegenRepo = path.join(outputDir, '_codegen_repo'); + +function mustEnv(name) { + const value = process.env[name]; + if (!value) { + throw new Error(`${name} must be set`); + } + return value; +} + +function assertOutput(name) { + const output = path.join(outputDir, name); + if (!fs.existsSync(output)) { + throw new Error(`Expected FBReactNativeSpec output missing: ${output}`); + } +} + +fs.rmSync(outputDir, {recursive: true, force: true}); +fs.mkdirSync(outputDir, {recursive: true}); +fs.mkdirSync(scratchCodegenRepo, {recursive: true}); +fs.symlinkSync(codegenLibDir, path.join(scratchCodegenRepo, 'lib'), 'dir'); + +process.env.NODE_PATH = [ + path.join(codegenLibDir, 'node_modules'), + process.env.NODE_PATH || '', +] + .filter(Boolean) + .join(path.delimiter); +Module._initPaths(); + +const originalResolveFilename = Module._resolveFilename; +Module._resolveFilename = function (request, parent, isMain, options) { + if (request.startsWith('@react-native/codegen/lib/')) { + const resolved = path.join( + codegenLibDir, + request.slice('@react-native/codegen/lib/'.length), + ); + return path.extname(resolved) ? resolved : `${resolved}.js`; + } + return originalResolveFilename.call(this, request, parent, isMain, options); +}; + +const executorRoot = path.join( + reactNativeRoot, + 'scripts/codegen/generate-artifacts-executor', +); +const constants = require(path.join(executorRoot, 'constants.js')); +constants.CODEGEN_REPO_PATH = scratchCodegenRepo; +constants.CORE_LIBRARIES_WITH_OUTPUT_FOLDER.FBReactNativeSpec.ios = outputDir; + +try { + const {generateFBReactNativeSpecIOS} = require(path.join( + executorRoot, + 'generateFBReactNativeSpecIOS.js', + )); + generateFBReactNativeSpecIOS(reactNativeRoot); + [ + 'FBReactNativeSpec/FBReactNativeSpec-generated.mm', + 'FBReactNativeSpec/FBReactNativeSpec.h', + 'FBReactNativeSpecJSI-generated.cpp', + 'FBReactNativeSpecJSI.h', + 'react/renderer/components/FBReactNativeSpec/ComponentDescriptors.cpp', + 'react/renderer/components/FBReactNativeSpec/ComponentDescriptors.h', + 'react/renderer/components/FBReactNativeSpec/EventEmitters.cpp', + 'react/renderer/components/FBReactNativeSpec/EventEmitters.h', + 'react/renderer/components/FBReactNativeSpec/Props.cpp', + 'react/renderer/components/FBReactNativeSpec/Props.h', + 'react/renderer/components/FBReactNativeSpec/RCTComponentViewHelpers.h', + 'react/renderer/components/FBReactNativeSpec/ShadowNodes.cpp', + 'react/renderer/components/FBReactNativeSpec/ShadowNodes.h', + 'react/renderer/components/FBReactNativeSpec/States.cpp', + 'react/renderer/components/FBReactNativeSpec/States.h', + ].forEach(assertOutput); +} finally { + fs.rmSync(scratchCodegenRepo, {recursive: true, force: true}); +} From c7eedc727f0acc8057f5cb03ef1af4525a882f76 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 17:04:57 -0700 Subject: [PATCH 22/24] build(bazel): link complete RNTester against source React Model Package.swift's React product as the aggregate of all generated regular targets, add the missing DevTools runtime settings targets, and preserve required macOS frameworks. The default-off rn_from_source mode now builds and launches RNTester without embedding React.framework while retaining prebuilt Hermes and ReactNativeDependencies as bootstrap inputs. Complete application resources as part of the same end-to-end milestone: save Metro assets returned by runBuild, compile the macOS asset catalog and storyboard, and embed app icons, privacy manifest, and entitlements. Verified both source and prebuilt modes build; source mode launches offline with the real native-example bundle and tab icons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/bazel.md | 15 ++- packages/react-native/BUILD.bazel | 12 +- packages/react-native/Package.swift | 18 ++- packages/react-native/bazel/spm_targets.bzl | 116 ++++++++++++++++++ packages/rn-tester/BUILD.bazel | 18 ++- packages/rn-tester/RNTester-macOS/BUILD.bazel | 12 ++ packages/rn-tester/bazel/bundle.js | 27 +++- tools/bazel/apple/spm_native_graph.bzl | 21 +++- 8 files changed, 226 insertions(+), 13 deletions(-) diff --git a/docs/bazel.md b/docs/bazel.md index 9cc1b0d7ee00..cab40b62894d 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -159,6 +159,14 @@ prebuilt-XCFramework link. Specifically: and the RCTLinking/RCTPushNotification modules built from source (not in the prebuilt framework). Its embedded `main.jsbundle` contains the real native-example JS (no stubs), and no rn-tester source is modified or `#ifdef`'d out. +* **React can be linked from source** with + `bazel build //packages/rn-tester/RNTester-macOS:app --//:rn_from_source=true`. + This mode builds the generated 58-target SwiftPM graph, links the resulting static + libraries into RNTester (no `React.framework` in the app), and launches offline. + Hermes and ReactNativeDependencies remain prebuilt bootstrap inputs. +* **Resources are complete**: Metro copies its 45 image/XML assets (including all six + bottom-nav icons), while rules_apple compiles the macOS asset catalog/storyboard and + embeds `Assets.car`, `AppIcon.icns`, entitlements, and `PrivacyInfo.xcprivacy`. ### Consuming the prebuilt XCFrameworks from Bazel (the header problem) @@ -278,10 +286,11 @@ the repo's `enableScripts: false`), which is inert for Yarn and not published. `swift package dump-package`, normalizes the resolved macOS target metadata, and writes `packages/react-native/bazel/spm_targets.bzl`. `rn_spm_native_graph()` turns those 56 targets into `spm_*` Bazel libraries without adding BUILD files throughout the React -source tree. The graph now compiles through `spm_React_RCTAppDelegate` (including a +source tree. The graph now compiles through the complete `spm_React` product (including a Bazel-generated `FBReactNativeSpec`) using a canonical header projection generated -from source. `--//:rn_from_source=true` is an experimental, default-off app wiring -while that source mode is validated end to end. Then output the same `.xcframework`s via +from source. `--//:rn_from_source=true` builds and launches RNTester but remains +default-off until Hermes and ReactNativeDependencies are available from a fresh checkout. +Then output the same `.xcframework`s via `apple_static_xcframework`, swapped in behind the P3 alias + `--//:rn_from_source`: * **FA — Hermes**: keep the prebuilt Hermes (`http_archive`) initially; optionally wrap diff --git a/packages/react-native/BUILD.bazel b/packages/react-native/BUILD.bazel index 5194dc36fad5..d2d5646ed1e2 100644 --- a/packages/react-native/BUILD.bazel +++ b/packages/react-native/BUILD.bazel @@ -91,16 +91,19 @@ cc_library( objc_library( name = "rntester_extra_rn_modules", srcs = [ - "Libraries/LinkingIOS/RCTLinkingManager.mm", - "Libraries/LinkingIOS/RCTLinkingPlugins.h", "Libraries/PushNotificationIOS/RCTPushNotificationManager.mm", "Libraries/PushNotificationIOS/RCTPushNotificationPlugins.h", "Libraries/PushNotificationIOS/RCTPushNotificationPlugins.mm", - ], + ] + select({ + "//:rn_from_source_enabled": [], + "//conditions:default": [ + "Libraries/LinkingIOS/RCTLinkingManager.mm", + "Libraries/LinkingIOS/RCTLinkingPlugins.h", + ], + }), tags = ["manual"], visibility = ["//visibility:public"], deps = [ - ":rct_linking_hdrs", ":rct_pushnotification_hdrs", ":rn_cxx_headers", "@rn_prebuilt_xcframeworks//:ReactNativeDependencies_headers", @@ -110,6 +113,7 @@ objc_library( "@rn_source_headers//:headers", ], "//conditions:default": [ + ":rct_linking_hdrs", "@rn_prebuilt_xcframeworks//:React", "@rn_prebuilt_xcframeworks//:React_headers", ], diff --git a/packages/react-native/Package.swift b/packages/react-native/Package.swift index d27caa9860ef..93102bb49a5d 100644 --- a/packages/react-native/Package.swift +++ b/packages/react-native/Package.swift @@ -277,11 +277,23 @@ let reactTurboModuleCore = RNTarget( dependencies: [.reactNativeDependencies, .reactDebug, .reactFeatureFlags, .reactUtils, .reactPerfLogger, .reactCxxReact, .reactTurboModuleBridging, .yoga, .reactRuntimeExecutor] ) +let reactDevToolsRuntimeSettings = RNTarget( + name: .reactDevToolsRuntimeSettings, + path: "ReactCommon/devtoolsruntimesettings", + dependencies: [.jsi] +) + +let reactDevToolsRuntimeSettingsModule = RNTarget( + name: .reactDevToolsRuntimeSettingsModule, + path: "ReactCommon/react/nativemodule/devtoolsruntimesettings", + dependencies: [.jsi, .reactDevToolsRuntimeSettings, .reactTurboModuleCore] +) + /// React-defaultsnativemodule.podspec let reactTurboModuleCoreDefaults = RNTarget( name: .reactTurboModuleCoreDefaults, path: "ReactCommon/react/nativemodule/defaults", - dependencies: [.reactNativeDependencies, .jsi, .reactJsiExecutor, .reactTurboModuleCore] + dependencies: [.reactNativeDependencies, .jsi, .reactJsiExecutor, .reactTurboModuleCore, .reactDevToolsRuntimeSettingsModule] ) /// React-microtasknativemodule.podspec @@ -603,6 +615,8 @@ let targets = [ reactCoreModules, reactTurboModuleBridging, reactTurboModuleCore, + reactDevToolsRuntimeSettings, + reactDevToolsRuntimeSettingsModule, reactTurboModuleCoreDefaults, reactTurboModuleCoreMicrotasks, reactIdleCallbacksNativeModule, @@ -779,6 +793,8 @@ extension String { static let reactCoreModules = "React-CoreModules" static let reactTurboModuleBridging = "ReactCommon/turbomodule/bridging" static let reactTurboModuleCore = "ReactCommon/turbomodule/core" + static let reactDevToolsRuntimeSettings = "ReactCommon/devtoolsruntimesettings" + static let reactDevToolsRuntimeSettingsModule = "ReactCommon/turbomodule/devtoolsruntimesettings" static let reactTurboModuleCoreDefaults = "ReactCommon/turbomodule/core/defaults" static let reactTurboModuleCoreMicrotasks = "ReactCommon/turbomodule/core/microtasks" static let reactIdleCallbacksNativeModule = "React-idlecallbacksnativemodule" diff --git a/packages/react-native/bazel/spm_targets.bzl b/packages/react-native/bazel/spm_targets.bzl index 733fa4a9da0e..c03f3233f0cc 100644 --- a/packages/react-native/bazel/spm_targets.bzl +++ b/packages/react-native/bazel/spm_targets.bzl @@ -3924,6 +3924,51 @@ SPM_TARGETS = { "CoreFoundation", ], }, + "ReactCommon/devtoolsruntimesettings": { + "bazel_name": "spm_ReactCommon_devtoolsruntimesettings", + "type": "regular", + "path": "ReactCommon/devtoolsruntimesettings", + "deps": [ + "React-jsi", + ], + "srcs": [ + "ReactCommon/devtoolsruntimesettings/**/*.c", + "ReactCommon/devtoolsruntimesettings/**/*.cc", + "ReactCommon/devtoolsruntimesettings/**/*.cpp", + "ReactCommon/devtoolsruntimesettings/**/*.m", + "ReactCommon/devtoolsruntimesettings/**/*.mm", + ], + "hdrs": [ + "ReactCommon/devtoolsruntimesettings/**/*.def", + "ReactCommon/devtoolsruntimesettings/**/*.h", + "ReactCommon/devtoolsruntimesettings/**/*.hh", + "ReactCommon/devtoolsruntimesettings/**/*.hpp", + "ReactCommon/devtoolsruntimesettings/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "ReactCommon", + "ReactCommon/devtoolsruntimesettings", + "ReactCommon/jsi", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, "ReactCommon/turbomodule/bridging": { "bazel_name": "spm_ReactCommon_turbomodule_bridging", "type": "regular", @@ -4073,6 +4118,7 @@ SPM_TARGETS = { "React-jsi", "React-jsiexecutor", "ReactCommon/turbomodule/core", + "ReactCommon/turbomodule/devtoolsruntimesettings", "ReactNativeDependencies", ], "srcs": [ @@ -4110,6 +4156,7 @@ SPM_TARGETS = { "ReactCommon", "ReactCommon/callinvoker", "ReactCommon/cxxreact", + "ReactCommon/devtoolsruntimesettings", "ReactCommon/jsi", "ReactCommon/jsiexecutor", "ReactCommon/jsinspector-modern", @@ -4123,6 +4170,7 @@ SPM_TARGETS = { "ReactCommon/react/nativemodule/core", "ReactCommon/react/nativemodule/core/platform/ios", "ReactCommon/react/nativemodule/defaults", + "ReactCommon/react/nativemodule/devtoolsruntimesettings", "ReactCommon/react/utils", "ReactCommon/react/utils/platform/ios", "ReactCommon/reactperflogger", @@ -4205,6 +4253,74 @@ SPM_TARGETS = { ], "sdk_frameworks": [], }, + "ReactCommon/turbomodule/devtoolsruntimesettings": { + "bazel_name": "spm_ReactCommon_turbomodule_devtoolsruntimesettings", + "type": "regular", + "path": "ReactCommon/react/nativemodule/devtoolsruntimesettings", + "deps": [ + "React-jsi", + "ReactCommon/devtoolsruntimesettings", + "ReactCommon/turbomodule/core", + ], + "srcs": [ + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.c", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.cc", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.cpp", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.m", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.mm", + ], + "hdrs": [ + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.def", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.h", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.hh", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.hpp", + "ReactCommon/react/nativemodule/devtoolsruntimesettings/**/*.inc", + ], + "excludes": [], + "copts": [ + "-std=c++20", + ], + "defines": [ + "USE_HERMES=1", + ], + "debug_defines": [ + "DEBUG", + ], + "release_defines": [ + "NDEBUG", + ], + "includes": [ + ".build/headers", + ".build/headers/React", + "Libraries/FBLazyVector", + "React/FBReactNativeSpec", + "ReactCommon", + "ReactCommon/callinvoker", + "ReactCommon/cxxreact", + "ReactCommon/devtoolsruntimesettings", + "ReactCommon/jsi", + "ReactCommon/jsinspector-modern", + "ReactCommon/jsinspector-modern/network", + "ReactCommon/jsinspector-modern/tracing", + "ReactCommon/logger", + "ReactCommon/oscompat", + "ReactCommon/react/bridging", + "ReactCommon/react/debug", + "ReactCommon/react/featureflags", + "ReactCommon/react/nativemodule/core", + "ReactCommon/react/nativemodule/core/platform/ios", + "ReactCommon/react/nativemodule/devtoolsruntimesettings", + "ReactCommon/react/utils", + "ReactCommon/react/utils/platform/ios", + "ReactCommon/reactperflogger", + "ReactCommon/runtimeexecutor", + "ReactCommon/runtimeexecutor/platform/ios", + "ReactCommon/yoga", + "third-party/ReactNativeDependencies.xcframework", + "third-party/ReactNativeDependencies.xcframework/Headers", + ], + "sdk_frameworks": [], + }, "ReactNativeDependencies": { "bazel_name": "spm_ReactNativeDependencies", "type": "binary", diff --git a/packages/rn-tester/BUILD.bazel b/packages/rn-tester/BUILD.bazel index ecb36b9145a9..d9227c4c1a1e 100644 --- a/packages/rn-tester/BUILD.bazel +++ b/packages/rn-tester/BUILD.bazel @@ -127,10 +127,16 @@ objc_library( # (mirrors how Buck2's apple prelude ingests a js_bundle as an AppleResource). macos_application( name = "RNTesterMacBazel", + app_icons = ["//packages/rn-tester/RNTester-macOS:app_icons"], bundle_id = "org.reactjs.native.RNTesterMacBazel", + entitlements = "//packages/rn-tester/RNTester-macOS:RNTester_macOS.entitlements", infoplists = ["bazel/Info.plist"], minimum_os_version = "14.0", - resources = [":rntester_macos_jsbundle"], + resources = [ + ":rntester_macos_jsbundle", + "PrivacyInfo.xcprivacy", + "//packages/rn-tester/RNTester-macOS:native_resources", + ], tags = ["manual"], deps = [":rntester_macos_minimal_host"], ) @@ -164,7 +170,7 @@ objc_library( "@rn_prebuilt_xcframeworks//:hermes", ] + select({ "//:rn_from_source_enabled": [ - "//packages/react-native:spm_React_RCTAppDelegate", + "//packages/react-native:spm_React", "@rn_source_headers//:headers", ], "//conditions:default": [ @@ -176,10 +182,16 @@ objc_library( macos_application( name = "RNTesterMacBazelFull", + app_icons = ["//packages/rn-tester/RNTester-macOS:app_icons"], bundle_id = "org.reactjs.native.RNTesterMacBazelFull", + entitlements = "//packages/rn-tester/RNTester-macOS:RNTester_macOS.entitlements", infoplists = ["bazel/Info.plist"], minimum_os_version = "14.0", - resources = [":rntester_macos_jsbundle"], + resources = [ + ":rntester_macos_jsbundle", + "PrivacyInfo.xcprivacy", + "//packages/rn-tester/RNTester-macOS:native_resources", + ], tags = ["manual"], visibility = ["//packages/rn-tester/RNTester-macOS:__pkg__"], deps = [":rntester_macos_full_host"], diff --git a/packages/rn-tester/RNTester-macOS/BUILD.bazel b/packages/rn-tester/RNTester-macOS/BUILD.bazel index ea0a4d52ee01..de361b32f5f7 100644 --- a/packages/rn-tester/RNTester-macOS/BUILD.bazel +++ b/packages/rn-tester/RNTester-macOS/BUILD.bazel @@ -2,6 +2,18 @@ package(default_visibility = ["//visibility:public"]) +filegroup( + name = "app_icons", + srcs = glob(["Assets.xcassets/**"]), +) + +filegroup( + name = "native_resources", + srcs = ["Base.lproj/Main.storyboard"], +) + +exports_files(["RNTester_macOS.entitlements"]) + alias( name = "app", actual = "//packages/rn-tester:RNTesterMacBazelFull", diff --git a/packages/rn-tester/bazel/bundle.js b/packages/rn-tester/bazel/bundle.js index fbe11140087c..54ebf21a251c 100644 --- a/packages/rn-tester/bazel/bundle.js +++ b/packages/rn-tester/bazel/bundle.js @@ -216,6 +216,25 @@ function resolveAssetFiles(filePath) { .map(name => path.join(dir, name)); return filePaths.length ? {type: 'assetFiles', filePaths} : null; } + +function saveAssets(assets, assetsDest) { + for (const asset of assets) { + asset.scales.forEach((scale, index) => { + const suffix = scale === 1 ? '' : `@${scale}x`; + const relativeDir = asset.httpServerLocation + .slice(1) + .replace(/\.\.\//g, '_'); + const destination = path.join( + assetsDest, + relativeDir, + `${asset.name}${suffix}.${asset.type}`, + ); + fs.mkdirSync(path.dirname(destination), {recursive: true}); + fs.copyFileSync(asset.files[index], destination); + }); + } +} + const originalGetOrComputeSha1 = DependencyGraph.prototype.getOrComputeSha1; DependencyGraph.prototype.getOrComputeSha1 = async function (filename) { try { @@ -277,7 +296,7 @@ async function main() { // Use `bundleOut` (verbatim) rather than `out`; Metro's runBuild rewrites // `out` through `.replace(/(\.js)?$/, '.js')`, which would turn our declared // Bazel output `RNTesterApp.macos.jsbundle` into `...jsbundle.js`. - await Metro.runBuild(config, { + const result = await Metro.runBuild(config, { entry: entryFile, platform: 'macos', dev: false, @@ -286,6 +305,12 @@ async function main() { assets: Boolean(assetsDest), assetsDest, }); + if (assetsDest != null) { + if (result.assets == null) { + throw new Error("Assets missing from Metro's runBuild result"); + } + saveAssets(result.assets, assetsDest); + } } main().catch(err => { diff --git a/tools/bazel/apple/spm_native_graph.bzl b/tools/bazel/apple/spm_native_graph.bzl index a8e7094db60a..12129d913d2a 100644 --- a/tools/bazel/apple/spm_native_graph.bzl +++ b/tools/bazel/apple/spm_native_graph.bzl @@ -18,6 +18,12 @@ _SOURCE_HEADER_BRIDGE = [ "@rn_source_headers//:headers", ] +_SDK_FRAMEWORK_OVERRIDES = { + "React-Core": ["CoreImage", "QuartzCore"], + "React-RCTFabric": ["UniformTypeIdentifiers"], + "React-RCTUIKit": ["CoreVideo", "QuartzCore"], +} + def _target_labels(name): target = SPM_TARGETS[name] if target["type"] == "binary": @@ -57,8 +63,21 @@ def rn_spm_native_graph(visibility = ["//visibility:public"]): copts = [flag for flag in target["copts"] if flag != "-std=c++20"], defines = target["defines"] + target["debug_defines"], includes = target["includes"], - sdk_frameworks = target["sdk_frameworks"], + sdk_frameworks = target["sdk_frameworks"] + _SDK_FRAMEWORK_OVERRIDES.get(name, []), tags = ["manual"], visibility = visibility, deps = _SOURCE_HEADER_BRIDGE + _deps(target["deps"]), ) + + # Package.swift's dynamic `React` product contains every regular target, not + # merely the dependency closure of React-RCTAppDelegate. + native.objc_library( + name = "spm_React", + tags = ["manual"], + visibility = visibility, + deps = [ + ":" + target["bazel_name"] + for target in SPM_TARGETS.values() + if target["type"] == "regular" + ], + ) From b7cdf7b40c3ff942858e2e4e5886cf300761913b Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 17:53:13 -0700 Subject: [PATCH 23/24] build(bazel): make source RNTester a one-command build Default rn_from_source to true and make native bootstrap artifacts available from a clean checkout. ReactNativeDependencies 0.86.0 and the ABI-exact RN 0.81.0 Hermes artifact are downloaded from Maven with pinned SHA-256 values; downloaded Hermes uses the archive's standalone macOS framework. Keep missing prebuilt React isolated behind the false canary branch instead of invalidating every native import. Also fix the case-sensitive Package.swift TypeSafety path surfaced by the fresh-artifact test. Verified the exact command with local React, RNDependencies, and Hermes artifacts hidden: bazel build //packages/rn-tester/RNTester-macOS:app The cold build completed and the resulting source-linked app launched with all resources. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- BUILD.bazel | 2 +- docs/bazel.md | 27 +++++-- packages/react-native/Package.swift | 2 +- packages/react-native/bazel/spm_targets.bzl | 46 +++++------ tools/bazel/apple/prebuilt_xcframeworks.bzl | 90 ++++++++++++++++----- 5 files changed, 114 insertions(+), 53 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index d684d60f0739..59b388cb51d2 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,7 +3,7 @@ load("@npm//:defs.bzl", "npm_link_all_packages") bool_flag( name = "rn_from_source", - build_setting_default = False, + build_setting_default = True, visibility = ["//visibility:public"], ) diff --git a/docs/bazel.md b/docs/bazel.md index cab40b62894d..eee3ba32e535 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -159,11 +159,12 @@ prebuilt-XCFramework link. Specifically: and the RCTLinking/RCTPushNotification modules built from source (not in the prebuilt framework). Its embedded `main.jsbundle` contains the real native-example JS (no stubs), and no rn-tester source is modified or `#ifdef`'d out. -* **React can be linked from source** with - `bazel build //packages/rn-tester/RNTester-macOS:app --//:rn_from_source=true`. - This mode builds the generated 58-target SwiftPM graph, links the resulting static +* **React is linked from source by default** with + `bazel build //packages/rn-tester/RNTester-macOS:app`. + This builds the generated 58-target SwiftPM graph, links the resulting static libraries into RNTester (no `React.framework` in the app), and launches offline. - Hermes and ReactNativeDependencies remain prebuilt bootstrap inputs. + Bazel downloads SHA-pinned, ABI-compatible Hermes and ReactNativeDependencies + bootstrap artifacts. Use `--//:rn_from_source=false` for the prebuilt-React canary. * **Resources are complete**: Metro copies its 45 image/XML assets (including all six bottom-nav icons), while rules_apple compiles the macOS asset catalog/storyboard and embeds `Assets.car`, `AppIcon.icns`, entitlements, and `PrivacyInfo.xcprivacy`. @@ -244,6 +245,20 @@ react-native-macos already carries the Hermes version-resolution patches (`:React`, …). A future from-source build produces the *same* artifacts and drops in behind these aliases with a `--//:rn_from_source` flag. +The default source mode does not require local XCFrameworks: + +* ReactNativeDependencies 0.86.0 is downloaded from Maven with SHA-256 + `f6533c53527e75349346d07a2bba1a5cc1da4be8c41f93635a593047700b78f2`. +* Hermes comes from the RN 0.81.0 artifact with SHA-256 + `45ae8f9d4ec3e1e63813cd89487855c5dd6ebd1aeb196738008e16e16aa22fbe`. + RN 0.81.0's `.hermesversion` names the exact `e0fc67142ec…` commit selected by + react-native-macos's merge-base resolver. The archive's standalone macOS + `hermes.framework` is imported because its universal XCFramework contains Apple + mobile slices but no macOS slice. + +The manual prebuild below is only needed for the +`--//:rn_from_source=false` prebuilt-React canary. + Generate the XCFrameworks with: ```sh @@ -288,8 +303,8 @@ the repo's `enableScripts: false`), which is inert for Yarn and not published. targets into `spm_*` Bazel libraries without adding BUILD files throughout the React source tree. The graph now compiles through the complete `spm_React` product (including a Bazel-generated `FBReactNativeSpec`) using a canonical header projection generated -from source. `--//:rn_from_source=true` builds and launches RNTester but remains -default-off until Hermes and ReactNativeDependencies are available from a fresh checkout. +from source. Source mode is the default after validating a build and launch with all +local XCFrameworks hidden; `--//:rn_from_source=false` keeps the prebuilt-React canary. Then output the same `.xcframework`s via `apple_static_xcframework`, swapped in behind the P3 alias + `--//:rn_from_source`: diff --git a/packages/react-native/Package.swift b/packages/react-native/Package.swift index 93102bb49a5d..8c0d1ad21259 100644 --- a/packages/react-native/Package.swift +++ b/packages/react-native/Package.swift @@ -327,7 +327,7 @@ let reactNativeModuleDom = RNTarget( /// RCTTypeSafety.podspec let rctTypesafety = RNTarget( name: .rctTypesafety, - path: "Libraries/Typesafety", + path: "Libraries/TypeSafety", searchPaths: [FBLazyVectorPath], dependencies: [.reactNativeDependencies, .yoga] ) diff --git a/packages/react-native/bazel/spm_targets.bzl b/packages/react-native/bazel/spm_targets.bzl index c03f3233f0cc..cb1aaf27a57a 100644 --- a/packages/react-native/bazel/spm_targets.bzl +++ b/packages/react-native/bazel/spm_targets.bzl @@ -61,24 +61,24 @@ SPM_TARGETS = { "RCTTypesafety": { "bazel_name": "spm_RCTTypesafety", "type": "regular", - "path": "Libraries/Typesafety", + "path": "Libraries/TypeSafety", "deps": [ "ReactNativeDependencies", "Yoga", ], "srcs": [ - "Libraries/Typesafety/**/*.c", - "Libraries/Typesafety/**/*.cc", - "Libraries/Typesafety/**/*.cpp", - "Libraries/Typesafety/**/*.m", - "Libraries/Typesafety/**/*.mm", + "Libraries/TypeSafety/**/*.c", + "Libraries/TypeSafety/**/*.cc", + "Libraries/TypeSafety/**/*.cpp", + "Libraries/TypeSafety/**/*.m", + "Libraries/TypeSafety/**/*.mm", ], "hdrs": [ - "Libraries/Typesafety/**/*.def", - "Libraries/Typesafety/**/*.h", - "Libraries/Typesafety/**/*.hh", - "Libraries/Typesafety/**/*.hpp", - "Libraries/Typesafety/**/*.inc", + "Libraries/TypeSafety/**/*.def", + "Libraries/TypeSafety/**/*.h", + "Libraries/TypeSafety/**/*.hh", + "Libraries/TypeSafety/**/*.hpp", + "Libraries/TypeSafety/**/*.inc", ], "excludes": [], "copts": [ @@ -98,7 +98,7 @@ SPM_TARGETS = { ".build/headers/React", "Libraries", "Libraries/FBLazyVector", - "Libraries/Typesafety", + "Libraries/TypeSafety", "ReactCommon", "ReactCommon/yoga", "third-party/ReactNativeDependencies.xcframework", @@ -191,7 +191,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/FBReactNativeSpec", @@ -532,7 +532,7 @@ SPM_TARGETS = { ".build/headers/React", "Libraries", "Libraries/FBLazyVector", - "Libraries/Typesafety", + "Libraries/TypeSafety", "React/FBReactNativeSpec", "ReactCommon", "ReactCommon/callinvoker", @@ -888,7 +888,7 @@ SPM_TARGETS = { ".build/headers/React", "Libraries", "Libraries/FBLazyVector", - "Libraries/Typesafety", + "Libraries/TypeSafety", "React/FBReactNativeSpec", "ReactCommon", "ReactCommon/callinvoker", @@ -1128,7 +1128,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/FBReactNativeSpec", @@ -1268,7 +1268,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/FBReactNativeSpec", @@ -1845,7 +1845,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/FBReactNativeSpec", @@ -2603,7 +2603,7 @@ SPM_TARGETS = { "Libraries", "Libraries/FBLazyVector", "Libraries/NativeAnimation", - "Libraries/Typesafety", + "Libraries/TypeSafety", "React/FBReactNativeSpec", "ReactCommon", "ReactCommon/callinvoker", @@ -2687,7 +2687,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/FBReactNativeSpec", @@ -2888,7 +2888,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/FBReactNativeSpec", @@ -3011,7 +3011,7 @@ SPM_TARGETS = { "Libraries", "Libraries/FBLazyVector", "Libraries/Image", - "Libraries/Typesafety", + "Libraries/TypeSafety", "React/FBReactNativeSpec", "ReactCommon", "ReactCommon/callinvoker", @@ -3664,7 +3664,7 @@ SPM_TARGETS = { "Libraries/NativeAnimation", "Libraries/Network", "Libraries/Text", - "Libraries/Typesafety", + "Libraries/TypeSafety", "Libraries/WebSocket", "React", "React/CoreModules", diff --git a/tools/bazel/apple/prebuilt_xcframeworks.bzl b/tools/bazel/apple/prebuilt_xcframeworks.bzl index 4abe89b7333c..d1a7b33a7d0c 100644 --- a/tools/bazel/apple/prebuilt_xcframeworks.bzl +++ b/tools/bazel/apple/prebuilt_xcframeworks.bzl @@ -22,31 +22,64 @@ _REL_PATHS = { # fails at launch with "Library not loaded: @rpath/React.framework/..."). _DYNAMIC = {"React": True, "ReactNativeDependencies": True, "hermes": True} +_REACT_NATIVE_DEPENDENCIES_URL = "https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.86.0/react-native-artifacts-0.86.0-reactnative-dependencies-debug.tar.gz" +_REACT_NATIVE_DEPENDENCIES_SHA256 = "f6533c53527e75349346d07a2bba1a5cc1da4be8c41f93635a593047700b78f2" +_HERMES_URL = "https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.81.0/react-native-artifacts-0.81.0-hermes-ios-debug.tar.gz" +_HERMES_SHA256 = "45ae8f9d4ec3e1e63813cd89487855c5dd6ebd1aeb196738008e16e16aa22fbe" + def _prebuilt_xcframeworks_impl(rctx): root = str(rctx.workspace_root) lines = [ - 'load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import", "apple_static_xcframework_import")', + 'load("@rules_apple//apple:apple.bzl", "apple_dynamic_framework_import", "apple_dynamic_xcframework_import", "apple_static_xcframework_import")', 'package(default_visibility = ["//visibility:public"])', "", ] missing = [] + available = {} + downloaded_hermes_framework = False for name, rel in _REL_PATHS.items(): src = "{}/{}".format(root, rel) - if not rctx.path(src).exists: + if rctx.path(src).exists: + rctx.symlink(src, name + ".xcframework") + available[name] = True + elif name == "ReactNativeDependencies": + rctx.download_and_extract( + url = _REACT_NATIVE_DEPENDENCIES_URL, + output = name + ".xcframework", + sha256 = _REACT_NATIVE_DEPENDENCIES_SHA256, + stripPrefix = "packages/react-native/third-party/ReactNativeDependencies.xcframework", + ) + available[name] = True + elif name == "hermes": + rctx.download_and_extract( + url = _HERMES_URL, + output = "hermes_artifact", + sha256 = _HERMES_SHA256, + stripPrefix = "destroot", + ) + rctx.symlink( + rctx.path("hermes_artifact/Library/Frameworks/macosx/hermes.framework"), + "hermes.framework", + ) + available[name] = True + downloaded_hermes_framework = True + else: missing.append(rel) continue - rctx.symlink(src, name + ".xcframework") - rule = "apple_dynamic_xcframework_import" if _DYNAMIC.get(name) else "apple_static_xcframework_import" - lines.append('{rule}(name = "{name}", xcframework_imports = glob(["{name}.xcframework/**"]))'.format( - rule = rule, - name = name, - )) + if name == "hermes" and downloaded_hermes_framework: + lines.append('apple_dynamic_framework_import(name = "hermes", framework_imports = glob(["hermes.framework/**"]))') + else: + rule = "apple_dynamic_xcframework_import" if _DYNAMIC.get(name) else "apple_static_xcframework_import" + lines.append('{rule}(name = "{name}", xcframework_imports = glob(["{name}.xcframework/**"]))'.format( + rule = rule, + name = name, + )) # ReactNativeDependencies ships canonical, nested third-party headers # (folly/, boost/, glog/, fmt/, double-conversion/, fast_float/) at the # xcframework root `Headers/`. Expose them on the include path so C++ sources # that pull `` etc. compile. - if "ReactNativeDependencies" not in missing: + if available.get("ReactNativeDependencies"): lines.append(""" cc_library( name = "ReactNativeDependencies_headers", @@ -55,8 +88,10 @@ cc_library( ) """) - if "hermes" not in missing: + if available.get("hermes"): hermes_headers = "{}/packages/react-native/.build/artifacts/hermes/destroot/include".format(root) + if not rctx.path(hermes_headers).exists: + hermes_headers = rctx.path("hermes_artifact/include") if rctx.path(hermes_headers).exists: rctx.symlink(hermes_headers, "hermes_headers") lines.append(""" @@ -72,7 +107,7 @@ cc_library( # ``, `` imports used by both the framework's own # headers and app sources. Reconstruct a canonical `-I` tree of symlinks so the # headers are consumable from Bazel, and expose it as `:React_headers`. - if "React" not in missing: + if available.get("React"): script = rctx.path(Label("//tools/bazel/apple:reconstruct_react_headers.py")) slice_dir = None for entry in rctx.path("React.xcframework").readdir(): @@ -100,17 +135,28 @@ cc_library( """) if missing: - # Emit a target that fails at build time with guidance, rather than failing analysis. - msg = ("Prebuilt XCFrameworks not found: {}. Build them first with " + - "`cd packages/react-native && HERMES_APPLE_PLATFORMS=macosx node scripts/ios-prebuild.js -s -f Debug " + - "&& node scripts/ios-prebuild.js -b -f Debug -p macos && node scripts/ios-prebuild.js -c -f Debug` " + - "(use cmake@3.x on Xcode 26).").format(", ".join(missing)) - lines = [ - 'package(default_visibility = ["//visibility:public"])', - 'genrule(name = "_missing", outs = ["missing.txt"], cmd = "echo \'{}\' >&2; exit 1")'.format(msg), - ] - for name in _REL_PATHS: - lines.append('alias(name = "{name}", actual = ":_missing")'.format(name = name)) + # Emit independent failure targets so source mode can omit React.xcframework + # while still consuming downloaded RNDependencies and a separately-built Hermes. + for name, rel in _REL_PATHS.items(): + if available.get(name): + continue + msg = ("Prebuilt XCFramework not found: {}. Build native artifacts with " + + "`cd packages/react-native && HERMES_APPLE_PLATFORMS=macosx node scripts/ios-prebuild.js -s -f Debug " + + "&& node scripts/ios-prebuild.js -b -f Debug -p macos && node scripts/ios-prebuild.js -c -f Debug` " + + "(use cmake@3.x on Xcode 26).").format(rel) + missing_target = "_missing_" + name + lines.append('genrule(name = "{target}", outs = ["{target}.txt"], cmd = "echo \'{msg}\' >&2; exit 1")'.format( + target = missing_target, + msg = msg, + )) + lines.append('alias(name = "{name}", actual = ":{target}")'.format( + name = name, + target = missing_target, + )) + if name == "React": + lines.append('alias(name = "React_headers", actual = ":{target}")'.format(target = missing_target)) + elif name == "hermes": + lines.append('alias(name = "hermes_headers", actual = ":{target}")'.format(target = missing_target)) rctx.file("BUILD.bazel", "\n".join(lines) + "\n") From cb64261b4c1189a6a9ff8e0162e0735c776ab7dd Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 9 Jul 2026 17:55:05 -0700 Subject: [PATCH 24/24] ci(bazel): verify clean-checkout RNTester source build Run the exact canonical build on macos-26 with no local native artifacts. Verify the resulting app is source-linked (no React.framework), signed, and contains pinned Hermes/RNDependencies, the JS bundle, asset catalog, privacy manifest, and all six navbar icons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/bazel.yml | 49 ++++++++++++++++++++++++++++++++++++- docs/bazel.md | 5 +++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index ccf843e24e22..e516cb061a8c 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,8 @@ on: - "package.json" - "yarn.lock" - "tools/bazel/**" - - "packages/**/BUILD.bazel" + - "packages/react-native/**" + - "packages/rn-tester/**" - ".github/workflows/bazel.yml" workflow_dispatch: {} @@ -54,3 +55,49 @@ jobs: run: | npx --yes @bazel/bazelisk test //tools/bazel/berry/example:verify \ --config=ci --test_output=errors + + rntester-macos: + name: RNTester macOS from source + runs-on: macos-26 + timeout-minutes: 90 + steps: + - uses: actions/checkout@v4 + with: + filter: blob:none + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Cache Bazel + uses: actions/cache@v4 + with: + path: ~/.cache/bazel-rnm-disk + key: bazel-rntester-macos-${{ hashFiles('MODULE.bazel', 'yarn.lock', 'packages/react-native/Package.swift', 'tools/bazel/**') }} + restore-keys: | + bazel-rntester-macos- + + - name: Build RNTester from a clean checkout + run: | + test ! -e packages/react-native/.build/output/xcframeworks/Debug/React.xcframework + test ! -e packages/react-native/third-party/ReactNativeDependencies.xcframework + test ! -e packages/react-native/.build/artifacts/hermes/destroot + npx --yes @bazel/bazelisk build \ + //packages/rn-tester/RNTester-macOS:app \ + --config=ci + + - name: Verify source-linked app + run: | + mkdir -p "$RUNNER_TEMP/rntester" + unzip -q bazel-bin/packages/rn-tester/RNTesterMacBazelFull.zip \ + -d "$RUNNER_TEMP/rntester" + app="$RUNNER_TEMP/rntester/RNTesterMacBazelFull.app" + test -f "$app/Contents/Resources/main.jsbundle" + test -f "$app/Contents/Resources/Assets.car" + test -f "$app/Contents/Resources/PrivacyInfo.xcprivacy" + test "$(find "$app/Contents/Resources" -name 'bottom-nav-*.png' | wc -l | tr -d ' ')" = 6 + test ! -e "$app/Contents/Frameworks/React.framework" + test -e "$app/Contents/Frameworks/hermes.framework" + test -e "$app/Contents/Frameworks/ReactNativeDependencies.framework" + ! otool -L "$app/Contents/MacOS/RNTesterMacBazelFull" | grep -q React.framework + codesign --verify --deep --strict "$app" diff --git a/docs/bazel.md b/docs/bazel.md index eee3ba32e535..934a50b53c37 100644 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -278,7 +278,10 @@ a supported Xcode via `DEVELOPER_DIR` / `--xcode_version`. Bazel is pinned to `8 ## CI and remote cache -`.github/workflows/bazel.yml` runs the green Berry-fork test on `ubuntu-latest`. It caches +`.github/workflows/bazel.yml` runs the Berry-fork test on `ubuntu-latest` and the exact +RNTester source-build command on `macos-26` from a clean checkout. The macOS job checks +that no native artifacts exist before the build, then verifies the source-linked, +signed app (frameworks, bundle, native asset catalog, and Metro tab icons). It caches Bazel's `--disk_cache` via `actions/cache` (a zero-infra remote-cache stand-in). For a real remote cache at scale, point `--remote_cache` at **BuildBuddy** (free tier: `grpcs` endpoint + API-key secret) or a self-hosted **bazel-remote** (GCS/S3): read-only on PRs,