项目:html5-games | 版本:v1.1 | 生成日期:2026-10-06 | 依据:源码分析
项目的全部工程化配置集中在 7 个根目录文件里(vite.config.ts、vitest.config.ts、tsconfig.json、tsconfig.node.json、eslint.config.js、.prettierrc、package.json)加一个 env.d.ts,总量不到 250 行,但每一项都与「79 款游戏的分割与加载」「框架 TS / 游戏 JS 双轨」这两大架构事实挂钩。本篇逐文件逐段解读,配置意图在既有篇章已论证过的(如 manualChunks 的 pixi 隔离)以引用方式带过,重点补足未展开的部分:未设 base 的子路径部署影响、tsconfig 双轨的精确边界、构建产物的实测分析。
plugins(第 7 行):vue() 与 tailwindcss()——@vitejs/plugin-vue 提供 SFC 编译,@tailwindcss/vite 是 Tailwind v4 的官方 Vite 插件(v4 不再走 PostCSS 配置链,src/assets/main.css 里的 @import "tailwindcss" 与 @theme 均由该插件处理)。无其他插件:没有 legacy 插件(与 build.target: 'esnext' 一致,不做旧浏览器降级)、没有组件自动注册插件(全项目显式 import,游戏组件甚至由 glob 动态注册)。
resolve.alias(9-11 行):@ → src/,全仓库跨目录 import 的统一形式;tsconfig.json 的 paths 与 vitest.config.ts 的 alias 是同一映射的三份声明(Vite/TS/Vitest 各自独立解析),三处必须同步修改——漏改任意一处会分别在构建、类型检查、测试时暴露。
server(13-16 行):port: 5556、host: '127.0.0.1'——host 钉回环地址意味着局域网设备默认无法访问 dev server(手机真机调试需临时改 host 或用 --host 覆盖),这是刻意的保守默认;package.json 的 dev 脚本再带一次 --port 5556 属于双保险。
build 主体(17-22 行):target: 'esnext' 面向现代浏览器(无 polyfill、无降级转译,产物体积最小化);minify: 'esbuild'(比 terser 快一个量级,压缩率略逊但本项目不敏感);cssCodeSplit: true(默认值,显式声明以示重要——每个异步 chunk 自带样式,游戏的 scoped CSS 随游戏 chunk 按需加载,见第 5 节产物表);chunkSizeWarningLimit: 600(超过 600K 的 chunk 告警,当前最大的是 pixi-vendor 488K,未触发);reportCompressedSize: false(跳过 gzip 体积统计,纯构建提速)。
rollupOptions.output.chunkFileNames(26-32 行):一个函数式命名——chunk 名含 vendor 时落到 assets/vendor-<name>-[hash].js(产物为 vendor-vendor-.js、vendor-pixi-vendor-.js),其余 assets/[name]-[hash].js(游戏 chunk 即 assets/<游戏id>-<hash>.js)。价值在排查与缓存策略:游戏 chunk 名直接可读,Network 面板按 id 即可过滤(见《12-FAQ与故障排查》第 6 节)。
manualChunks(33-48 行):只对 node_modules 内模块生效,四条分支的意图与影响已在《03-接口设计》第 6 节与《10-性能设计与优化》第 1 节论证,此处只补一个易错点:pixi 的匹配写了三个模式(pixi.js、/pixi.js/、pixi/),是因为 Rollup 的 id 形态在不同 pnpm 布局下有差异——新增其他重依赖时照抄这个三重匹配的谨慎风格,否则可能出现依赖被意外并入 vendor 或业务 chunk 的静默回归。
esbuild(51-54 行):legalComments: 'none' 移除产物中的许可证注释——对闭源部署友好,但注意义务层面仍需以其他方式保留第三方许可信息(当前仓库未提供 LICENSE 汇总文件,⚠️ 待确认是否需要补充);target: 'esnext' 与 build 顶层重复声明,属防御性冗余。
未设 base 的影响(重要):配置未设置 base,默认 '/',所有产物内资源引用是绝对路径(/assets/xxx.js)。部署到子路径(如 https://example.com/hall/)会全面失效,且需要两处联动修改而非一处:其一,vite.config.ts 加 base: '/hall/',资源 URL 与 import.meta.glob 的 chunk 引用、worker 的 new URL(...) 均随构建改写(《06-部署运行》3.2 已提示此步);其二——06 篇未提及但同样必须——src/router/index.ts 38 行的 createWebHistory() 没有传 base 参数,vue-router 会按根路径拼接链接,子路径部署下「点开游戏」会跳到 /game/xxx 而丢失 /hall 前缀,需改为 createWebHistory(import.meta.env.BASE_URL)。两处都改完再构建,深链、刷新、预取才全部正常。
元信息:name html5-games、version 1.0.0、private: true(防误发布)、type: module(ESM 仓库,配置文件可用顶层 import)、packageManager: pnpm@10.23.0(corepack 据此自动取版,CI 的 pnpm/action-setup@v4 也按它取版)、engines.node: >=22。description 中的「79 款」是三处文案联动点之一(games.test.ts 防漂移哨兵的另一端)。
scripts 全量表:
| 脚本 | 实际命令 | 说明 |
|---|---|---|
| dev | vite --port 5556 | 与 server.port 双保险 |
| build | vite build | 产物 dist/,无类型检查前置(CI 编排里 typecheck 单独一步) |
| preview | vite preview | 本地预览 dist/,生产问题的最接近复现环境 |
| test | vitest run | 一次性 |
| test:watch | vitest | watch 模式 |
| lint / lint:fix | eslint . / eslint . --fix | 平面配置,ignore 规则见 eslint.config.js |
| format | prettier --write "src/**/*.{ts,vue,js,css,json}" | 手动触发;CI 无格式校验(09 篇 P1) |
| typecheck | vue-tsc --noEmit | 只产诊断不产出 |
注意 build 不依赖 typecheck/lint/test——单独跑 pnpm build 会成功通过含类型错误的代码;本地「提交前五连」与 CI 五步是等价的显式序列(《09-测试与质量保障》第 3 节)。
依赖:dependencies 仅 5 个(vue、vue-router、@vueuse/core、pixi.js、material-symbols),全部是运行时必需;devDependencies 11 个覆盖构建(vite、@vitejs/plugin-vue、tailwindcss、@tailwindcss/vite)、质量(eslint 系、prettier、typescript、vue-tsc)、测试(vitest)。锁文件 pnpm-lock.yaml(84KB)+ CI --frozen-lockfile 构成供应链锚(《08-安全与权限设计》第 6 节)。
**tsconfig.json(框架轨)**的 compilerOptions 逐项:target/module: ESNext + moduleResolution: bundler 是 Vite 时代的标准三件套(bundler 模式允许省扩展名导入与 allowImportingTsExtensions);lib: ["ESNext","DOM","DOM.Iterable"] 补齐浏览器全局类型(OffscreenCanvas、WebWorker 类型部分来自 DOM lib 与 vite/client);useDefineForClassFields: true 对齐 ES2022 类字段语义;isolatedModules 强制单文件可转译(esbuild 的约束);resolveJsonModule 与 skipLibCheck(跳过第三方 .d.ts 检查,提速);noEmit: true(vue-tsc --noEmit 与 Vite 分工,tsc 从不产出);严格族五项 strict / noUnusedLocals / noUnusedParameters / noFallthroughCasesInSwitch / forceConsistentCasingInFileNames 全开——最后一项在 macOS 开发者场景尤其重要:文件系统大小写不敏感时本地通过、Linux CI 失败的大小写问题会被它提前拦下(《12-FAQ与故障排查》Q7 的大小写事故的第二道防线)。paths 声明 @/* 与 Vite 别名对应;types: ["vite/client"] 限定全局类型来源(不自动吸收 node 类型)。include 是双轨边界的精确表述:"src/**/*.ts" 与 "src/**/*.vue" 看似覆盖全部 .vue,但 env.d.ts 里 declare module '*.vue' 把无 lang="ts" 的 SFC 声明为空壳 DefineComponent——vue-tsc 对 JS SFC 只认壳不进内,这就是 74/79 游戏不受类型检查的机制根源(《13-技术债务与演进建议》E-05)。references 指向 tsconfig.node.json。
tsconfig.node.json(构建工具轨):只 include vite.config.ts,composite: true 供主配置 project reference,不继承主配置的严格族(构建配置不需要 DOM lib 与 strict 全家桶)。两轨的分工意义:主代码的 strict 检查不会被 vite.config.ts 的 Node API 类型(process、__dirname)污染,同时避免把 DOM lib 注入构建配置。
env.d.ts:两行职责——/// <reference types="vite/client" /> 提供 import.meta.env、静态资源模块与 glob 的类型;declare module '*.vue' 兜底 SFC 导入类型(对 lang="ts" 的 SFC,vue-tsc 实际会优先真实编译结果)。
eslint.config.js 用 tseslint.config 平面组装,分层与定制已在《09-测试与质量保障》第 3 节展开(essential 档、no-explicit-any 唯一 error、^_ 豁免、prettier 兼容层收尾),本节只补配置结构上的三个细节:其一,ignores 显式列出 dist、node_modules、*.d.ts、public/**、.archive/**——.archive 是仓库根的历史归档目录,不进 lint 半径;其二,为 .vue 与 .ts/.js 分别注入 globals.browser(平面配置下 parserOptions 与 globals 必须逐块声明,.vue 块的 parser: pluginVue.parser + parserOptions.parser: tseslint.parser 是「Vue 模板用 vue parser、script 用 TS parser」的双层解析标准写法);其三,tsconfigRootDir: import.meta.dirname 显式指定——没有它 typescript-eslint 可能在 monorepo 场景找错 tsconfig。.prettierrc 九项:无分号、单引号、100 列、2 空格、es5 尾逗号、括号内空格、箭头函数恒括号、LF、Vue 不缩进 script/style——与源码现状一致,pnpm format 即以此为准;与 eslint 的冲突由 eslint-config-prettier 兜底关闭。
以下数据来自仓库当前 dist/(du/ls 实测,构建于 2026-09-10,hash 会变、量级稳定)。总体积 6.5M,构成如下:
| 产物 | 体积 | 来源与说明 |
|---|---|---|
vendor-pixi-vendor-*.js | 488K | pixi.js 8;仅 3 款 pixi 游戏会触发下载,普通会话不加载 |
vendor-vendor-*.js | 104K | Vue + vue-router + @vue 运行时,首屏必载 |
index-*.js | 32K | 入口(createApp + 路由表 + config/games.ts 的 79 条元数据被入口与页面共享引用) |
GamesPage-*.js | 20K | 大厅:筛选管道 + 分页 + 键盘导航 |
GameShell-*.js / .css | 10K / 10.5K | 外壳随首个游戏 chunk 并行加载 |
GameDetailPage-*.js / .css | 3.2K / 7.2K | 详情页骨架 |
79 个游戏 *.js | 各 6-20K(最大 20K:metroidvania / space-shooter / roguelike / zelda) | import.meta.glob 分割;多数 6-12K |
游戏样式 *.css | 多数 86-101B,个别 1.4-3.2K(connect-pipe / cloud-defense / fifteen-puzzle) | cssCodeSplit 的直接体现:无样式的 canvas 游戏只产出极小的空样式文件,DOM 类游戏样式随 chunk 走 |
coverEncode.worker-*.js | 283B | 封面编码 worker |
registry-*.js | 16K | glob 映射与 config 的共享模块层(入口与详情页共享的中间 chunk) |
media/mov_bbb.mp4、favicon.svg | 5.3M / 662B | public 原样拷贝;全站体积的大头是这一个视频素材,与代码无关 |
三点解读:第一,首屏链路(index + vendor + vueuse + GamesPage + 样式)合计约 180K 量级,符合「打开即玩」的体感承诺(《10-性能设计与优化》第 1 节的下载模型);第二,视频素材占了 6.5M 的 82%,若未来要瘦身仓库或 CDN 流量,评估 mov_bbb.mp4 的替代(更小的样例视频或程序化生成帧)是唯一有数量级收益的动作,代码侧已无肥肉;第三,游戏 CSS 的 86-101B 尾部文件提示另一个可选优化——为纯 canvas 游戏关闭样式注入收益为零(Vite 不支持按 chunk 关闭 cssCodeSplit),保持现状即可。产物结构与部署缓存的配合(hash 资产长缓存、index.html 短缓存)见《06-部署运行》3.2。
| 环境 | 入口 | 关键差异 |
|---|---|---|
| 开发 | pnpm dev(127.0.0.1:5556) | HMR、SPA 回退内置、无缓存问题、类型错误不阻塞运行 |
| 测试 | pnpm test(vitest,node 环境) | 与构建同用 @ 别名;node 无 DOM(09 篇) |
| 生产复现 | pnpm build && pnpm preview | chunk 404、缓存、子路径等生产独有问题在此复现 |
| CI | GitHub Actions verify job | frozen-lockfile 安装 + 五步编排(09 篇第 3 节) |
接手者拿到项目后的第一小时建议路线:跑五连确认基线全绿 → 打开 vite.config.ts 与本篇第 1 节对照一遍(它是唯一同时影响「构建产物形态」与「游戏加载机制」的文件)→ 读《06-部署运行》第 2 节的命令级操作。配置层的改动纪律一句话:每改一处配置,想清楚它在 Vite/TS/Vitest/ESLint 四套解析里的映射伙伴是否需要同步——本篇第 1、3 节至少指出了三组「三份声明必须同步」的耦合(@ 别名、双轨 tsconfig、chunk 命名与测试 glob)。