Next.js项目部署Vercel遇HTMLVideoElement未定义错误求助
问题解决:Next.js + PhaserJS 部署Vercel时
HTMLVideoElement is not defined错误 问题根源
报错是因为Next.js默认的**服务端渲染(SSR)**会在服务器环境下执行代码,而PhaserJS的内部依赖(比如requestVideoFrame.js)引用了浏览器专属的HTMLVideoElement对象,服务器环境不存在这个对象,导致构建失败。你之前在Home.js里加的判断只覆盖了Phaser初始化逻辑,但SceneMain.js在构建阶段就被服务器端加载解析了,触发了错误。
解决方案
核心思路是让Phaser相关代码完全只在客户端执行,禁止服务器端加载解析,通过Next.js的动态导入(dynamic)实现:
步骤1:修改Home.js的SceneMain导入方式
用Next.js的dynamic函数导入SceneMain,同时禁用SSR:
import { useEffect, useRef } from 'react'; import dynamic from 'next/dynamic'; import toast from '你的toast库路径'; // 动态导入SceneMain,强制仅在客户端加载 const SceneMain = dynamic(() => import('../scenes/SceneMain'), { ssr: false, loading: () => <div>加载游戏中...</div> // 可选:添加加载占位符 }); const Home = () => { const gameContainer = useRef(null); const gameInstance = useRef(null); const loadingMessage = useRef(null); const notify = (text) => toast(text); useEffect(() => { // 动态导入Phaser,确保仅在客户端执行 import('phaser').then((Phaser) => { const config = { type: Phaser.AUTO, parent: gameContainer.current, width: "75%", height: "84%", scene: [SceneMain], physics: { default: 'arcade', arcade: {} } }; gameInstance.current = new Phaser.Game(config); // 后续样式和事件逻辑保持不变 gameContainer.current.style.borderRadius = '15px'; gameContainer.current.style.overflow = 'hidden'; gameContainer.current.addEventListener('click', () => { gameInstance.current.input.keyboard.enabled = true; }); gameInstance.current.scene.scenes.forEach(scene => { scene.events.on('create', () => { const mapWidth = 2208; const mapHeight = 1408; scene.cameras.main.setBounds(0, 0, mapWidth, mapHeight, true); scene.cameras.main.setZoom(Math.min(gameInstance.current.scale.width / mapWidth, gameInstance.current.scale.height / mapHeight)); scene.cameras.main.centerOn(mapWidth / 2, mapHeight / 2); loadingMessage.current.style.display = 'none'; }); }); return () => { gameInstance.current.destroy(true); }; }); }, []); // 渲染部分示例 return ( <div> <div ref={loadingMessage}>加载中...</div> <div ref={gameContainer}></div> </div> ); }; export default Home;
步骤2:确保SceneMain.js仅在客户端执行
通过dynamic加ssr: false的配置,SceneMain.js的代码只会在客户端加载执行,不会触发服务器端的Phaser依赖解析,彻底避免HTMLVideoElement未定义的问题。
额外验证
- 本地执行
npm run build,确认构建过程无报错后再部署到Vercel - 检查
next.config.js,确保没有强制SSR的特殊配置
为什么之前的判断没用?
你之前在Home.js里加的typeof HTMLVideoElement !== 'undefined'只覆盖了Phaser初始化逻辑,但SceneMain.js在构建阶段就被Next.js的SSR机制加载解析了,此时还没进入useEffect的客户端执行阶段,判断逻辑根本没生效。
内容的提问来源于stack exchange,提问作者Sneakers World
相关产品推荐
相关产品推荐

