Skip to content

Conversation

@thisislvca
Copy link
Contributor

@thisislvca thisislvca commented Feb 9, 2026

Yesterday, when I first tried to contribute to this package, the experience was honestly a mess, mainly because of all the committed native output. I started working on this to remove that, and ended up fixing most of the issues I could see in the development setup. Hopefully this leads to more contributions :)

TL;DR:

This PR stabilizes the contributor/dev workflow without changing the public JS API. I moved iOS tests and harness ownership into the package, aligned the example app with Expo's CNG workflow guidance (generate native output instead of tracking it in git), hardened CI/local test and lint paths, and tightened npm publish filtering so package contents stay lean and aligned with current release expectations.

What the situation looked like before

  • Our development workflow mixed toolchains (npm, npx, bun) and had stale path references from the old example/ layout
  • The example app still tracked generated native output (apps/example/ios, apps/example/android, apps/example/targets), which created high PR churn after expo prebuild
  • Example app identity/signing values were effectively hardcoded in tracked config, so local setup details were easy to leak into commits
  • Swift tests were package concerns but lived under the example app, so ownership and execution paths were split across app/package boundaries
  • SwiftLint and test harness wiring depended on example-app CocoaPods paths, making local and CI behavior harder to keep aligned
  • Test coverage around config plugin behavior and runtime wrapper delegation was too thin for this setup
  • Prettier invocation vulnerable to binary shadowing from transitive tooling (expo-module-scripts), which made formatting on save different from formatting through the CLI

Why I made these changes

  • Reduce noisy, non-functional diffs from generated native files.
  • Make local setup safe and repeatable without committing developer-specific values.
  • Put tests and test infrastructure where they belong: in the package.
  • Make pre-push and CI checks match real usage paths and fail earlier when setup is incomplete.
  • Remove ambiguity from formatting/lint/tool invocation so contributors get the same behavior.

What changed

