📁 File path: apps/weshipit/pages/plan/2026-W27.md

React Native Roadmap 2026-W27

Week of June 29–July 5, 2026

Items This Week

#TitleLabelLink
1Rollipop: A Rust Replacement for Metro🟦 RNRead
2React Native Windows v0.84🟦 RNRead
3Expo SDK 57🟧 EXPORead
4How Tapaya Added In-Store Card Payments to a POS App🟧 EXPORead
5Chasing a Phantom Jump: Skia Animations on Low-End Android🟦 RNRead
6React Status #481 – Meta Releases Astryx Design System⚛️ REACTRead

5-Day Action Plan


🟦 Chunk 1 — Configure Rollipop as Metro Drop-in Replacement

Goal: Replace Metro bundler with Rollipop (Rust-based, built on Rolldown) to unlock faster cold starts, better module resolution, and a real-time bundler dashboard in a bare React Native project.

Scope:

  • Install Rollipop via npx @rollipop/init
  • Update react-native.config.js to register Rollipop commands
  • Configure rollipop.config.ts for existing project structure
  • Verify HMR, Fast Refresh, source maps, and error symbolication work
  • Test the bundler dashboard at http://localhost:8081/dashboard

Out of scope: Expo-managed projects (Rollipop does not support Expo CLI today), CI/CD pipeline changes, production build benchmarking.

Dependencies: Bare React Native CLI project (not managed by Expo). Node.js ≥ 18.

Acceptance criteria:

  • rollipop start boots the dev server without errors
  • HMR and Fast Refresh work on both iOS simulator and Android emulator
  • Bundler dashboard shows connected clients and build status
  • No $FlowFixMe errors introduced

Estimated effort: S

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Configure Rollipop as a drop-in Metro replacement.

Goal: Replace Metro with Rollipop (Rust-based bundler built on Rolldown) to get faster cold starts, better package.json exports support, and a live bundler dashboard.

Files to create/modify:

  • react-native.config.js — register rollipop/commands
  • rollipop.config.ts — generated by init, review and tweak for your monorepo if needed
  • package.json — add rollipop dev dependency (done automatically by init)
  • android/app/build.gradle and ios/Podfile — wired automatically by init; verify no conflicts

Step-by-step:

  1. Run npx @rollipop/init at the project root. Accept all prompts.
  2. Open react-native.config.js and confirm it contains commands: require('rollipop/commands').
  3. Run rollipop start and open http://localhost:8081/dashboard in a browser.
  4. Launch your app on an iOS simulator with react-native run-ios.
  5. Launch your app on an Android emulator with react-native run-android.
  6. Make a source change and verify Fast Refresh updates the app without a full reload.
  7. Check the dashboard's "Bundle Preview" section to confirm no unexpectedly large modules.

Acceptance criteria checklist:

  • rollipop start exits cleanly and logs no errors
  • App boots on iOS simulator within expected time
  • App boots on Android emulator within expected time
  • Editing a component triggers Fast Refresh within 2 s
  • Dashboard shows connected client and current bundle size
  • Source maps resolve correctly in the React Native DevTools

🟦 Chunk 2 — Fix Skia Animation Jank on Low-End Android via SurfaceView

Goal: Eliminate mid-animation frame hitches on budget Android phones (120 Hz) by switching react-native-skia canvases from the default TextureView to SurfaceView compositing mode, as documented in Margelo's deep-dive on Pingo's animation performance.

Scope:

  • Identify all <Canvas> components in the app backed by SkiaTextureView
  • Switch to opaque prop or SurfaceView-backed canvas mode where available
  • Profile before/after with GPU rendering bars on a budget Android device
  • Validate that Reanimated worklets no longer cause per-frame texture uploads

Out of scope: iOS-specific compositing changes, full Reanimated worklet refactor, Hermes GC tuning.

Dependencies: react-native-skia installed, Reanimated v3, access to a low-end Android device or emulator.

Acceptance criteria:

  • Frame delivery stays ≤ 8.3 ms p95 at 120 Hz on a budget Android device during the target animation
  • No visible "phantom jump" on animated cards or morph transitions
  • GPU profiling bars show reduced compositing cost for the Skia canvas layer
  • Animation spring curve behavior is unchanged

Estimated effort: M

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Fix Skia animation jank on low-end Android by switching to SurfaceView compositing.

Goal: Eliminate frame hitches on budget 120 Hz Android phones where SkiaTextureView causes 2–3 GPU passes per frame by migrating to a SurfaceView-backed Skia canvas.

Files to modify:

  • Any screen/component that renders a <Canvas> from @shopify/react-native-skia

