DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 964,423 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Dalci Bagolin
Dalci Bagolin

Posted on • Updated on

esbuild & react-native-web - II

In our previous post, 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 and the author wrote an article 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 file
  • Alias react-native to react-native-web in the tsconfig.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:
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))
Enter fullscreen mode Exit fullscreen mode

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=windowin 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:

$ 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 
Enter fullscreen mode Exit fullscreen mode

And the new build script:

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))
Enter fullscreen mode Exit fullscreen mode

Result:

Alt Text

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.

Top comments (0)

🌚 Life is too short to browse without dark mode