Skip to main content

Bundler polyfill issues - React Native Metro

This page documents how to configure Metro to handle Node.js polyfills required by the Embedded Wallets React Native SDK.

SDK v9 ships a single helper that configures Metro and polyfills automatically. No manual extraNodeModules is needed.

1. Install the SDK

npm install @web3auth/react-native-sdk
npm install --save-dev @babel/plugin-transform-export-namespace-from

2. Entry point — add setup import

Add import "@web3auth/react-native-sdk/setup" as the first line of your app's entry file:

index.js
import '@web3auth/react-native-sdk/setup' // must be first
import { AppRegistry } from 'react-native'
import App from './App'
import { name as appName } from './app.json'
AppRegistry.registerComponent(appName, () => App)

3. Update metro.config.js

metro.config.js
const { getDefaultConfig } = require('@react-native/metro-config')
const { withWeb3Auth } = require('@web3auth/react-native-sdk/metro-config')

const config = getDefaultConfig(__dirname)
module.exports = withWeb3Auth(config)

withWeb3Auth applies all required polyfill aliases (crypto, stream, buffer, and so on) internally. You can still add custom sourceExts or other resolver options after calling it.

4. Update babel.config.js

Add @babel/plugin-transform-export-namespace-from. Without it, Metro fails to parse some SDK internal re-exports.

babel.config.js
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['@babel/plugin-transform-export-namespace-from'],
}

v8 (legacy manual setup)

If you are still using @web3auth/react-native-sdk@^8.x, follow the manual polyfill steps below. We recommend upgrading to v9.

1. Install polyfill packages

npm install --save empty-module readable-stream crypto-browserify react-native-get-random-values buffer process

2. metro.config.js (v8)

metro.config.js
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
const defaultConfig = getDefaultConfig(__dirname)

const config = {
resolver: {
extraNodeModules: {
assert: require.resolve('empty-module'),
http: require.resolve('empty-module'),
https: require.resolve('empty-module'),
os: require.resolve('empty-module'),
url: require.resolve('empty-module'),
zlib: require.resolve('empty-module'),
path: require.resolve('empty-module'),
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('readable-stream'),
},
sourceExts: [...defaultConfig.resolver.sourceExts, 'svg'],
},
}

module.exports = mergeConfig(defaultConfig, config)

3. globals.js and entry point (v8)

Create globals.js at your project root:

globals.js
global.Buffer = require('buffer').Buffer
global.location = { protocol: 'file:' }
global.process.version = 'v16.0.0'
if (!global.process.version) {
global.process = require('process')
}
process.browser = true

Then import it in your entry point:

index.js
import { AppRegistry } from 'react-native'
import './globals'
import 'react-native-get-random-values'
import App from './App'
import { name as appName } from './app.json'
AppRegistry.registerComponent(appName, () => App)