The issue arises when creating React Native apps using Expo.js where you wish to have a local backend instead of a live url. Ngrok is used by many to accomplish this, however, if you are using a free account it can take some repeated effort to keep everything working
Free Ngrok urls are only available for 90 minutes, after which you need to restart it and get a fresh url
We can automate the process to make it as painless as possible
All files mentioned should be created in the project root beside package.json
Ensure axios and expo-constants are installed: expo add axios expo-constants
We will assume your local api is running on port 3333
First create a script called local
in package.json
:
"scripts": {
"start": "expo start",
"local": "node ngrokhandler.js && EXPO_NGROK=1 expo start",
...
}
Pass EXPO_NGROK=1
to expo start
that way app.config.js
can choose to load ngrok or just ingore it
Once you've added all the pieces, start the app locally using yarn run local
create a file ngrokhandler.js
Note: if this is your only tunnel, then the local ngrok server is on port 4040, if you have more than one this number increments, so note it when you start ngrok. If you see a number greater than 4040, you may have ngrok running elsewhere
const fs = require('fs')
const axios = require('axios')
// ngrok starts at port 4040
// subsequent tunnels are numbered 4040 + n
axios.get('http://127.0.0.1:4040/api/tunnels')
.then(resp => {
const httpsTunnel = resp.data.tunnels.find(t => t.proto==='https')
const url = httpsTunnel.public_url
fs.writeFileSync('./NGROK_URL', url)
})
.catch(e => {
console.log('START NGROK in another window: ngrok http 3333')
// exit err code so && in package json does not execute the expo start command
process.exit(2)
})
This writes the current https tunnel url to a text file called NGROK_URL
Create or modify app.config.js
:
const fs = require('fs')
// on production ngrokUrl will be null
// you don't need to have the file NGROK_URL
// in production
let ngrokUrl = null
if (process.env.EXPO_NGROK === '1') {
ngrokUrl = fs.readFileSync('./NGROK_URL', { encoding: 'utf8'})
}
export default ({ config }) => {
return {
...config,
extra: {
...config.extra,
ngrokUrl,
}
}
}
This brings in your app.json
via the config param and adds the ngrok url to the extra object. Put anything else you want to add in extra
You can then access this via expo-constants
. You probably don't want to use an ngrok url in production so we can turn it off by applying the __DEV__
variable expo provides:
Example: api.js
:
import Constants from 'expo-constants'
const { ngrokUrl } = Constants.manifest.extra
const isLocal = ngrokUrl && __DEV__
const productionUrl = 'https://example.com'
const baseUrl = isLocal ? ngrokUrl : productionUrl
// now we can export an object of api endpoints
export default {
login: `${baseUrl}/login`,
etc: ...
}
Get your api running on port 3333.
Open another terminal and enter ngrok http 3333
Now you can run the app using yarn run local
and the local url will be automatically added to the app. You have 90 minutes before you'll need to break the expo app and ngrok and re-run the commands (ctrl-c, up and enter in each terminal window)
Top comments (0)