Remix Speed Metal Stack
了解更多关于 Remix Stacks 的信息。
npx create-remix --template Girish21/speed-metal-stack
Remix 博客 📖
这个博客启动模板的灵感很大程度上来自于 Kent C. Dodds 对 kentcdodds.com 的实现。您可以在 我如何在 2021 年构建一个现代网站 中阅读更多关于架构和背后思想的内容。
架构 💡
重要 🚧
Fly 要求所有应用程序具有全局唯一的名称,我们使用目录名和随机哈希作为应用程序名称。当然,您可以在使用 Fly CLI 启动应用程序之前随时更改此名称。但这无关紧要,因为您可以通过将 CNAME
记录添加到您的自定义域名,使其指向 Fly 内部 URL,从而将 Fly 内部 URL 重新分配给任何自定义域名。我们稍后在将应用程序部署到生产环境时会看到这一点。
快速开始
# run database migrations and set up the initial blog
npm run setup
# run the initial build for the development server
npm run build
# start the development server and run other processes in parallel in watch mode
npm run dev
可用脚本
build
- 编译并构建 express 服务器、Remix 应用程序和 Tailwind,使用production
模式dev
- 启动 express 服务器、Remix 监听器和 Tawilwind CLI,使用监听模式format
- 对代码库运行 prettier 并修复可修复的问题lint
- 对代码库运行 ESLintnew:blog
- 从命令行创建一个新的博客文章模板start
- 启动 express 服务器(应仅在运行npm run build
之后执行)test
- 运行vitest
test:e2e:dev
- 在开发模式下启动 cypress 运行器test:e2e:run
- 在 CI 模式下启动 cypress 运行器typecheck
- 对代码库运行类型检查
Fly 设置 🛠
-
注册并登录 Fly
flyctl auth signup
数据库 🗃
我们在此模板中使用 SQLite 作为数据库。SQLite 是一个快速的数据库引擎,是持久化数据而无需使用 Postgres 等高级数据库引擎的绝佳选择。
安装 ⚙️
SQLite 在所有 Mac 上都预装了。您可以查看其他操作系统的官方安装指南 SQLite 安装指南
为什么我们需要数据库 ❓
我们使用 MDX-Bundler 来编译 MDX 文件,MDX-Bundler 内部使用 esbuild
来编译 MDX 文件。虽然 esbuild
非常快,但在编译过程中仍然存在明显的延迟,这不利于站点的性能和用户体验。而且,当数据没有变化时,没有必要在每次请求时都编译 MDX,这似乎是时间和性能的浪费。因此,我们可以缓存已编译的 MDX,并且仅当内容发生变化时才重新编译。
Prisma △
我们在此模板中使用 Prisma 作为 ORM。要创建 SQLite 数据库并初始化数据库模式,请运行
npx prisma migrate dev
上述命令会提示输入迁移名称,您可以将其命名为 initial migration
。此命令还将安装 Prisma Client 以与数据库进行交互。
开发 💻
我们可以启动开发服务器,并运行迁移,并使用初始模式填充 SQLite 数据库。然后,在终端的新选项卡中,运行该命令。
npm run dev
此命令同时启动四个进程。
- Remix 开发服务器在开发模式下启动,并在文件更改时重建资源。
- Tailwind CLI 在样式更改时重建样式表
- MSW 服务器会拦截对 GitHub 的 API 调用,并从本地提供内容,而不是调用远程 API
- 文件监视器会监视
content
目录并重建资源。
相关文件 🔍
- Tailwind 配置 tailwind.config.js
- MSW API 模拟服务器 mock
- 内容更改监视器 refresh-on-content-change
部署 🚀
初始设置 👀
在继续部署应用程序之前,我们需要执行一些步骤
- 创建一个 GitHub 账户 GitHub
- 在 Fly 上创建一个新应用程序
flyctl launch --name YOUR_APP_NAME --copy-config --no-deploy
⚠️ 请记住不要部署,因为我们还有一些设置步骤需要完成!
环境变量和密钥 🤫
此模板带有 GitHub actions 工作流,可自动将应用程序部署到 Fly.io。首先,我们需要使用一些密钥设置 GitHub actions 和 Fly 应用程序。现在开始执行此操作。
要从 GitHub action 将构建映像推送到远程 Fly 注册表,我们需要 Fly 的访问令牌。我们可以使用 Fly 命令行生成该令牌,运行
flyctl auth token
该命令将生成一个访问令牌。然后,您可以访问 GitHub 存储库的 settings
页面 https://github.com/:owner/:repo/settings/secrets/actions
,然后单击 New repository secret
,将此令牌添加到 GitHub actions 密钥。接下来,GitHub 会提示输入键和值。键应为 FLY_API_TOKEN
,值将是命令行生成的令牌。
我们还需要将 Fly 应用程序名称设置为密钥,键应为 FLY_APP_NAME
,值将是 fly.toml 中指定的应用程序名称
现在我们需要在 Fly 应用程序中设置密钥。
由于我们按需从 GitHub 获取内容,而不是预先构建所有页面,因此我们需要一个来自 GitHub 的访问令牌来调用 GitHub API 并获取内容。此外,GitHub 不会限制应用程序更频繁地调用 GitHub API。因此,您可以在 个人访问令牌 中生成访问令牌。然后,您可以复制生成的令牌并将其设置为应用程序的密钥。我们可以通过运行以下命令来执行此操作
flyctl secrets set GITHUB_TOKEN={GITHUB_TOKEN}
我们还需要一个密钥来签署我们的会话。我们可以通过运行命令来执行此操作
flyctl secrets set SESSION_SECRETS=$(openssl rand -hex 32)
如果
openssl
不可用,您可以使用像1Password
这样的密码生成服务来生成安全令牌。
所需的最后一个密钥是在 GitHub action 和部署在远程服务器上的应用程序之间进行安全通信的令牌,因为我们需要一个面向公众的 API 来进行此通信。
openssl rand -hex 32
我们必须将此密钥设置为 GitHub actions 密钥和 Fly 密钥的一部分。键应为 REFRESH_TOKEN
。您可以在 GitHub 中创建一个新的 actions 密钥,并通过运行该命令为 Fly 应用程序创建一个新的密钥。
flyctl secrets set REFRESH_TOKEN={GENERATED_PASSWORD}
卷 💾
我们还需要在 Fly 中创建一个卷来持久化应用程序数据 (SQLite DB),以便 Fly 可以持久化跨部署和容器重启存储的数据。同样,我们可以使用 Fly 命令行执行此操作。
flyctl volumes create data --region [REGION] --size 1
注意:REGION 应该是启动应用程序时选择的区域。您可以通过运行
flyctl regions list
来检查选择的区域。
重要的是要注意,卷绑定到区域中的应用程序,并且不能在同一区域或多个区域中的应用程序之间共享。
您可以在 此处 了解有关 Fly 卷的更多信息
推送到生产环境 🥳
我们已准备好进行首次部署。GitHub actions 工作流配置为在推送到 main
分支时运行。因此,让我们将本地分支 main
推送到远程,从而触发工作流。
一旦所有检查都通过,并且部署完成,您就可以运行
flyctl info
以获取当前应用程序 URL 和 IP 地址。应用程序 URL 将是 https://YOUR_APP_NAME.fly.dev
。您可以访问该 URL,网站应该在线。就是这样。您已经部署了使用 REMIX 构建的博客!
添加自定义域名 🔖
要将自定义域名添加到应用程序,您首先必须从域名注册商处购买一个域名,您可以选择您的首选项之一。一些流行的选项是 Domain.com、Google、Cloudflare。
购买域名后,我们可以添加 DNS 记录以指向该域名,或者创建一个子域名并将其指向 Fly 应用程序 URL。我们可以通过使用 CNAME 选项添加 DNS 记录并输入 Fly URL https://YOUR_APP_NAME.fly.dev
来实现此目的。
我们还必须使用域名在 Fly 上创建 SSL 证书。我们可以通过运行命令来执行此操作
flyctl certs create [DOMAIN]
您可以在 自定义域的 SSL 中阅读有关此内容的更多信息
就是这样,我们已准备好与世界其他地方分享我们的博客!但在分享之前,还有一步需要处理。
扩展 ⚖️
扩展应用程序有两种方式:垂直扩展和水平扩展。
在垂直扩展中,通过向服务器添加更多计算资源(增加 CPU/RAM)来扩展系统。Fly 支持垂直扩展,您可以在此处查看文档 扩展虚拟机。
水平扩展是通过添加同一应用程序的更多副本来实现的,可以在同一区域或全球其他区域中进行。Fly 支持全球多个区域,您可以在此处阅读有关它们的更多信息 Fly 区域。
我们的应用程序当前仅部署在我们运行 flyctl launch
时选择的一个区域中。这在原型设计和开发期间很好,但是当推向生产环境时,我们希望我们的应用程序可以从全球各个区域访问,并为全球用户提供相似的性能。在这种情况下,我们可以在全球范围内添加更多应用程序副本,至少在具有许多目标用户的区域中添加,以便应用程序将在离用户更近的服务器上运行,并且所有用户都将具有可比较的性能。
由于 Fly 基于创建的卷 锚定区域,我们可以通过在新区域中创建一个卷或在同一区域中添加副本,来添加更多区域。例如,我们可以通过以下方式执行此操作
flyctl volumes create data --region [NEW_REGION] --size 1
您可以在 Fly 区域 查看可用区域列表。
然后,通过运行以下命令增加 Fly 应用的规模计数
flyctl scale count 2
上述命令会将规模计数设置为 2,这意味着我们的应用程序的两个实例将在创建卷的指定区域上运行。
您可以在 Fly 扩展 了解更多关于扩展的信息。
API 模拟 🔸
我们的架构是从 GitHub 存储库按需获取博客内容,而不是将内容作为构建的一部分进行捆绑。因此,我们将向 GitHub 发出大量的 API 调用。与任何 API 一样,都会有限制,例如速率限制、每分钟调用次数等。当我们撰写文章时,由于我们需要调用 GitHub API,所以这个过程会变得很繁琐;文章必须在 GitHub 上,API 才能返回内容。这个过程并不理想。我们可以做得更好。
相反,我们可以模拟对 GitHub 的 API 请求,并在本地提供文章,从而提供更好的体验。我们不调用 GitHub API,而是使用 MSW 拦截请求并返回一个模拟的响应,该响应从本地文件系统提供内容。
代码检查 ⬡
此模板预配置了 ESLint 和 Prettier 规则,并作为构建步骤集成到工作流中。例如,您可以运行 npm run lint
以在项目上运行 ESLint,并运行 npm run format
以运行 Prettier。
样式 💅🏻
此模板预配置了 Tailwindcss,其中包含开发和生产期间所需的所有脚本。
该模板还预配置了一个主题切换器,可以检测合适的主题并防止 FART。
测试 🔬
此模板预配置了用于单元测试的 Jest 和 React 测试库,以及用于 e2e 测试的 Cypress,并配置为作为 GitHub 操作的一部分运行。您可以运行 npm run test
命令来运行 Jest 测试套件。并运行 npm run test:e2e:run
以在无头模式下运行 Cypress 测试。您可以查看 package.json 以获取可用命令。
类型检查 ʦ
您可以运行 npm run typecheck
以在代码库上运行 tsc
。类型检查也包含在部署工作流程中。
调试
一些有用的命令,用于在 Fly 上使用命令行调试应用程序
日志
您可以使用项目目录中的命令 flyctl logs
查看日志,其中包含项目根目录中的 fly.toml
文件。您还可以通过访问 fly.io/apps 从控制台查看日志。
控制台
您还可以使用 flyctl ssh console
命令登录到远程控制台。
数据库
登录到控制台后,您还可以检查 SQLite 数据库。但是首先,我们必须在远程机器上安装 SQLite。我们可以使用 apt-get install sqlite3
命令来完成。然后,使用 cd data
命令进入卷(注意:data
是指从命令行创建的卷的名称)。然后运行命令 sqlite3 sqlite.db
以打开数据库的命令行界面。