# LYStack **Repository Path**: wanglaibin/LYStack ## Basic Information - **Project Name**: LYStack - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-05 - **Last Updated**: 2026-09-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # LYStack 构建工具无关的企业级 Vue3 Monorepo 底座:Vite / Rsbuild 可插拔,多应用共享 `@repo/*` 底层包,环境变量统一收口,内置写给 AI 的工程规范。 **简体中文** | [English](./README.en.md) ![LYStack Rsbuild 示例应用](./docs/images/lystack.png) 如果你写了几年 Vue3,已经能写页面、接接口、改 Bug,但一到从 0 搭项目就会纠结这些问题: - 目录到底怎么分,为什么 `components` 和 `utils` 越来越像垃圾桶? - axios 请求层为什么越封越重,最后谁都不敢动? - 环境变量为什么不能到处读,为什么 `?? ''` 会埋线上坑? - 今天用 Vite,明天想切 Rsbuild,为什么业务代码会被构建工具绑死? - 多个应用如何共享 services、shared、ui,而不是复制粘贴? - AI 写代码为什么总是能跑但不像团队代码? LYStack 想回答的就是这些问题。它不是又一个前端框架,也不是套一层 UI 的后台模板——市面上不缺框架,真正稀缺的是一套能解释“企业项目为什么会变复杂、复杂度应该被放在哪里、边界应该如何长期维护”的架构思想。 ## 快速开始 ```bash pnpm install # 交互式单选 / 多选应用 pnpm dev # 非交互式启动一个、多个或全部应用 pnpm dev example-vite pnpm dev example-vite example-rsbuild pnpm dev all # 构建 pnpm build # 类型检查 / 规范 / 测试 pnpm typecheck pnpm lint pnpm test ``` 启动后可以访问: | 应用 | 地址 | | ----------- | --------------------- | | Vite SPA | http://localhost:5173 | | Rsbuild SPA | http://localhost:5273 | | Rsbuild MPA | http://localhost:5373 | ## 构建能力矩阵 | 构建工具 | SPA | MPA | | -------- | --- | ---------- | | Vite | ✅ | 🚧 Roadmap | | Rsbuild | ✅ | ✅ | > MPA 默认由 Rsbuild 承载——Rspack 的 js-first 入口模型 + TS 可编程的 PageConfig 契约天生适合多页场景。Vite 是 html-first 心智,其 MPA 支持需要一层 html 生成翻译层,已列入 roadmap。 ## 五个核心设计 ### 1. 构建工具可插拔 应用只声明“我要构建什么”,不直接处理 Vite / Rsbuild 的细节。 ```ts // apps/example-vite/vite.config.ts import { defineViteConfig, resolveRoot } from '@repo/build-config/vite'; export default defineViteConfig({ kind: 'spa', appName: 'example-vite', root: resolveRoot(import.meta.url), entry: 'index.html', }); ``` ```ts // apps/example-rsbuild/rsbuild.config.ts import { defineRsbuildConfig, resolveRoot } from '@repo/build-config/rsbuild'; export default defineRsbuildConfig({ kind: 'spa', appName: 'example-rsbuild', root: resolveRoot(import.meta.url), entry: 'src/main.ts', }); ``` 应用层只面对中立契约 `AppBuildOptions`,真正的构建工具差异被关进 adapter。 ### 2. services 依赖反转 请求层不直接依赖 router、UI 组件库或 token 存储。 应用启动时在组合根注入运行时能力: ```ts configureServiceAuth({ getToken: () => localStorage.getItem(STORAGE_TOKEN_KEY) ?? '', onAuthenticationFailure: () => { // 真实项目里可以 router.push('/login') 或触发 SSO console.warn('[bootstrap] 认证失效,请接入路由跳转逻辑'); }, }); setErrorMessenger((msg: string) => { // 接入 UI 框架后可替换为 ElMessage.error(msg) console.error(`[LYStack] ${msg}`); }); ``` 这样 `@repo/services` 可以被不同应用复用,而不是被某个 app 的 router / UI / localStorage 绑死。 ### 3. env 统一收口 业务层不直接读 `import.meta.env` / `process.env`,统一走 `@repo/shared/env`。 ```ts const apiBase = getEnv('PUBLIC_API_BASE_URL'); ``` 必填配置缺失时 fail loudly,不用空字符串静默兜底。 `shared/env` 内部会按优先级读取: 1. 构建期聚合快照 `__PUBLIC_ENV__` 2. Vite 的 `import.meta.env` 3. Rsbuild / Node 的 `process.env` 业务代码不需要认识构建工具的环境变量机制。 ### 4. MPA 使用 PageConfig 作为单一真相源 Rsbuild MPA 示例通过 `page.config.ts` 管理多入口。 ```ts export const pages: PageEntry[] = [ { name: 'index', entry: './src/pages/index/main.ts', title: 'LYStack · 首页', }, { name: 'about', entry: './src/pages/about/main.ts', title: 'LYStack · 关于', }, ]; ``` 登记了的页面才会成为入口,`name` 同时作为入口名和产物 html 名。新增页面由 `pnpm new:page` 注入配置,避免入口散落。 ### 5. 给 AI 看的工程规范 LYStack 内置 `AGENTS.md` 和 `.rules/*`,把团队工程约束写给 AI 看: - 注释风格 - 命名规范 - 目录组织 - Vue3 写法 - TypeScript 约束 - services / axios 约束 - env 收口 - 错误处理 - 编码自查 AI 不知道你的团队规矩,就会按自己的默认风格生成代码。把规矩写进仓库,才能让 AI 产出更接近团队代码。 ## 技术栈 | 类别 | 技术 | | ---------- | ------------------------------------ | | 框架 | Vue 3.5 + TypeScript 6(strict) | | 构建 | Vite 8 / Rsbuild 2(可插拔 adapter) | | HTTP | Axios 1.16(多实例 + 依赖反转) | | 包管理 | pnpm 9.x workspace + catalog | | 任务编排 | Turborepo 2.x | | 测试 | Vitest(Vite)/ Rstest(Rsbuild) | | 代码规范 | ESLint 9 flat + Prettier 3 | | 提交工作流 | husky 9 + commitlint + lint-staged | | UI | 无(由使用者自选接入) | ## 项目结构 ``` LYStack/ ├── apps/ │ ├── example-vite/ # Vite SPA 示例 │ ├── example-rsbuild/ # Rsbuild SPA 示例 │ └── example-rsbuild-mpa/ # Rsbuild MPA 示例 │ ├── packages/ │ ├── build-config/ # 构建抽象层:AppBuildOptions + Vite/Rsbuild adapter │ ├── shared/ # 构建无关共享层:env / utils / types / constants │ ├── services/ # HTTP 层:AxiosFactory + interceptor + 依赖反转 │ └── ui/ # 基础 UI 与样式变量,不绑定业务 │ ├── plop-templates/ # new:app / new:page 代码生成模板 ├── app.config.ts # 应用端口与静态构建配置的单一真相源 ├── pnpm-workspace.yaml # workspace + catalog 版本单一真相源 ├── turbo.json # 任务编排 └── tsconfig.base.json # 共享 TypeScript 严格配置 ``` 核心依赖方向: ```txt apps/* ├─> @repo/services ──> @repo/shared ├─> @repo/ui ──> @repo/shared └─> @repo/shared apps/*.config.ts ──> @repo/build-config/vite | @repo/build-config/rsbuild └─> adapter 内部消化 Vite/Rsbuild 差异 ``` 原则很简单:业务应用可以装配底层能力,但底层包不要反过来认识具体应用。 ## 环境变量契约 - 全仓只维护根目录的一套 `.env.development` / `.env.test` / `.env.production`。 - 只有 `PUBLIC_` 前缀变量会进入客户端产物,业务代码统一经 `@repo/shared/env` 读取。 - Vite `mode` 与 Rsbuild `envMode` 统一映射为 `APP_ENV`,env 文件不重复声明。 - `dev/build` 只决定 HMR、压缩、hash、sourcemap;测试环境同样使用生产级构建优化。 ## 版本检测与离线缓存 正式构建会为 Vite / Rsbuild 生成同一套更新协议: - 所有业务 HTML 注入 `lystack-app-name`、`lystack-build-id`、`lystack-build-time` meta。 - 输出 `version.json`,页面在加载、联网、聚焦、重新可见及每 5 分钟检查一次。 - 检测到新构建时派发 `app-update-ready` 事件;离线缓存开启时同时检查 Service Worker 更新。 - `offlineCache: true` 默认只在 `test` / `production` 环境启用,生成 `sw.js` 与 `offline.html`。 应用在自身构建配置中显式决定是否启用: ```ts export default defineViteConfig({ // ... offlineCache: true, }); ``` 也可传详细配置,或设为 `false` 关闭。Service Worker 仅在 HTTPS 或 localhost 等安全上下文注册;注册和版本检查失败都会静默降级,不阻断应用。 ## Roadmap - [x] Rsbuild adapter(SPA + MPA) - [x] Vite adapter(SPA) - [x] services 依赖反转层(HTTP + 认证注入 + 错误展示注入) - [x] env 统一收口与 fail loudly - [x] pnpm workspace + catalog 版本单一真相源 - [x] Turborepo 任务编排 - [x] husky + commitlint + lint-staged - [x] `AGENTS.md` + `.rules/*` AI 友好规范 - [ ] Vite MPA 支持(统一 PageConfig 入口契约的 html 翻译层) - [ ] 可选认证适配层 - [x] 分栈测试体系(Vitest + Rstest)与 Plop 模板 smoke test - [ ] CI - [x] Vite / Rsbuild 统一版本检测与可选离线缓存 ## 许可证 [MIT](./LICENSE)