1) Tooling and path consistency

  • Added repo-level Prettier config/ignore and explicit format scripts.
  • Standardized local script entrypoints on Bun (.husky/pre-push, example prebuild using bunx).
  • Fixed stale example/* references to apps/example/* in workflows, ignores, docs, and scripts.
  • Added a deterministic Prettier invocation (node ./node_modules/prettier/bin/prettier.cjs) to avoid PATH/bin shadowing (where transitive tooling can resolve the wrong Prettier binary/version). See expo/expo#42994.

2) Example app moved to env-driven CNG flow

  • Replaced apps/example/app.json with env-driven apps/example/app.config.ts.
  • Added apps/example/.env.example for:
    • RNDA_APPLE_TEAM_ID
    • RNDA_APP_GROUP
    • RNDA_IOS_BUNDLE_ID
    • RNDA_ANDROID_PACKAGE
  • Aligned the example workflow with Expo's Continuous Native Generation (CNG) guidance (generate native folders from config rather than tracking generated native output in git): https://docs.expo.dev/workflow/continuous-native-generation/
  • Stopped tracking generated example native output (apps/example/ios, apps/example/android) and generated target output (apps/example/targets).
  • Removed already-tracked generated files from those folders to stop recurring churn.
  • This is intentional: apps/example/ios, apps/example/android, and apps/example/targets are generated outputs and are expected to be regenerated locally, not committed.

3) iOS tests now package-owned, with a package-owned harness

  • Moved Swift test sources to packages/react-native-device-activity/ios/Tests.
  • Moved the iOS test runner project to packages/react-native-device-activity/ios/TestHarness.
  • Rewired harness paths (Podfile/Xcode project references) so the harness resolves the app root and targets correctly from its new package location.
  • Updated SwiftLint scopes and hook/editor paths to run through the package-owned harness setup.

4) Clear source-of-truth for Apple target artifacts

  • packages/react-native-device-activity/targets is now the canonical source for Apple target templates.
  • Removed duplicate generated target artifacts under apps/example/targets.

5) Test workflow hardening

  • Added config-plugin regression tests in packages/react-native-device-activity/plugin/__tests__/config-plugin.test.ts.
  • Added plugin Jest config and a dedicated runtime Jest config.
  • Reworked packages/react-native-device-activity/src/index.test.ts to properly mock runtime dependencies and verify native delegation behavior.
  • Updated package test scripts so bun run test runs both runtime and plugin tests with CI=1 to keep Jest non-watch and deterministic in hooks/CI.
  • Updated root pre-push to run typecheck, lint, tests, and SwiftLint.
  • Updated iOS CI test job to run against the harness without the previous signing override flags that produced simulator-only behavior differences.

6) Packaging safety

  • Updated packages/react-native-device-activity/ios/ReactNativeDeviceActivity.podspec to exclude Tests/**/* and TestHarness/**/* from pod source globs.
  • Added packages/react-native-device-activity/.npmignore to exclude dev-only harness/test/plugin test files from npm publish artifacts.
  • Excluded compiled test outputs from publish artifacts (build/*.test.*).
  • Kept target template files in targets/ but excluded generated target metadata that is not part of the current published package (generated.entitlements and PrivacyInfo.xcprivacy files).

7) Docs and contributor workflow updates

  • Rewrote CONTRIBUTING.md setup guidance around env config, CNG regeneration, harness ownership, SwiftLint setup, and formatting behavior.
  • Updated README contributing/setup references to point to repository-specific guidance.

8) Post-review hardening fixes before merge

(On top of my manual review, I ran a few passes of codex and claude code reviews and fixed all regressions/bugs :)

  • Fixed a clean-checkout regression where running example prebuild without the helper script could omit Apple targets:
    • CI prebuild now uses bun run prebuild from apps/example (which sets the required env toggles).
    • Example ios/android run scripts now also set COPY_TO_TARGET_FOLDER=true so target generation is consistent.
  • Added JS test enforcement in CI so runtime/plugin tests are part of required validation (bun run test in test.yml and publish test gate).
  • Restored Swift quality gates for production iOS module files by expanding SwiftLint include scope and pre-commit swift format coverage beyond tests/harness-only paths.
  • Fixed the root swiftlint script guard so missing harness SwiftLint binaries fail fast and stop execution (instead of falling through to a second command failure).
  • Aligned SwiftLint severity between local and CI by running CI SwiftLint with --strict (matching bun run pre-push behavior).
  • Kept npm publish filtering aligned with current publish expectations so package artifacts stay lean and release-oriented.

NPM package footprint check

Measured on February 9, 2026 with npm pack --dry-run after prepublishOnly, compared against currently published react-native-device-activity@0.5.3.

Package artifact Tarball size Unpacked size File count
Current npm package (0.5.3) 60,238 B 313,764 B 70
This PR candidate 59,845 B 312,107 B 66
Delta (candidate - current) -393 B -1,657 B -4

Important note on formatter-only file changes

Some files changed only because we ran the formatter. Those edits are non-functional style/layout normalization, not behavior changes. This includes a few tiny package file touches, but no logic change.

How the situation is now

  • Generated native/example artifacts are no longer creating PR noise.
  • Local setup is reproducible and safer via env-driven app config.
  • iOS tests are owned by the package and executed via a package-owned harness.
  • Prebuild paths used in local scripts and CI now deterministically generate Apple targets in clean environments.
  • JS runtime/plugin tests are now enforced in CI, not just local hooks.
  • Package tests now run with CI=1, preventing local/CI watch-mode prompts during automated checks.
  • Swift lint/format gates cover production iOS module files in addition to tests/targets/harness files.
  • SwiftLint strictness is now consistent between local pre-push and CI.
  • Lint/test/format commands are more deterministic locally and in CI.
  • Plugin/runtime behavior has explicit regression coverage.
  • Packaging excludes test/harness internals from pod source files and npm publish artifacts.

API / runtime impact

  • No public JS API changes. No logic/package file changes.
  • Primary impact is development workflow reliability, test ownership clarity, and CI/local determinism.

- ignore apps/example/targets as generated prebuild output to reduce churn
- remove tracked example target artifacts from version control
- point VS Code and pre-push lint command to TestHarness SwiftLint binary
- document one-time pod install setup in CONTRIBUTING
- ensure clean example prebuild paths generate Apple targets in local scripts and CI

- enforce JS runtime/plugin tests in CI and release gates

- restore SwiftLint and Swift format coverage for production iOS module files

- exclude dev-only harness/test artifacts from published npm package
@thisislvca thisislvca force-pushed the codex/stability-sweep branch from 7a01fac to b2c8a66 Compare February 9, 2026 22:36
@thisislvca thisislvca changed the title Stability and dev experience improvements chore(devx): make dev/CI deterministic and move iOS tests into package ownership Feb 9, 2026
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 9, 2026

Open in StackBlitz

npm i https://pkg.pr.new/kingstinct/react-native-device-activity@85

commit: 3f95fb7

@thisislvca thisislvca marked this pull request as ready for review February 9, 2026 23:31
@thisislvca
Copy link
Contributor Author

thisislvca commented Feb 9, 2026

@robertherber yo sorry for the monster-sized PR! I started working on it cuz I wanted to improve a couple things, but it ended up taking almost a full day. Honestly tho, was worth it, esp considering I need to add a couple more features to this package, including reporting as I mentioned (almost done).

DX now feels sublime compared to before. The codebase is also way more maintainable now. Lmk if you have any feedback/want some things changed. If you had other DX setup changes in mind happy to implement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant