You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-Typescript视频聊天App出现process未定义错误求助

React+TypeScript视频聊天应用转译后调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:45:04