react-native-web with react-navigation - error "Module parse failed: Unexpected token"

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Describe the issue

Hi all

Am trying to add react-native-web to an existing react-native project based on Ignite Bowser template. I have tried with many variation of versions, config of webpack, etc… without success.

Main version and library I am using, see below for full config files.

react-native 0.63.2
react-navigation 5.x
react-native-web 0.18.6
typescript 3.9.7
webpack 5.73.0

Here is my main issue: when running my react native web app, I get the following error message:

$ webpack serve --mode=development --config webpack.config.js
<w> [webpack-dev-server] "hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://10.0.1.229:8080/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:8080/
<i> [webpack-dev-server] Content not from webpack is served from '/Users/rdewolff/Projects/meetme/dev/meetme-mobile/public' directory
asset meetme.bundle.js 14.8 MiB [emitted] (name: app)
asset index.html 458 bytes [emitted]
runtime modules 28.1 KiB 16 modules
orphan modules 2.45 KiB [orphan] 9 modules
modules by path ./node_modules/ 9.41 MiB
  javascript modules 9.26 MiB 2805 modules
  json modules 147 KiB 5 modules
modules by path ./app/ 2.09 MiB
  javascript modules 2.02 MiB 215 modules
  json modules 72.2 KiB 3 modules
modules by path ./*.json 8.74 KiB
  ./app.json 50 bytes [built] [code generated]
  ./package.json 8.69 KiB [built] [code generated]
./index.web.js 492 bytes [built] [code generated]
external "react-native" 42 bytes [built] [code generated]
./util.inspect (ignored) 15 bytes [built] [code generated]
ws (ignored) 15 bytes [optional] [built] [code generated]

ERROR in ./node_modules/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js 21:5
Module parse failed: Unexpected token (21:5)
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
| const sizesDiffer = require('../../Utilities/differ/sizesDiffer');
|
> type ReturnBoolType = <V>(V) => true;
| type BoolifiedDeprecatedViewStylePropTypes = $ObjMap<
|   typeof DeprecatedViewStylePropTypes,
 @ ./node_modules/react-native-screens/lib/module/native-stack/views/FontProcessor.js 1:229-305
 @ ./node_modules/react-native-screens/lib/module/native-stack/views/HeaderConfig.js 1:436-462
 @ ./node_modules/react-native-screens/lib/module/native-stack/views/NativeStackView.js 1:922-947
 @ ./node_modules/react-native-screens/lib/module/native-stack/index.js 1:553-587
 @ ./app/navigation/root-navigator.web.tsx 1:286-330
 @ ./app/navigation/index.ts 1:76-103
 @ ./app/app.web.tsx 1:555-578
 @ ./index.web.js 1:241-261

ERROR in ./node_modules/react-native/Libraries/ReactNative/AppContainer.js 21:5
Module parse failed: Unexpected token (21:5)
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
| const View = require('../Components/View/View');
|
> type Context = {rootTag: number, ...};
|
| type Props = $ReadOnly<{|
 @ ./node_modules/react-native-screens/lib/module/native-stack/views/NativeStackView.js 1:765-823
 @ ./node_modules/react-native-screens/lib/module/native-stack/index.js 1:553-587
 @ ./app/navigation/root-navigator.web.tsx 1:286-330
 @ ./app/navigation/index.ts 1:76-103
 @ ./app/app.web.tsx 1:555-578
 @ ./index.web.js 1:241-261

webpack 5.73.0 compiled with 2 errors in 3830 ms

The problem seems to be very similar to the one described and discussed here : https://github.com/necolas/react-native-web/discussions/2052

I tried checking source code from other app like https://github.com/criszz77/luna that have it working but could not find the difference and make it work in my project. It seems to me this is a webpack configuration issue to use react-native-web properly.

The error is located specifically here in react-native-screens:

import ReactNativeStyleAttributes from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes';

How can I fix the babel/webpack config to handle properly react-native-screens that is importing the file? Specifically in an external lib?

I have the following ideas in mind:

  1. Fix the webpack of rnw to work with that use case
  2. Use another lib like react-router-dom for the navigation to not use the package causing problem.
  3. Use eslib ? Seems not very common and not sure I want to take this road.

I’d love to get some ideas or feedback on how to proceed with that error.

Config files

package.json
{
 "name": "meetme",
 "version": "0.0.1",
 "private": true,
 "scripts": {
   "clean": "rm -rf node_modules && yarn cache clean && yarn install && yarn start -- --reset-cache",
   "set-env:dev": "cp app/config/env.dev.js app/config/env.js",
   "set-env:beta": "cp app/config/env.beta.js app/config/env.js",
   "set-env:production": "cp app/config/env.production.js app/config/env.js",
   "build": "rm -rf dist/ && webpack --mode=production --config webpack.config.js",
   "web": "webpack serve --mode=development --config webpack.config.js",
   "dev": "osascript launch-iterm.scpt",
   "android": "react-native run-android",
   "ios": "react-native run-ios",
   "start": "react-native start",
   "test": "jest",
   "lint": "eslint index.js app storybook test --fix --ext .js,.ts,.tsx",
   "test:e2e": "detox test -c ios.sim.debug",
   "build:e2e": "detox build -c ios.sim.debug",
   "ci:test:e2e": "detox test -c ios.sim.release -l verbose --cleanup",
   "ci:build:e2e": "detox build -c ios.sim.release",
   "compile": "tsc --noEmit -p . --pretty",
   "format": "npm-run-all format:*",
   "format:js": "prettier --write '**/*.js'",
   "format:json": "prettier --write '**/*.json'",
   "format:md": "prettier --write '**/*.md'",
   "format:ts": "prettier --write '**/*.ts{,x}'",
   "hack:types-react-navigation": "rimraf node_modules/@types/react-navigation/node_modules/@types",
   "hack:types-react-native": "rimraf node_modules/@types/react-native/node_modules/@types",
   "hack:types-react-test-renderer": "rimraf node_modules/@types/react-test-renderer/node_modules/@types",
   "patch": "patch-package",
   "postinstall": "node ./bin/postInstall",
   "prepare": "npm-run-all patch hack:*",
   "storybook": "start-storybook -p 9001 -c ./storybook",
   "adb": "adb reverse tcp:9090 tcp:9090 && adb reverse tcp:3000 tcp:3000 && adb reverse tcp:9001 tcp:9001 && adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3030 tcp:3030",
   "fastlane:ios:beta": "fastlane ios beta",
   "fastlane:ios:production": "fastlane ios production",
   "fastlane:android:beta": "fastlane android beta",
   "fastlane:android:production": "fastlane android production",
   "codepush:android:beta": "fastlane codepush platform:android env:beta",
   "codepush:android:production": "fastlane codepush platform:android env:production",
   "codepush:ios:beta": "fastlane codepush platform:ios env:beta",
   "codepush:ios:production": "fastlane codepush platform:ios env:production",
   "xcode:cleanup": "rm -rf \"~/Library/MobileDevice/Provisioning Profiles/*\" && rm -rf ~/Library/Developer/Xcode/DerivedData/*"
 },
 "dependencies": {
   "@babel/preset-react": "^7.18.6",
   "@eva-design/eva": "^1.4.0",
   "@feathersjs/feathers": "^4.5.2",
   "@feathersjs/socketio-client": "^4.5.2",
   "@formatjs/intl": "^1.4.5",
   "@formatjs/intl-relativetimeformat": "^7.3.6",
   "@meetme/shared": "link:./../meetme-shared",
   "@react-native-community/async-storage": "^1.11.0",
   "@react-native-community/masked-view": "0.1.10",
   "@react-native-community/push-notification-ios": "^1.2.0",
   "@react-navigation/bottom-tabs": "5.11.15",
   "@react-navigation/drawer": "5.12.9",
   "@react-navigation/native": "5.9.8",
   "@react-navigation/native-stack": "5.0.4",
   "@sentry/react-native": "^1.6.2",
   "@sentry/wizard": "^1.1.4",
   "@ui-kitten/components": "^4.4.1",
   "@ui-kitten/eva-icons": "^4.4.1",
   "analytics-react-native": "^1.2.0",
   "apisauce": "1.1.2",
   "i18n-js": "^3.0.11",
   "libphonenumber-js": "^1.7.50",
   "lodash.throttle": "4.1.1",
   "luxon": "^1.23.0",
   "mobx": "^4.15.4",
   "mobx-react-lite": "^1.4.1",
   "mobx-state-tree": "^3.14.1",
   "moment": "2.17.1",
   "qs": "^6.9.6",
   "ramda": "0.27.1",
   "react": "16.13.1",
   "react-hook-form": "^6.14.2",
   "react-native": "0.63.2",
   "react-native-appstate-hook": "^1.0.4",
   "react-native-calendar-events": "^2.1.2",
   "react-native-calendar-strip": "^2.2.1",
   "react-native-calendars": "^1.265.0",
   "react-native-chart-kit": "^6.6.0",
   "react-native-code-push": "^6.2.1",
   "react-native-contacts": "morenoh149/react-native-contacts#e9241d7017842af37af67498d561088e6c9b0342",
   "react-native-date-picker": "^3.2.2",
   "react-native-deep-linking": "^2.2.0",
   "react-native-dropdownalert": "^4.2.1",
   "react-native-gesture-handler": "^1.5.0",
   "react-native-iap": "^4.5.2",
   "react-native-image-picker": "3.6.0",
   "react-native-keychain": "6.1.1",
   "react-native-localize": "^1.0.0",
   "react-native-push-notification": "7.3.1",
   "react-native-reanimated": "^2.2.0",
   "react-native-safe-area-context": "3.4.1",
   "react-native-safe-area-view": "1.1.1",
   "react-native-screens": "^2.18.1",
   "react-native-splash-screen": "3.2.0",
   "react-native-svg": "^12.1.0",
   "react-native-uuid": "^1.4.9",
   "react-native-web": "^0.18.6",
   "react-native-week-view": "^0.16.0",
   "react-query": "^3.8.2",
   "reactotron-mst": "^3.1.4",
   "reactotron-react-js": "^3.3.7",
   "reactotron-react-native": "^5.0.2",
   "socket.io-client": "^2.3.0",
   "tiny-emitter": "^2.1.0",
   "tipsi-stripe": "^9.1.4",
   "validate.js": "0.13.1"
 },
 "devDependencies": {
   "@babel/core": "^7.11.6",
   "@babel/plugin-proposal-decorators": "^7.0.0",
   "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
   "@babel/runtime": "^7.11.2",
   "@storybook/addon-storyshots": "5.3.19",
   "@storybook/react-native": "5.3.19",
   "@storybook/react-native-server": "5.3.19",
   "@svgr/webpack": "^6.2.1",
   "@types/http-errors": "^1.6.3",
   "@types/i18n-js": "^3.0.3",
   "@types/jest": "^25.2.3",
   "@types/luxon": "^1.22.0",
   "@types/ramda": "0.26.44",
   "@types/react": "16.9.23",
   "@types/react-native": "^0.63.2",
   "@types/react-native-calendars": "^1.20.7",
   "@types/react-native-push-notification": "7.2.0",
   "@types/react-test-renderer": "^16.9.2",
   "@typescript-eslint/eslint-plugin": "^2.27.0",
   "@typescript-eslint/parser": "^2.27.0",
   "babel-jest": "^26.3.0",
   "babel-loader": "^8.2.5",
   "babel-plugin-react-native-web": "^0.18.6",
   "babel-plugin-transform-class-properties": "^6.24.1",
   "detox": "^16.0.0",
   "eslint": "^6.8.0",
   "eslint-config-prettier": "^6.0.0",
   "eslint-config-standard": "^14.1.0",
   "eslint-plugin-import": "^2.15.0",
   "eslint-plugin-node": "^11.0.0",
   "eslint-plugin-promise": "^4.0.1",
   "eslint-plugin-react": "^7.12.4",
   "eslint-plugin-react-hooks": "^4.1.0",
   "eslint-plugin-react-native": "^3.6.0",
   "eslint-plugin-standard": "^4.0.0",
   "html-webpack-plugin": "^5.5.0",
   "ignite-bowser": "5.4.1",
   "jest": "25.5.4",
   "jetifier": "^1.6.2",
   "metro-react-native-babel-preset": "^0.63.0",
   "npm-run-all": "4.1.5",
   "patch-package": "6.2.2",
   "postinstall-prepare": "1.0.1",
   "prettier": "^2.0.4",
   "react-devtools-core": "4.8.2",
   "react-dom": "^16.0.0",
   "react-native-clean-project": "^3.6.3",
   "react-powerplug": "1.0.0",
   "react-test-renderer": "16.13.1",
   "rimraf": "3.0.2",
   "solidarity": "3.0.0",
   "typescript": "3.9.7",
   "url-loader": "^4.1.1",
   "webpack": "^5.73.0",
   "webpack-cli": "^4.10.0",
   "webpack-dev-server": "^4.9.3"
 },
 "jest": {
   "preset": "react-native",
   "setupFiles": [
     "<rootDir>/node_modules/react-native/jest/setup.js",
     "<rootDir>/test/setup.ts"
   ],
   "testPathIgnorePatterns": [
     "/node_modules/",
     "/e2e"
   ],
   "transformIgnorePatterns": [
     "node_modules/(?!(jest-)?react-native|react-native|@react-navigation|@storybook|@react-native-community)"
   ]
 },
 "prettier": {
   "printWidth": 100,
   "semi": false,
   "singleQuote": true,
   "trailingComma": "all"
 },
 "detox": {
   "test-runner": "jest",
   "configurations": {
     "ios.sim.debug": {
       "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/meetme.app",
       "build": "xcodebuild -workspace ios/meetme.xcworkspace -scheme meetme -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build -UseModernBuildSystem=NO",
       "type": "ios.simulator",
       "name": "iPhone 8"
     },
     "ios.sim.release": {
       "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/meetme.app",
       "build": "xcodebuild -workspace ios/meetme.xcworkspace -scheme meetme -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -UseModernBuildSystem=NO",
       "type": "ios.simulator",
       "name": "iPhone 8"
     }
   }
 },
 "eslintConfig": {
   "parser": "@typescript-eslint/parser",
   "extends": [
     "prettier",
     "plugin:@typescript-eslint/recommended",
     "plugin:react/recommended",
     "plugin:react-native/all",
     "plugin:react-hooks/recommended",
     "standard"
   ],
   "parserOptions": {
     "ecmaFeatures": {
       "jsx": true
     },
     "project": "./tsconfig.json"
   },
   "plugins": [
     "@typescript-eslint",
     "react",
     "react-native"
   ],
   "settings": {
     "react": {
       "pragma": "React",
       "version": "detect"
     }
   },
   "globals": {
     "__DEV__": false,
     "jasmine": false,
     "beforeAll": false,
     "afterAll": false,
     "beforeEach": false,
     "afterEach": false,
     "test": false,
     "expect": false,
     "describe": false,
     "jest": false,
     "it": false
   },
   "rules": {
     "comma-dangle": 0,
     "no-unused-vars": 0,
     "no-undef": 0,
     "quotes": 0,
     "react/no-unescaped-entities": 0,
     "react/prop-types": "off",
     "react-native/no-raw-text": 0,
     "space-before-function-paren": 0,
     "@typescript-eslint/ban-ts-ignore": 0,
     "@typescript-eslint/indent": 0,
     "@typescript-eslint/explicit-member-accessibility": 0,
     "@typescript-eslint/explicit-function-return-type": 0,
     "@typescript-eslint/member-delimiter-style": 0,
     "@typescript-eslint/no-explicit-any": 0,
     "@typescript-eslint/no-object-literal-type-assertion": 0,
     "@typescript-eslint/no-empty-interface": 0,
     "@typescript-eslint/no-var-requires": 0
   }
 },
 "hyperlayout": {
   "default": [
     [
       [
         "cd ~/Projects/meetme/dev/meetme-mobile && yarn start",
         "cd ~/Projects/meetme/dev/meetme-backend && DEBUG=* yarn dev"
       ],
       "cd ~/Projects/meetme/dev/meetme-backup && docker-compose up -d && cd ../meetme-mobile"
     ]
   ]
 }
}

