Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1e45261
Add Bazel foundation with a rules_js Yarn Berry fork (draft)
Saadnajmi Jul 6, 2026
bebb914
Bazel: first-party package linking + rn-tester macOS bundle/app scaff…
Saadnajmi Jul 6, 2026
97e9501
docs: correct Hermes/XCFramework blocker diagnosis (Xcode/CMake, not …
Saadnajmi Jul 6, 2026
5fe1590
Fix Hermes host build on Xcode 26 (force macOS target for hermesc)
Saadnajmi Jul 6, 2026
6248c78
docs: record the Xcode-26 Hermes host-build fix and status
Saadnajmi Jul 6, 2026
3bbbcff
Allow building a subset of Hermes Apple platforms (HERMES_APPLE_PLATF…
Saadnajmi Jul 6, 2026
85222de
docs: react-native-macos native prebuild now builds on Xcode 26
Saadnajmi Jul 6, 2026
7943e12
Bazel: repo rule to import the prebuilt XCFrameworks (builds on Xcode…
Saadnajmi Jul 6, 2026
97d231d
Berry converter fix (resolutions + trailing space) and rn-tester JS b…
Saadnajmi Jul 7, 2026
80fed2a
docs: precise rn-tester JS bundle status (converter fix, first-party …
Saadnajmi Jul 7, 2026
e9819ba
Bazel: green rn-tester JS bundle (Metro) + codegen (AppSpecs + provid…
Saadnajmi Jul 7, 2026
877a0ad
Bazel: build RNTester.app on Xcode 26 (native host + XCFramework link)
Saadnajmi Jul 7, 2026
1221a93
Bazel: build the FULL rn-tester host (real AppDelegate + codegen + na…
Saadnajmi Jul 7, 2026
dd2733e
Bazel: complete rn-tester host — enable the Fabric NativeComponentExa…
Saadnajmi Jul 7, 2026
0104b7a
Bazel: generate the :pkg BUILD files instead of hand-writing them
Saadnajmi Jul 8, 2026
73b75ac
Bazel: import React/ReactNativeDependencies as dynamic frameworks (fi…
Saadnajmi Jul 8, 2026
290ed74
docs: honest scope/limitations — Bazel for the native slice, not the …
Saadnajmi Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 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

# 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
1 change: 1 addition & 0 deletions .bazelversion
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8.7.0
51 changes: 51 additions & 0 deletions .github/workflows/bazel.yml
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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-*
6 changes: 6 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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/<pkg>.
npm_link_all_packages(name = "node_modules")
67 changes: 67 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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")

# 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")
Loading
Loading