带你玩 frontend
  • Vue 71%
  • TypeScript 20.3%
  • JavaScript 4.1%
  • CSS 3.9%
  • Dockerfile 0.5%
  • Other 0.2%
Find a file
AkagiYui dc5d343167
Some checks failed
ci / check (push) Failing after 16s
ci / images (app-admin-web/Dockerfile, admin-web) (push) Has been skipped
ci / images (app-website/Dockerfile, website) (push) Has been skipped
ci / deploy (push) Has been skipped
发票界面与 EasyTier 真实进程接入
- app-client/main/easytier:拉起 easytier-core 子进程,用 easytier-cli -o json
  轮询状态;虚拟 IP、对端延迟、p2p/中继、上下行速率都来自真实数据
- 组网凭据与入网节点由服务端在进房时下发,客户端不再自己编
- app-client:发票页(抬头管理、可开票订单、开票、换开)
- app-admin-web:发票列表与详情,含红冲链路
- Dockerfile 基础镜像走 build-arg
- .forgejo/workflows/ci.yaml:检查 → 构建镜像(sha tag)→ 回写 deploy 仓库
2026-09-03 05:34:37 +08:00
.forgejo/workflows 发票界面与 EasyTier 真实进程接入 2026-09-03 05:34:37 +08:00
app-admin-web 发票界面与 EasyTier 真实进程接入 2026-09-03 05:34:37 +08:00
app-client 发票界面与 EasyTier 真实进程接入 2026-09-03 05:34:37 +08:00
app-website 发票界面与 EasyTier 真实进程接入 2026-09-03 05:34:37 +08:00
.gitignore 初始提交:frontend 2026-09-03 03:53:42 +08:00
package.json 初始提交:frontend 2026-09-03 03:53:42 +08:00
pnpm-lock.yaml 初始提交:frontend 2026-09-03 03:53:42 +08:00
pnpm-workspace.yaml 初始提交:frontend 2026-09-03 03:53:42 +08:00
README.md 初始提交:frontend 2026-09-03 03:53:42 +08:00
vite.config.ts 初始提交:frontend 2026-09-03 03:53:42 +08:00

带你玩 · 前端 monorepo

官网、管理站点、以后的玩家客户端都放在这里,用 pnpm workspace + Vite+vp)管理。后端是独立的 Go workspace../backend

frontend/
├── package.json           # workspace 根,只装工具链
├── pnpm-workspace.yaml    # 工作区范围app-* 和 lib-*
├── vite.config.ts         # Vite+ 根配置:格式化 / lint / 任务编排
├── .npmrc  .gitignore
├── app-website/           # 官网Nuxt 4SSR + 宣传页 SSG
├── app-admin-web/         # 管理站点Vue 3 SPA + shadcn-vue
└── app-client/            # 玩家客户端Electron 44 + electron-vite

子项目平铺在本目录下,用前缀区分:app-* 是可独立部署的应用, lib-* 是跨应用共享的库(还没有)。加新子项目只要建目录、写 package.json pnpm-workspace.yaml 的通配符会自动带上它。

需求与排期见 上级目录的 README

环境要求

Node 和 pnpm 都钉死在 package.jsondevEngines 里,本机版本不对会自动下载对应版本, 不需要手工装、也不需要 nvm/fnm

  • Node.js 26.8.1
  • pnpm 12.3.0
vp env doctor    # 看当前解析到哪个 Node、从哪读的
vp env pin 27    # 换大版本:改 devEngines.runtime 并装好

运行时是 Vite+ 在管,不是 pnpm。 装了 vite-plus 之后 node / npm / npx / corepack 在 PATH 上都是 ~/.vite-plus/bin 下的 shim它按 .node-versiondevEngines.runtimeengines.node.nvmrc 的顺序找版本声明, 就近目录优先。所以别再往 pnpm-workspace.yaml 里写 nodeVersion,两处声明会打架。

engines.node 保持和 devEngines.runtime 同步,是为了 CI 里那些只会读 engines 的工具(比如 actions/setup-nodenode-version-file: package.json)也能挑对版本。

上手

pnpm install          # 装全部子项目的依赖
pnpm dev:website      # 官网      http://localhost:3000
pnpm dev:admin        # 管理站点  http://localhost:5173
pnpm dev:client       # 玩家客户端(拉起 Electron 窗口)

