DEV Community

Cover image for How to create React Native App for Android, iOS and Web without Expo
Shivam Sharma
Shivam Sharma

Posted on • Edited on

How to create React Native App for Android, iOS and Web without Expo

Note: This article is updated on 08-Aug-2021, to solve this StackOverflow issue, In this update, Creation of .babelrc is removed, babel.config.js & webpack.config.js are updated. The changes are equivalent to this commit.


In this article, we are going to see, how to create a React Native App which can run on Android, iOS and Web Browser. We'll NOT be using Expo in this process. For web support, we'll be using the package react-native-web.

I am using a Windows machine so I'll be showing the project run in Android and Web only. I am assuming that you have already downloaded and setup Node, NPM, Android SDK, Java and Emulator/Device for build and debugging purpose. If not, don't worry follow this article.

My Environment:

  • OS: Windows 10 (64 Bit)
  • Node: 16.3.0
  • NPM: 7.17

In case, if you want to explore more about which Hybrid App Development Framework to choose then you can have a look at this article: React Native vs Ionic vs Flutter


Step 1: Init a React Native Application:

This step is same as the official React Native Doc. So to init a React Native app:
Command-Prompt-Screenshot

  • Open command Prompt and go to the path where you want to create the project, In my case the path is C:\Users\shivam\Desktop\React.
  • Init App: ```sh

npx react-native init AwesomeProject

- Your folder will be looking like [this commit](https://github.com/ShivamS136/react-native-web-setup/commit/f66c8f85665ab1eb0bbef563b069762ad54baf5d).
- You'll find a new folder `AwesomeProject` in the current Directory, Now open this folder using any editor, I am using [Visual Studio Code](https://code.visualstudio.com/).

---

## Step 2: Run this new app in Android (optional)
If you have Android setup done and an emulator or device connected, then you can simply run the app in android by simply running below command using command prompt in the folder `AwesomeProject`.
```sh


npx react-native run-android


Enter fullscreen mode Exit fullscreen mode

Step 3: Web Setup

As already mentioned we'll be using the package react-native-web for web support. So you can find short setup instructions in the official doc of this package.


1. Add Web packages

Add the package react-native-web for web APIs and react-dom for browser.



npm install react-dom react-native-web


Enter fullscreen mode Exit fullscreen mode

If you see any error saying unable to resolve dependency tree then you can use the --legacy-peer-deps option like below.



npm install react-dom react-native-web --legacy-peer-deps


Enter fullscreen mode Exit fullscreen mode

2. Babel Plugin for build time optimization

As per official doc's recommendation, use the babel plugin babel-plugin-react-native-web.



npm install --save-dev babel-plugin-react-native-web


Enter fullscreen mode Exit fullscreen mode

3. Babel Module Aliasing

As we are going to alias react-native as react-native-web so as Babel supports module aliasing using babel-plugin-module-resolver, we'll be using this.



npm install --save-dev babel-plugin-module-resolver


Enter fullscreen mode Exit fullscreen mode

Now, to set alias, we'll use this package in webpack configuration. (These settings will be inside web/webpack.config.js, we'll introduce this file later in this article)


4. Mock Jest

Jest can be configured using the provided preset. This will map react-native to react-native-web and provide appropriate mocks.
For this, in /package.json file, update the value of the key "jest" from "react-native" to "react-native-web". Final value:

/package.json



{
  // Other Settings
  "jest": {
    "preset": "react-native-web"
  }
}


Enter fullscreen mode Exit fullscreen mode

5. Configure Flow

Flow is a static type checker for Javascript like TypeScript. It's used by React-Native by default if you don't init the project using TypeScript template.

It can be configured to understand the aliased module. For this we need to add some config text under [options] key inside the file /.flowconfig.

/.flowconfig



[options]
# Alias the package name
module.name_mapper='^react-native$' -> 'react-native-web'


Enter fullscreen mode Exit fullscreen mode

