ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spree 5.6 项目布局与 React Dashboard 脚手架:从 backend/ 重命名到 `spree add dashboard` 全解析

Spree 5.6 项目布局与 React Dashboard 脚手架:从 backend/ 重命名到 `spree add dashboard` 全解析 Spree 5.6 项目布局与 React Dashboard 脚手架从 backend/ 重命名到spree add dashboard全解析【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree本文围绕 Spree 5.6 的规划文档 5.6-project-layout-and-dashboard.md 展开讲解生成项目目录结构的重设计Rails 目录从backend/更名为api/、React Dashboardapps/dashboard/的脚手架与构建期内嵌模板机制以及spree add dashboard、spree upgrade layout两条 CLI 命令的实现细节。读完本文你可以理解 Spree 单仓多语言Rails TypeScript项目的布局决策、双布局兼容检测的原理并能在已有项目中正确加装 Dashboard、配置其开发代理与生产部署拓扑。背景与要解决的问题5.6 版本的目标是把 React Dashboard开发者预览版随create-spree-app一起交付同时把生成项目的布局对齐 Rails 应用未来API-only的角色定位。规划文档指出了四个具体问题backend/不再描述真实角色。即使在 5.6Rails 应用已经同时服务两个前端storefront 与 dashboard加上后台 worker。一旦出现两个前端消费同一 API哪个 backend就说不清了6.0 中 Rails 应用彻底失去 admin UI、变成薄 REST API worker这个名字会更名不副实。命名冲突。5.4 规划曾为未来的 Dashboard 预留apps/admin/但它与遗留 Rails 引擎spree/admin以及 monorepo 中到处使用的spree/dashboard包名冲突需要收敛到统一命名。无法事后加装 Dashboard。脚手架时跳过了 Dashboard或项目生成得更早的用户只能手工拷 starter、写.env.local、装依赖——而create-spree-app已经为 storefront 自动做了同样的事。存量 5.4 项目没有升级路径。backend/已经写进了 Dockerfile、CI 配置和 shell 习惯缺一个迁移命令就只能手工改名。关键决策一览规划文档列出了若干不得偏离的关键决策api/是生成项目中 Rails 应用目录的新名字不是backend/、也不是server/与apps/dashboard/、apps/storefront/三足鼎立。apps/dashboard/是 React SPA 后台的规范位置不是apps/admin/与spree/dashboard包名一致避免与spree/admin引擎冲突此决定取代 5.4 规划中的apps/admin/。apps/放 JS/TS 可部署物api/留在根目录。不把 Rails 应用挪进apps/api/——它语言不同、运行时不同、CLI 面也不同spree console/spree logs把它视为单例放根部表示这是核心JS 应用消费它。Dashboard 是可选组件与 storefront 地位相同。预览期间从交互提示中隐藏WIP 阶段问 yes/no 像是在推荐只通过--react-dashboardflag 或事后spree add dashboard引入。spree/dashboard发布到 npm导出应用外壳一个Dashboard /组件provider 栈 路由含 bootstrap 副作用。宿主拥有index.html、main.tsx、styles.css和 Vite 配置。分发是纯源码与dashboard-core/dashboard-ui同一模型宿主的 Vite 编译外壳从而让 TanStack Router 的生成路由类型在宿主程序中保持一等公民地位。推论外壳源码只用相对导入宿主编译的东西里不允许/别名。Dashboard 模板内嵌在 npm 包里而不是独立模板仓库详见后文构建期内嵌机制。Dashboard 脚手架不携带任何凭据。apps/dashboard/.env.local只有 API 地址一项管理员用邮箱/密码交互登录JWT 存内存 httpOnly 刷新 cookie见 5.5-admin-auth-cookie-refresh.md。因为VITE_前缀变量会被编译进客户端 bundle任何密钥放进去都会发到每个浏览器——脚手架与spree add dashboard永不生成密钥。改名对 5.6 新项目第一天生效npx create-spree-app在 5.6 直接生成api/。存量项目不自动迁移保留backend/继续可用CLI 按命令检测布局用户自行择时运行spree upgrade layout。双布局支持有边界5.6 及整个 5.x 线同时支持两种布局6.0 GA 移除backend/检测。5.6 新增两条 CLI 命令spree add dashboard克隆 starter 到apps/dashboard/、写.env.local、装依赖幂等和spree upgrade layout重命名backend/→api/改写 compose/README/CI/.env脏工作区拒绝执行单提交原子完成。目标生成布局5.6 新项目规划文档给出的目标结构如下my-shop/ ├── api/ ← RailsAPI 5.6 中的 admin 引擎worker由 backend/ 更名而来 │ ├── Gemfile │ ├── Dockerfile │ ├── config/ │ ├── app/ │ └── ... ├── apps/ │ ├── dashboard/ ← 新增React SPAVite、spree/admin-sdk— 5.6 开发者预览 │ │ ├── package.json │ │ ├── vite.config.ts │ │ ├── src/ │ │ └── .env.local ← 指向 API 的变量 │ └── storefront/ ← 不变Next.js可选 │ ├── package.json │ └── ... ├── docker-compose.yml ← 默认预构建镜像 ├── docker-compose.dev.yml ← context: ./apieject 之后 ├── package.json ├── README.md ├── .env ← SECRET_KEY_BASE, PORT └── .gitignore为什么api/在根部而不是apps/api/语言/运行时/部署故事不同CLI 把它当单例spree console、spree logs隐式指那个 api视觉上表达 hub-and-spoke 关系一个 API多个消费者。规划文档还用一张表论证了命名取舍名字读起来像TS 开发者预期结论backend/前端之外的另一个东西泛化、有遗留感两个以上前端时就含糊否server/一个做点什么的服务器暗示通用性SSR、websockets 等不说明提供什么否api/这就是 API 面符合 Vercel/Turborepo/T3 对 API-only 服务的约定一眼可读是即便 5.6 中 Rails 仍服务遗留spree/admin引擎对 JS 消费者暴露的契约是 REST API6.0 admin 引擎消失后目录内容与名字完全吻合。Sidekiq workerwebhook 投递、事件处理从外部观察者视角也是 API 面的一部分——目录名应描述对外角色而非内部进程模型。适用前提与限制以当前仓库实际内容为准当前仓库中create-spree-app已经把 Rails 目录定名为server/——见 constants.ts 中的SERVER_REPO与 server.ts 中downloadServer()克隆到project/servercompose 文件被改写为context: ./server、- ./server:/rails见 scaffold.ts。规划文档中api/vsserver/二选一的争论最终落地为server/规划里的目标布局应理解为该决策过程的一部分本文后续对 CLI 行为的描述均以仓库现状为准涉及server/与backend//api/的兼容在 context.ts 中体现。双布局检测findApiDir与ProjectContext规划文档提出的detectApiDir思路是一个集中式 helper让所有命令用ctx.apiDir而不是硬编码字符串。当前仓库的实现见 context.ts// packages/cli/src/context.ts export const API_DIRS [server, backend] as const export function findApiDir(projectDir: string): string { return API_DIRS.find((dir) fs.existsSync(path.join(projectDir, dir))) ?? server }优先匹配server/新布局backend/旧布局仍然被接受保证存量项目继续工作两者都不存在时回退到server让错误消息报出当前布局名。同文件中还有几个与该机制配套的检测函数值得注意resolveProjectDir()当用户在server/目录内运行 CLI 时通过父目录 compose 文件中的./server:/rails挂载标记正则mountMarker证明父目录才是真正的项目根自动重新定位根目录——因为 scaffold 时克隆进server/的原始 compose 是残留文件挂载.:/rails、期望不存在的同级.envCLI 若直接以它为靶会失败。hasMonorepoSpreePath()检测.env中的SPREE_PATH标识 monorepo 边缘项目isEjectedProject()通过 compose 文件里是否存在build:段判断项目是否已 eject 到源码构建模式。规划文档还给出了弃用时间线5.6/5.x 双布局静默共存 → 6.0 RC 对backend/打印弃用警告并指向spree upgrade layout→ 6.0 GA 删除旧分支。从当前API_DIRS只含server/backend来看api/分支最终未进入实现。spree add dashboard给存量项目加装 Dashboard命令入口实现位于 add.ts。registerAddCommand注册spree add thing目前仅接受dashboard源码注释明确 storefront 对等能力是后续工作指向本规划文档。可选参数--template src指定 starter 模板的 git URL 或本地目录默认用 CLI 内嵌模板SPREE_DASHBOARD_TEMPLATE环境变量可覆盖--no-install跳过依赖安装--quiet跳过结尾摘要供create-spree-app这类包装工具打印自己的总结。核心流程addDashboard()addDashboard() 的执行步骤幂等性检查apps/dashboard/已存在时进入恢复模式——调用ensureDashboardDevEnv()修复缺失或损坏的.env.local其余不动直接返回。取模板fetchTemplate()支持本地目录拷贝测试/CI 用或git clone --depth 1随后restoreGitignore()把gitignore.template还原为.gitignore——因为 npm 从不打包.gitignore文件模板里只能以这个名字发布。写.env.localwriteDashboardEnv()只写代理目标附大段注释说明为什么本地开发不要设置VITE_SPREE_API_URL# apps/dashboard/.env.localwriteDashboardEnv 生成的实际内容 VITE_API_PROXY_TARGEThttp://localhost:端口// packages/cli/src/commands/add.tswriteDashboardEnv 核心 fs.writeFileSync( envPath, [ # Dev-server proxy target — where Vite forwards /api and /rails (your, # Rails backend). The SPA stays same-origin with the API: the SDK uses, # relative URLs and the proxy bridges the port gap., #, # Do NOT set VITE_SPREE_API_URL for local dev — it switches the SDK to, # absolute cross-origin URLs, which breaks on CORS and the SameSiteLax, # auth cookie. Set it only when building for a deploy where the, # dashboard is hosted on a different origin than the API., #, # No credentials belong in this file — every VITE_-prefixed value is, # compiled into the client bundle., VITE_API_PROXY_TARGEThttp://localhost:${port}, ].join(\n), )端口从项目根.env的SPREE_PORT读取readPortFromEnv()。同源于 API是刻意设计SDK 用相对 URLVite 代理补上端口差SameSiteLax的刷新 cookie 才能正常工作。检测包管理器并安装detectPackageManager() 按 lockfile 识别 pnpm/yarn/npm缺省 pnpm安装失败只告警不中断。打印后续步骤spree dev会同时拉起 API 与 Dashboard开发服务器地址http://localhost:5173见 constants.ts 的DASHBOARD_PORT。修复逻辑ensureDashboardDevEnv()一个值得留意的健壮性设计在 ensureDashboardDevEnv()const BROKEN_SCAFFOLD_ENV /^VITE_SPREE_API_URL(https?:\/\/localhost\S*)$/m旧版脚手架曾写入指向 localhost 的VITE_SPREE_API_URL导致请求绕过开发代理、死在 CORS 与SameSiteLaxcookie 上。该函数在spree add dashboard、首次运行配置、以及每次spree dev启动时都会被调用见 dev.ts若发现这种只有旧脚手架输出才会出现的 localhost 值就把那一行替换为VITE_API_PROXY_TARGET文件其余内容用户管理的部分原样保留。可读但不可访问的文件非不存在错误会直接抛出绝不覆盖。spree dev如何带起 Dashboarddev.ts 展示了脚手架成果的运行时闭环spree dev通过hasDashboardApp()检查apps/dashboard/是否存在、dashboardDevRunnable()判断依赖是否就绪可用则startDashboardDevServer()把 Vite 开发服务器与 Docker 栈共跑日志带dashboard |前缀CtrlC 一并停止并在启动前调用ensureDashboardDevEnv()自愈环境。不可运行时打印spree add dashboard提示。模板分发构建期内嵌而不是模板仓库规划文档在Dashboard starter一节中给出了与业界实践对比后的结论Vendure 式 npm 内嵌而非独立模板仓库。规范源在 monorepo 的 packages/dashboard-starter构建时渲染为独立副本塞进spree/cli的 tarball。当前仓库的实现是 scripts/sync-dashboard-starter.mjs其头部注释完整记录了改写规则workspace:^依赖范围 → 发布包上的浮动范围新版本下界取本次发布版本删除 monorepo 专属 devDependencies示例插件不在 npm 上biome.json原本 extends 工作区根配置 → 替换为自包含等价物其余逐字拷贝包括src/routeTree.gen.ts刻意提交——升级时它的 diff 直接展示哪些 admin 页面变了脚本在spree/cli与create-spree-app的构建时运行输出到各自templates/dashboard-starter/gitignore随 tarball 分发prepublishOnly发布前重建版本下界永远与本次发布一致——没有模板仓库要同步、没有 sync token、没有 404 窗口。create-spree-app自己不内嵌副本它的 dashboard 阶段直接委托给项目本地 CLI。见 dashboard.tsexport async function scaffoldDashboard( projectDir: string, opts: { install: boolean; packageManager: PackageManager }, ): Promisevoid { const args [spree, add, dashboard, --quiet] if (!opts.install) args.push(--no-install) await execa(runCommand(opts.packageManager), args, { cwd: projectDir, stdio: inherit }) }注释解释了原因生成项目已依赖spree/cliroot 依赖在本阶段之前装好CLI 携带与发布版本锁步的模板——单一模板源。create-spree-app的 scaffold.ts 中dashboard 是可选阶段失败时清理残留的apps/dashboard/保证事后spree add dashboard的目录不存在前提只告警不中断——因为后续spree init阶段才是保证新镜像与种子数据的关键。CLI 侧定位内嵌模板的逻辑在 resolveBundledTemplate()先找开发态路径src/commands/../../templates/dashboard-starter再找构建态dist/templates/dashboard-starter找不到时明确提示在 monorepo 里先对packages/cli执行pnpm build或传--template。spree/dashboard导出应用外壳Phase 2规划文档 Phase 2 的要求及当前 starter 中的落地形态把包内/别名导入改写为相对路径——纯源码库不能携带宿主 Vite 无法解析的别名导出Dashboard /provider 栈 RouterProvideri18n/默认导航/搜索的 bootstrap 副作用在模块内完成。dashboard-starter 的 main.tsx 正是第一个消费者// packages/dashboard-starter/src/main.tsx节选 import { createDashboardRouter, Dashboard } from spree/dashboard import virtual:spree-dashboard-plugins // 由 spreeDashboardPlugin() 合成 import { routeTree } from ./routeTree.gen // basepath 与 Vite 的 base 对齐使单节点拓扑/dashboard 子路径挂载路由正确 const router createDashboardRouter(routeTree, { basepath: import.meta.env.BASE_URL }) createRoot(document.getElementById(root)!).render(Dashboard router{router} /)注意注释中的顺序约束外壳模块的 bootstrap 副作用必须先于插件导入执行副作用导入充当顺序栅栏。starter 的 vite.config.ts 只挂spreeDashboardPlugin()react()两个插件不需要 TanStack Router 插件——路由树已在spree/dashboard内预生成。该 Vite 插件的职责见配置内注释捆绑 Tailwind、为每个 Spree dashboard 包注入source指令、按 package.json 依赖中的spree.dashboard.plugin标记自动发现插件、伺服virtual:spree-dashboard-plugins虚拟模块、在每次 dev/build 时把外壳与各插件的 file routes 合成进src/routeTree.gen.ts。开发代理配置同样在 vite.config.ts用loadEnv而不是process.env读取.env.local里的VITE_API_PROXY_TARGET默认http://localhost:3000把/api代理到 Rails保持 SPA 与 API 同源。base取VITE_BASE_PATH生产单节点拓扑下构建时设VITE_BASE_PATH/dashboard/让资源 URL 正确解析开发或 CDN 根部署时留空Vite 默认/。monorepo 中 starter 带spree/dashboard-plugin-example作为 devDependency见 starter package.json启动即走发现 →virtual:spree-dashboard-plugins→ 注册全链路充当插件流水线的常设消费方测试发布模板时该依赖被 sync 脚本剥离。spree upgrade版本升级与布局迁移的分工规划文档中的spree upgrade layout重命名backend/→api/脏树拒绝、git mv保历史、单提交、先停容器在当前仓库中并未以同名子命令形式存在——当前 upgrade.ts 实现的是版本升级流程bundle update限定spree*gem避免无关依赖意外大版本→spree:install:migrations db:migrate→rake spree:upgrade支持--planDRY_RUN、--step id、--to version、--yes。规划中布局迁移的安全原则在当前实现里演变为通用约束所有涉及 Rails 目录的命令统一经过 detectProject()必须找到根docker-compose.yml才认定为 Spree 项目目录名检测集中在API_DIRS/findApiDir任何命令不再各自硬编码。规划文档Constraints一节的要求——不得在任何其他命令里自动执行布局迁移迁移永远 opt-in——在仓库中同样成立没有任何命令会自动重命名目录。CLI 命令面与布局适配规划文档列出的 5.6 CLI 面在 packages/cli/src/commands 中可逐一对照命令用途现状spree dev启动服务API 可选 Dashboard 开发服务器已实现见 dev.tsspree stop/spree restart停止/重启已实现spree eject切换到本地 Rails 源码构建已实现见 eject.tsspree console/spree logs [worker]容器内 console / 日志流已实现spree update拉最新镜像 迁移已实现见 update.tsspree seed/spree sample-data/spree user create种子数据 / 示例数据 / 建管理员已实现spree api-key create/list/revokeAPI 密钥管理已实现见 api-key.tsspree upgrade版本升级bundle migrate rake 三步走已实现见 upgrade.tsspree add dashboard为存量项目加装 Dashboard两种布局皆可已实现见 add.tsspree add storefront对等能力规划中标注为后续源码注释中同样标注为 planned关键约束来自规划文档Constraints on Current Work仓库代码可印证新文档、注释、规划一律用apps/dashboard/不再用apps/admin/任何触碰 Rails 目录的新命令必须走集中检测findApiDir/ctx绝不硬编码目录名字符串spree/dashboard包名不得更改——改名会击穿整个dashboard 命名收敛Dashboard 的 env 文件不得出现任何密钥没有命令可以向 Dashboard 构建所读的文件写入sk_开头的 key。单节点托管Rails 托管 Dashboard默认部署拓扑规划文档Single-node hosting一节是部署侧的核心设计值得完整继承默认生产拓扑是单节点Spree 服务器在/dashboard提供构建好的 Dashboard与 Admin API 同源——无 CORS、SameSiteLaxcookie、单一可部署物。Rails 托管方spree_dashboardgemGemfile 可选引入把构建产物目录环境兜底SPREE_DASHBOARD_DIST_PATH按 SPA 语义挂在/dashboard——路径回退index.htmlno-cache、assets/不可变、防路径穿越、未配置时 404。Basepath 配合构建时VITE_BASE_PATH/dashboard/即 Vite 的base运行时createDashboardRouter(routeTree, { basepath: import.meta.env.BASE_URL })保持路由与挂载路径对齐VITE_SPREE_API_URL保持不设 → SDK 发出同源相对 URL →一个 bundle 适用于所有宿主/环境无需按环境重新构建。/admin永久保留给 Classic Admin因此/dashboard这个路径跨版本升级稳定无路由迁移、无冲突。自定义 Dashboard 走自建镜像starter Dockerfile 用ARG DASHBOARD_SOURCE选择阶段stock默认提取 CLI 内嵌模板custom构建名为dashboard-src的命名 build contextBuildKit 惰性求值使普通docker build无需额外参数spree build --production负责组装。Renderspree add dashboard改写项目 Blueprint 的 backend 服务而非新增静态站点——把 Dashboard 构建追加进buildCommand并设置SPREE_DASHBOARD_DIST_PATH无法识别手工编辑过的 Blueprint 原样保留并给文档指引。从 server.ts 可以看到脚手架已为 Render 做了准备把 starter 的render.yaml专为该布局编写Docker 运行时、以仓库根为 context 构建server/Dockerfile使 eject 后的 server 与apps/dashboard打进同一镜像直接搬到项目根因为 Render 只读仓库根的 Blueprint。规划 vs 现状实现落点速查把规划文档的各 Phase 与当前仓库对应起来可避免按过期描述操作规划条目仓库现状新项目目录名api/落定为实现server/server.ts、scaffold.tsCLI 兼容server/backendcontext.ts--dashboardflag当前为--react-dashboard且默认值为false、不出现在交互提示prompts.tsflags.reactDashboard ?? false与规划中预览期间隐藏提示、flag 专属的修订一致脚手架阶段委托spree add dashboard已实现dashboard.ts 执行spree add dashboard --quietdetectApiDir演化为API_DIRS findApiDir()另加根目录重定位resolveProjectDirspree upgrade layout当前spree upgrade是版本升级bundle migrate rake 三步走布局重命名未以独立子命令形式存在backend/仍被静默兼容构建期内嵌模板已实现scripts/sync-dashboard-starter.mjsprepublishOnly发布前重建spree add storefront对等标注为后续planned实操要点生成含 Dashboard 的新项目5.6npx create-spree-app my-shop --react-dashboard --storefront --no-startDashboard 阶段在项目本地执行spree add dashboard模板来自spree/cli内嵌副本依赖安装由--no-install控制阶段失败不会中止脚手架可用npx spree add dashboard事后补齐残留目录会被清理以保证命令前提成立。给存量项目加装npx spree add dashboard # 默认CLI 内嵌模板 安装依赖 npx spree add dashboard --template git-url|本地路径 npx spree add dashboard --no-install幂等apps/dashboard/已存在时只修复/补写.env.local无需先做布局迁移——Dashboard 是独立 Node 应用通过 HTTP 与 Rails 通信不关心 Rails 目录叫server/还是backend/启动npx spree dev共跑 API 与 Vite 开发服务器访问http://localhost:5173用管理员邮箱/密码登录首次运行会创建管理员账户。环境文件纪律规划与实现一致的安全底线apps/dashboard/.env.local只放VITE_API_PROXY_TARGET本地开发不要设VITE_SPREE_API_URL会把 SDK 切成绝对跨域 URL破坏 CORS 与SameSiteLaxcookie仅在跨源部署时设置任何集成需要的密钥 API key 用spree api-key create单独签发与 Dashboard 脚手架无关。构建单节点生产镜像VITE_BASE_PATH/dashboard/构建产物交由 Rails 侧spree_dashboardgem /SPREE_DASHBOARD_DIST_PATH在/dashboard提供静态/CDN 拓扑仍是自定义 Dashboard 独立发版节奏的替代方案。参考规划全文docs/plans/5.6-project-layout-and-dashboard.md被取代部分5.4-spree-starter-and-create-spree-app.mdapps/admin/与backend/命名依赖6.0-admin-spa.mdspree/dashboard/-core/-ui包与defineDashboardPluginAPI、5.5-admin-auth-cookie-refresh.mdDashboard 使用的认证模型、5.5-admin-api-key-scopes.md密钥 scope 方案相关实现packages/cli/src/commands/add.ts、packages/cli/src/context.ts、packages/cli/src/commands/dev.ts、packages/cli/src/commands/upgrade.ts、packages/create-spree-app/src/scaffold.ts、packages/create-spree-app/src/dashboard.ts、packages/dashboard-starter/、scripts/sync-dashboard-starter.mjs、5.6-dashboard-typed-plugin-routes.md构建期类型化路由合成【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表