Skip to content
This repository was archived by the owner on Oct 27, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ A React Native application built with Expo v54 and [Porto](https://porto.sh) for
- [Node.js](https://nodejs.org/) (LTS)
- [Yarn Classic](https://classic.yarnpkg.com/) (v1.22+)
- [Expo CLI](https://docs.expo.dev/get-started/installation/)
- For iOS development: Xcode and iOS Simulator
- For iOS development: XCode and iOS Simulator
- For Android development: Android Studio and Android SDK
- For EAS Builds: EAS CLI (for running EAS Build locally)

### Installation

1. **Clone and install dependencies:**

```bash
git clone <your-fork-url>
cd porto-rn
gh repo clone o-az/porto-react-native
cd porto-react-native
yarn install
```

Expand All @@ -32,12 +33,24 @@ A React Native application built with Expo v54 and [Porto](https://porto.sh) for

### Running the App

- **Start development server:** `yarn dev` or `yarn expo start`
- **Start with dev client:** `yarn start`
- **Run on iOS:** `yarn ios`
- **Run on Android:** `yarn android`
- **Run on Web:** `yarn web`
- **Clear cache and restart:** `just clear`
```sh
yarn expo start --clear --tunnel --no-build-cache --dev-client
```

Press:

- `a` to run on Android. If your physical device is connected, it will automatically select it,
- `shift + a` to view Android options,
- `i` for iOS. Note that passkeys are not supported on iOS Simulator so you need to use an actual device,
- `w` for Web.

### Crypto/Buffer setup (React Native)

We install `react-native-quick-crypto` at startup (see `shims/crypto-bridge.js`).
It provides `globalThis.crypto` (including `subtle`) and `Buffer`, so no custom Metro aliases or
extra shims are needed for `crypto`, `buffer`, or `@noble/hashes`.

Metro is configured to prefer ESM (e.g., for `viem`) via package exports, avoiding Node-only CJS deps.

### Available Commands (via [just](https://github.com/casey/just))

Expand Down Expand Up @@ -180,7 +193,7 @@ keytool -list -v -keystore your-release-key.keystore -alias your-alias
## Useful Links

- [Expo Documentation](https://docs.expo.dev/)
- [Porto Documentation](https://context7.com/ithacaxyz/porto/llms.txt)
- [Porto Documentation](https://porto.sh)
- [Apple Universal Links](https://developer.apple.com/ios/universal-links/)
- [Android App Links](https://developer.android.com/training/app-links)
- [WebAuthn/Passkeys Guide](https://webauthn.guide/)
14 changes: 1 addition & 13 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,6 @@ module.exports = (api) => {
},
],
],
plugins: [
'babel-plugin-transform-import-meta',
[
'module-resolver',
{
alias: {
stream: 'readable-stream',
crypto: 'react-native-quick-crypto',
buffer: '@craftzdog/react-native-buffer',
},
},
],
],
plugins: ['babel-plugin-transform-import-meta'],
}
}
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.3/schema.json",
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
Expand Down
8 changes: 8 additions & 0 deletions eas.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
},
"production": {
"autoIncrement": true
},
"development-simulator": {
"developmentClient": true,
"distribution": "internal",
"ios": {
"simulator": true
},
"environment": "development"
}
},
"submit": {
Expand Down
11 changes: 3 additions & 8 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import 'react-native-get-random-values'

try {
if (!global.crypto || typeof global.crypto.getRandomValues !== 'function') {
const QuickCrypto = require('react-native-quick-crypto')
if (QuickCrypto?.install) QuickCrypto.install()
}
} catch {}
// ensure required polyfills are in place before routing loads
import './shims/crypto-bridge.js'
import '@bacons/text-decoder/install'

import 'expo-router/entry'
42 changes: 27 additions & 15 deletions metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,29 @@ const { getDefaultConfig } = require('expo/metro-config')
const defaultConfiguration = getDefaultConfig(__dirname)

/** @type {MetroConfig} */
const configuration = {
module.exports = {
...defaultConfiguration,
resolver: {
...defaultConfiguration.resolver,
// Prefer ESM when available for packages that ship both builds.
unstable_conditionNames: [
...(defaultConfiguration.resolver.unstable_conditionNames || []),
'import',
],
resolverMainFields: ['react-native', 'browser', 'module', 'main'],
resolveRequest: (context, moduleName, platform) => {
// prefer CJS to avoid `window.*` APIs
// Ensure @noble/hashes reads crypto from globalThis at access time
if (
moduleName === '@noble/hashes/crypto' ||
moduleName === '@noble/hashes/crypto.js'
) {
return {
type: 'sourceFile',
filePath: require.resolve('./shims/crypto-bridge.js'),
}
}

// Prefer CJS for ox & @noble/hashes to avoid `window.*` usage in ESM builds
if (
moduleName.startsWith('ox') ||
moduleName.startsWith('@noble/hashes')
Expand All @@ -25,7 +42,13 @@ const configuration = {
}
}

// Prefer ESM avoid ws/node deps from CJS
// Force CJS build for punycode to interop with CJS consumers (e.g., whatwg-url)
if (moduleName === 'punycode' || moduleName.startsWith('punycode/')) {
const filePath = require.resolve('punycode/punycode.js')
return { type: 'sourceFile', filePath }
}

// Prefer ESM for viem to avoid ws/node deps from CJS.
if (moduleName === 'viem' || moduleName.startsWith('viem/')) {
const pkgDir = path.dirname(require.resolve('viem/package.json'))
const subpath =
Expand All @@ -36,6 +59,7 @@ const configuration = {
return { type: 'sourceFile', filePath: file }
}

// Map Node builtins to RN shims when needed
if (
(moduleName === 'crypto' || moduleName === 'node:crypto') &&
platform !== 'web'
Expand All @@ -46,11 +70,9 @@ const configuration = {
platform,
)
}

if (moduleName === 'stream' || moduleName === 'node:stream') {
return context.resolveRequest(context, 'readable-stream', platform)
}

if (moduleName === 'buffer' || moduleName === 'node:buffer') {
return context.resolveRequest(
context,
Expand All @@ -62,14 +84,4 @@ const configuration = {
return context.resolveRequest(context, moduleName, platform)
},
},
server: {
...defaultConfiguration.server,
forwardClientLogs: true,
},
watcher: {
...defaultConfiguration.watcher,
healthCheck: { enabled: true },
},
}

module.exports = configuration
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,29 @@
"@bacons/text-decoder": "^0.0.0",
"@craftzdog/react-native-buffer": "^6.1.0",
"@expo/metro-runtime": "~6.1.1",
"@expo/ui": "~0.2.0-alpha.9",
"@expo/ui": "^0.2.0-beta.0",
"@hexagon/base64": "^2.0.4",
"buffer": "^6.0.3",
"expo": "54.0.0-preview.16",
"expo": "^54.0.1",
"expo-application": "~7.0.6",
"expo-blob": "^0.1.0",
"expo-build-properties": "~1.0.7",
"expo-constants": "~18.0.7",
"expo-constants": "~18.0.8",
"expo-crypto": "~15.0.6",
"expo-dev-client": "~6.0.9",
"expo-dev-client": "~6.0.11",
"expo-device": "~8.0.6",
"expo-linking": "~8.0.7",
"expo-local-authentication": "~17.0.6",
"expo-network": "~8.0.6",
"expo-router": "~6.0.0-preview.16",
"expo-router": "^6.0.0",
"expo-secure-store": "~15.0.6",
"expo-status-bar": "~3.0.7",
"expo-web-browser": "~15.0.6",
"ox": "^0.9.6",
"porto": "^0.0.87",
"porto": "^0.1.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "^0.81.0",
"react-native": "0.81.4",
"react-native-get-random-values": "~1.11.0",
"react-native-passkeys": "^0.3.3",
"react-native-quick-base64": "^2.2.2",
Expand All @@ -56,11 +56,11 @@
"react-native-webview": "13.15.0",
"react-native-worklets": "~0.5.0",
"readable-stream": "^4.7.0",
"viem": "^2.37.4"
"viem": "^2.37.5"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@biomejs/biome": "^2.2.3",
"@biomejs/biome": "^2.2.4",
"@types/babel__core": "^7.20.5",
"@types/bun": "^1.2.21",
"@types/node": "^24.3.1",
Expand All @@ -75,6 +75,9 @@
"tsx": "^4.20.5",
"typescript": "~5.9.2"
},
"resolutions": {
"expo-dev-menu": "^7.0.10"
},
"private": true,
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
56 changes: 0 additions & 56 deletions patches/@noble+hashes+1.8.0.patch

This file was deleted.

Loading