Skip to content

Commit 4e5b831

Browse files
kraenhansenclaude
andauthored
chore: migrate from npm workspaces to pnpm (#381)
* chore: migrate from npm workspaces to pnpm Motivation: pnpm's recursive runner (`pnpm -r run`) is fail-fast by default and runs in topological (dependency-graph) order, so the root `bootstrap` and `prerelease` no longer need the non-fail-fast `npm run <s> --workspaces` pattern that buried the real root cause under cascading failures. Workspace + package manager: - Replace the root `workspaces` array with pnpm-workspace.yaml - Add `packageManager: pnpm@10.33.0` and switch devEngines to pnpm ^10 - Allow only esbuild's build script via onlyBuiltDependencies (pnpm 10 blocks dependency lifecycle scripts by default); no shamefully-hoist needed - Replace package-lock.json with pnpm-lock.yaml; keep node_modules isolated Internal deps -> workspace:* protocol (cmake-rn, ferric, gyp-to-cmake, host, node-addon-examples, node-tests, ferric-example, test-app). Add explicit `weak-node-api` edges to node-addon-examples and node-tests so the topological bootstrap sequences weak-node-api (which builds the xcframework/.so they link) before its consumers. Phantom dependencies surfaced by pnpm's isolated node_modules (npm hoisting had masked these): - host: add `@types/babel__core` (used by src/node/babel-plugin/plugin.ts) - host: add `weak-node-api` as a devDependency (used by scripts/generate-injector.mts; previously only a peerDependency) Scripts: - bootstrap: `tsc --build && pnpm -r run bootstrap` (fail-fast, topological) - prerelease/release: make the build explicit instead of relying on npm's implicit prerelease hook (pnpm disables pre/post scripts by default) - test: `pnpm --filter ... run test` - depcheck/run-in-published: replace `npm query .workspace` with `pnpm ls -r` - Pin prettier to 3.6.2: 3.7+ is incompatible with @prettier/plugin-oxc@0.0.4 (regenerating any lockfile floated it to 3.9.5 and crashed the plugin) CI: port check.yml and release.yml to pnpm (pnpm/action-setup, cache: pnpm, `pnpm install --frozen-lockfile`, `--filter`, `pnpm exec`). The ephemeral, non-workspace macOS test app keeps its own `npm install` in scripts/init-macos-test-app.ts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * ci: fix pnpm github-dep clone on CI and drop redundant --frozen-lockfile pnpm records GitHub git dependencies (node-addon-examples) with an SSH repo URL (git@github.com:...). Stock CI runners have no SSH key, so the clone fails. Add an ad-hoc git config via workflow-level env (GIT_CONFIG_COUNT/KEY_0/VALUE_0) that rewrites git@github.com: to https://github.com/, so the public repo is fetched anonymously over HTTPS in every job without a per-job step. Also drop the explicit `--frozen-lockfile` from `pnpm install`: pnpm enables it by default when the CI environment variable is set, so it was redundant. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * fix: declare cmake-rn dependency in weak-node-api weak-node-api's `prebuild:build` script invokes the `cmake-rn` CLI, but the package never declared cmake-rn. Under npm's hoisting every workspace bin was linked into the root node_modules/.bin, so `cmake-rn` was always on PATH. pnpm only links a package's *declared* dependencies' bins, so on CI the bootstrap failed with `cmake-rn: not found` (a phantom bin dependency that only surfaces when the native prebuild runs). Declare `cmake-rn` as a devDependency (workspace:*) so pnpm links its bin into weak-node-api/node_modules/.bin. This introduces a benign dev-time cycle (cmake-rn imports weak-node-api's JS for prebuild paths; weak-node-api's build uses the cmake-rn CLI) which pnpm reports as a warning and handles fine; the topological bootstrap still sequences weak-node-api before its consumers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * ci: adopt main's test-android gating and CMake-pin removal after rebase Reconcile the pnpm-migrated check.yml with two changes that landed on main while this branch was in review: - #382 fixed the CMake 4.2 framework-HEADERS root cause in weak-node-api/CMakeLists.txt (included via the rebase) and removed the now-redundant "Install compatible CMake version" pin from all five macOS jobs. Drop those steps here too; CMAKE_VERSION is retained since test-android still uses it to select the Android SDK cmake package. - #380 gated test-android to labeled PRs only (the ubuntu-self-hosted runner is offline and otherwise leaves the job queued forever on main). With this, check.yml differs from main purely by the pnpm conversion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * fix: resolve unit-test regressions from lockfile regen and workspace filter Two unit-test failures surfaced on CI that are artifacts of the migration, not real behavioural changes: 1. host apple.test.ts (macOS) — `@expo/plist` floated from 0.4.7 (held by main's package-lock) to 0.4.9 when the lockfile was regenerated. 0.4.9's `parse()` returns a null-prototype object, so the test's strict `deepEqual` against a plain object literal fails on the prototype. Pin `@expo/plist` to 0.4.7 to match main's resolved version (same class of fix as the prettier 3.6.2 pin). The null prototype only affects the test's strict equality, not runtime property access. 2. node-addon-examples test (ubuntu/windows) — its `verify-prebuilds` step requires all four Android ABIs, but the unit-tests job only builds x86_64 (no CMAKE_RN_TRIPLETS). This test never actually ran on main: `npm test --workspace node-addon-examples` does not match the package's scoped name (@react-native-node-api/node-addon-examples), so npm silently skipped it. The faithful pnpm `--filter <scoped-name>` translation ran it for the first time and it failed. Drop it from the root `test` filter to preserve main's effective behaviour; properly enabling it would require building every ABI in the job (out of scope for the package-manager migration). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * ci: trigger label-gated jobs Empty commit to start a fresh Check run now that the Apple 🍎 / MacOS 💻 / Ferric 🦀 / weak-node-api labels are applied, so the label-gated iOS, macOS, ferric-apple-triplet and weak-node-api jobs actually run against the pnpm migration. (The workflow only triggers on opened/synchronize/reopened, not on labeling.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * fix: run macOS test-app scaffolding via pnpm dlx (avoid npm devEngines error) The test-macos job failed at `init-macos-test-app`: it scaffolds the app with `npx @react-native-community/cli init` run from the workspace root, whose package.json now declares `devEngines.packageManager: pnpm`. npm 11 refuses to run (EBADDEVENGINES) because it isn't pnpm. Switch that single root-level invocation to `pnpm dlx` — pnpm doesn't enforce devEngines.packageManager (and satisfies it anyway). The remaining steps (`npm install`, `npx react-native-macos-init`) run inside the scaffolded standalone app directory, which isn't linked to the root as a workspace, so they keep using npm/npx unaffected. Keeps the devEngines guardrail intact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * fix(macos-test-app): get the label-gated `test-macos` job green (#384) * fix(macos-test-app): unblock the macOS test app bundle and native build Two independent failures kept the label-gated `test-macos` job red. Metro bundle: the babel plugin rewrites `require("*.node")` in the workspace packages into `require("react-native-node-api").requireNodeAddon(...)`. Those files live outside the (intentionally non-workspace) macOS app, so Metro resolves the bare `react-native-node-api` specifier by walking up from the package directory. npm's hoisted workspaces happened to place it in the repo-root node_modules; pnpm's isolated node_modules does not, so the rewritten require failed with "Unable to resolve module react-native-node-api". Add the app's own node_modules (where its `file:` deps are installed) to Metro's `nodeModulesPaths` so resolution no longer depends on the root package manager's hoisting layout. Native build: GitHub's macos-latest runner now ships Xcode 26.4 / Apple clang 21, which enforces C++20 `consteval` strictly and rejects fmt 11.0.2's FMT_STRING() usages ("call to consteval function ... is not a constant expression") in fmt, Yoga and React-logger. React Native 0.81 bundles fmt 11.0.2 and the upstream fix (fmt 12.1.0) only reached RN >= 0.83.9, so patch the generated Podfile to define FMT_USE_CONSTEVAL=0 across all pods, falling back to runtime format-string validation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PM3HdJVbivXpzc2MQJV9T * fix(macos-test-app): patch fmt header directly, add mocha dep, pipefail build First CI run showed the Metro-bundle fix works (the job reached xcodebuild), but surfaced two more issues: - fmt consteval still failed: the GCC_PREPROCESSOR_DEFINITIONS FMT_USE_CONSTEVAL=0 define did not reach every fmt-consuming translation unit. Patch the vendored fmt headers directly instead (flip `#define FMT_USE_CONSTEVAL 1` to 0), the approach known to work for RN 0.81 on Xcode 26.4. - "Run test app" failed with "Cannot find module 'mocha'": mocha-remote-server needs mocha at runtime. It resolves via hoisting in the workspace apps, but the standalone macOS app must depend on it explicitly, so add mocha to the deps transferred from apps/test-app. Also add `set -o pipefail` to the xcodebuild step so a build failure is not masked by xcbeautify's exit code (which is what let the previous run limp past a failed archive into the run step). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PM3HdJVbivXpzc2MQJV9T * chore(macos-test-app): trim inline comments to essentials Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PM3HdJVbivXpzc2MQJV9T * fix(macos-test-app): bump react-native-macos to 0.81.8, drop fmt patch react-native-macos 0.81.8 bumps its vendored fmt from 11.0.2 to 12.1.0 (verified: third-party-podspecs/fmt.podspec pins 11.0.2 at v0.81.1 and 12.1.0 at v0.81.8), which resolves the Xcode 26.4 / Apple clang 21 consteval build failure at its source. Bump REACT_NATIVE_MACOS_VERSION from 0.81.1 to 0.81.8 and remove the manual Podfile header patch that forced FMT_USE_CONSTEVAL off. Core react-native stays at 0.81.5 (facebook's 0.81 line has no 0.81.8; the two packages track independent patch cadences within the same minor). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PM3HdJVbivXpzc2MQJV9T * fix(macos-test-app): bump react-native core to 0.81.6 for the macos 0.81.8 peer react-native-macos-init failed to install react-native-macos@0.81.8 because it peer-pins react-native 0.81.6 exactly, while REACT_NATIVE_VERSION was still 0.81.5 (the peer for the previous 0.81.1). Bump core to 0.81.6 so the two align. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PM3HdJVbivXpzc2MQJV9T * test(macos-test-app): drop repo-root watchFolders to check if still needed Experiment: with nodeModulesPaths in place, is the watchFolders push still required for Metro to serve the out-of-tree workspace package sources? Revert if the bundle step fails. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011PM3HdJVbivXpzc2MQJV9T * Revert "test(macos-test-app): drop repo-root watchFolders to check if still needed" This reverts commit 30f8e58. --------- Co-authored-by: Claude <noreply@anthropic.com> * fix: declare react-native-node-api in packages shipping .node addons The react-native-node-api babel plugin rewrites `require("./x.node")` into `require("react-native-node-api").requireNodeAddon(...)`, so every package that ships a Node-API addon has an implicit *runtime* dependency on react-native-node-api once its JS is bundled by Metro. npm hoisted react-native-node-api to the root node_modules, so Metro resolved it from those packages; pnpm's isolated node_modules does not, so the Metro bundle failed with `Unable to resolve module react-native-node-api from packages/ferric-example/ferric_example.js`. This is what made the iOS test app hang for ~6h: Metro errored on the first bundle, but `test:ios:allTests` runs Metro under `mocha-remote -- concurrently`, which never exits on a bundle error and waits for a client that never connects until the job hits GitHub's 6h timeout. It affects the Android app the same way. Declare `react-native-node-api` (workspace:*) in the two addon packages that were missing it — ferric-example and node-addon-examples (node-tests already declares it) — so pnpm links it into their node_modules and Metro can resolve the injected require. Verified locally that it now resolves from each package. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnwodAoNbqPec77191HVXn * fix(node-tests): declare `assert` dependency, fail bundling on unresolved imports (#385) * fix(node-tests): declare assert dependency and fail bundling on unresolved imports The bundled Node.js test for 2_function_arguments requires 'assert', which was previously satisfied as a phantom dependency: npm workspaces hoisted node-addon-examples' assert@2.1.0 ponyfill to the root node_modules, where rolldown resolved and inlined it. Under pnpm's strict node_modules layout the package is no longer reachable from node-tests, so rolldown silently kept a runtime __require("assert") call in the bundle (UNRESOLVED_IMPORT is only a warning), which then fails at runtime on device where Metro cannot resolve it. The failure surfaced as the masked 'test.titlePath(...).forEach is not a function' error, a secondary crash in mocha-remote-server's failure formatter. Declaring assert as a dependency of node-tests lets rolldown inline it again. Also make the bundle step fail hard on unresolved imports, so any future phantom dependency breaks bootstrap loudly instead of failing masked on-device. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MBr6N8caYidCuijvV5ak2A * ci: trigger label-gated jobs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MBr6N8caYidCuijvV5ak2A --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1dee1a0 commit 4e5b831

22 files changed

Lines changed: 10595 additions & 15553 deletions

File tree

.github/copilot-instructions.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ See the [README.md](../README.md#packages) for detailed descriptions of each pac
3333
### Development Setup
3434

3535
```bash
36-
npm ci && npm run build # Install deps and build all packages
37-
npm run bootstrap # Build native components (weak-node-api, examples)
36+
pnpm install && pnpm run build # Install deps and build all packages
37+
pnpm run bootstrap # Build native components (weak-node-api, examples)
3838
```
3939

4040
### Package Development
4141

4242
- **TypeScript project references**: Use `tsc --build` for incremental compilation
43-
- **Workspace scripts**: Most build/test commands use npm workspaces (`--workspace` flag)
43+
- **Workspace scripts**: Most build/test commands use pnpm workspaces (`--filter` flag), run in topological (dependency) order and fail fast
4444
- **Focus on Node.js packages**: AI development primarily targets the Node.js tooling packages rather than native mobile code
4545
- **No TypeScript type asserts**: You have to ask explicitly and justify if you want to add `as` type assertions.
4646

@@ -70,8 +70,8 @@ Library names use double-dash separation: `package-name--path-component--addon-n
7070

7171
### Testing
7272

73-
- **Individual packages**: Some packages have VS Code test tasks and others have their own `npm test` scripts for focused iteration (e.g., `npm test --workspace cmake-rn`). Use the latter only if the former is missing.
74-
- **Cross-package**: Use root-level `npm test` for cross-package testing once individual package tests pass
73+
- **Individual packages**: Some packages have VS Code test tasks and others have their own test scripts for focused iteration (e.g., `pnpm --filter cmake-rn run test`). Use the latter only if the former is missing.
74+
- **Cross-package**: Use root-level `pnpm test` for cross-package testing once individual package tests pass
7575
- **Mobile integration**: Available but not the primary AI development focus - ask the developer to run those tests as needed
7676

7777
**Documentation**: Integration details, platform setup, and toolchain configuration are covered in existing repo documentation files.

.github/workflows/check.yml

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ env:
66
NDK_VERSION: 27.1.12297006
77
# Enabling the Gradle test on CI (disabled by default because it downloads a lot)
88
ENABLE_GRADLE_TESTS: true
9+
# pnpm records GitHub git dependencies (e.g. node-addon-examples) with an SSH
10+
# repo URL, which anonymous CI runners can't clone. Rewrite git@github.com: to
11+
# HTTPS so the public repo is fetched over HTTPS. Provided as ad-hoc git config
12+
# via env so it applies to every job without a per-job step.
13+
GIT_CONFIG_COUNT: 1
14+
GIT_CONFIG_KEY_0: "url.https://github.com/.insteadOf"
15+
GIT_CONFIG_VALUE_0: "git@github.com:"
916

1017
on:
1118
push:
@@ -24,9 +31,11 @@ jobs:
2431
runs-on: ubuntu-latest
2532
steps:
2633
- uses: actions/checkout@v4
34+
- uses: pnpm/action-setup@v4
2735
- uses: actions/setup-node@v6
2836
with:
2937
node-version: lts/krypton
38+
cache: pnpm
3039
- name: Setup cpp tools
3140
uses: aminya/setup-cpp@v1
3241
with:
@@ -47,18 +56,18 @@ jobs:
4756
with:
4857
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
4958
- run: rustup target add x86_64-linux-android
50-
- run: npm ci
51-
- run: npm run build
59+
- run: pnpm install
60+
- run: pnpm run build
5261
# Bootstrap weak-node-api and ferric-example to get types
5362
# TODO: Solve this by adding an option to ferric to build only types or by committing the types into the repo as a fixture for an "init" command
54-
- run: npm run bootstrap --workspace weak-node-api
55-
- run: npm run bootstrap --workspace @react-native-node-api/ferric-example
56-
- run: npm run lint
63+
- run: pnpm --filter weak-node-api run bootstrap
64+
- run: pnpm --filter @react-native-node-api/ferric-example run bootstrap
65+
- run: pnpm run lint
5766
env:
5867
DEBUG: eslint:eslint
59-
- run: npm run prettier:check
60-
- run: npm run depcheck
61-
- run: npm run publint
68+
- run: pnpm run prettier:check
69+
- run: pnpm run depcheck
70+
- run: pnpm run publint
6271
unit-tests:
6372
strategy:
6473
fail-fast: false
@@ -71,9 +80,11 @@ jobs:
7180
name: Unit tests (${{ matrix.runner }})
7281
steps:
7382
- uses: actions/checkout@v4
83+
- uses: pnpm/action-setup@v4
7484
- uses: actions/setup-node@v6
7585
with:
7686
node-version: lts/krypton
87+
cache: pnpm
7788
- name: Setup cpp tools
7889
uses: aminya/setup-cpp@v1
7990
with:
@@ -92,9 +103,9 @@ jobs:
92103
with:
93104
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
94105
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
95-
- run: npm ci
96-
- run: npm run bootstrap
97-
- run: npm test
106+
- run: pnpm install
107+
- run: pnpm run bootstrap
108+
- run: pnpm test
98109
weak-node-api-tests:
99110
if: github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'weak-node-api')
100111
strategy:
@@ -108,9 +119,11 @@ jobs:
108119
name: Weak Node-API tests (${{ matrix.runner }})
109120
steps:
110121
- uses: actions/checkout@v4
122+
- uses: pnpm/action-setup@v4
111123
- uses: actions/setup-node@v6
112124
with:
113125
node-version: lts/krypton
126+
cache: pnpm
114127
- name: Setup cpp tools
115128
uses: aminya/setup-cpp@v1
116129
with:
@@ -119,10 +132,10 @@ jobs:
119132
uses: hendrikmuhs/ccache-action@v1.2
120133
with:
121134
key: ${{ github.job }}-${{ runner.os }}
122-
- run: npm ci
123-
- run: npm run build
135+
- run: pnpm install
136+
- run: pnpm run build
124137
- name: Prepare weak-node-api
125-
run: npm run prebuild:prepare --workspace weak-node-api
138+
run: pnpm --filter weak-node-api run prebuild:prepare
126139
- name: Build and run weak-node-api C++ tests
127140
run: |
128141
cmake -S . -B build -DBUILD_TESTS=ON
@@ -135,9 +148,11 @@ jobs:
135148
runs-on: macos-latest
136149
steps:
137150
- uses: actions/checkout@v4
151+
- uses: pnpm/action-setup@v4
138152
- uses: actions/setup-node@v6
139153
with:
140154
node-version: lts/krypton
155+
cache: pnpm
141156
- name: Setup cpp tools
142157
uses: aminya/setup-cpp@v1
143158
with:
@@ -156,17 +171,17 @@ jobs:
156171
with:
157172
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
158173
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
159-
- run: npm ci
160-
- run: npm run bootstrap
174+
- run: pnpm install
175+
- run: pnpm run bootstrap
161176
env:
162177
CMAKE_RN_TRIPLETS: arm64;x86_64-apple-ios-sim
163178
FERRIC_TARGETS: aarch64-apple-ios-sim
164-
- run: npm run pod-install
179+
- run: pnpm run pod-install
165180
working-directory: apps/test-app
166181
- name: Run tests (iOS)
167-
run: npm run test:ios:allTests
182+
run: pnpm run test:ios:allTests
168183
# TODO: Enable release mode when it works
169-
# run: npm run test:ios:allTests -- --mode Release
184+
# run: pnpm run test:ios:allTests -- --mode Release
170185
working-directory: apps/test-app
171186
test-macos:
172187
# Disabling this on main for now, as initializing the template takes a long time and
@@ -176,9 +191,11 @@ jobs:
176191
runs-on: macos-latest
177192
steps:
178193
- uses: actions/checkout@v4
194+
- uses: pnpm/action-setup@v4
179195
- uses: actions/setup-node@v6
180196
with:
181197
node-version: lts/krypton
198+
cache: pnpm
182199
- name: Setup cpp tools
183200
uses: aminya/setup-cpp@v1
184201
with:
@@ -193,19 +210,20 @@ jobs:
193210
java-version: "17"
194211
distribution: "temurin"
195212
- run: rustup target add x86_64-apple-darwin
196-
- run: npm ci
197-
- run: npm run bootstrap
213+
- run: pnpm install
214+
- run: pnpm run bootstrap
198215
env:
199216
CMAKE_RN_TRIPLETS: arm64;x86_64-apple-darwin
200217
FERRIC_TARGETS: aarch64-apple-darwin,x86_64-apple-darwin
201-
- run: npm run init-macos-test-app
218+
- run: pnpm run init-macos-test-app
202219
- run: pod install --project-directory=macos
203220
working-directory: apps/macos-test-app
204221
- name: Bundle test app
205222
run: npx react-native bundle --entry-file index.js --platform macos --dev false --minify false --bundle-output dist/main.macos.jsbundle --assets-dest dist/res
206223
working-directory: apps/macos-test-app
207224
- name: Build test app
208-
run: xcodebuild archive -workspace MacOSTestApp.xcworkspace -configuration Release -scheme MacOSTestApp-macOS -destination generic/platform="macOS" -archivePath ./build/macos-test-app.xcarchive | xcbeautify
225+
# pipefail so an xcodebuild failure is not masked by xcbeautify's exit code
226+
run: set -o pipefail && xcodebuild archive -workspace MacOSTestApp.xcworkspace -configuration Release -scheme MacOSTestApp-macOS -destination generic/platform="macOS" -archivePath ./build/macos-test-app.xcarchive | xcbeautify
209227
working-directory: apps/macos-test-app/macos
210228
- name: Run test app
211229
run: npx mocha-remote --exit-on-error -- macos/build/macos-test-app.xcarchive/Products/Applications/MacOSTestApp.app/Contents/MacOS/MacOSTestApp
@@ -222,9 +240,11 @@ jobs:
222240
runs-on: ubuntu-self-hosted
223241
steps:
224242
- uses: actions/checkout@v4
243+
- uses: pnpm/action-setup@v4
225244
- uses: actions/setup-node@v6
226245
with:
227246
node-version: lts/krypton
247+
cache: pnpm
228248
- name: Setup cpp tools
229249
uses: aminya/setup-cpp@v1
230250
with:
@@ -243,15 +263,15 @@ jobs:
243263
with:
244264
packages: tools platform-tools ndk;${{ env.NDK_VERSION }} cmake;${{ env.CMAKE_VERSION }}
245265
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
246-
- run: npm ci
247-
- run: npm run bootstrap
266+
- run: pnpm install
267+
- run: pnpm run bootstrap
248268
env:
249269
CMAKE_RN_TRIPLETS: x86_64-linux-android
250270
FERRIC_TARGETS: x86_64-linux-android
251271
- name: Clone patched Hermes version
252272
shell: bash
253273
run: |
254-
REACT_NATIVE_OVERRIDE_HERMES_DIR=$(npx react-native-node-api vendor-hermes --silent)
274+
REACT_NATIVE_OVERRIDE_HERMES_DIR=$(pnpm exec react-native-node-api vendor-hermes --silent)
255275
echo "REACT_NATIVE_OVERRIDE_HERMES_DIR=$REACT_NATIVE_OVERRIDE_HERMES_DIR" >> $GITHUB_ENV
256276
working-directory: apps/test-app
257277
# - name: Setup Android Emulator cache
@@ -269,9 +289,9 @@ jobs:
269289
sudo udevadm control --reload-rules
270290
sudo udevadm trigger --name-match=kvm
271291
- name: Build weak-node-api for all Android architectures
272-
run: npm run prebuild:build:android --workspace weak-node-api
292+
run: pnpm --filter weak-node-api run prebuild:build:android
273293
- name: Build ferric-example for all architectures
274-
run: npm run build -- --android
294+
run: pnpm run build -- --android
275295
working-directory: packages/ferric-example
276296
- name: Run tests (Android)
277297
timeout-minutes: 75
@@ -293,7 +313,7 @@ jobs:
293313
adb logcat > emulator-logcat.txt 2>&1 &
294314
LOGCAT_PID=$!
295315
# Build, install and run the app
296-
npm run test:android:allTests -- --mode Release
316+
pnpm run test:android:allTests -- --mode Release
297317
# Wait a bit for the sub-process to terminate, before terminating the emulator
298318
sleep 5
299319
# Stop logcat
@@ -310,9 +330,11 @@ jobs:
310330
runs-on: macos-latest
311331
steps:
312332
- uses: actions/checkout@v4
333+
- uses: pnpm/action-setup@v4
313334
- uses: actions/setup-node@v6
314335
with:
315336
node-version: lts/krypton
337+
cache: pnpm
316338
- name: Setup cpp tools
317339
uses: aminya/setup-cpp@v1
318340
with:
@@ -328,14 +350,14 @@ jobs:
328350
distribution: "temurin"
329351
- run: rustup target add x86_64-apple-darwin x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim
330352
- run: rustup toolchain install nightly --component rust-src
331-
- run: npm ci
332-
- run: npm run build
353+
- run: pnpm install
354+
- run: pnpm run build
333355
- name: Build weak-node-api for all Apple architectures
334356
run: |
335-
npm run prebuild:prepare --workspace weak-node-api
336-
npm run prebuild:build:apple --workspace weak-node-api
357+
pnpm --filter weak-node-api run prebuild:prepare
358+
pnpm --filter weak-node-api run prebuild:build:apple
337359
# Build Ferric example for all Apple architectures
338-
- run: npx ferric --apple
360+
- run: pnpm exec ferric --apple
339361
working-directory: packages/ferric-example
340362
- name: Inspect the structure of the prebuilt binary
341363
run: lipo -info ferric_example.apple.node/*/libferric_example.framework/libferric_example > lipo-info.txt

.github/workflows/release.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ name: Release
33
env:
44
# Version here should match the one in React Native template and packages/cmake-rn/src/cli.ts
55
NDK_VERSION: 27.1.12297006
6+
# pnpm records GitHub git dependencies (e.g. node-addon-examples) with an SSH
7+
# repo URL, which anonymous CI runners can't clone. Rewrite git@github.com: to
8+
# HTTPS so the public repo is fetched over HTTPS.
9+
GIT_CONFIG_COUNT: 1
10+
GIT_CONFIG_KEY_0: "url.https://github.com/.insteadOf"
11+
GIT_CONFIG_VALUE_0: "git@github.com:"
612

713
on:
814
push:
@@ -18,9 +24,11 @@ jobs:
1824
environment: main
1925
steps:
2026
- uses: actions/checkout@v4
27+
- uses: pnpm/action-setup@v4
2128
- uses: actions/setup-node@v6
2229
with:
2330
node-version: lts/krypton
31+
cache: pnpm
2432
- name: Setup cpp tools
2533
uses: aminya/setup-cpp@v1
2634
with:
@@ -39,12 +47,12 @@ jobs:
3947
with:
4048
packages: tools platform-tools ndk;${{ env.NDK_VERSION }}
4149
- run: rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android aarch64-apple-ios-sim
42-
- run: npm install
50+
- run: pnpm install
4351

4452
- name: Create Release Pull Request or Publish to NPM
4553
id: changesets
4654
uses: changesets/action@v1
4755
with:
48-
publish: npm run release
56+
publish: pnpm run release
4957
env:
5058
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ Pods
55
target
66
.cxx
77

8+
# Ignore the pnpm lockfile (managed by pnpm, not formatted by Prettier)
9+
pnpm-lock.yaml
10+
811
# Ignore hermes
912
packages/host/hermes
1013
packages/node-addon-examples/examples

apps/test-app/metro.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ if (config.projectRoot.endsWith("macos-test-app")) {
1717
// duplicate react-native version and pollution of the package lock.
1818
const path = require("node:path");
1919
config.watchFolders.push(path.resolve(__dirname, "../.."));
20+
21+
// Resolve workspace packages (and the specifiers the babel plugin rewrites
22+
// their `*.node` requires to) from this app's own node_modules, independent of
23+
// the root package manager's hoisting layout.
24+
config.resolver = config.resolver || {};
25+
config.resolver.nodeModulesPaths = [
26+
...(config.resolver.nodeModulesPaths || []),
27+
path.resolve(__dirname, "node_modules"),
28+
];
2029
}
2130

2231
module.exports = config;

apps/test-app/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
"@react-native-community/cli": "^20.0.2",
2828
"@react-native-community/cli-platform-android": "^20.0.2",
2929
"@react-native-community/cli-platform-ios": "^20.0.2",
30-
"@react-native-node-api/ferric-example": "*",
31-
"@react-native-node-api/node-addon-examples": "*",
32-
"@react-native-node-api/node-tests": "*",
30+
"@react-native-node-api/ferric-example": "workspace:*",
31+
"@react-native-node-api/node-addon-examples": "workspace:*",
32+
"@react-native-node-api/node-tests": "workspace:*",
3333
"@react-native/babel-preset": "0.81.4",
3434
"@react-native/metro-config": "0.81.4",
3535
"@react-native/typescript-config": "0.81.4",
@@ -42,8 +42,8 @@
4242
"mocha-remote-react-native": "^1.13.2",
4343
"react": "19.1.0",
4444
"react-native": "0.81.4",
45-
"react-native-node-api": "*",
45+
"react-native-node-api": "workspace:*",
4646
"react-native-test-app": "^4.4.7",
47-
"weak-node-api": "*"
47+
"weak-node-api": "workspace:*"
4848
}
4949
}

0 commit comments

Comments
 (0)