@rm30/metro-config
v0.1.0
Published
Shared RM30 Metro configuration for Expo monorepos.
Maintainers
Readme
@rm30/metro-config
The shared Metro configuration for RM30's Expo apps.
pnpm add -D @rm30/metro-config// apps/mobile/metro.config.cjs
const { getDefaultConfig } = require('expo/metro-config')
const { withRm30Metro } = require('@rm30/metro-config')
module.exports = withRm30Metro(getDefaultConfig(__dirname), {
workspaceAliases: { '@myproject/types': '../../packages/types/src' },
uniwind: { cssEntryFile: './global.css', dtsFile: './src/uniwind-types.d.ts' },
})Why the base config is passed in
The projects do not agree on how the base config is made, and both ways are right:
most call getDefaultConfig from expo/metro-config, while superwallet calls
getSentryExpoConfig so Sentry can attach to the bundle. Creating the config inside this
package would take that choice away, so it takes one instead.
const { getSentryExpoConfig } = require('@sentry/react-native/metro')
module.exports = withRm30Metro(getSentryExpoConfig(__dirname), { /* … */ })Options
| Option | Default | |
|---|---|---|
| projectRoot | config.projectRoot | Throws if neither is set, rather than silently building paths from undefined. |
| workspaceAliases | {} | Package name to path, absolute or relative to projectRoot. |
| blockList | [] | Extra patterns, added to the built-in test-file ones. |
| platforms | ios, android, native, web | |
| uniwind | omitted | { cssEntryFile, dtsFile }, or omitted/false to skip the wrapper. |
What it does for you
- Blocks test files from the bundle. All three apps had their own copy of the same two regexes.
- Adds every alias target to
watchFolders. Metro watches only the project root by default, so a symlinked workspace package outside it is read once and never again — edits to a shared package appear to do nothing until the bundler is restarted. This is the single easiest thing to forget, which is why it is automatic here. - Applies Uniwind outermost. It has to be the last wrapper, and doing it by hand is how it ends up in the wrong place.
watchFolders are merged and de-duplicated, so passing an alias that is already watched
is harmless.
Project-specific blocks stay in the project
superpool blocks Hardhat's build output:
blockList: [/[/\\]packages[/\\]contracts[/\\](cache|artifacts|coverage|typechain-types)[/\\].*/]That is not shared policy — it exists because Metro watches the whole monorepo while
Hardhat creates and deletes lock files under packages/contracts/cache during compilation,
and a file vanishing mid-watch kills the watcher with ENOENT, taking the dev server down
whenever contracts are compiled. Real variance, and it belongs where the reason lives.
