Game-All-In-One 架构复盘:游戏目录、宿主集成与安全边界
本文目录
这篇复盘基于个人项目 Game-All-In-One 当前可读到的 React/TypeScript 前端、Vite 配置与宿主服务代码。它不是对每个旧游戏源码的逐个审计,也不代表这些小游戏都由同一套技术实现:项目目录里保留了多个年代、框架和资源组织方式不同的独立 HTML 游戏。文章只总结外层游戏中心与构建/集成边界,并把能从代码确认的事实和改进建议分开。
项目分层
游戏中心主要由四块组成:
GameCenter/data保存分类与游戏条目。条目包含名称、描述、封面文件名和相对 HTML 地址;gamesData["0"]被用作搜索目录,其他键保存分类结果。GameCenter/hooks管理当前视图、选中分类、搜索词、选中的游戏地址和列表滚动位置。GameCenter/components将分类页、游戏列表页和游戏播放页拆开,由中心组件根据视图状态选择渲染。client/_components/game存放独立游戏页面及其依赖资源。它们不需要被逐个重写成 React 组件,游戏中心通过 iframe 容纳这些不同来源的页面。
这是一种适合渐进整合旧作品的边界:目录和导航用现代 React 管理,游戏仍保留自己的 DOM、样式、音频和 Canvas 生命周期。代价是宿主与 iframe 之间还需要明确约定导航、尺寸、全屏、错误反馈和安全策略。
从分类到游戏页面
useGameNavigation 用 categories、games、play 三种视图表达主要流程。进入游戏前保存列表容器的 scrollTop,返回列表时恢复位置;选分类会清空搜索词,搜索则切换到搜索结果视图。useFilteredGames 在搜索视图中扫描主目录的名称和描述,否则按分类键返回对应列表。
这个设计让状态流向清晰,也有一些值得补齐的边缘:搜索历史目前是组件状态,刷新后消失;视图不在 URL 中,浏览器前进/后退、深链和刷新恢复没有自然语义;清空搜索词时,搜索视图切换需要由调用方额外保证。后续可以把分类、关键词和游戏 ID 编码到 query/path 中,用浏览器 History API 同步导航,并为无结果、资源加载失败和无效游戏地址设计稳定状态。
Vite 开发与产物
项目把 UI 与宿主服务分开构建:开发脚本并行运行 Vite UI 和 service watch;生产构建先后生成 UI 与 service。Vite 插件在构建结束时把 client/_components/game 整体复制到 .deploy-dist/client/_components/game,这样旧 HTML 页面引用的脚本、样式、图片和音频可以与 React 壳一起发布。
这个方案解决了“入口页面能打开,但游戏内部资源 404”的部署问题,同时也意味着构建产物会携带整棵旧资源树。发布前应统计体积、检查是否有重复依赖和不再使用的素材,并为大资源设置缓存策略;不能只根据 UI bundle 的大小判断整个插件包的体积。
iframe 是集成边界,也是安全边界
当前播放组件把目录中的游戏地址转换成宿主环境下的绝对路径,然后直接设置到 iframe 的 src。地址转换逻辑会检查当前路径是否包含 plugin,再寻找 client 段拼接资源根路径;这能适配现有运行目录,但把 URL 结构和插件平台的路径约定耦合在一起。更稳妥的做法是由宿主显式传入资源 base URL,避免从当前页面路径猜测。
目前 iframe 没有 sandbox 属性。只要被加载的页面与博客/宿主同源,页面脚本就可能获得比“展示一个小游戏”更大的权限。若游戏资源来源不是完全可信,应把它们放到独立 origin,并按需设置 sandbox 权限;不要为了修复某个旧游戏就默认开放脚本、弹窗、下载、表单和顶层导航等所有能力。允许脚本与同源访问组合时尤其要谨慎,因为这种组合可能削弱 sandbox 的隔离价值。
本地 Vite 插件还会根据请求路径读取游戏目录下的文件。开发服务器不应暴露到不可信网络;若需要远程联调,文件路径应先规范化并确认仍位于允许的游戏资源根目录内,采用异步文件读取,并只开放必要的扩展名与 MIME 类型。当前代码检查文件是否存在后同步读取,适合本机开发的简单场景,但不应直接作为公网静态文件服务复制到生产环境。
可执行的改进清单
- 将游戏清单改为单一规范数据源:分类只存游戏 ID,搜索、分类和详情都从同一张目录读取,构建时检查 ID 唯一、资源地址存在、封面可加载。
- 将导航状态同步到 URL,并处理浏览器返回、刷新恢复、空搜索、无结果和未知 ID。
- 为 iframe 设计受限权限策略;需要宿主通信时使用版本化
postMessage协议,同时校验origin、消息类型和 payload。 - 把旧游戏迁到专用静态子域,避免与管理后台、博客登录态和其他同源存储共享信任边界。
- 在开发中间件里校验规范化后的真实路径,限制到资源根目录和允许的文件类型;开发服务默认只监听本机。
- 构建时生成资源清单与体积报告,区分 UI、service、游戏 HTML 和媒体资源,按内容哈希设置长缓存。
- 为最常见的移动端、桌面端和资源失败场景建立冒烟检查;游戏本体来源、依赖许可和第三方素材授权需要逐项记录,不能由“能运行”推断为“可再分发”。
结论
这个项目最有价值的工程选择,是用现代宿主承接旧页面,而不是一次性重写所有游戏;目录、导航和独立游戏资源已经形成可理解的职责分层。下一阶段的重点不是再堆一个展示页,而是补齐清单一致性、URL 导航、产物可观测性和 iframe 隔离。尤其在把小游戏迁入公开博客之前,应先确认每款游戏及其图片、音频、字体和第三方脚本的授权与来源。
项目源码
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。