react-native-esbuild v0.6.0
Features
- Fast – ~10-50x faster depending on project
- Tree shaking – Smaller bundles means faster apps (21% smaller for
initproject) - Compatible – Drop-in replacement for metro
- Configurable – Support for custom transformers and env variables
Sponsoring
If this library helped you, please consider sponsoring.
Installation
yarn add react-native-esbuild esbuildConfiguration
react-native CLI plugin
Make sure react-native.config.js exists in the root of your project, and create one if not. Add this library to the commands section like this:
// react-native.config.js
const { commands } = require('react-native-esbuild');
module.exports = {
commands,
};Optional: Esbuild settings
If you want to customize the esbuild configuration, for example by adding your own plugins you may do so with the createEsbuildCommands function:
// react-native.config.js
const { createEsbuildCommands, babelPlugin } = require('react-native-esbuild');
// See https://esbuild.github.io/api/#simple-options
const commands = createEsbuildCommands((config) => ({
...config,
plugins: config.plugins.concat(
babelPlugin({
filter: /src\/my-babel-components\/.+\.[tj]sx?$/,
})
),
}));
module.exports = {
commands,
};Optional: Use esbuild for development
- Open
package.jsonin your editor and locatescriptssection. - Edit
startscript to bereact-native esbuild-start. - Prevent metro from starting automatically by appending
--no-packagerto theios/androidscripts.
{
"scripts": {
"android": "react-native run-android --no-packager",
"ios": "react-native run-ios --no-packager",
"start": "react-native esbuild-start"
}
}Optional: Build production app with esbuild
Android
Set project.ext.react.bundleCommand to esbuild-bundle in android/app/build.gradle:
// android/app/build.gradle
project.ext.react = [
enableHermes: false,
bundleCommand: "esbuild-bundle",
]iOS
- Open your iOS project in Xcode manually or with
xed ios - Select the
Build Phasestab in your project settings. - Expand the
Bundle React Native code and imagessection and addexport BUNDLE_COMMAND=esbuild-bundleso it looks like this:
set -e
export BUNDLE_COMMAND=esbuild-bundle
export NODE_BINARY=node
../node_modules/react-native/scripts/react-native-xcode.shUsage
This library aims to be a plug-in replacement for the metro equivalent commands with the esbuild- prefix.
react-native esbuild-start
| Argument | Description | Default |
|---|---|---|
--port | Port to listen for http requests | 8081 |
--host | Host to listen for http requests | 127.0.0.1 |
--projectRoot | Path to a custom project root. | None |
--reset-cache | Removes cached files. | N/A |
--no-interactive | Disables interactive mode. | false |
react-native esbuild-bundle
| Argument | Description | Default |
|---|---|---|
--entry-file | Path to the root JS file, either absolute or relative to JS root | index.js |
--platform | Either ios or android | ios |
--dev | If false, warnings are disabled and the bundle is minified | true |
--minify | Allows overriding whether bundle is minified otherwise determined by dev value. | Opposite of dev |
--bundle-output | File name where to store the resulting bundle. | None |
--sourcemap-output | File name where to store the sourcemap file for resulting bundle. | None |
--assets-dest | Directory name where to store assets referenced in the bundle. | None |
--reset-cache | Removes cached files. | N/A |
Troubleshooting
Flow syntax errors such as Expected "from" but found "{"
Esbuild doesn't natively support flow so such syntax needs to be stripped with a plugin. By default any file with @flow or @noflow pragmas will be stripped from flow, but you may also opt-in to flow stripping for more files by passing a custom flow syntax checker:
// react-native.config.js
const {
createEsbuildCommands,
defaultHasFlowSyntax,
syntaxAwareLoaderPlugin,
} = require('react-native-esbuild');
const FLOW_MODULES_WITHOUT_PRAGMA = ['react-native-video', 'rn-fetch-blob'];
const commands = createEsbuildCommands((config, args) => ({
...config,
plugins: config.plugins
.filter((plugin) => plugin.name !== 'syntax-aware-loader')
.concat(
syntaxAwareLoaderPlugin({
filter: /\.([mc]js|[tj]sx?)$/,
cache: args.dev,
hasFlowSyntax: (contents, filePath) =>
defaultHasFlowSyntax(contents, filePath) ||
FLOW_MODULES_WITHOUT_PRAGMA.find((m) =>
filePath.includes(`node_modules/${m}/`)
),
})
),
}));
module.exports = {
commands,
};Limitations
Hermes engine
Hermes doesn't support crucial ES6 features like block level scoping (let/const) and the team doesn't seem to want to merge this feature mentioning it being a too big of a change without having good enough reasons to add it.
HMR/Fast Refresh
Esbuild doesn't support Fast Refresh or Hot Module Replacement, but this library supports live reload instead.
License
MIT © Joel Arvidsson 2022-