Skip to content

Commit 23ca2ef

Browse files
committed
feat: re-export shared JavaScript APIs from nitro-core
1 parent b86c1f9 commit 23ca2ef

35 files changed

Lines changed: 615 additions & 36 deletions

‎.github/workflows/lint-typescript.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ on:
1111
- 'packages/react-native-nitro-modules/nitro'
1212
- '.gitmodules'
1313
- 'scripts/sync-core.mjs'
14+
- 'scripts/update-core-version.mjs'
15+
- 'bun.lock'
1416
- '.github/workflows/lint-typescript.yml'
1517
- 'config'
1618
- '**/*.ts'
@@ -25,6 +27,8 @@ on:
2527
- 'packages/react-native-nitro-modules/nitro'
2628
- '.gitmodules'
2729
- 'scripts/sync-core.mjs'
30+
- 'scripts/update-core-version.mjs'
31+
- 'bun.lock'
2832
- '.github/workflows/lint-typescript.yml'
2933
- 'config'
3034
- '**/*.ts'
@@ -48,6 +52,9 @@ jobs:
4852
- name: Install npm dependencies (bun)
4953
run: bun install
5054

55+
- name: Test nitro-core
56+
run: bun nitro-core test
57+
5158
- name: Run TypeScript (tsc)
5259
run: bun typecheck
5360

@@ -66,6 +73,9 @@ jobs:
6673
- name: Run ESLint CI in apps/example/
6774
working-directory: apps/example
6875
run: bun lint-ci
76+
- name: Run ESLint CI in nitro-core
77+
working-directory: packages/react-native-nitro-modules/nitro/packages/nitro-core
78+
run: bun lint-ci
6979
- name: Run ESLint CI in packages/react-native-nitro-modules/nitro/packages/nitrogen
7080
working-directory: packages/react-native-nitro-modules/nitro/packages/nitrogen
7181
run: bun lint-ci
@@ -82,6 +92,9 @@ jobs:
8292
- name: Run ESLint with auto-fix in apps/example/
8393
working-directory: apps/example
8494
run: bun lint
95+
- name: Run ESLint with auto-fix in nitro-core
96+
working-directory: packages/react-native-nitro-modules/nitro/packages/nitro-core
97+
run: bun lint
8598
- name: Run ESLint with auto-fix in packages/react-native-nitro-modules/nitro/packages/nitrogen
8699
working-directory: packages/react-native-nitro-modules/nitro/packages/nitrogen
87100
run: bun lint