babel.config.js
module.exports = {
presets: [
  // mobile
  'module:metro-react-native-babel-preset',
  // web
  '@babel/preset-react',
],
env: {
  production: {},
},
plugins: [
  [
    '@babel/plugin-proposal-decorators',
    {
      legacy: true,
    },
  ],
  ['@babel/plugin-proposal-optional-catch-binding'],
],
}
webpack.config.js
/**
 * Webpack is used for the web version.
 * It has been configured based on the info shared by Aryan Goharzad
 * in the following paper:
 * https://arry.medium.com/how-to-add-react-native-web-to-an-existing-react-native-project-eb98c952c12f
 */

const path = require('path')

const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const appDirectory = path.resolve(__dirname)
const { presets } = require(`${appDirectory}/babel.config.js`)

const compileNodeModules = [
  // Add every react-native package that needs compiling
  'react-native-safe-area-context',
  'react-native-safe-area-view',
  'react-native-reanimated',
  'react-native-gesture-handler',
  'react-native-screens',
  'react-native-calendars',
  'react-native-swipe-gestures',

  '@eva-design/eva',
  '@ui-kitten/eva-icons',
  '@ui-kitten/components',
  '@ui-kitten/eva-icons',
  'react-native-svg',
  'react-native-eva-icons',
  'react-native-week-view',
  '@react-navigation/bottom-tabs',
  '@react-navigation/drawer',
  '@react-navigation/native',
  '@react-navigation/native-stack',
  'react-native-calendar-strip',
  'react-native-date-picker',
  'react-native-dropdownalert',
  'react-native-image-picker',
  '@react-native-community/push-notification-ios',
  'react-native-calendar-events',
  'tipsi-stripe',
  'react-native-code-push',
  '@react-native-community/masked-view',
  '@react-native-community/async-storage',
].map((moduleName) => path.resolve(appDirectory, `node_modules/${moduleName}`))

