ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

shadcn 仓库中的 Remix Indie Stack 夹具:一个可直接部署的全栈应用参考实现解析

shadcn 仓库中的 Remix Indie Stack 夹具:一个可直接部署的全栈应用参考实现解析 shadcn 仓库中的 Remix Indie Stack 夹具一个可直接部署的全栈应用参考实现解析【免费下载链接】uiA set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.项目地址: https://gitcode.com/GitHub_Trending/ui/ui本文以 shadcn 仓库测试夹具packages/shadcn/test/fixtures/frameworks/remix-indie-stack/中的 README.md 为核心完整解析 Remix Indie Stack 的技术栈组成、本地开发流程、Prisma 数据模型、基于 Cookie 的会话认证以及 Fly.io Docker 的生产部署方案。读完之后你可以掌握一套「SQLite Prisma Remix Tailwind Fly」的组合拳如何从零搭建到上线并理解 shadcn CLI 是如何把这类 Remix 项目识别为可注入组件的目标框架的。这个夹具在 shadcn 仓库中的角色Remix Indie Stack 是 Remix 官方社区的经典全栈模板在本仓库中它被放在packages/shadcn/test/fixtures/frameworks/目录下作为 shadcn CLI 的框架识别测试夹具。从 get-project-info.test.ts 中的用例可以看到remix-indie-stack目录会被getProjectInfo解析为如下项目信息{ name: remix-indie-stack, type: { framework: FRAMEWORKS[remix], isSrcDir: false, isRSC: false, isTsx: true, tailwindConfigFile: tailwindConfig.ts, // 实际为 tailwind.config.ts tailwindCssFile: app/tailwind.css, tailwindVersion: v3, frameworkVersion: null, aliasPrefix: ~, }, }即 CLI 从该目录的package.json、tailwind.config.ts等文件结构推断出这是一个非src目录布局、使用 TSX、Tailwind v3、路径别名为~的 Remix 项目。这也意味着 Indie Stack 是验证 shadcn 组件注入能力的重要参考实现——本文接下来就按 README 自身的骨架逐层拆解这个项目的实际内容与实现。技术栈总览Whats in the stackREADME 开篇给出了该模板的完整能力清单覆盖开发、部署、测试三大维度Fly app 部署Docker容器化生产可用的SQLite 数据库供 Fly 备份区域回退backups region fallbacks使用的Healthcheck 端点GitHub Actions持续部署到 production 与 staging 环境基于cookie 会话的邮箱/密码认证Prisma作为数据库 ORMTailwind样式系统Cypress端到端测试MSW本地第三方请求 mockVitestTesting Library单元测试Prettier代码格式化ESLint代码检查TypeScript静态类型README 同时给出了一条重要建议模板中任何不喜欢的部分都可以 Fork 后修改再用npx create-remix --template your/repo作为自己的起点。快速创建项目README 给出的创建命令是npx create-remixlatest --template remix-run/indie-stack从当前仓库夹具的 package.json 可以确认该模板实际依赖的版本基线remix-run/node/remix-run/react/remix-run/serve均为^2.12.1prisma/client为^5.19.1tailwindcss为^3.4.10vitest为^2.0.5cypress为^13.14.2并声明了 Node 引擎要求18.0.0。本地开发流程README 的 Development 章节定义了从初始化到跑起数据库的标准三步这三步全部可以在package.json的 scripts 中得到印证# 1. 运行模板自带的 remix.init 脚本并提交改动 npx remix init git init # if you havent already git add . git commit -m Initialize project # 2. 初始化数据库生成 Prisma Client、执行迁移、写入种子数据 npm run setup # 3. 启动开发服务器 npm run dev对应 package.json 中的脚本定义dev: remix dev -c \npm run dev:serve\, dev:serve: binode --require mocks -- remix-run/serve:remix-serve ./build/index.js, setup: prisma generate prisma migrate deploy prisma db seed, start: remix-serve ./build/index.js几个值得注意的实现细节dev:serve通过binode --require mocks预加载 mocks/ 目录即 MSW 的第三方请求拦截在本地开发期自动生效setup串联了 Prisma 的三步操作generate生成类型化 Client、migrate deploy应用 prisma/migrations 下的 SQL 迁移、db seed执行种子脚本种子脚本的入口由package.json的prisma.seed字段指定ts-node -r tsconfig-paths/register prisma/seed.ts。种子数据开箱即用的登录账号README 指出数据库种子脚本会创建一个可以直接登录的账号Emailrachelremix.runPasswordracheliscool对照 prisma/seed.ts 的实现该脚本会先清理同名旧用户避免重复运行失败再用bcrypt.hash(racheliscool, 10)生成哈希创建用户并附带两条笔记My first note 与 My second note最后打印Database has been seeded. 确认完成。核心业务代码定位README 将该项目描述为一个简单的笔记应用但完整演示了 Prisma Remix 的全栈写法核心功能为创建用户、登录登出、创建与删除笔记。README 指向的三处关键代码在夹具中均真实存在功能文件用户创建、登录校验、登出app/models/user.server.ts用户会话管理与校验app/session.server.ts笔记的创建与删除app/models/note.server.ts路由侧则由 app/routes/ 下的join.tsx、login.tsx、logout.tsx、notes.*.tsx以及/healthcheck端点共同构成。数据层Prisma 数据模型与 SQLite数据模型定义在 prisma/schema.prisma 中datasource db { provider sqlite url env(DATABASE_URL) } model User { id String id default(cuid()) email String unique // ... password Password? notes Note[] } model Password { hash String user User relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) userId String unique } model Note { id String id default(cuid()) title String body String // ... userId String }从源码结构看这个模型有两个设计考量Password独立成表密码哈希不与用户主表混存配合user.server.ts中verifyLogin返回时显式解构剔除password字段const { password: _password, ...userWithoutPassword } userWithPassword保证密码哈希绝不流向客户端级联删除Password与Note到User的外键都声明了onDelete: Cascade删除用户时自动清理关联数据——这一点与后文 Cypress 测试中cy.cleanupUser()的清理机制正好呼应。认证与会话cookie-based sessionsREADME 将「Email/Password Authentication with cookie-based sessions」列为核心能力之一。app/session.server.ts 的实现展示了 Remix 的 cookie 会话存储标准写法invariant(process.env.SESSION_SECRET, SESSION_SECRET must be set); export const sessionStorage createCookieSessionStorage({ cookie: { name: __session, httpOnly: true, path: /, sameSite: lax, secrets: [process.env.SESSION_SECRET], secure: process.env.NODE_ENV production, }, });要点包括SESSION_SECRET环境变量为强制项缺失时启动即抛错生产环境 Cookie 自动启用securecreateUserSession支持「记住我」选项勾选时 CookiemaxAge为 7 天60 * 60 * 24 * 7requireUser在用户不存在时会主动logout并重定向防止脏会话。这与部署章节要求设置SESSION_SECRET飞书密钥的步骤前后呼应。密码校验逻辑在 user.server.ts 的verifyLogin中按 email 查询用户include: { password: true }用bcrypt.compare比对哈希失败返回null成功后剥离密码字段再返回用户对象。生产部署Fly.io DockerREADME 的 Deployment 章节给出了完整的首次部署清单以下按原文步骤继承并补充夹具中对应的配置证据。部署前准备安装 Fly CLI 并注册登录fly auth signup注意若你拥有多个 Fly 账号请确保 Fly CLI 与浏览器登录的是同一账号fly auth whoami核对邮箱。为 staging 和 production 各创建一个 Fly appfly apps create indie-stack-template fly apps create indie-stack-template-staging注意应用名必须与fly.toml中的app字段一致否则无法部署。初始化 Git 并关联远程仓库此时不要 pushgit init git remote add origin ORIGIN_URL在 GitHub 仓库 secrets 中添加FLY_API_TOKEN在 Fly 用户设置中创建 Personal Access Token。为两个应用设置会话密钥fly secrets set SESSION_SECRET$(openssl rand -hex 32) --app indie-stack-template fly secrets set SESSION_SECRET$(openssl rand -hex 32) --app indie-stack-template-staging没有 openssl 时可用任意随机字符串生成器替代$(openssl rand -hex 32)。为 SQLite 数据库创建持久化卷fly volumes create data --size 1 --app indie-stack-template fly volumes create data --size 1 --app indie-stack-template-staging完成以上步骤后提交并推送代码main分支的每次提交部署到生产环境dev分支部署到 staging。fly.toml健康检查与卷挂载上述命令背后的行为由 fly.toml 精确控制[mounts]将名为data的卷挂载到/data目录——这就是 SQLite 文件与持久化卷的落点[[services.http_checks]]每 10 秒GET /healthcheck一次grace period 5 秒即 README 提到的健康检查端点对应路由 app/routes/healthcheck.tsxinternal_port 8080与 80/443 入口force_https true完成流量接入[experimental]中auto_rollback true支持部署失败自动回滚。Dockerfile多阶段构建与启动钩子Dockerfile 采用四阶段构建以控制最终镜像体积deps安装含 dev 依赖的完整node_modulesproduction-depsnpm prune --omitdev得到生产依赖build执行npx prisma generate与npm run build最终镜像仅拷贝生产node_modules、.prisma引擎、构建产物与start.sh并设定关键环境变量ENV DATABASE_URLfile:/data/sqlite.db ENV PORT8080 # 数据库 CLI 快捷方式直接连接 $DATABASE_URL RUN echo #!/bin/sh\nset -x\nsqlite3 \$DATABASE_URL /usr/local/bin/database-cli chmod x /usr/local/bin/database-cli ENTRYPOINT [ ./start.sh ]其中DATABASE_URLfile:/data/sqlite.db指向飞书卷挂载路径。而 start.sh 存在的意义正如其注释所写在启动服务器前先把未执行的 Prisma 迁移跑完——#!/bin/sh -ex npx prisma migrate deploy npm run start这保证了 Fly 容器每次冷启动时数据库 schema 都是最新的也是 README 中「连接线上数据库」操作能正常工作的前提。连接线上数据库README 说明 SQLite 文件位于部署应用的/data/sqlite.db执行fly ssh console -C database-cli即可进入交互式 SQLite CLIdatabase-cli即 Dockerfile 中定义的快捷命令。持续集成GitHub ActionsREADME 的 GitHub Actions 章节说明main分支的任何变更在经过测试、构建等 CI 步骤后部署到生产环境dev分支则部署到 staging。这一约定与上文 Fly 双应用命名indie-stack-template与-staging一一对应构成「分支 → 环境」的映射规则。测试与工程化README 将 Testing 拆分为四个小节以下逐一继承并结合 package.json 脚本说明。Cypress 端到端测试Cypress 用例位于cypress/e2e目录夹具中当前含 cypress/e2e/smoke.cy.ts使用testing-library/cypress以语义化方式选择页面元素。本地运行npm run test:e2e:dev该脚本实际为start-server-and-test dev http://localhost:3000 npx cypress open会同时拉起应用 dev server 与 Cypress 客户端前提是数据库已在 Docker 中运行。CI 场景则走test:e2e:run先npm run build再以start:mocks在 8811 端口启动构建产物配合 MSW mock 外部请求最后执行npx cypress run。README 特别介绍了两个测试工具函数定义在 cypress/support/ 下// 无需走登录流程即可获得登录态 cy.login(); // you are now logged in as a new user// 每个测试结束后自动删除用户保持本地数据库干净、测试互相隔离 afterEach(() { cy.cleanupUser(); });cleanupUser之所以能安全地删除整个用户正依赖于上文 Prisma schema 中的onDelete: Cascade级联约束。Vitest 单元测试对工具函数与单个组件的低层级测试使用vitest并借助testing-library/jest-dom提供 DOM 断言辅助testing-library/jest-dom已在 devDependencies 中测试环境由 test/setup-test-env.ts 初始化。运行npm test即可。类型检查、Lint 与格式化TypeScriptREADME 建议在编辑器中配置 TS 以获得完整的类型检查与补全体验全项目类型检查命令为npm run typecheck实际执行tsc tsc -p cypress将应用代码与 Cypress 代码一并纳入检查ESLint代码检查由 ESLint 承担且 devDependencies 中挂载了react、react-hooks、jest、cypress、jsx-a11y、testing-library等一整套针对性插件覆盖 README 提到的 Linting 能力Prettier自动格式化README 建议安装编辑器插件如 VSCode Prettier实现保存时格式化也可运行npm run format格式化全部文件此外还有format:repo脚本将prettier --write与eslint --fix串接执行。一键验证全部质量门可用npm run validate它通过npm-run-all --parallel并行执行单测--run模式、lint、typecheck 与 e2e 测试——从脚本结构看这正是 CI 流程中「测试/build」步骤的本地等价物。remix.init模板初始化的自动化逻辑README 强调「首次使用请先运行npx remix init并提交改动」。这一步的完整逻辑实现在 remix.init/index.js 中从源码结构看它做了以下事情基于目录名生成唯一应用名目录名-随机后缀并将fly.toml与 README 中的占位名indie-stack-template全部替换为该应用名——这解释了 README 中「app 名必须匹配fly.toml」的注意事项从何而来用crypto.randomBytes生成随机SESSION_SECRET写入.env格式由.env.example模板替换而来按检测到的包管理器npm/pnpm/yarn/bun调整package.json与 lockfile 引用bun 下还会把 seed 命令中的ts-node替换为bun清理仓库级文件.github/ISSUE_TEMPLATE、仓库维护用 workflowsformat-repo、lint-repo、no-response、dependabot、LICENSE.md 等让 Fork 出来的项目保持干净最后自动执行setup即 Prisma 生成 迁移 种子与format并提示「Setup is complete」后以npm run dev开始开发。理解了这段脚本就能明白 README 中「run this stacks remix.init script and commit the changes it makes」这一要求的具体含义它把模板改造成属于你的独立应用且这些改动应当作为初始提交的一部分。小结Remix Indie Stack 夹具完整地示范了一条独立开发者友好的全栈路径Prisma SQLite 提供零配置的生产数据库Fly 卷挂载与start.sh中的prisma migrate deploy保证 schema 随部署自动演进cookie 会话 SESSION_SECRET密钥体系覆盖认证安全GitHub Actions 的 main/dev 双分支策略支撑 staging 与 production 两级环境Cypress Vitest typecheck lint format 构成完整质量门。对 shadcn 项目而言它同时还是 CLI 框架识别逻辑的标准 Remix 参考样本app/tailwind.css、别名前缀~、Tailwind v3是理解「模板 → 可部署应用 → 组件注入目标」这条链路的极佳入口。【免费下载链接】uiA set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.项目地址: https://gitcode.com/GitHub_Trending/ui/ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表