Phaser在React应用中无法渲染资源,外部运行正常求排查原因
已将Phaser集成至React应用中,目前遇到资源渲染困难。该资源在非React环境(含服务器与模板渲染)中可正常显示,但在React应用中运行时出现报错。
Home.jsx代码:
import React from 'react'; import Phaser from 'phaser'; import GameComponent from './GameComponent'; class MyGame extends Phaser.Scene { preload() { this.load.image('bg1', './assets/bgs/bg1.png'); this.load.image('field', './assets/field.png'); this.load.image('char', './assets/characters/woman.png'); } create() { this.add.image(0, 0, 'bg1').setOrigin(0, 0); } } const Home = () => { const config = { type: Phaser.AUTO, scene: [MyGame], parent: 'phaser-container', scale: { mode: Phaser.Scale.ScaleModes.RESIZE, width: window.innerWidth, height: window.innerHeight }, physics: { default: 'arcade', arcade: { gravity: {y: 200}, }, }, }; return <div><GameComponent config={config} /></div> } export default Home;
index.html代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser-arcade-physics.min.js"></script> <title>Family Trip</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html>
目录结构:

控制台输出:

问题:
为何React加载这些资源会出现问题?
解答:
核心问题是Create React App(CRA)的资源路径解析规则和Phaser的加载逻辑不匹配:
路径解析差异
CRA项目中,./assets/xxx这类相对路径不会被webpack正确处理。React项目构建后,资源会被打包到static/media目录并添加哈希后缀,而Phaser会直接以当前页面路由为基准去查找资源,导致路径错误(比如当前路由是/home,Phaser会去/home/assets/xxx找资源,而实际资源在项目根目录的static/media下)。两种可行的修复方案:
方案一:将资源移至public目录,使用绝对路径加载
把assets文件夹整个移动到项目的public目录下,然后修改Phaser的加载路径为绝对路径:this.load.image('bg1', '/assets/bgs/bg1.png'); this.load.image('field', '/assets/field.png'); this.load.image('char', '/assets/characters/woman.png');CRA会直接将
public目录下的资源复制到构建产物根目录,无需webpack处理,绝对路径能确保Phaser找到正确位置。方案二:通过import引入资源获取正确路径
在代码中先导入资源,webpack会自动处理路径并返回构建后的URL,再传给Phaser:import React from 'react'; import Phaser from 'phaser'; import GameComponent from './GameComponent'; // 导入资源 import bg1 from './assets/bgs/bg1.png'; import field from './assets/field.png'; import char from './assets/characters/woman.png'; class MyGame extends Phaser.Scene { preload() { this.load.image('bg1', bg1); this.load.image('field', field); this.load.image('char', char); } // ...其他代码 }
额外优化点
你同时通过CDN和import Phaser from 'phaser'引入了Phaser,可能导致重复加载冲突。建议二选一:要么删除CDN脚本,通过npm安装Phaser并保持import;要么保留CDN,去掉代码中的import语句。
内容的提问来源于stack exchange,提问作者appdeveloper