Step-by-step:

  1. Audit all <Canvas> usages: grep -r "<Canvas" src/.
  2. For each canvas used in an animated transition, add the opaque prop: <Canvas opaque style={...}>.
  3. Connect a budget Android device and enable GPU rendering profiling: Developer Options → "Profile GPU rendering → On screen as bars".
  4. Screenshot the GPU bars during the animation before the change.
  5. Apply the opaque change, rebuild, and rerun the same animation.
  6. Screenshot the bars again — the green draw bar should drop by 30–60%.
  7. Use Perfetto trace to confirm no per-frame HWUI texture uploads for the canvas layer.
  8. Verify the Reanimated worklet driving the animation still runs without dropped frames.

Acceptance criteria checklist:

  • GPU profiling bars stay below the 8.3 ms line during the animation on the budget device
  • No visible jump or hold visible to the human eye
  • opaque canvas compiles without errors on both Android and iOS
  • Existing animation behavior (spring curve) is unchanged

🟧 Chunk 3 — Upgrade App to Expo SDK 57 (React Native 0.86)

Goal: Migrate from Expo SDK 56 to SDK 57, picking up React Native 0.86, edge-to-edge Android fixes, light/dark mode DevTools emulation, and the updated expo prebuild clean-by-default behavior.

Scope:

  • Run npx expo install expo@latest --fix to upgrade all Expo packages
  • Review expo prebuild behavior change (now clears android/ios by default)
  • Test edge-to-edge layout on Android for regressions
  • Verify expo-image new cache APIs if used (writeToCacheAsync / readFromCacheAsync)
  • Check expo-router Stack.Toolbar.Badge on Android if toolbars are used

Out of scope: React 19 upgrade (unchanged from SDK 56), Expo Go App Store availability (pending), new Expo Router features beyond badge support.

Dependencies: Existing Expo SDK 56 project. EAS Build or local build toolchain configured.

Acceptance criteria:

  • npx expo install expo@latest --fix completes without peer-dependency conflicts
  • App builds successfully on iOS and Android
  • Edge-to-edge screens on Android render system bars correctly
  • All existing screens render without visual regressions in light and dark mode

Estimated effort: S

**Copy/paste this prompt:**

Implement the following React Native chunk for your mobile app: Upgrade from Expo SDK 56 to Expo SDK 57.

Goal: Apply the Expo SDK 57 upgrade to get React Native 0.86, edge-to-edge Android improvements, and updated prebuild behavior.

Files to modify:

  • package.json (versions updated automatically by the install command)
  • app.json / app.config.js — set "sdkVersion": "57.0.0" if hardcoded
  • android/ and ios/ — regenerated by expo prebuild if running a clean build

Step-by-step:

  1. Run npx expo install expo@latest --fix. Review the diff carefully.
  2. Run npx expo-doctor to identify remaining version mismatches.
  3. If you manage native directories, run npx expo prebuild --clean (this now clears android/ and ios/ — stash custom native code first).
  4. Build for Android: eas build --platform android --profile preview.
  5. Build for iOS: eas build --platform ios --profile preview.
  6. On Android, scroll through edge-to-edge screens and verify status/navigation bar areas are correct.
  7. In React Native DevTools, toggle light/dark mode emulation and verify themed components respond correctly.
  8. Optionally test expo-image writeToCacheAsync to pre-warm the image cache on startup.

Acceptance criteria checklist:

  • npx expo install expo@latest --fix exits with no errors
  • npx expo-doctor reports no critical issues
  • App launches on Android emulator without crashes
  • App launches on iOS simulator without crashes
  • Edge-to-edge screens look correct on Android 15
  • No TypeScript type errors introduced by the upgrade

🟧 Chunk 4 — Add In-Store Card Payments to an Expo App

Goal: Integrate in-store (physical card reader) payments into an Expo app using Stripe Terminal SDK, following the Tapaya POS case study pattern: a complete NFC/tap-to-pay flow shippable in under one day.

Scope:

  • Install and configure @stripe/stripe-terminal-react-native
  • Implement reader discovery and connection UI
  • Build a payment intent creation → collect → confirm flow
  • Add a transaction result screen (success / failure states)

Out of scope: Cloud-based Stripe Checkout, subscription billing, multi-currency support, receipt printing.

Dependencies: Stripe account with Terminal enabled, Expo with expo-dev-client (custom native build required), Stripe simulated reader for testing.

Acceptance criteria:

  • App discovers and connects to a Stripe simulated reader in test mode
  • A test payment of $1.00 processes end-to-end without errors
  • Success and failure states are correctly displayed
  • No Stripe secret keys are exposed in the client bundle

Estimated effort: M

**Copy/paste this prompt:**

Implement the following React Native chunk for your Expo app: Add in-store card payment support using Stripe Terminal.

