React Native转Web运行报错:Module parse failed 求助解决方案
执行npm run web将React Native应用运行在Web端时,出现以下错误:
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 https://webpack.js.org/concepts#loaders | const App = () => { | return ( <> | | {/* @ ./index.web.js 1:261-277
按文档操作后仍出现该错误,项目配置文件如下:
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)$/, 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'], }, };
App.js
import LogoImage from "./Atoms/LogoImage"; import react from React import SignInButton from "./Atoms/SignInButton"; import { Button, TextInput, View } from "react-native"; const App = () => { return ( <> <LogoImage /> {/* <InputField /> <InputField /> */} <SignInButton /> </> ); }; // const InputField = () => { // return ( // <View> // <TextInput // style={{height: 40, // borderWidth: 1, // }} // /> // <Button title="press"/> // </View> // )} export default App;
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'], };
.flowconfig
[ignore] ; We fork some components by platform .*/*[.]android.js ; Ignore "BUCK" generated dirs <PROJECT_ROOT>/\.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/\(.*\)$' -> '<PROJECT_ROOT>/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\)$' -> '<PROJECT_ROOT>/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
该错误源于Webpack无法解析JSX语法,同时配置中存在几处需要修正的问题:
1. 修正Webpack的Babel Loader匹配规则
当前test: /\.js$|jsx/的正则写法错误,无法正确匹配.jsx文件,且会导致.js文件匹配逻辑异常。修改为正确的正则表达式,并确保根目录下的App.js被纳入Babel处理范围:
修改webpack.config.js中的babelLoaderConfiguration:
const babelLoaderConfiguration = { test: /\.(js|jsx)$/, // 修正正则表达式 include: [ path.resolve(appDirectory, 'index.web.js'), path.resolve(appDirectory, '.'), // 新增该行,确保根目录文件被处理 path.resolve(appDirectory, 'src'), path.resolve(appDirectory, 'node_modules/react-native-uncompiled'), ], // 其余配置保持不变 };
2. 修复App.js中的React导入错误
App.js中React导入写法错误,导致React无法被正确识别,进而影响JSX解析:
// 错误写法 import react from React // 修改为正确写法 import React from 'react'
3. 确保Babel配置支持JSX解析
为确保Babel能正确处理JSX语法,在babel.config.js中添加@babel/preset-react预设:
module.exports = { presets: [ 'module:metro-react-native-babel-preset', '@babel/preset-react' // 新增该预设 ], };
同时安装该依赖:
npm install --save-dev @babel/preset-react
4. 验证Webpack的resolve配置
确认resolve.extensions已包含.jsx,当前配置已满足要求:
extensions: ['.web.js', '.js', '.jsx'],
完成以上修改后,重新执行npm run web即可正常编译运行。
内容的提问来源于stack exchange,提问作者Ashutosh