Flow can be configured to pull types from React Native for Web’s source code. For that add below config text also in the [options] key.

/.flowconfig



[options]
# Point flow to the 'module' field by default
module.system.node.main_field=module
module.system.node.main_field=main


Enter fullscreen mode Exit fullscreen mode

6. Package Optimization

We added a package babel-plugin-module-resolver in step-3, It is recommended for build-time optimizations and to prune modules not used by your application. To config this we'll use webpack configurattions so your /babel.config.js file should look something like below.

/babel.config.js



module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
};


Enter fullscreen mode Exit fullscreen mode

7. Create Entry Files

For web version, we need to create 2 entry files, First one is index.html and second one is index.web.js, both needs to be placed at root path.

/index.html



<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Testing React Native on the Web!</title>
    <meta content="initial-scale=1,width=device-width" name="viewport" />
    <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
    <style>
      /* These styles make the body full-height */
      html,
      body,
      #root {
        height: 100%;
      }
      /* These styles disable body scrolling if you are using <ScrollView> */
      body {
        overflow: hidden;
      }
      /* These styles make the root element flex and column wise filling */
      #root {
        display: flex;
        flex-direction: column;
      }
    </style>
  </head>
  <body>
    <div id="react-native-web-app"></div>
    <script type="text/javascript" src="/bundle.web.js"></script>
  </body>
</html>



Enter fullscreen mode Exit fullscreen mode

Notice the script name src="/bundle.web.js", We'll be using this file name while configuring webpack.

/index.web.js



import React from 'react';
import {AppRegistry} from 'react-native';
import App from './src/components/App';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);

AppRegistry.runApplication(appName, {
  rootTag: document.getElementById('react-native-web-app'),
});


Enter fullscreen mode Exit fullscreen mode

If you notice this almost same as index.js except the last line. As you can see above, we are using an App component but from where did it came? So it's the same App.js file copied with the name App.jsx inside the path /src/components/, It's just to demonstrate an important concept which we'll learn later in this article, as this file will be creating some problems. So /src/components/App.jsx will look like below:

Note: As in many Editors/IDE the same App.js file can show errors as the file is using Flow syntax for type definitions and this syntax might not be supported in your IDE, to solve this you can either add Flow Language support via extensions or remove the flow specific code. I have removed the flow specific code in the below example for saving your time in troubleshooting.

/src/components/App.jsx



/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React from 'react';
import {Node} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

const Section = ({children, title}) => {
  const isDarkMode = useColorScheme() === 'dark';
  return (
    <View style={styles.sectionContainer}>
      <Text
        style={[
          styles.sectionTitle,
          {
            color: isDarkMode ? Colors.white : Colors.black,
          },
        ]}>
        {title}
      </Text>
      <Text
        style={[
          styles.sectionDescription,
          {
            color: isDarkMode ? Colors.light : Colors.dark,
          },
        ]}>
        {children}
      </Text>
    </View>
  );
};

