📁 File path:
apps/weshipit/pages/plan/2026-W27.md
React Native Roadmap 2026-W27
Week of June 29–July 5, 2026
Items This Week
| # | Title | Label | Link |
|---|---|---|---|
| 1 | Rollipop: A Rust Replacement for Metro | 🟦 RN | Read |
| 2 | React Native Windows v0.84 | 🟦 RN | Read |
| 3 | Expo SDK 57 | 🟧 EXPO | Read |
| 4 | How Tapaya Added In-Store Card Payments to a POS App | 🟧 EXPO | Read |
| 5 | Chasing a Phantom Jump: Skia Animations on Low-End Android | 🟦 RN | Read |
| 6 | React Status #481 – Meta Releases Astryx Design System | ⚛️ REACT | Read |
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.jsto register Rollipop commands - Configure
rollipop.config.tsfor 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 startboots 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
$FlowFixMeerrors 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— registerrollipop/commandsrollipop.config.ts— generated by init, review and tweak for your monorepo if neededpackage.json— addrollipopdev dependency (done automatically by init)android/app/build.gradleandios/Podfile— wired automatically by init; verify no conflicts
Step-by-step:
- Run
npx @rollipop/initat the project root. Accept all prompts. - Open
react-native.config.jsand confirm it containscommands: require('rollipop/commands'). - Run
rollipop startand openhttp://localhost:8081/dashboardin a browser. - Launch your app on an iOS simulator with
react-native run-ios. - Launch your app on an Android emulator with
react-native run-android. - Make a source change and verify Fast Refresh updates the app without a full reload.
- Check the dashboard's "Bundle Preview" section to confirm no unexpectedly large modules.
Acceptance criteria checklist:
-
rollipop startexits 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 bySkiaTextureView - Switch to
opaqueprop 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:
- Audit all
<Canvas>usages:grep -r "<Canvas" src/. - For each canvas used in an animated transition, add the
opaqueprop:<Canvas opaque style={...}>. - Connect a budget Android device and enable GPU rendering profiling: Developer Options → "Profile GPU rendering → On screen as bars".
- Screenshot the GPU bars during the animation before the change.
- Apply the
opaquechange, rebuild, and rerun the same animation. - Screenshot the bars again — the green draw bar should drop by 30–60%.
- Use Perfetto trace to confirm no per-frame HWUI texture uploads for the canvas layer.
- 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
-
opaquecanvas 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 --fixto upgrade all Expo packages - Review
expo prebuildbehavior change (now clearsandroid/iosby default) - Test edge-to-edge layout on Android for regressions
- Verify
expo-imagenew cache APIs if used (writeToCacheAsync/readFromCacheAsync) - Check
expo-routerStack.Toolbar.Badgeon 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 --fixcompletes 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 hardcodedandroid/andios/— regenerated byexpo prebuildif running a clean build
Step-by-step:
- Run
npx expo install expo@latest --fix. Review the diff carefully. - Run
npx expo-doctorto identify remaining version mismatches. - If you manage native directories, run
npx expo prebuild --clean(this now clears android/ and ios/ — stash custom native code first). - Build for Android:
eas build --platform android --profile preview. - Build for iOS:
eas build --platform ios --profile preview. - On Android, scroll through edge-to-edge screens and verify status/navigation bar areas are correct.
- In React Native DevTools, toggle light/dark mode emulation and verify themed components respond correctly.
- Optionally test
expo-imagewriteToCacheAsyncto pre-warm the image cache on startup.
Acceptance criteria checklist:
-
npx expo install expo@latest --fixexits with no errors -
npx expo-doctorreports 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 withStripeTerminalProviderapp/payment/index.tsx— main payment screen (reader discovery + payment flow)app/payment/success.tsx— success screen after confirmed paymentplugins/stripe-terminal.js— Expo config plugin for native permissionsapp.config.js— register the config plugin
Step-by-step:
- Install:
npx expo install @stripe/stripe-terminal-react-native. - Add
plugins: [["./plugins/stripe-terminal.js"]]toapp.config.js. - Run
npx expo prebuildto add Bluetooth and NFC permissions to native projects. - In
app/_layout.tsx, wrap<Slot />with<StripeTerminalProvider fetchTokenProvider={fetchConnectionToken} logLevel="verbose">. - Implement
fetchConnectionToken— call your backend/connection-tokenendpoint (never expose the Stripe secret key). - In
app/payment/index.tsx: a. UseuseStripeTerminal()to getdiscoverReaders,connectLocalMobileReader,createPaymentIntent,collectPaymentMethod,confirmPaymentIntent. b. On mount, calldiscoverReaders({ discoveryMethod: 'localMobile', simulated: true }). c. Show discovered readers; callconnectLocalMobileReader(reader)on tap. d. On "Charge" press: create intent → collect → confirm. - Navigate to
app/payment/success.tsxon confirmed payment. - Test fully with the simulated reader — no physical hardware needed.
Acceptance criteria checklist:
- App builds with
expo-dev-clientwithout 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/astryxand@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/astryxinstalls 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 pluginmetro.config.js— add StyleX Metro resolversrc/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:
- Install:
npm install @meta/astryx @stylexjs/stylexand dev dep@stylexjs/babel-plugin. - In
babel.config.js, add["@stylexjs/babel-plugin", { "dev": true, "test": true }]to plugins. - In
metro.config.js, configure StyleX atomic CSS resolution (follow the official StyleX Metro guide). - Render a smoke-test
<astryx.Button label="Test" onPress={() => {}} />in a throwaway screen to verify it renders without errors. - Replace
src/components/Button.tsx: import Astryx Button, forward props (label, onPress, disabled, variant), remove old StyleSheet rules. - Repeat for
TextInputandCard. - Run on iOS and Android simulators and screenshot the replaced components.
- 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