React-Typescript视频聊天App出现process未定义错误求助
leaveCall()出现process未定义错误 我正在开发基于React+TypeScript、WebRTC、Socket.io的视频聊天Web应用,原本JavaScript版本运行正常,转为TypeScript后,点击调用leaveCall()函数时出现错误:ReferenceError: process is not defined,我的代码中并未使用process,附上前后端代码,请求帮助排查问题。
错误信息
process is not defined ReferenceError: process is not defined at emitReadable (http://localhost:3000/static/js/bundle.js:116743:5) at onEofChunk (http://localhost:3000/static/js/bundle.js:116722:5) at readableAddChunk (http://localhost:3000/static/js/bundle.js:116493:5) at Readable.push (http://localhost:3000/static/js/bundle.js:116481:10) at http://localhost:3000/static/js/bundle.js:123896:44
前端TypeScript代码
import React, { createContext, useState, useRef, useEffect } from 'react'; import { io, Socket } from 'socket.io-client'; import Peer, { SignalData } from 'simple-peer'; interface CallData { isReceivingCall: boolean; from: string; name: string; signal: SignalData; } interface SocketContextProps { call: CallData | undefined; callAccepted: boolean; myVideo: React.RefObject<HTMLVideoElement>; userVideo: React.RefObject<HTMLVideoElement>; stream: MediaStream | undefined; name: string; setName: React.Dispatch<React.SetStateAction<string>>; callEnded: boolean; me: string; callUser: (id: string) => void; leaveCall: () => void; answerCall: () => void; } const SocketContext = createContext<SocketContextProps>({} as SocketContextProps); const socket: Socket = io('http://localhost:5000'); const ContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [callAccepted, setCallAccepted] = useState(false); const [callEnded, setCallEnded] = useState(false); const [stream, setStream] = useState<MediaStream>(); const [name, setName] = useState(''); const [call, setCall] = useState<CallData | undefined>(undefined); const [me, setMe] = useState(''); const myVideo = useRef<HTMLVideoElement>(null); const userVideo = useRef<HTMLVideoElement>(null); const connectionRef = useRef<Peer.Instance>(); useEffect(() => { navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then((currentStream) => { setStream(currentStream); if (myVideo.current) { myVideo.current.srcObject = currentStream; } }); socket.on('me', (id: string) => setMe(id)); socket.on('callUser', ({ from, name: callerName, signal }: CallData) => { setCall({ isReceivingCall: true, from, name: callerName, signal }); }); }, []); const answerCall = () => { setCallAccepted(true); const peer = new Peer({ initiator: false, trickle: false, stream }); peer.on('signal', (data: SignalData) => { socket.emit('answerCall', { signal: data, to: call?.from }); }); peer.on('stream', (currentStream: MediaStream) => { if (userVideo.current) { userVideo.current.srcObject = currentStream; } }); if (call?.signal) { peer.signal(call.signal); } connectionRef.current = peer; }; const callUser = (id: string) => { const peer = new Peer({ initiator: true, trickle: false, stream }); peer.on('signal', (data: SignalData) => { socket.emit('callUser', { userToCall: id, signalData: data, from: me, name }); }); peer.on('stream', (currentStream: MediaStream) => { if (userVideo.current) { userVideo.current.srcObject = currentStream; } }); socket.on('callAccepted', (signal: SignalData) => { setCallAccepted(true); peer.signal(signal); }); connectionRef.current = peer; }; const leaveCall = () => { setCallEnded(true); connectionRef.current?.destroy(); window.location.reload(); }; const socketContextValue: SocketContextProps = { call, callAccepted, myVideo, userVideo, stream, name, setName, callEnded, me, callUser, leaveCall, answerCall, }; return (<SocketContext.Provider value={socketContextValue}> {children} </SocketContext.Provider>); }; export { ContextProvider, SocketContext };
原JavaScript版本代码
import React, { createContext, useState, useRef, useEffect } from 'react'; import { io } from 'socket.io-client'; import Peer from 'simple-peer'; const SocketContext = createContext(); const socket = io('http://localhost:5000'); const ContextProvider = ({ children }) => { const [callAccepted, setCallAccepted] = useState(false); const [callEnded, setCallEnded] = useState(false); const [stream, setStream] = useState(); const [name, setName] = useState(''); const [call, setCall] = useState({}); const [me, setMe] = useState(''); const myVideo = useRef(); const userVideo = useRef(); const connectionRef = useRef(); useEffect(() => { navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then((currentStream) => { setStream(currentStream); myVideo.current.srcObject = currentStream; }); socket.on('me', (id) => setMe(id)); socket.on('callUser', ({ from, name: callerName, signal }) => { setCall({ isReceivingCall: true, from, name: callerName, signal }); }); }, []); const answerCall = () => { setCallAccepted(true); const peer = new Peer({ initiator: false, trickle: false, stream }); peer.on('signal', (data) => { socket.emit('answerCall', { signal: data, to: call.from }); }); peer.on('stream', (currentStream) => { userVideo.current.srcObject = currentStream; }); peer.signal(call.signal); connectionRef.current = peer; }; const callUser = (id) => { const peer = new Peer({ initiator: true, trickle: false, stream }); peer.on('signal', (data) => { socket.emit('callUser', { userToCall: id, signalData: data, from: me, name }); }); peer.on('stream', (currentStream) => { userVideo.current.srcObject = currentStream; }); socket.on('callAccepted', (signal) => { setCallAccepted(true); peer.signal(signal); }); connectionRef.current = peer; }; const leaveCall = () => { setCallEnded(true); connectionRef.current.destroy(); window.location.reload(); }; return ( <SocketContext.Provider value={{ call, callAccepted, myVideo, userVideo, stream, name, setName, callEnded, me, callUser, leaveCall, answerCall, }} > {children} </SocketContext.Provider> ); }; export { ContextProvider, SocketContext };
问题排查与解决
这个错误并非你的代码直接使用process导致,而是依赖包(大概率是simple-peer或其依赖)在浏览器环境中引用了Node.js的process对象,而React+TS的打包环境默认没有注入这个全局变量。
解决步骤:
注入process全局变量
如果使用Create React App,安装react-app-rewired和customize-cra:npm install react-app-rewired customize-cra --save-dev在项目根目录创建
config-overrides.js:const { override, addWebpackPlugin } = require('customize-cra'); const webpack = require('webpack'); module.exports = override( addWebpackPlugin( new webpack.DefinePlugin({ 'process.env': JSON.stringify(process.env), 'process': { env: JSON.stringify(process.env) } }) ) );修改
package.json中的启动脚本:"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test" }降级或替换依赖包
检查simple-peer的版本,部分新版本可能引入了Node环境的依赖。可以尝试降级到JavaScript版本使用的旧版:npm install simple-peer@<原JS版本使用的版本号>临时规避验证
暂时注释connectionRef.current?.destroy(),确认是否是该方法触发了依赖包中的process引用:const leaveCall = () => { setCallEnded(true); // connectionRef.current?.destroy(); 先注释这行 window.location.reload(); };如果注释后错误消失,说明是
simple-peer的destroy方法内部调用了依赖Node环境的代码,此时优先考虑降级依赖或注入process变量。
补充说明
React+TypeScript的打包环境(如CRA)默认不会在浏览器中提供Node.js的全局变量,而JavaScript版本可能因为依赖包版本较低,没有引入这些Node环境的代码,所以运行正常。
内容的提问来源于stack exchange,提问作者MOHAMMAD SIDDIQUE