const App = () => {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Section title="Step One">
            Edit <Text style={styles.highlight}>App.js</Text> to change this
            screen and then come back to see your edits.
          </Section>
          <Section title="See Your Changes">
            <ReloadInstructions />
          </Section>
          <Section title="Debug">
            <DebugInstructions />
          </Section>
          <Section title="Learn More">
            Read the docs to discover what to do next:
          </Section>
          <LearnMoreLinks />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

export default App;


Enter fullscreen mode Exit fullscreen mode

8. Configuring and budling

We'll be using Webpack for bundling and Babel for transpiling along with babel-loader.

Install Webpack and related dependencies: Run below command in the terminal to install packages for dev environment.



npm install --save-dev babel-loader url-loader webpack webpack-cli webpack-dev-server


Enter fullscreen mode Exit fullscreen mode

Tree-Shaking: React Native’s Babel preset rewrites ES modules to CommonJS modules, preventing bundlers from automatically performing “tree-shaking” to remove unused modules from your web app build. To help with this, you can install the following Babel plugin:



npm install --save-dev babel-plugin-react-native-web


Enter fullscreen mode Exit fullscreen mode

Webpack Configuration:
This cofiguration is picked from the official doc and slightly modified to add .jsx support and module-resolver we added above via babel-plugin-module-resolver. So to configure Webpack create a file at /web/webpack.config.js. We will be using webpack-cli to diffrentiate between development and production builds, if you want to manage this via script then you can use this guide.

/web/webpack.config.js



const path = require('path');
const webpack = require('webpack');

const appDirectory = path.resolve(__dirname, '../');

// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
  test: /\.(js)|(jsx)$/,
  // Add every directory that needs to be compiled by Babel during the build.
  include: [
    path.resolve(appDirectory, 'index.web.js'),
    path.resolve(appDirectory, 'src'),
    path.resolve(appDirectory, 'node_modules/react-native-uncompiled'),
  ],
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true,
      // The 'metro-react-native-babel-preset' preset is recommended to match React Native's packager
      presets: ['module:metro-react-native-babel-preset'],
      // Re-write paths to import only the modules needed by the app
      plugins: [
        'react-native-web',
        [
          'module-resolver',
          {
            alias: {
              '^react-native$': 'react-native-web',
            },
          },
        ],
      ],
    },
  },
};

// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
  test: /\.(gif|jpe?g|png|svg)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: '[name].[ext]',
      esModule: false,
    },
  },
};

module.exports = {
  entry: [
    // load any web API polyfills
    // path.resolve(appDirectory, 'polyfills-web.js'),
    // your web-specific entry file
    path.resolve(appDirectory, 'index.web.js'),
  ],

  // configures where the build ends up
  output: {
    filename: 'bundle.web.js',
    path: path.resolve(appDirectory, 'dist'),
  },

  // ...the rest of your config

  module: {
    rules: [babelLoaderConfiguration, imageLoaderConfiguration],
  },

  resolve: {
    // This will only alias the exact import "react-native"
    alias: {
      'react-native$': 'react-native-web',
    },
    // If you're working on a multi-platform React Native app, web-specific
    // module implementations should be written in files using the extension
    // `.web.js`.
    extensions: ['.web.js', '.js', '.jsx'],
  },
};


Enter fullscreen mode Exit fullscreen mode

9. Scripts to run on web

Now we are going to add some scripts to run our web app with short command instead of full webpack-cli command. For this, we need to add below two options in the file /package.json inside "scripts" key.

To know more about webpack-cli options for webpack-5 go here and to know more about dev-tool go here

/package.json



{
  "scripts": {
    "web": "webpack serve -d source-map --mode development --config \"./web/webpack.config.js\" --inline --color --hot",
    "build:web": "webpack --mode production --config \"./web/webpack.config.js\" --hot"
  }
}


Enter fullscreen mode Exit fullscreen mode

10. RUN OUR WEBAPP

So, Finally we are here, as we have set shortcut in our package.json for script so now we can simply run below command to start our webapp in browser.



npm run web


Enter fullscreen mode Exit fullscreen mode

Wait a minute!!! I'm getting error, like below:



