React Vite环境下SimplePeer实例化报错:Cannot read properties of undefined
问题描述
我参考非React+Vite环境的多人会议Demo编写代码,逻辑与Demo完全一致,但运行时出现以下报错:
stream_readable.js:178 Uncaught (in promise) TypeError: 无法读取未定义的属性(读取'call') at Peer.Readable (_stream_readable.js:178:10) at new Duplex (_stream_duplex.js:51:12) at new Peer (index.js:37:5) at createPeer (createroom.jsx:72:16) at createroom.jsx:43:28 at Array.forEach (<anonymous>) at Socket2.<anonymous> (createroom.jsx:42:17) at Emitter.emit (index.mjs:136:20) at Socket2.emitEvent (socket.js:498:20) at Socket2.onevent (socket.js:485:18)
报错指向new Peer()(即new SimplePeer())语句。我尝试使用vite-compatible-simple-peer替换,问题仍未解决。
相关代码片段
createPeer与addPeer函数
function createPeer(userToSignal, callerID, stream) { const peer = new SimplePeer ({ initiator: true, trickle:false, iceServers: [{ urls: "stun:stun.l.google.com:19302" }], stream: stream, }); peer.on("signal", signal => { socketRef.current.emit("sending signal", { userToSignal, callerID, signal }) }); return peer; } function addPeer(incomingSignal, callerID, stream) { const peer = new SimplePeer ({ initiator: false, trickle:false, iceServers: [{ urls: "stun:stun.l.google.com:19302" }], stream: stream, });
vite.config.js配置
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; import { resolve } from 'path'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], define: { global: {}, } });
完整客户端代码
import { useEffect, useRef, useState } from "react"; import "./createRoom.css"; import io from "socket.io-client"; import { useParams } from "react-router-dom"; import SimplePeer from "simple-peer"; const Video = (props) => { const ref = useRef(); useEffect(() => { if (props.peer) { props.peer.on("stream", stream => { ref.current.srcObject = stream; }); } }, []); return ( <video style={{ width: "100%", transform: "rotateY(180deg)" }} ref={ref} autoPlay playsInline ></video> ); }; export default function CreateRoom({ username }) { const [peers, setPeers] = useState([]); const socketRef = useRef(); const userVideo = useRef(); const peersRef = useRef([]); const { id } = useParams(); const roomID = id; useEffect(() => { socketRef.current = io.connect("http://localhost:3000/"); navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => { userVideo.current.srcObject = stream; socketRef.current.emit("join room", roomID); socketRef.current.on("all users", users => { const peers = []; users.forEach(userID => { const peer = createPeer(userID, socketRef.current.id, stream); peersRef.current.push({ peerID: userID, peer, }) peers.push(peer); }) setPeers(peers); }) socketRef.current.on("user joined", payload => { console.log(payload); const peer = addPeer(payload.signal, payload.callerID, stream); peersRef.current.push({ peerID: payload.callerID, peer, }) setPeers(users => [...users, peer]); }); socketRef.current.on("receiving returned signal", payload => { const item = peersRef.current.find(p => p.peerID === payload.id); item.peer.signal(payload.signal); }); }) }, [roomID]); function createPeer(userToSignal, callerID, stream) { const peer = new SimplePeer ({ initiator: true, trickle:false, iceServers: [{ urls: "stun:stun.l.google.com:19302" }], stream: stream, }); peer.on("signal", signal => { socketRef.current.emit("sending signal", { userToSignal, callerID, signal }) }); return peer; } function addPeer(incomingSignal, callerID, stream) { const peer = new SimplePeer ({ initiator: false, trickle:false, iceServers: [{ urls: "stun:stun.l.google.com:19302" }], stream: stream, }); peer.on("signal", signal => { socketRef.current.emit("returning signal", { signal, callerID }) }); peer.on("stream", stream => { const item = { peerID: callerID, peer, stream, }; peersRef.current.push(item); setPeers(users => [...users, peer]); }); peer.signal(incomingSignal); return peer; } return ( <div className="video-wrap"> <span style={{ position: "absolute", top: "1px", left: "1px" }}> {username} </span> <video style={{ width: "100%", transform: "rotateY(180deg)" }} ref={userVideo} autoPlay playsInline ></video> {peers.map((peer, index) => { return <Video key={index} peer={peer} />; })} </div> ); }
解决方法
这个报错是因为SimplePeer依赖Node.js的stream模块,而Vite浏览器环境未原生提供该模块,且你当前的global配置不正确,导致模块初始化失败。按以下步骤修复:
- 安装polyfill依赖
在项目中安装浏览器环境的stream和buffer兼容包:
npm install stream-browserify buffer
- 修改vite.config.js配置
更新配置,添加别名映射、正确配置global并优化依赖:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; export default defineConfig({ plugins: [react()], resolve: { alias: { stream: 'stream-browserify', buffer: 'buffer', }, }, define: { global: 'window', }, optimizeDeps: { include: ['stream-browserify', 'buffer'], }, });
- 在项目入口引入polyfill
在main.jsx/main.tsx顶部添加以下代码:
import { Buffer } from 'buffer'; import 'stream-browserify'; window.Buffer = Buffer;
- 替换为官方SimplePeer包
卸载兼容包,使用官方包即可:
npm uninstall vite-compatible-simple-peer npm install simple-peer
完成以上修改后,SimplePeer就能在Vite+React环境中正常初始化,报错即可解决。
内容的提问来源于stack exchange,提问作者777kkk
相关产品推荐
相关产品推荐