管理站点要连后端,先把 API 起起来(第一次需要建表和灌数据):

cd ../backend && make docker-up && make migrate-up && make seed && make run

常用命令

vp 是 Vite+ 的 CLI装在 workspace 根,用 pnpm exec vp <cmd> 调用。

命令 作用
pnpm install 安装依赖
pnpm dev:website / pnpm dev:admin 起单个子项目
pnpm build:all 按依赖顺序构建全部子项目
pnpm typecheck:all 全部子项目跑类型检查
pnpm exec vp check 格式检查 + lint一遍过
pnpm exec vp fmt 用 oxfmt 格式化
pnpm exec vp lint 用 oxlint 检查
pnpm exec vp run -F @dainiwan/admin-web build 只构建某一个
pnpm exec vp cache clean 清任务缓存

vp run 带任务缓存:输入没变就直接复用上次产物。 @dainiwan/website#build@dainiwan/client#build 目前不走缓存——Nuxt 和 electron-vite 在构建过程中都会读回自己刚写进输出目录的文件,自动追踪判定为 「任务改了自己的输入」就放弃缓存了;两者本身都有内部缓存,影响不大。

加一个子项目

mkdir app-foo
# app-foo/package.json 里 name 写 @dainiwan/foo
pnpm install

vp run -r buildvp check 都不用改配置。子项目之间要共享代码时, 建一个 lib-xxx/,在使用方的 package.json 里写 "@dainiwan/xxx": "workspace:*"

带安装脚本的依赖要在 pnpm-workspace.yamlallowBuilds 里显式写 true 或 false 少写一个 pnpm 12 会直接报错。Electron 44 起没有 postinstall 了, 二进制改成首次启动时惰性下载,不需要在这里放行。)

pnpm 配置都在 pnpm-workspace.yaml

pnpm 12 起,package.json"pnpm" 字段不再被读取,.npmrc 里的同名项也在下线, 配置的正式位置是 pnpm-workspace.yaml。写错的键会直接报错而不是静默忽略—— 这是好事,但从旧版本迁过来时要留意。

两个需要知道的设置:

  • allowBuilds:取代了 onlyBuiltDependencies,是个 包名: true/false 的表。 没列到的包如果带安装脚本,安装会失败(旧版本只是警告),所以要显式写 false 表示「就是不给跑」。
  • minimumReleaseAge:供应链冷静期,拒绝安装发布时间不足这个时长的版本, 挡一手「投毒版本发布后被 CI 立刻拉走」。pnpm 12 默认 1440 分钟24 小时), 这里放宽到了 60原因写在配置文件的注释里。这是个安全取舍 想更保守就删掉那一行用回默认值。

代码规范

格式化与 lint 的规则全部集中在根 vite.config.ts,没有单独的配置文件, 也不需要 prettier —— oxfmt 就是格式化器,连忽略规则都写在同一份配置里。

  • oxfmt:单引号、无分号、行宽 320oxfmt 允许的上限), objectWrap: 'collapse'。合起来的效果是「能不换行就不换行」: 中文字符按两列算,行宽小了会把中文字面量拆得很碎,换行位置交给写代码的人自己把握, 格式化只统一引号、缩进和尾逗号。
  • oxlinttypescript / vue / import 三个插件,开了 typeAware (能查出漏 await 的 Promise 这类问题)。
  • 没开 oxlint 的 typeCheck——它的类型检查器还不认识 .vue 单文件组件, 会把所有 import X from './X.vue' 报成找不到模块。类型检查走各子项目自己的 vue-tsc / nuxt typecheck,即 pnpm typecheck:all
  • 不参与格式化的路径写在 vite.config.tsfmt.ignorePatterns (目前只有 shadcn-vue 生成的组件),.gitignore 里的路径 oxfmt 自动跳过。

Vue 模板里不要写多语句的内联事件处理器。 oxfmt 会把 @click="a = null; b = null" 的分号去掉、拆成两行Vue 的表达式解析器接受不了。 两句以上就抽成 <script setup> 里的方法。

待办

  • 各子项目的 Dockerfile / 打包流水线与 Forgejo Runner
  • lib-*:官网、管理站点、客户端共用的类型与常量
  • 客户端的代码签名Windows 证书、Apple 公证)与自动更新