esbuild & react-native-web - II
Tags: esbuild
Published: 2021-01-10 15:02:06

In our previous [post](https://dev.to/dalcib/esbuild-react-native-web-i-afn), we used `esbuild` to transpile, bundle and minify a very simple `react-native-web` project. 
Now, in this post, let's try a more complex project, a clone of the GoogleFit app. The original repository is [https://github.com/Chandankkrr/googlefit](https://github.com/Chandankkrr/googlefit) and the author wrote an [article](https://levelup.gitconnected.com/lets-build-a-google-fit-component-81139bb06e36) about how he built the app. 
We choose this project because it uses Typescript, Expo, react-navigation 5.0, react-native-svg and react-native-paper. 
## Previous setup
First of all, let's remember what we did in the last post:
- Install Esbuild: `npm i -g esbuild` or `npm i esbuild`.
- Create a [`./web/index.html`](https://github.com/dalcib/rnw-esbuild/blob/master/web/index.html) file
- Alias `react-native` to `react-native-web` in the [`tsconfig.json`](https://github.com/dalcib/rnw-esbuild/blob/master/jsconfig.json).
`  {"compilerOptions": {..., "baseUrl": ".", "paths": {"react-native": ["./node_modules/react-native-web"]}}}`
- Execute Esbuild with this command: `esbuild --bundle node_modules/expo/AppEntry.js --outfile=./web/bundle.js --resolve-extensions=.web.tsx,.web.ts,.web.jsx,.web.js,.tsx,.ts,.jsx,.js --loader:.js=jsx  '--define:process.env.NODE_ENV="production"' --tsconfig=tsconfig.json --minify --sourcemap`. 
- The command can be replaced for a build script:
```javascript
require('esbuild').build({
  entryPoints: ['./node_modules/expo/AppEntry.js'],
  bundle: true,
  outfile: './web/bundle.js',
  tsconfig: 'jsconfig.json',
  define: {'process.env.NODE_ENV': '"production"'},
  resolveExtensions: ['.web.jsx','.web.js','.jsx','.js',],
  minify: true,
  sourcemap: true
}).catch(() => process.exit(1))
```

## Fixing the issues
Running the above command, we will see several errors related to the .png and .font files. To fix it, we need to include the following arguments in our command: `--loader:.png=file --loader:.ttf=file`. It will copy these files to the web directory.

We also need to change `jsconfig.json` to `tsconfig.json` and included the extensions `.web.tsx,.web.ts,.tsx,.ts`, because we are using Typescript now.

Some libraries use `.js` files for JSX instead of `.jsx`. To guide Esbuild how to use `.js` with React, we need to include `--loader:.js=jsx` in the command line or the loader ` {".js": "jsx"}` in the build script.

After building the app, when we open the HTML page, the browser complains that `global` and `__DEV__` are not define. Therefore, we need to include `--define:__DEV__=false --define:global=window`in the command line or `define: {'process.env.NODE_ENV': '"production"', '__DEV__': false, global:'window'}` in the build script. `process.env.NODE_ENV` and`__DEV__` must be defined appropriately, according to the environment.

The new command line is:

```cmd
$ esbuild ./node_modules/expo/AppEntry.js --bundle --outfile=./web/bundle.js --resolve-extensions=.web.tsx,.web.ts,.web.jsx,.web.js,.tsx,.ts,.jsx,.js --loader:.js=jsx --loader:.png=file --loader:.ttf=file --tsconfig=tsconfig.json  --define:__DEV__=false --define:process.env.NODE_ENV='\"production\"' --define:global=window --sourcemap --minify 
```

And the new build script:

```javascript
require('esbuild').build({
  entryPoints: ['./node_modules/expo/AppEntry.js'],
  bundle: true,
  outfile: './web/bundle.js',
  tsconfig: 'tsconfig.json',
  define: {'process.env.NODE_ENV': '"production"', '__DEV__': false, global:'window'},
  loader: {".png": "file", ".ttf": "file", ".js": "jsx" },
  resolveExtensions: ['.web.tsx','.web.ts','.web.jsx','.web.js','.tsx','.ts','.jsx','.js',],
  minify: true,
  sourcemap: true,
}).catch(() => process.exit(1))
```
## Result:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ngnixu2jiz6yok1mz4is.png)

## Plugins

Some react-native libraries like `react-native-gesture-handler` are distributed without transpilation and with Flow types annotations. Esbuild doesn't work with Flow out of the box. But Esbuild now supports plugins. 
It is not possible to use plugins with the command line, therefore, we need to use the build script.
First, we need to install the plugin: `npm i esbuild-plugin-flow`.
Next, we need require or import the package and to include this line in the build script: `plugins: [flow(/node_modules\\react-native-gesture-handler.*\.jsx?$/)]`. 
It is not necessary for this example (GoogleFit app).

## Why Esbuild?

The big question is, why to use Esbuild instead of WebPack or Metro?
The answers are easy to set up, as we could see, and performance.
In our next post, we will explore the performance of Esbuild compared with these alternatives.