Goal: Enable physical card reader payments (tap-to-pay / insert) in an Expo managed workflow app using @stripe/stripe-terminal-react-native.

Files to create/modify:

  • app/_layout.tsx — wrap root with StripeTerminalProvider
  • app/payment/index.tsx — main payment screen (reader discovery + payment flow)
  • app/payment/success.tsx — success screen after confirmed payment
  • plugins/stripe-terminal.js — Expo config plugin for native permissions
  • app.config.js — register the config plugin

Step-by-step:

  1. Install: npx expo install @stripe/stripe-terminal-react-native.
  2. Add plugins: [["./plugins/stripe-terminal.js"]] to app.config.js.
  3. Run npx expo prebuild to add Bluetooth and NFC permissions to native projects.
  4. In app/_layout.tsx, wrap <Slot /> with <StripeTerminalProvider fetchTokenProvider={fetchConnectionToken} logLevel="verbose">.
  5. Implement fetchConnectionToken — call your backend /connection-token endpoint (never expose the Stripe secret key).
  6. In app/payment/index.tsx: a. Use useStripeTerminal() to get discoverReaders, connectLocalMobileReader, createPaymentIntent, collectPaymentMethod, confirmPaymentIntent. b. On mount, call discoverReaders({ discoveryMethod: 'localMobile', simulated: true }). c. Show discovered readers; call connectLocalMobileReader(reader) on tap. d. On "Charge" press: create intent → collect → confirm.
  7. Navigate to app/payment/success.tsx on confirmed payment.
  8. Test fully with the simulated reader — no physical hardware needed.

Acceptance criteria checklist:

  • App builds with expo-dev-client without errors
  • Simulated reader appears in discovery list within 5 s
  • A $1.00 simulated payment completes end-to-end
  • Success screen displays payment ID and amount
  • Declined card shows a user-friendly error message
  • No Stripe secret key present in the JS bundle (grep -r "sk_" . returns nothing)

⚛️ Chunk 5 — Integrate Meta's Astryx Design System Components

Goal: Adopt selected components from Meta's newly released Astryx design system (React + StyleX, 160+ components) to standardize UI, accelerate screen development, and align with accessibility-first patterns across the app.

Scope:

  • Install @meta/astryx and @stylexjs/stylex
  • Set up the StyleX Babel/Metro transform
  • Replace 2–3 existing UI primitives (Button, TextInput, Card) with Astryx equivalents
  • Configure theming tokens to match the app's existing brand colors

Out of scope: Full app-wide migration to Astryx, custom component creation, native module extensions, web-only features.

Dependencies: React 18+ (React Native compatible), Metro bundler. Verify React Native compatibility of Astryx components before a full rollout.

Acceptance criteria:

  • @meta/astryx installs without peer-dependency conflicts
  • StyleX transforms compile correctly through Metro
  • Replaced Button, TextInput, and Card components render correctly on iOS and Android
  • Light/dark theming toggle applies Astryx theme tokens correctly

Estimated effort: M

**Copy/paste this prompt:**

Implement the following React Native chunk for your app: Integrate selected Meta Astryx design system components.

Goal: Replace 2–3 core UI primitives with Meta's Astryx components (React + StyleX) to evaluate the design system for wider adoption.

Files to create/modify:

  • babel.config.js — add StyleX Babel plugin
  • metro.config.js — add StyleX Metro resolver
  • src/components/Button.tsx — swap internals to use <astryx.Button>
  • src/components/TextInput.tsx — swap to <astryx.TextInput>
  • src/theme/tokens.ts — map brand color tokens to Astryx theme variables

Step-by-step:

  1. Install: npm install @meta/astryx @stylexjs/stylex and dev dep @stylexjs/babel-plugin.
  2. In babel.config.js, add ["@stylexjs/babel-plugin", { "dev": true, "test": true }] to plugins.
  3. In metro.config.js, configure StyleX atomic CSS resolution (follow the official StyleX Metro guide).
  4. Render a smoke-test <astryx.Button label="Test" onPress={() => {}} /> in a throwaway screen to verify it renders without errors.
  5. Replace src/components/Button.tsx: import Astryx Button, forward props (label, onPress, disabled, variant), remove old StyleSheet rules.
  6. Repeat for TextInput and Card.
  7. Run on iOS and Android simulators and screenshot the replaced components.
  8. Toggle system dark mode and verify Astryx theme tokens apply correctly.

Acceptance criteria checklist:

  • StyleX Babel plugin compiles without errors through Metro
  • Astryx Button renders on iOS simulator
  • Astryx Button renders on Android emulator
  • Dark mode toggle changes Astryx theme tokens visibly
  • No TypeScript errors in replaced component files
  • Existing snapshot tests (if any) are updated to reflect new markup