const babelLoaderConfiguration = {
  test: /\.js$|tsx?$/,
  // Add every directory that needs to be compiled by Babel during the build.
  include: [
    path.resolve(__dirname, 'index.web.js'),
    path.resolve(__dirname, 'app/app.web.tsx'),
    path.resolve(__dirname, 'app'),
    ...compileNodeModules,
  ],
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true,
      presets,
      plugins: ['react-native-web'],
    },
  },
}

const svgLoaderConfiguration = {
  test: /\.svg$/,
  use: [
    {
      loader: '@svgr/webpack',
    },
  ],
}

const imageLoaderConfiguration = {
  test: /\.(gif|jpe?g|png)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: '[name].[ext]',
    },
  },
}

module.exports = {
  entry: {
    app: path.join(__dirname, 'index.web.js'),
  },
  output: {
    path: path.resolve(appDirectory, 'dist'),
    publicPath: '/',
    filename: 'meetme.bundle.js',
  },
  externals: {
    'react-native': true,
  },
  resolve: {
    extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js'],
    alias: {
      'react-native$': 'react-native-web',
    },
  },
  module: {
    rules: [babelLoaderConfiguration, imageLoaderConfiguration, svgLoaderConfiguration],
  },
  // this should be only enabled on web version
  // devtool: 'eval-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'index.html'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      // See: https://github.com/necolas/react-native-web/issues/349
      __DEV__: JSON.stringify(true),
    }),
  ],
}

