Next.js引入第三方JavaScript失效问题排查求助
问题:Vanilla JS开发的Phaser双陆棋迁移Next.js后无反应
问题背景
原Vanilla JS版本通过HTML直接引入脚本并调用controller.createGame()即可正常运行游戏,但迁移到Next.js后,页面加载无任何反应。
原Vanilla JS核心HTML结构
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Backgammon</title> <link rel="stylesheet" href="build/css/min.css" type="text/css"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" /> <meta name="msapplication-tap-highlight" content="no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta name="apple-mobile-web-app-title" content="Darts Credits"> <script src="build/js/top-min.js" type="text/javascript"></script> </head> <body> <div id="game"> </div> <script src="libs/socket.io.js"></script> <script src="src/controller.js" type="text/javascript"></script> <script src="src/global.js" type="text/javascript"></script> <script src="src/checker.js" type="text/javascript"></script> <script src="src/dice.js" type="text/javascript"></script> <script src="src/placeholder.js" type="text/javascript"></script> <script src="src/gameplay.js" type="text/javascript"></script> <script src="src/preload.js" type="text/javascript"></script> <script>controller.createGame();</script> </body> </html>
Next.js当前实现
项目结构中游戏脚本放置在public/game/src目录,核心代码逻辑:
page.js通过动态导入关闭SSR的客户端组件BackgammonComponent尝试通过Head标签引入脚本并调用游戏初始化函数
问题根源
- 脚本路径错误:public目录下的资源需使用绝对路径,原相对路径
../game/src/xxx.js无法正确指向public下的文件,应改为/game/src/xxx.js - 脚本执行时机未控制:直接在
Head中添加script标签,无法保证所有依赖脚本加载完成后再执行controller.createGame(),导致初始化时controller可能未定义 - socket.io重复引入冲突:组件中import了
socket.io-client,同时原脚本又要引入libs/socket.io.js,可能导致全局对象冲突 - DOM就绪问题:游戏初始化依赖
#game容器存在,原代码未确保容器渲染完成后再执行初始化
修正方案
步骤1:修正资源路径
将所有脚本、样式的路径改为绝对路径,确保指向public目录下的对应文件
步骤2:用Next.js Script组件控制加载顺序
通过next/script的onLoad回调,确保最后一个依赖脚本加载完成后再初始化游戏,同时指定加载策略为afterInteractive适配游戏资源加载场景
步骤3:统一socket.io引入
移除组件中socket.io-client的import,将原项目的libs/socket.io.js放到public/game/libs目录,通过Script组件引入,避免冲突
修正后的BackgammonComponent代码
"use client"; import React, { useRef } from 'react'; import Script from 'next/script'; export default function BackgammonComponent() { const gameContainerRef = useRef(null); // 初始化游戏函数 const initGame = () => { if (window.controller && gameContainerRef.current) { window.controller.createGame(); console.log("游戏初始化完成"); } else { console.error("controller未定义或游戏容器不存在"); } }; return ( <main> <div>Game component</div> <div id='game' ref={gameContainerRef}></div> {/* 按依赖顺序加载脚本,最后一个脚本加载完成后触发初始化 */} <Script src="/game/src/top-min.js" strategy="afterInteractive" /> <Script src="/game/libs/socket.io.js" strategy="afterInteractive" /> <Script src="/game/src/controller.js" strategy="afterInteractive" /> <Script src="/game/src/global.js" strategy="afterInteractive" /> <Script src="/game/src/checker.js" strategy="afterInteractive" /> <Script src="/game/src/dice.js" strategy="afterInteractive" /> <Script src="/game/src/placeholder.js" strategy="afterInteractive" /> <Script src="/game/src/gameplay.js" strategy="afterInteractive" /> <Script src="/game/src/preload.js" strategy="afterInteractive" onLoad={initGame} /> {/* 引入原项目的样式文件 */} <link rel="stylesheet" href="/game/build/css/min.css" type="text/css" /> </main> ); }
额外排查要点
- 打开浏览器控制台查看是否有404错误,确认资源路径是否正确
- 检查是否有脚本报错,比如
controller未定义的提示,进一步验证加载顺序 - 确保原项目的所有依赖资源(如样式、图片等)都已同步到public目录对应位置
内容的提问来源于stack exchange,提问作者lastpeony4
相关产品推荐
相关产品推荐