ERROR in ./node_modules/react-native/Libraries/NewAppScreen/components/DebugInstructions.js 11:12
Module parse failed: Unexpected token (11:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|  */
|
> import type {Node} from 'react';
| import {Platform, StyleSheet, Text} from 'react-native';
| import React from 'react';
 @ ./node_modules/react-native/Libraries/NewAppScreen/index.js 17:0-63 20:0-27:2
 @ ./src/components/App.jsx 1:864-910
 @ ./index.web.js 1:261-292


Enter fullscreen mode Exit fullscreen mode

So this is the error we talked about in Step 7. I literally spent 3-4 days to find a solution for this. And then the creator and maintainer of react-native-web package, Nicolas Gallagher helped me via this discussion.
So the issue is in the import statement on line 21 of src/components/App.jsx, where we are trying to do something like below:

This line in the stack trace is telling us that we're trying to bundle RN internal code in our web bundle: node_modules/react-native/Libraries/NewAppScreen/index.js.

First, we should not be loading any of the RN package on web, especially not parts that aren't part of the public API . Second, as mentioned in the inline comments of the config web/webpack.config.js, we need to explicitly list everything in node_modules that needs compiling.



import {
 Colors,
 DebugInstructions,
 Header,
 LearnMoreLinks,
 ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';


All this code of the problem. We should not import from Libraries. This is not part of the public API.

To solve this, remove the dependency on the library: react-native/Libraries, for that update the code of /src/components/App.jsx as below:

/src/components/App.jsx



/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React from 'react';
import {Node} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

// import {
//   Colors,
//   DebugInstructions,
//   Header,
//   LearnMoreLinks,
//   ReloadInstructions,
// } from 'react-native/Libraries/NewAppScreen';

const Colors = {
  white: '#fff',
  black: '#000',
  light: '#ddd',
  dark: '#333',
  lighter: '#eee',
  darker: '#111',
};

const Section = ({children, title}) => {
  const isDarkMode = useColorScheme() === 'dark';
  return (
    <View style={styles.sectionContainer}>
      <Text
        style={[
          styles.sectionTitle,
          {
            color: isDarkMode ? Colors.white : Colors.black,
          },
        ]}>
        {title}
      </Text>
      <Text
        style={[
          styles.sectionDescription,
          {
            color: isDarkMode ? Colors.light : Colors.dark,
          },
        ]}>
        {children}
      </Text>
    </View>
  );
};

const App = () => {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        {/* <Header /> */}
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Section title="Step One">
            Edit <Text style={styles.highlight}>App.js</Text> to change this
            screen and then come back to see your edits.
          </Section>
          <Section title="See Your Changes">
            {/* <ReloadInstructions /> */}
            <Text>Reload Instruction</Text>
          </Section>
          <Section title="Debug">
            {/* <DebugInstructions /> */}
            <Text>Debug Instruction</Text>
          </Section>
          <Section title="Learn More">
            Read the docs to discover what to do next:
          </Section>
          {/* <LearnMoreLinks /> */}
          <Text>Learn More Links</Text>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

export default App;


Enter fullscreen mode Exit fullscreen mode

11. Finally run after Troubleshooting

We can simply run below command in the terminal if it was stopped previously to start our webapp in browser.



npm run web


Enter fullscreen mode Exit fullscreen mode

You should get output similar to below screenshot, and you can go to http://localhost:8080 to see your webapp running.

Final Output


I'm sure it will help someone, at least it could save my 4 days if I know this before. All the changes done to add web support can be found in this before-update commit and this after-update commit.

I created a release also for the same.

I used the same configurations on this Dummy project and faced no issues after update.

If you find any issue in the configurations and gets it resolved, don't hesitate to contribute to the repo.

You can connect with me on Linkedin or Github as well.

Top comments (41)

Collapse
 
keiteldog profile image
Keitel Jovin

Thanks for helping me out on this, I've learned a lot here. I always want to have more control on my codes.
I want to stay away of Expo because it's too big and lack of some features that I wanted to test each time on Local. I tried react-scripts, but at some points, I couldn't know what was happening. Didn't try expo eject though, but I heard it's still not reducing enough the size. This full babel and webpack config was what I wanted.

TIP for readers, read carefully the Babel Compilation part in Webpack Config to know when to add a module to be compiled. For example, this compiled the package react-native-paper (Material Design):

path.resolve(appDirectory, 'node_modules/react-native-paper'),

Collapse
 
shivams136 profile image
Shivam Sharma

Your most welcome, I am happy that my learning could helped someone.

Collapse
 
zoodika profile image
zoodika

روشهاي تميز كردن نقره
نقره به مرور زمان کدر مي‌شود و لکه‌دار مي‌گردد. براي تميز کردن نقره مي‌توانيد از روش‌هاي مختلفي استفاده کنيد. در زير چند روش مؤثر براي تميز کردن نقره آورده شده است:
استفاده از محلول آب و جوش شيرين:
يک قاشق غذاخوري جوش شيرين را در يک فنجان آب گرم حل کنيد. تميز كردن نقره با جوش شيرين نقره را در اين محلول قرار دهيد و بگذاريد به مدت ?? تا ?? دقيقه بماند. سپس با يک پارچه نرم تميز کنيد.
استفاده از سرکه و جوش شيرين:
نقره را در محلولي از نصف فنجان سرکه سفيد و دو قاشق غذاخوري جوش شيرين به مدت دو تا سه ساعت قرار دهيد. سپس با آب گرم بشوييد و خشک کنيد.

Collapse
 
19007361 profile image
CJ Meyer • Edited

I have a weird issue

When I use exactly this file of yours: github.com/ShivamS136/react-native...

It runs fine with npx react-native run-android

But when I enter even one single letter differently, inside Text, styles, variable names, anything, it shows many errors "Error: Text strings must be rendered within a component.", and also some errors "Invariant Violation: View config getter callback for component div must be a function (received undefined). Make sure to start component names with a capital letter."

Collapse
 
shivams136 profile image
Shivam Sharma

div component is not available in React Native, It's part of react-dom... So can't be used here.
For the Text issue, can you please share a screenshot or code block or regeneratable example.
I hope you are running for android, not web as in web it'll not run as mentioned in the step 10.

Collapse
 
19007361 profile image
CJ Meyer

Thank you for your reply. It is exactly the same code as you have in App.js, I am running for Android yes

Collapse
 
dgtman profile image
David Taylor

I just get a blank page, no rendered HTML, no JS assets loaded by the browser. The CLI reports that everything worked though:

i 「wds」: Project is running at localhost:8080/
i 「wds」: webpack output is served from /
i 「wds」: Content not from webpack is served from E:\Storage\Projects\react-native\AwesomeProject
i 「wdm」: asset bundle.web.js 1.72 MiB emitted 1 related asset
runtime modules 26.7 KiB 13 modules
modules by path ./node_modules/ 1.56 MiB 105 modules
./index.web.js 526 bytes [built] [code generated]
./src/components/App.jsx 4.99 KiB [built] [code generated]
./app.json 66 bytes [built] [code generated]
webpack 5.40.0 compiled successfully in 2378 ms
i 「wdm」: Compiled successfully.

I've been over the steps 3 times, everything in the instructions I did as far as I can tell.

Collapse
 
keiteldog profile image
Keitel Jovin

Then the configuration worked for you, now you need to go on the Browser console and see what's the javascript error. It could be syntax error, could be your own code importing "type" code (you should tell webpack to convert node module that uses them), it could be metro bundler not running, etc.
But you have to debug it in Browser console now.

Collapse
 
dgtman profile image
David Taylor

I forgot to say, nothing in the browser console. Not even a request to load the generated JS bundle. The index.html page is not loading.

However, if I change the URL to put a filename that does NOT exist in the app, I do get a "not found" error. So it's talking to the server, just not rendering anything.

Thread Thread
 
keiteldog profile image
Keitel Jovin

Oh ok, I see what you mean. Did you set the bable presets and plugins in config?

What does your web/webpack.config.js look like?

Thread Thread
 
keiteldog profile image
Keitel Jovin

Keep in mind that webpack serve is serving in memory in development. You won't even see the bundle file generated.

Thread Thread
 
shivams136 profile image
Shivam Sharma • Edited

@dgtman , Can you please check that you have included budle.web.js there or the entry point index.web.js is correct in webpack config and this file exists. Or you can share a github repo like the one I mentioned to generate the error at my end.

Collapse
 
mdmudassir47 profile image
Mohammed Mudassir

Getting this error
ERROR in ./index.web.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions. In /Users/Projects/demo-app/node_modules/babel-preset-es2015/lib/index.js

Collapse
 
railway17 profile image
Rail Way • Edited

Hi, I've noticed strange issue while working on windows.
I have successfully run out by using this article, but can't start in windows.
It shows error that I attached at stackoverflow.com/questions/705180...
Please help me why it shows error.
Thank you
Han

Collapse
 
shivams136 profile image
Shivam Sharma

Hi @railway17

Actually, I worked on React Native for a very short amount of time, I was also stuck too many times in setting this up that's why created that article along with learning, I don't have any knowledge apart from that, So I'll not able to help here.

I would suggest you to post a help discussion on react-native-web package, the community there is very helpful, I also got help from there when I was stuck.

Collapse
 
ironsteel profile image
ironsteel

آهن پرمصرف‌ترین فلز دنیا است و اصلی‌ترین دلیل هم قیمت مناسب و استحکام بسیار بالای آن است. به‌طوری که تقریباً تمام سازه‌‌های دنیا با استفاده از آهن آلات و انواع مقاطع فولادی ساخته شده از مشتقات آهن ساخته شده‌اند. میزان مقاومت و کیفیت آهن به درجۀ خلوص آن بستگی دارد. در ترکیبات سنگ آهن ناخالصی‌‌هایی وجود دارد که باید از آن جدا شود. مهم است آهن و فولاد که محصول نهایی چقدر خالص باشد و چگونه و توسط کدام فرایند به درصد خلوص لازم برسد.در واقع زمانی که ناخالصی‌‌ها از سنگ آهن جدا‌‌‌ می‌شوند و افزودنی‌هایی به آن اضافه‌‌‌ می‌شود، آلیاژهای مختلفی از این ماده به‌وجود می‌آید. آلیاژها ‌ترکیبی از فلز با ماده‌ای دیگر هستند که ممکن است آن فلز آهنی یا غیرآهنی باشد.

Collapse
 
shivams136 profile image
Shivam Sharma

Note: This article is updated on 08-Aug-2021, to solve this StackOverflow issue, In this update, Creation of .babelrc is removed, babel.config.js & webpack.config.js are updated. The changes are equivalent to this commit.

Collapse
 
reinraus profile image
ReinRaus

Step 9

"web": "webpack serve -d source-map --mode development --config \"./web/webpack.config.js\" --inline --color --hot"
Enter fullscreen mode Exit fullscreen mode

--inline is deprecated

stackoverflow.com/questions/705284...

Collapse
 
ashutoshmukherjee35 profile image
AshutoshMukherjee35

Getting the following error while following your documentation:-

ERROR in ./App.js 8:4
Module parse failed: Unexpected token (8:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See webpack.js.org/concepts#loaders
| const App = () => {
| return (

<>

|
|
@ ./index.web.js 1:261-277

webpack 5.75.0 compiled with 1 error in 1193 ms

Here's how my web/webpack.config.js file looks:-

const path = require('path');
const webpack = require('webpack');

const appDirectory = path.resolve(__dirname, '../');

// This is needed for webpack to compile JavaScript.
// Many OSS React Native packages are not compiled to ES5 before being
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
const babelLoaderConfiguration = {
  // test: /\.(js)|(jsx)$/,
  test: /\.js$|jsx/,
  // Add every directory that needs to be compiled by Babel during the build.
  include: [
    path.resolve(appDirectory, 'index.web.js'),
    path.resolve(appDirectory, 'src'),
    path.resolve(appDirectory, 'node_modules/react-native-uncompiled'),
  ],
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true,
      // The 'metro-react-native-babel-preset' preset is recommended to match React Native's packager
      presets: ['module:metro-react-native-babel-preset'],
      // Re-write paths to import only the modules needed by the app
      plugins: [
        'react-native-web',
        [
          'module-resolver',
          {
            alias: {
              '^react-native$': 'react-native-web',
            },
          },
        ],
      ],
    },
  },
};

// This is needed for webpack to import static images in JavaScript files.
const imageLoaderConfiguration = {
  test: /\.(gif|jpe?g|png|svg)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: '[name].[ext]',
      esModule: false,
    },
  },
};

module.exports = {
  entry: [
    // load any web API polyfills
    // path.resolve(appDirectory, 'polyfills-web.js'),
    // your web-specific entry file
    path.resolve(appDirectory, 'index.web.js'),
  ],

  // configures where the build ends up
  output: {
    filename: 'bundle.web.js',
    path: path.resolve(appDirectory, 'dist'),
  },

  // ...the rest of your config

  module: {
    rules: [babelLoaderConfiguration, imageLoaderConfiguration],
  },

  resolve: {
    // This will only alias the exact import "react-native"
    alias: {
      'react-native$': 'react-native-web',
    },
    // If you're working on a multi-platform React Native app, web-specific
    // module implementations should be written in files using the extension
    // `.web.js`.
    extensions: ['.web.js', '.js', '.jsx'],
  },
};
Enter fullscreen mode Exit fullscreen mode

Package.json

{
"name": "AwesomeProject",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint .",
"web": "webpack serve -d source-map --mode development --config \"./web/webpack.config.js\" --color --hot",
"build:web": "webpack --mode production --config \"./web/webpack.config.js\" --hot"
},
"dependencies": {
"react": "18.1.0",
"react-dom": "^18.2.0",
"react-native": "0.70.6",
"react-native-web": "^0.18.10"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"ajv": "^7.2.4",
"babel-jest": "^26.6.3",
"babel-loader": "^9.1.0",
"babel-plugin-module-resolver": "^4.1.0",
"babel-plugin-react-native-web": "^0.18.10",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "0.72.3",
"react-test-renderer": "18.1.0",
"url-loader": "^4.1.1",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0"
},
"jest": {
"preset": "react-native-web"
}
}

babel.config.js

module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};

