DEV Community

Cover image for Using react-native-web with Webpack in a Nx monorepo
Emily Xiong
Emily Xiong

Posted on

2

Using react-native-web with Webpack in a Nx monorepo

This blog shows how to add a web app using react-native-web with Webpack as the bundler in a Nx monorepo.

Github Repo: https://github.com/xiongemi/nx-react-native-monorepo-jokes

Installation

First, I need to install react-native-web:

# npm
npm install react-native-web --save-dev

# yarn
yarn add react-native-web --dev

# pnpm
pnpm add react-native-web --save-dev
Enter fullscreen mode Exit fullscreen mode

Add a React App in the Nx Monorepo

Run command:

npx nx g @nx/react:app <web app name>
Enter fullscreen mode Exit fullscreen mode

In the terminal output, select webpack as bundler:

>  NX  Generating @nx/react:application

✔ Which stylesheet format would you like to use? · none
✔ Would you like to add React Router to this application? (y/N) · false
✔ Which E2E test runner would you like to use? · none
✔ Which bundler do you want to use to build the application? · webpack
Enter fullscreen mode Exit fullscreen mode

Import the Native App

In the web app, in apps/<web app name>/src/main.tsx, change the import of App to:

// eslint-disable-next-line @nx/enforce-module-boundaries
import App from '../../<native app name>/src/app/App';
Enter fullscreen mode Exit fullscreen mode

Also, in web app's project.json, add implicitDependencies:

  "implicitDependencies": ["<native app name>"]
Enter fullscreen mode Exit fullscreen mode

Add Alias in webpack.config.ts

In apps/techy-jokes-webpack/webpack.config.ts, add below alias:

  config.resolve.alias = {
    ...config.resolve?.alias ?? {},
    'react-native$': 'react-native-web',
  };
Enter fullscreen mode Exit fullscreen mode

Change index.html to be full height

In the index.html, change the:

  • style="height: 100%" to html tag
  • style="min-height: 100%" to body tag
  • style="display: flex; min-height: 100vh" to div with root id

These style changes are taken from examples in https://reactnavigation.org/docs/server-rendering.

So the index.html would look like:

<!DOCTYPE html>
<html lang="en" style="height: 100%">
  <head>
    ...
  </head>
  <body style="min-height: 100%">
    <div id="root" style="display: flex; min-height: 100vh"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Then that is it, I can now view the web app using npx nx serve <web app name>.


Troubleshooting

react-native-vector-icons

Because I use react-native-vector-icons, I got this error:

ERROR in ../../node_modules/react-native-vector-icons/lib/create-icon-set.js 70:8
Module parse failed: Unexpected token (70:8)
File was processed with these loaders:
 * ../../node_modules/source-map-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| 
|       return (
>         <Text selectable={false} {...props}>
|           {glyph}
|           {children}

webpack compiled with 1 error (af4bf9f7c72b44dc)
Enter fullscreen mode Exit fullscreen mode

This happens because react-native-vector-icons contains jsx code (e.g. <Text>) inside .js file.

First, I need to add files with .web to the extensions (the order of the extension in the array actually matters):

  config.resolve.extensions = [
    '.web.tsx',
    '.web.ts',
    '.web.jsx',
    '.web.js',
    ...config.resolve.extensions,
  ];
Enter fullscreen mode Exit fullscreen mode

Then I need to add a rule to load the .js file from react-native-vector-icons using babel loader (https://stackoverflow.com/questions/56750269/react-native-web-failed-to-compile-react-native-vector-icons):

  config.module.rules.push({
    test: /\.(js|jsx)$/,
    include: /react-native-vector-icons/,
    loader: 'babel-loader',
    options: {
      presets: [
        '@babel/preset-env',
        ['@babel/preset-react', { runtime: 'automatic' }],
      ],
    },
  });
Enter fullscreen mode Exit fullscreen mode

When I serve up the web app, I will get this error message:

MaterialCommunityIcon.tsx:49 Error: Dynamic require of "react-native-vector-icons/MaterialCommunityIcons" is not supported
Enter fullscreen mode Exit fullscreen mode

I copy the font file from react-native-vector-icons library to the src/assets folder: https://github.com/oblador/react-native-vector-icons/tree/master/Fonts.
So in my web app's index.html, I need to add:

    <style type="text/css">
      @font-face {
        font-family: 'MaterialCommunityIcons';
        src: url('/assets/MaterialCommunityIcons.ttf') format('truetype');
      }
    </style>
Enter fullscreen mode Exit fullscreen mode

Now build command (nx build <web app name>) should work.


The final webpack.config.js would look like:

const { composePlugins, withNx } = require('@nx/webpack');
const { withReact } = require('@nx/react');

// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config) => {
  // Update the webpack config as needed here.
  // e.g. `config.plugins.push(new MyPlugin())`
  config.resolve.alias = {
    ...config.resolve?.alias ?? {},
    'react-native$': 'react-native-web',
  };
  config.resolve.extensions = [
    '.web.tsx',
    '.web.ts',
    '.web.jsx',
    '.web.js',
    ...config.resolve.extensions,
  ];
  config.module.rules.push({
    test: /\.(js|jsx)$/,
    include: /react-native-vector-icons/,
    loader: 'babel-loader',
    options: {
      presets: [
        '@babel/preset-env',
        ['@babel/preset-react', { runtime: 'automatic' }],
      ],
    },
  });
  return config;
});

Enter fullscreen mode Exit fullscreen mode

Deploy to GitHub Pages

GitHub Pages is designed to host your personal, organization, or project pages from a GitHub repository.

To deploy this web app to GitHub page:

  • Install gh-pages ``` # npm npm install gh-pages --save-dev

yarn

yarn add gh-pages --dev

pnpm

pnpm add gh-pages --save-dev


- Create a script called `gh-pages.js` under the app:
Enter fullscreen mode Exit fullscreen mode

var ghpages = require('gh-pages');

ghpages.publish('', function (err) {
if (!err) {
console.error(err);
}
});


For this example, the `gh-pages.js` look like:
Enter fullscreen mode Exit fullscreen mode

var ghpages = require('gh-pages');

ghpages.publish('../../dist/apps/techy-jokes-webpack', function (err) {
if (!err) {
console.error(err);
}
});


- If your GitHub has a base href, run the build command with `--baseHref`. For example, my GitHub page is at https://xiongemi.github.io/nx-react-native-monorepo-jokes/, to build for it, the command is `nx build techy-jokes-webpack --baseHref=/nx-react-native-monorepo-jokes/`.

- Add a target in project.json:
Enter fullscreen mode Exit fullscreen mode
"gh-pages": {
  "command": "npx nx build <app name> --base=<app base href> --prod && node gh-pages.js",
  "cwd": "{projectRoot}"
},
Enter fullscreen mode Exit fullscreen mode

For this example, the target would be:
Enter fullscreen mode Exit fullscreen mode
"gh-pages": {
  "command": "npx nx build techy-jokes-webpack --prod --baseHref=/nx-react-native-monorepo-jokes && node gh-pages.js",
  "cwd": "{projectRoot}"
},
Enter fullscreen mode Exit fullscreen mode

Now you can run the command `nx gh-pages <your app name>` to deploy your app to GitHub Pages.

---
## Nx Graph

If you run command `nx graph`, you should see the web app implict depends on the react native mobile app:


![nx dependency graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcdbru3zwq12aaech5wn.png)
Enter fullscreen mode Exit fullscreen mode

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more