Expected behavior

Expecting the project to start and display the web app properly.

Steps to reproduce

n/a

Test case

n/a

Additional comments

No response

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
rdewolffcommented, Jul 11, 2022

Of course I have tried that and done it, check my config files. It’s all in there as far as I can see. But when using react-navigation and react-native-screens it doesn’t work anymore. Isn’t there a config item I am missing?

3reactions
necolascommented, Jul 11, 2022

There are dozens of past issues like this that you should have found in a search. You need to configure the bundler to compile RN dependencies with Babel https://necolas.github.io/react-native-web/docs/multi-platform/#compiling-and-bundling

Read more comments on GitHub >

github_iconTop Results From Across the Web

Module parse failed: Unexpected token. react-native/index.js ...
I just spent a few hours dealing with this exact issue. First, you can try adding "@babel/preset-flow" to your .babelrc file (after ...
Read more >
React-Native 0.7, React-Native-Web and React-Navigation ...
However, webpack build continues to error out with "Module parse failed: Unexpected token" on the NavigationContainer.
Read more >
expo you may need an appropriate loader to handle this file ...
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...
Read more >
Module parse failed: Unexpected Token. You may need an ...
Coding example for the question React - Module parse failed: Unexpected Token. ... (js|jsx)$/, in webpack-config.js; I think there is also an error...
Read more >
Troubleshooting | React Navigation
Error : While trying to resolve module "@react-navigation/native" from file ... or "SyntaxError: /xxx/@react-navigation/xxx/xxx.tsx: Unexpected token"​.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found