Skip to content

refactor: migrate native module from Expo Modules API to React Native Turbo Modules#149

Merged
V3RON merged 26 commits into
mainfrom
refactor/turbomodule
May 25, 2026
Merged

refactor: migrate native module from Expo Modules API to React Native Turbo Modules#149
V3RON merged 26 commits into
mainfrom
refactor/turbomodule

Conversation

@V3RON
Copy link
Copy Markdown
Contributor

@V3RON V3RON commented May 12, 2026

Why this matters

This branch finishes the move away from the old monolithic voltra package and lands the package layout that matches how the library is actually structured now.

Instead of shipping one mixed package with Expo Modules-era assumptions, Voltra is now split into explicit platform and responsibility-focused workspaces:

  • @use-voltra/ios-client and @use-voltra/android-client for React Native client APIs and native bindings
  • @use-voltra/ios and @use-voltra/android for platform JSX/runtime packages
  • @use-voltra/ios-server, @use-voltra/android-server, and @use-voltra/server for server rendering flows
  • @use-voltra/generator as the private source of truth for generated component metadata
  • @use-voltra/expo-plugin as shared plugin utilities used by the client packages

The branch also removes the old packages/voltra workspace entirely, updates docs/examples to the new install/import paths, and adds regression coverage around renderer/server/generator behavior so the split is safer to maintain.

Closes #148

What changed

Package and workspace restructuring

  • migrated the native module work into @use-voltra/ios-client and @use-voltra/android-client
  • kept platform JSX/runtime code in @use-voltra/ios and @use-voltra/android
  • introduced dedicated server packages: @use-voltra/server, @use-voltra/ios-server, @use-voltra/android-server
  • extracted generation logic and schemas into the private @use-voltra/generator workspace
  • removed the legacy packages/voltra package instead of keeping it as a compatibility layer

Native and plugin integration cleanup

  • completed the Turbo Module / Fabric-oriented native client setup in the split client packages
  • added codegenConfig to iOS and Android client packages
  • moved Expo config plugin entry points into the client packages while keeping shared plugin helpers in @use-voltra/expo-plugin
  • preserved plugin build output and restored monorepo Babel/Jest/example app setup needed by the new workspace layout

Shared rendering and server changes

  • updated renderer/server packages to use the generated component id registries from the new generator workspace
  • fixed prerender package imports after the workspace split
  • aligned example app imports and server code with the new package boundaries

Tests and CI

  • added regression coverage for:
  • @use-voltra/core renderer
  • @use-voltra/ios renderer
  • @use-voltra/android renderer
  • @use-voltra/server
  • @use-voltra/ios-server
  • @use-voltra/android-server
  • @use-voltra/generator
  • switched JS test execution to turbo run test
  • added/updated expo-plugin validation tests in split client packages
  • removed workspace smoke checks in favor of the more targeted regression suites above

Docs and examples

  • updated README, CONTRIBUTING, website docs, and agent skill references to the new package names and setup flow
  • updated the example app configuration and imports to use @use-voltra/ios-client / @use-voltra/android-client
  • refreshed installation/setup guidance around platform-specific client packages and plugin usage

Test plan

  • JS test suites run via Turbo (npm run test:js)
  • Regression tests added for core/platform/server/generator packages
  • Expo plugin validation tests added for split client packages
  • iOS example app manual verification: Live Activities, widgets, VoltraView, events
  • Android example app manual verification: widgets, ongoing notifications, VoltraView, events
  • Bare React Native manual verification: install split client packages and confirm no legacy monolithic package assumptions remain

@V3RON V3RON force-pushed the refactor/turbomodule branch from 09e4936 to 2ef632e Compare May 18, 2026 08:41
V3RON and others added 19 commits May 18, 2026 11:34
Add root babel.config.js with @react-native/babel-preset for Voltra node
tests on RN 0.83, wire babel-jest to the monorepo root, and restore
server/payload re-exports used by tests. Fix example app.json android
plugin JSON, remove an unused expo-plugin import, and apply Prettier.

Co-authored-by: Cursor <cursoragent@cursor.com>
Clean was running after build:expo-plugin and deleted expo-plugin/build
before publish/CI prebuild, causing config plugin resolution to fail.

Co-authored-by: Cursor <cursoragent@cursor.com>
burczu and others added 6 commits May 25, 2026 09:36
## Summary

Follow-up to #149. The package split was done mostly automatically,
leaving behind a few cases of code duplication. This PR finishes the
cleanup.

- **Delete `packages/ios/src/renderer/` shims** — 7 one-liner re-export
files (`context-registry`, `dispatcher`, `element-registry`,
`flatten-styles`, `render-cache`, `stylesheet-registry`, `types`) were
left over from the split, making `@use-voltra/ios` look like it had its
own renderer. Removed them and cleaned up the barrel `index.ts`.
- **Re-export `createVoltraComponent` from core** — the implementation
was duplicated verbatim in `@use-voltra/ios` and `@use-voltra/android`.
Core already owns and exports it — both platform packages now re-export
from there. Internal consumers within each package continue to import
from the local path, transparently resolving through the re-export.

### What was considered but left alone

- `chart-types.ts` (`ChartDataPoint`, `SectorDataPoint`) — identical
2-line type file in both platform packages. Moving to core would give a
platform-agnostic renderer package chart-domain knowledge. Duplication
is acceptable at this size.
- `useUpdateOnHMR.ts` — identical 20-line RN hook in both client
packages. Uses `__DEV__` and Metro's `global.__accept`, so it can't go
to core. No appropriate shared home without a new package for 20 lines.
- `widgets/server-credentials.ts` — near-identical in
`@use-voltra/ios-client` and `@use-voltra/android-client`, differing
only in the native module import, error message platform label, and
caller. The differences are genuine platform facts; there is no valid
shared home (clients cannot depend on each other, and both are
restricted from importing `@use-voltra/core` directly).
- `VoltraRNNativeComponent.ts` — present in both client `native/` dirs,
differing only in the registered native view name (`'VoltraView'` vs
`'AndroidVoltraView'`). Intentional — different native components for
each platform.
- `fonts.ts` across expo-plugins — not actually duplicated.
`packages/expo-plugin/src/utils/fonts.ts` is a shared utility; the
platform-specific plugin files (`ios-client/expo-plugin` and
`android-client/expo-plugin`) import `resolveFontPaths` from it.
Structure is correct.
- Lint rules for RN/expo in `@use-voltra/ios` and `@use-voltra/android`
— already in place in #149.
- Dependency audit — all packages clean; RN and expo only appear in
`peerDependencies`.

## Test plan

- [x] `tsc --noEmit` passes on `@use-voltra/ios` and
`@use-voltra/android`
- [x] `@use-voltra/ios` test suite passes (5/5)
- [x] `@use-voltra/android` test suite passes (6/6)
- [x] `oxlint` passes on all changed packages
@V3RON V3RON merged commit f3dfff1 into main May 25, 2026
12 checks passed
@V3RON V3RON deleted the refactor/turbomodule branch May 25, 2026 11:36
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.

Migrate native module from Expo Modules to Turbo Modules

3 participants