react-native-web with react-navigation - error "Module parse failed: Unexpected token"
See original GitHub issueIs 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:
- Fix the webpack of rnw to work with that use case
- Use another lib like react-router-dom for the navigation to not use the package causing problem.
- 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:
- Created a year ago
- Comments:5 (1 by maintainers)
Top Related StackOverflow Question
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?
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