Remix Supa Fly 堆栈
此自述文件将很快重新编写
了解有关 Remix 堆栈 的更多信息。
npx create-remix --template rphlmr/supa-fly-stack
堆栈内容
- 使用 Docker 进行 Fly 应用程序部署
- 生产就绪的 Supabase 数据库
- 用于 Fly 备份区域回退 的健康检查端点
- 用于在合并到生产和暂存环境时部署的 GitHub Actions
- 使用 基于 cookie 的会话 的电子邮件/密码身份验证/神奇链接
- 使用 Prisma 的数据库 ORM
- 使用 Remix 参数助手 的表单架构(客户端和服务器端!)验证
- 使用 Tailwind 进行样式设计
- 使用 Cypress 进行端到端测试
- 使用 MSW 进行本地第三方请求模拟
- 使用 Vitest 和 测试库 进行单元测试
- 使用 Prettier 进行代码格式化
- 使用 ESLint 进行代码检查
- 使用 TypeScript 进行静态类型检查
不喜欢堆栈中的某些部分?分叉它、更改它,并使用 `npx create-remix --template your/repo`!让它成为你自己的。
开发
-
创建一个 Supabase 数据库(免费层级提供 2 个数据库)
注意:仅用于玩转 Supabase 或用于 `staging` 和 `production` 的 2 个数据库。
注意:用完免费层级了吗?也适用于 Supabase CLI 和本地自托管。
注意:创建一个强数据库密码,但优先使用密码短语,这在连接字符串中更易于使用(无需转义特殊字符)
例如:my_strong_passphrase
-
访问 https://app.supabase.io/project/{PROJECT}/settings/api 以查找你的密钥
-
"项目 API 密钥"
-
在 `.env` 文件中添加你的 `SUPABASE_URL`、`SERVER_URL`、`SUPABASE_SERVICE_ROLE`(也称为 `service_role` `secret`)、`SUPABASE_ANON_PUBLIC`(也称为 `anon` `public`)和 `DATABASE_URL`
注意:`SERVER_URL` 是你在开发环境中的本地主机。它将适用于神奇链接登录。
DATABASE_URL="postgres://postgres:{STAGING_POSTGRES_PASSWORD}@db.{STAGING_YOUR_INSTANCE_NAME}.supabase.co:5432/postgres"
SUPABASE_ANON_PUBLIC="{ANON_PUBLIC}"
SUPABASE_SERVICE_ROLE="{SERVICE_ROLE}"
SUPABASE_URL="https://{STAGING_YOUR_INSTANCE_NAME}.supabase.co"
SESSION_SECRET="super-duper-s3cret"
SERVER_URL="https://127.0.0.1:3000"
-
此步骤仅适用于你选择不使用 CLI 安装依赖项的情况。
npx remix init
-
初始设置
npm run setup
-
启动开发服务器
npm run dev
这将在开发模式下启动你的应用程序,并在文件更改时重新构建资产。
数据库种子脚本创建了一个新用户,其中包含一些你可以用来入门的示例数据。
- 电子邮件:`[email protected]`
- 密码:`supabase`
相关代码
这是一个非常简单的记笔记应用程序,但它很好地展示了如何使用 Prisma、Supabase 和 Remix 构建一个完整的堆栈应用程序。主要功能包括创建用户、登录和注销(处理访问和刷新令牌,并在到期时刷新)、创建和删除笔记。
- 身份验证/会话 ./app/modules/auth
- 创建和删除笔记 ./app/modules/note
部署
如果你是一位 Fly.io 专家,请按你所知的方式进行操作。
此 Remix 堆栈附带两个 GitHub Actions,用于自动将你的应用程序部署到生产和暂存环境。
在首次部署之前,你需要做几件事
-
注册并登录 Fly
fly auth signup
注意:如果你有多个 Fly 帐户,请确保你已在 Fly CLI 中登录与在浏览器中登录的同一帐户。在你的终端中,运行 `fly auth whoami` 并确保电子邮件与已登录浏览器的 Fly 帐户的电子邮件匹配。
-
在 Fly 上创建两个应用程序,一个用于暂存,另一个用于生产。
fly apps create supa-fly-stack-template fly apps create supa-fly-stack-template-staging # ** not mandatory if you don't want a staging environnement **
注意:对于生产应用程序,请确保此名称与你的 `fly.toml` 文件中设置的 `app` 相匹配。否则,你将无法部署。
- 初始化 Git。
git init
-
创建一个新的 GitHub 仓库,然后将其添加为项目的远程仓库。不要推送你的应用程序!
git remote add origin <ORIGIN_URL>
-
将 `FLY_API_TOKEN` 添加到你的 GitHub 仓库。为此,请访问你 Fly 上的用户设置并创建一个新的 令牌,然后将其添加到 你的仓库密钥 中,名称为 `FLY_API_TOKEN`。
-
将 `SESSION_SECRET`、`SUPABASE_URL`、`SUPABASE_SERVICE_ROLE`、`SUPABASE_ANON_PUBLIC`、`SERVER_URL` 和 `DATABASE_URL` 添加到你的 Fly 应用程序密钥中。
注意:要查找你的 `SERVER_URL`,请访问 你的 fly.io 仪表板
要执行此操作,你可以运行以下命令
# production (--app name is resolved from fly.toml) fly secrets set SESSION_SECRET=$(openssl rand -hex 32) fly secrets set SUPABASE_URL="https://{YOUR_INSTANCE_NAME}.supabase.co" fly secrets set SUPABASE_SERVICE_ROLE="{SUPABASE_SERVICE_ROLE}" fly secrets set SUPABASE_ANON_PUBLIC="{SUPABASE_ANON_PUBLIC}" fly secrets set DATABASE_URL="postgres://postgres:{POSTGRES_PASSWORD}@db.{YOUR_INSTANCE_NAME}.supabase.co:5432/postgres" fly secrets set SERVER_URL="https://{YOUR_STAGING_SERVEUR_URL}" # staging (specify --app name) ** not mandatory if you don't want a staging environnement ** fly secrets set SESSION_SECRET=$(openssl rand -hex 32) --app supa-fly-stack-template-staging fly secrets set SUPABASE_URL="https://{YOUR_STAGING_INSTANCE_NAME}.supabase.co" --app supa-fly-stack-template-staging fly secrets set SUPABASE_SERVICE_ROLE="{STAGING_SUPABASE_SERVICE_ROLE}" --app supa-fly-stack-template-staging fly secrets set SUPABASE_ANON_PUBLIC="{STAGING_SUPABASE_ANON_PUBLIC}" --app supa-fly-stack-template-staging fly secrets set DATABASE_URL="postgres://postgres:{STAGING_POSTGRES_PASSWORD}@db.{STAGING_YOUR_INSTANCE_NAME}.supabase.co:5432/postgres" --app supa-fly-stack-template-staging fly secrets set SERVER_URL="https://{YOUR_STAGING_SERVEUR_URL}" --app supa-fly-stack-template-staging
如果你没有安装 openssl,你也可以使用 1password 生成一个随机密钥,只需将 `$(openssl rand -hex 32)` 替换为生成的密钥即可。
现在一切都已设置好,你可以提交并推送你的更改到你的仓库。每次提交到你的 `main` 分支都会触发对生产环境的部署,每次提交到你的 `dev` 分支都会触发对暂存环境的部署。
注意:要手动部署,只需运行 `fly deploy`(它将部署在 `fly.toml` 中定义的应用程序)。
GitHub Actions
免责声明:Github actions ==> 我对此并不精通。使用前请仔细阅读。
我们使用 GitHub Actions 进行持续集成和部署。任何进入 `main` 分支的内容将在运行测试/构建等操作后部署到生产环境。`dev` 分支中的任何内容都将部署到暂存环境。
👉 你必须添加一些环境密钥用于 Cypress。 👈
将 `SESSION_SECRET`、`SUPABASE_URL`、`SUPABASE_SERVICE_ROLE`、`SUPABASE_ANON_PUBLIC`、`SERVER_URL` 和 `DATABASE_URL` 添加到 你的仓库密钥 中。
测试
Cypress
我们在此项目中使用 Cypress 进行端到端测试。你可以在 `cypress` 目录中找到它们。在进行更改时,请添加现有文件或在 `cypress/e2e` 目录中创建一个新文件来测试你的更改。
我们使用 @testing-library/cypress
以语义方式选择页面上的元素。
要在开发环境中运行这些测试,请完成你的 `.env` 并运行 `npm run test:e2e:dev`,这将启动应用程序的开发服务器以及 Cypress 客户端。确保数据库在 docker 中运行,如上所述。
我们还提供了一个实用程序,用于在测试结束时自动删除用户。只需确保在每个测试文件中添加它
afterEach(() => {
cy.cleanupUser();
});
这样,我们可以保持你的测试数据库清洁,并保持你的测试相互隔离。
Vitest
对于实用程序和单个组件的更低级测试,我们使用 `vitest`。我们通过 @testing-library/jest-dom
提供特定于 DOM 的断言助手。
类型检查
此项目使用 TypeScript。建议你为你的编辑器设置 TypeScript,以便在编辑器中获得类型检查和自动完成功能的出色体验。要对整个项目运行类型检查,请运行 `npm run typecheck`。
代码检查
此项目使用 ESLint 进行代码检查。这在 `.eslintrc.js` 中配置。
格式化
我们在此项目中使用 Prettier 进行自动格式化。建议你安装一个编辑器插件(如 VSCode Prettier 插件),以便在保存时自动格式化。你也可以运行 `npm run format` 脚本,以格式化项目中的所有文件。
开始使用 Supabase
你现在准备好了,恭喜!
要扩展你的 Prisma 架构并在你的 Supabase 数据库上应用更改
-
在 ./app/database/schema.prisma 中进行更改
-
准备你的架构迁移
npm run db:prepare-migration
-
检查你的迁移 ./app/database/migrations
-
将此迁移应用到生产环境
npm run db:deploy-migration
如果你的令牌在不到 1 小时(在 Supabase 仪表板中为 3600 秒)内过期
如果你比我拥有更短的令牌生命周期(1 小时),你应该查看 ./app/modules/auth/session.server.ts 中的 `REFRESH_ACCESS_TOKEN_THRESHOLD` 并设置你认为最适合你的用例的值。
Supabase RLS
你可能会问“我可以在 Remix 中使用 RLS 吗”。
答案是“可以”,但它有一定的代价。
在服务器端使用 Supabase SDK 查询你的数据库(对于那些使用 RLS 功能的人)会增加额外的延迟,因为它是调用 Gotrue REST API 而不是直接调用 Postgres 数据库(这是可以的,因为 Supabase SDK 最初是为那些没有/不需要后端的人设计的)。
在我的基准测试中,这使得我的页面速度降低了一倍。(与使用 Prisma 的直接查询相比,增加了约 200 毫秒)
Supabase 使用神奇链接登录
为了使使用神奇链接进行注册/登录正常工作,你需要在 Supabase 中添加一些配置。你需要添加站点 URL 以及将用于 OAuth 的本地、测试和实时应用程序的重定向 URL。为此,请导航到身份验证 > URL 配置,并添加以下值