‎.gitignore‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,8 @@ apps/*/.harness/
9393
# Claude Code local settings
9494
.claude/settings.local.json
9595

96-
# Shared implementation staged by bun sync-core. Edit packages/react-native-nitro-modules/nitro/ instead.
96+
# Native implementation staged by bun sync-core. Edit packages/react-native-nitro-modules/nitro/ instead.
9797
/packages/react-native-nitro-modules/cpp/
9898
/packages/react-native-nitro-modules/ios/
9999
/packages/react-native-nitro-modules/android/src/
100-
/packages/react-native-nitro-modules/src/
101100
/packages/react-native-nitro-modules/LICENSE

‎CONTRIBUTING.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ Either is welcome. A clean, deterministic repro is often more valuable than a gu
2323
The React Native repository is a Bun monorepo with a pinned `packages/react-native-nitro-modules/nitro/` submodule from [margelo/nitro](https://github.com/margelo/nitro):
2424

2525
- [apps/example/](apps/example) — React Native example app that hosts the runtime test harness.
26+
- [packages/react-native-nitro-modules/nitro/packages/nitro-core/](https://github.com/margelo/nitro/tree/core-split/packages/nitro-core) - shared JS/TS definitions and runtime helpers, published from `nitro`.
2627
- [packages/react-native-nitro-modules/nitro/packages/nitrogen/](https://github.com/margelo/nitro/tree/core-split/packages/nitrogen) - the `nitrogen` code generator, maintained in `nitro`.
27-
- [packages/react-native-nitro-modules/](packages/react-native-nitro-modules) - the published React Native package and its CocoaPods, Gradle, and CMake configuration. Its implementation is staged from `packages/react-native-nitro-modules/nitro/packages/react-native-nitro-modules/`.
28+
- [packages/react-native-nitro-modules/](packages/react-native-nitro-modules) - the published React Native package and its CocoaPods, Gradle, and CMake configuration. Its native sources are staged from `packages/react-native-nitro-modules/nitro/packages/react-native-nitro-modules/`; its RN-specific JS is maintained here. Shared JS/TS comes from `nitro-core`.
2829
- [packages/react-native-nitro-test/](packages/react-native-nitro-test) — a Nitro module full of specs used as compile-time and runtime tests.
2930
- [packages/react-native-nitro-test-external/](packages/react-native-nitro-test-external) — a second Nitro module used to cover cross-module behavior.
3031
- [packages/template/](packages/template) - the `npx nitrogen init` React Native library template. It stays here with the CocoaPods/Gradle/CMake integration and React Native dependencies it configures.
@@ -40,7 +41,7 @@ We use **Bun** as the package manager and task runner. Don't use `npm`, `yarn`,
4041
bun bootstrap # initialize the pinned core submodule, install, and build
4142
bun bootstrap:ios # also install Bundler dependencies and example app Pods
4243
bun sync-core # refresh staged implementation sources
43-
bun run build # stage sources and build nitro, nitrogen, and the test modules
44+
bun run build # stage native sources and build core, RN, Nitrogen, and tests
4445
bun specs # regenerate nitrogen output for react-native-nitro-test
4546
bun lint-all # run all linters (JS/TS, C++, Swift, Kotlin)
4647
```
@@ -49,7 +50,7 @@ bun lint-all # run all linters (JS/TS, C++, Swift, Kotlin)
4950

5051
The `packages/react-native-nitro-modules/nitro/` gitlink records the exact Nitro commit used by this repository. This repository develops on `main`; the submodule's development branch in `nitro` is `core-split`. Ordinary builds and `git submodule update --init --recursive` use the recorded commit. Do not use `git submodule update --remote` in builds.
5152

52-
Edit the runtime implementation in `packages/react-native-nitro-modules/nitro/packages/react-native-nitro-modules/`. The wrapper's `cpp/`, `ios/`, `android/src/`, and `src/` directories are generated by `bun sync-core` and ignored by Git. The staging command owns only those directories and the additional shared files listed in `scripts/sync-core.mjs`. Keep handwritten package and build configuration outside them. Nitrogen is used directly from `packages/react-native-nitro-modules/nitro/packages/nitrogen/` and is not copied into the wrapper.
53+
Edit native sources in `packages/react-native-nitro-modules/nitro/packages/react-native-nitro-modules/` and shared JS/TS in `packages/react-native-nitro-modules/nitro/packages/nitro-core/`. The wrapper's `cpp/`, `ios/`, and `android/src/` directories are generated by `bun sync-core` and ignored by Git. The wrapper maintains `src/` for RN bootstrap, views, worklets, and shared API re-exports. The staging command owns only those directories and the additional shared files listed in `scripts/sync-core.mjs`. Keep handwritten package and build configuration outside them. Nitrogen is used directly from `packages/react-native-nitro-modules/nitro/packages/nitrogen/` and is not copied into the wrapper.
5354

5455
To update the pinned core:
5556

@@ -59,11 +60,11 @@ To update the pinned core:
5960
4. If the core version changed, run `bun update-core-version`. Run `bun install`, `bun specs`, and the relevant native checks, then commit the core pin, version/lockfile changes, and any intended generated test bindings here. Push the wrapper commit after the core commit is available remotely.
6061
5. On another checkout, run `git submodule update --init --recursive` followed by `bun install` after pulling the wrapper commit.
6162

62-
Prepare version changes in the standalone `nitro` repository with `bun version:set VERSION`. This updates the shared runtime, Nitrogen, its runtime dependency, and native `NITRO_VERSION`. Build Nitrogen and refresh the core lockfile before committing. Publish `nitrogen` through the `nitro` release workflow, then use the final pushed core commit when updating the wrapper as described above. Nitrogen's existing semver dependency on `react-native-nitro-modules` still applies, so coordinate matching package versions in both repositories.
63+
Prepare version changes in the standalone `nitro` repository with `bun version:set VERSION`. This updates `nitro-core`, Nitrogen, its core dependency, the native source manifest, and embedded JS/native versions. Build Nitrogen and refresh the core lockfile before committing. Publish `nitro-core` followed by `nitrogen` from the `nitro` repository, then use the final pushed core commit when updating the wrapper as described above. Nitrogen depends on `nitro-core` with a compatible semver range. The RN package depends on the exact core version to match its native runtime. All three packages use the coordinated release version.
6364

64-
`bun update-core-version` copies the authoritative version into the wrapper and test packages. Inspect real `npm pack` tarballs from both package directories and run the native consumer checks before publishing. In this repository, `bun release` checks the existing version and publishes only `react-native-nitro-modules` through `npm publish`; it does not bump versions with release-it.
65+
`bun update-core-version` copies the authoritative version into the wrapper and test packages. Inspect real `npm pack` tarballs for `nitro-core`, `nitrogen`, and the RN package and run the native consumer checks before publishing. In this repository, `bun release` checks the existing version and publishes only `react-native-nitro-modules` through `npm publish`; it does not bump versions with release-it.
6566

66-
The runtime tarball includes staged implementation files and needs no core checkout or Git access when installed from npm.
67+
The RN tarball includes staged native files and its own JS integration. Shared JS is installed through its `nitro-core` dependency. Neither package needs a core checkout or Git access when installed from npm.
6768

6869
## You don't need to ship a fix — a clean repro is enough
6970

‎apps/benchmark/metro.config.js‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ const corePath = path
1515
const config = {
1616
watchFolders: [root],
1717
resolver: {
18-
// Metro reads the staged package, so exclude the second source tree.
19-
blockList: [new RegExp(`^${corePath}[/\\\\].*`)],
18+
// Native sources are staged in the RN package. Only nitro-core is a JS workspace.
19+
blockList: [
20+
new RegExp(
21+
`^${corePath}[/\\\\](?!packages(?:[/\\\\]nitro-core(?:[/\\\\]|$)|$)).*`
22+
),
23+
],
2024
},
2125
}
2226

‎apps/example/__tests__/nitro.harness.ts‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
import { describe, it } from 'react-native-harness'
2-
import { NitroModules } from 'react-native-nitro-modules'
1+
import { describe, expect, it } from 'react-native-harness'
2+
import {
3+
getHybridObjectConstructor,
4+
NitroModules,
5+
} from 'react-native-nitro-modules'
6+
import {
7+
getHybridObjectConstructor as getCoreHybridObjectConstructor,
8+
getInstalledNitro,
9+
NitroModules as CoreNitroModules,
10+
} from 'nitro-core'
311
import type {
412
TestObjectCpp,
513
TestObjectSwiftKotlin,
@@ -30,5 +38,13 @@ const testObjectSwiftKotlin =
3038
'TestObjectSwiftKotlin'
3139
)
3240

41+
describe('nitro-core integration', () => {
42+
it('shares the installed native proxy and constructor helper with React Native', () => {
43+
expect(getInstalledNitro()).toBe(NitroModules)
44+
expect(CoreNitroModules).toBe(NitroModules)
45+
expect(getCoreHybridObjectConstructor).toBe(getHybridObjectConstructor)
46+
})
47+
})
48+
3349
describe('TestObject (C++)', createTestRunner(testObjectCpp))
3450
describe('TestObject (Swift/Kotlin)', createTestRunner(testObjectSwiftKotlin))

‎apps/example/metro.config.js‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ const config = {
2020
// We need to make sure that only one version is loaded for peerDependencies
2121
// So we block them at the root, and alias them to the versions in example's node_modules
2222
resolver: {
23-
// Metro reads the staged package, so exclude the second source tree.
24-
blockList: [new RegExp(`^${corePath}[/\\\\].*`)],
23+
// Native sources are staged in the RN package. Only nitro-core is a JS workspace.
24+
blockList: [
25+
new RegExp(
26+
`^${corePath}[/\\\\](?!packages(?:[/\\\\]nitro-core(?:[/\\\\]|$)|$)).*`
27+
),
28+
],
2529
extraNodeModules: modules.reduce((acc, name) => {
2630
acc[name] = path.join(__dirname, 'node_modules', name)
2731
return acc

‎apps/example/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"react-native-nitro-test-external": "*",
3030
"react-native-nitro-modules": "*",
3131
"react-native-safe-area-context": "^5.8.0",
32-
"react-native-screens": "^4.25.2"
32+
"react-native-screens": "^4.25.2",
33+
"nitro-core": "0.37.1"
3334
},
3435
"devDependencies": {
3536
"@babel/core": "^7.29.7",

‎bun.lock‎

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"author": "Marc Rousavy <me@mrousavy.com> (https://github.com/mrousavy)",
1010
"workspaces": [
1111
"packages/react-native-nitro-modules",
12+
"packages/react-native-nitro-modules/nitro/packages/nitro-core",
1213
"packages/react-native-nitro-modules/nitro/packages/nitrogen",
1314
"packages/react-native-nitro-test",
1415
"packages/react-native-nitro-test-external",
@@ -20,7 +21,7 @@
2021
"build": "bun sync-core && bun nitro build && bun nitrogen build && bun nitro-test-external build && bun nitro-test build",
2122
"bootstrap": "git submodule update --init --recursive && bun install",
2223
"typecheck": "bun --filter=\"**\" typecheck",
23-
"lint": "bun nitro lint && bun nitrogen lint && bun nitro-test lint && bun example lint",
24+
"lint": "bun nitro-core lint && bun nitro lint && bun nitrogen lint && bun nitro-test lint && bun example lint",
2425
"lint-cpp": "./scripts/clang-format.sh",
2526
"lint-swift": "./scripts/swift-format.sh",
2627
"lint-kotlin": "./scripts/kotlin-format.sh",
@@ -39,7 +40,8 @@
3940
"benchmark": "bun --cwd apps/benchmark",
4041
"sync-core": "node scripts/sync-core.mjs",
4142
"bootstrap:ios": "bun bootstrap && bun example bundle-install && bun example pods",
42-
"update-core-version": "node scripts/update-core-version.mjs"
43+
"update-core-version": "node scripts/update-core-version.mjs",
44+
"nitro-core": "bun --cwd packages/react-native-nitro-modules/nitro/packages/nitro-core"
4345
},
4446
"devDependencies": {
4547
"@eslint/eslintrc": "^3.3.5",

‎packages/react-native-nitro-modules/README.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ npm i react-native-nitro-modules
2222
cd ios && pod install
2323
```
2424

25+
The package re-exports the shared `nitro-core` API and installs it into the React Native runtime. Existing imports from `react-native-nitro-modules` remain supported.
26+
2527
### Inside a nitro module library
2628

2729
If you are building a nitro module yourself, add [react-native-nitro-modules](https://npmjs.org/react-native-nitro-modules) as a `peerDependency` into your library's `package.json`:
@@ -212,7 +214,7 @@ The following C++ / JS types are supported out of the box:
212214
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/Promise.kt">Promise&lt;T&gt;</a></code></td>
213215
</tr>
214216
<tr>
215-
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/src/AnyMap.ts">AnyMap</a></code></td>
217+
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/nitro-core/src/AnyMap.ts">AnyMap</a></code></td>
216218
<td><code>std::shared_ptr&lt;<a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/cpp/core/AnyMap.hpp">AnyMap</a>&gt;</code></td>
217219
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/ios/core/AnyMap.swift">AnyMap</a></code></td>
218220
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/AnyMap.kt">AnyMap</a></code></td>
@@ -230,7 +232,7 @@ The following C++ / JS types are supported out of the box:
230232
<td><code>java.time.Instant</code></td>
231233
</tr>
232234
<tr>
233-
<td>..any <code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/src/HybridObject.ts">HybridObject</a></code></td>
235+
<td>..any <code><a href="https://github.com/margelo/nitro/blob/core-split/packages/nitro-core/src/HybridObject.ts">HybridObject</a></code></td>
234236
<td><code>std::shared_ptr&lt;<a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/cpp/core/HybridObject.hpp">HybridObject</a>&gt;</code></td>
235237
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/ios/core/HybridObject.swift">HybridObject</a></code></td>
236238
<td><code><a href="https://github.com/margelo/nitro/blob/core-split/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/HybridObject.kt">HybridObject</a></code></td>

0 commit comments

Comments
 (0)