My folder Structure:-

Image description

index.web.js

`import React from 'react';
import {AppRegistry} from 'react-native';
// import App from './src/components/App';
import App from './App'
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);

AppRegistry.runApplication(appName, {
rootTag: document.getElementById('react-native-web-app'),
});`

.flowconfig:-
`
[ignore]
; We fork some components by platform
./[.]android.js

; Ignore "BUCK" generated dirs
/.buckd/

; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*

; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js

.*/node_modules/resolve/test/resolver/malformed_package_json/package.json$

[untyped]
./node_modules/@react-native-community/cli/./.*

[include]

[libs]
node_modules/react-native/interface.js
node_modules/react-native/flow/

[options]
emoji=true

exact_by_default=true

format.bracket_spacing=false

module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js

munge_underscores=true

module.name_mapper='^react-native/(.*)$' -> '/node_modules/react-native/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+.(bmp|gif|jpg|jpeg|png|psd|svg|webp|m4v|mov|mp4|mpeg|mpg|webm|aac|aiff|caf|m4a|mp3|wav|html|pdf)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState

Alias the package name

module.name_mapper='^react-native$' -> 'react-native-web'

Point flow to the 'module' field by default

module.system.node.main_field=module
module.system.node.main_field=main

[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
unnecessary-invariant=warn

[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import

[version]
^0.182.0
`

Please help me to resolve this error.

Collapse
 
criszz77 profile image
criszz77

This is a very hard and messy way to get it started. You can use react-scripts which have react-native-web support. I created a react-native-web template which also has web configurations for important libraries like react-navigation and react-native-vector-icons using CRACO to override react-scripts web pack config without ejecting.

github.com/plaut-ro/luna

Collapse
 
ccheever profile image
Charlie Cheever

Hi - Just curious, why did you not want to use Expo here?

Collapse
 
shivams136 profile image
Shivam Sharma

For me, the main reason was the overhead Expo brings... A simple Hello World app is about 25 MB. You can find the full list here.

Collapse
 
shelzxy profile image
Shelton tembo

I think it's because expo is trash and doesn't work.....