Leaving it in production
Shipping the code is safe. One switch decides whether anything runs.
Shipping the code is safe. There is one switch, config.enabled, and with it off nothing is patched
and nothing is recorded, so the cost of leaving the package in a production bundle is the bundle size
and nothing else.
<DevtoolsProvider config={{ enabled: process.env.EXPO_PUBLIC_APP_ENV !== 'prod' }}>
<YourApp />
</DevtoolsProvider>The mount can stay exactly where it is. With enabled: false the provider renders its children and
the crash sheet and nothing else:
- No capture. The
fetch,XMLHttpRequest,WebSocketandconsolepatches are never installed, no store is ever read, and no navigator is watched. - No access. There is no launcher button, and
useDevtoolsPanel().show()opens nothing. That hook reportsenabledso your own trigger can hide itself rather than open an empty panel.
enabled is whatever condition you want, evaluated at runtime.
process.env.EXPO_PUBLIC_APP_ENV !== 'prod' from the Quick start and
__DEV__ are the two usual choices; anything else works too, including a value you fetch for a
specific user.
Read once, on the first render
The patches are global and go in one time, so the config that first render saw is the one that
applies. enabled cannot be flipped mid-session, and rebuilding the config object later changes
nothing.
That also settles the Debug tab, whose buttons call straight into the native module and are not restricted to development builds. They live behind the panel, and the panel is unreachable with the devtools off.
The two things that do run in production
- Crash reporting, if you asked for it.
crash: { enableWhileDevtoolsDisabled: true }installs the handlers even withenabled: false. It is the one subsystem meant to survive into a release build. See Crash reporting. - The
>prompt, in any build where the devtools are on.console.repldefaults totrueand is not gated on__DEV__, so a build withenabled: truegets a prompt that runs whatever is typed into it. Setconsole: { repl: false }for any build where that is not what you want.
Keeping secrets out of a build that records
A build with enabled: true, such as one for testers, keeps every request whole: headers, query
strings and bodies. Two options strip what should not be kept before a request is stored:
network.redactHeaderslists header names whose values are stored as[redacted].network.redact(entry)rewrites a request before it is stored, or returnsnullto drop it.
Both are on Network. navigation.redact does the same for a screen's
params, on Navigation, and crash.redact for a crash report, on
Crash reporting.
The Metro line
withDevtools in metro.config.js costs a release build nothing. All it adds to the config is
dev-server middleware, which nothing but a dev server reads, so the bundle is the same with it as
without. The tab itself registers only when __DEV__ is true, so a release bundle carries none of it.
Metro reads the config when it builds for release too, so keep @axonpack/expo-devtools in
dependencies, not devDependencies, if your release install skips dev dependencies. A __DEV__
check cannot guard the line: metro.config.js runs in Node, where __DEV__ does not exist.