JStack + Appwrite:现代 Web 开发的完美组合
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
如果每次有 YouTuber 发布自己的技术栈我都能得到一分钱,那我总共也就两分钱,虽然不多,但奇怪的是这种情况发生了两次。
我指的是大家喜爱的Theo之前推出的T3 Stack ,但最近市场上出现了一个新的竞争者,名为JStack,由Upstash的首席开发工程师Josh开发。公平地说,它其实也不算新,但一如既往。
我来晚了。我通常会给框架一些时间去完善,并收集社区的反馈意见,然后再进行尝试。
那么,我更喜欢 JStack 还是 T3 Stack?它与我最喜欢的后端提供商 Appwrite 的兼容性如何?它能否托管在 Appwrite Sites 上?让我们一探究竟。
入门
让我们从初始化项目开始:
bunx create-jstack-app@latest
已选选项:
┌ jStack CLI
│
◇ What will your project be called?
│ testing-jstack-appwrite
│
◇ Which database ORM would you like to use?
│ None
│
◇ Should we run 'bun install' for you?
│ Yes
Using: bun
✔ testing-jstack-appwrite scaffolded successfully!
我们先快速运行一个开发服务器,看看它能提供什么功能:
cd cd testing-jstack-appwrite
bun dev
项目初始化
即使跳过 ORM 选项,该堆栈仍然会创建一个/src/server包含示例文章路由的文件夹。但它只是使用一个不会持久化的数组来模拟数据库:
// Mocked DB
interface Post {
id: number
name: string
}
const posts: Post[] = [
{
id: 1,
name: "Hello World",
},
]
我们跳过了 ORM 选项,因为 Appwrite 通过其 SDK 提供了内置的模式管理功能,无需单独的 ORM 层。要开始使用,请访问https://cloud.appwrite.io设置我们的项目。
如果您是第一次使用 Appwrite,我强烈建议您查看我们的Web 入门文档。
以下是快速设置指南:
- 创建新项目 -
- 添加一个新的 Web 平台并选择 Next.js -
- 前往项目概览页面,获取项目 ID 和区域特定端点:
.env在项目目录中创建一个新文件,并将这些值粘贴到该文件中:
NEXT_PUBLIC_APPWRITE_PROJECT_ID=686a271700323696d223
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
NEXT_PUBLIC_APP_DOMAIN=localhost # we will change it later
- 现在,让我们使用以下命令在项目中初始化 Appwrite SDK:
bun add appwrite
以上介绍了如何在普通的 Next.js 项目中初始化 Appwrite。现在我们需要根据项目配置 Appwrite 数据库。在本演示中,我们将创建一个Posts集合,把 JStack 示例中使用的模拟数据库迁移到 Appwrite。
定义模式
- 转到 Appwrite 控制台 > 数据库 > 创建数据库。我们将它命名为 `
main<database_name>`,并将其 ID 保留为 `<main>`:
- 同样地,创建一个集合
posts并将其 ID 保存为posts。 - Appwrite 中的每个文档都已附加一个唯一的 ID,因此
name目前我们只需要以下属性:
- 最后,您需要定义谁可以访问您的集合。要了解更多信息,请查看Appwrite 权限文档。现在,我们将其设置为“任何用户”:
同步类型
好了,Appwrite 控制台的配置已经全部完成。现在让我们把它应用到项目中。我还会借助 Appwrite CLI 来加快配置速度。您可以参考安装文档了解更多安装信息。
完成后,运行:
appwrite init project
? How would you like to start? Link directory to an existing project
? Choose your organization 67610b8ee51f147ca943
? Choose your Appwrite project. [object Object]
✓ Success: Project successfully linked. Details are now stored in appwrite.json file.
Would you like to pull all resources from project you just linked? Yes
完成后,让我们利用最后一个类型生成功能来同步我们定义的类型:
appwrite types src/types
ℹ Info: Detected language: ts
ℹ Info: Directory: src/types does not exist, creating...
ℹ Info: Found 1 collections: posts
ℹ Info: Found 1 attributes across all collections
ℹ Info: Added types to src/types/appwrite.d.ts
✓ Success: Generated types for all the listed collections
结果大致如下:
import { type Models } from 'appwrite';
/**
* This file is auto-generated by the Appwrite CLI.
* You can regenerate it by running `appwrite types -l ts src/types`.
*/
export type Posts = Models.Document & {
name: string;
}
目前看来这个功能还很小,但随着项目扩展和定义更多集合,它将是一个非常有用的功能。
配置代码
最后一步是将 Appwrite 后端与我们的技术栈连接起来。为此,让我们appwrite.ts在文件夹中创建一个简单的文件src/lib:
import { Client, Databases, ID } from "appwrite";
const client = new Client()
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!);
const databases = new Databases(client);
export { client, databases };
现在,我们可以修改原始post-router.ts文件以使用已定义的数据库:
import { z } from "zod";
import { j, publicProcedure } from "../jstack";
import { databases } from "@/lib/appwrite";
import { type Posts } from "@/types/appwrite";
import { ID } from "appwrite";
const DATABASE_ID = "main";
const POSTS_COLLECTION_ID = "posts";
export const postRouter = j.router({
recent: publicProcedure.query(async ({ c }) => {
const posts = await databases.listDocuments<Posts>(
DATABASE_ID,
POSTS_COLLECTION_ID,
);
return c.superjson(posts.documents.at(-1) ?? null);
}),
create: publicProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ c, input }) => {
const post = await databases.createDocument<Posts>(
DATABASE_ID,
POSTS_COLLECTION_ID,
ID.unique(),
{
name: input.name,
},
);
return c.superjson(post);
}),
});
完成!现在您的 JStack 应用程序正在使用 Appwrite 作为其后端提供程序。
测试
- 如果开发服务器尚未启动,请运行以下命令启动它:
bun run dev
- 您的应用程序应该已在以下地址启动:http://localhost:3000/
- 创建新帖子。
- 你应该能在最近的帖子中看到它:
- 此外,数据应该会显示在您的 Appwrite 控制台中:
部署您的应用程序
直到最近,部署 Next.js 应用的选择还非常有限。但现在情况不同了,Appwrite Sites让这一切成为可能。现在,您可以将后端和前端都托管在 Appwrite 上。
请查看以下文档,了解如何开始使用 Sites 功能 - https://appwrite.io/docs/advanced/self-hosting/sites
让我们使用 Sites 部署您的应用程序:
- 转到 Appwrite 控制台 > 站点 > 创建站点。
- 您可以直接上传 tar 文件,或者连接到 GitHub 存储库(我更喜欢使用 GitHub 选项进行自动部署)。
- 选择存储库:
- 您可以保留所有默认设置,只需确保上传我们之前定义的环境变量即可:
- 根据您被分配/计划使用的领域,您还需要更新
APP_DOMAIN我们之前定义的变量。对我来说,我会保留它:
NEXT_PUBLIC_APP_DOMAIN=jstack-appwrite-template.appwrite.network
- 点击部署。
搞定!您的申请应该已经生效了🎉
您可以在这里查看演示应用程序 - https://jstack-appwrite-template.appwrite.network/
结论
让我们先来回答博客开头提出的问题:我更喜欢 JStack 还是 T3 Stack?抱歉了,Theo,但我确实更喜欢 JStack。
JStack解决了我在使用Next.js时遇到的根本问题:
- 使用Hono而不是 Next.js 内置的 API 路由定义约定。
- 直接使用TanStack查询。相信我,如果你还没用过,现在就应该开始用了。
- 类型安全且使用Zod。
T3 Stack 和 JStack 最显著的区别在于它们的轻量级,这主要归功于 T3 Stack 内置了 tRPC 协议。虽然 JStack 也使用了 tRPC,但它的实现方式似乎要简单得多。大多数项目并不需要 tRPC 带来的复杂性,而且在我看来,它反而会使代码的维护难度增加十倍。
所以,如果你正在启动一个新项目(或者想花一个周末将现有技术栈迁移到 JStack),不妨试试 JStack。特别感谢Josh创建了这个出色的技术栈。最后,也请尝试一下 Appwrite,它或许能成为你下一个一体化的云平台,满足你的后端和前端需求。
资料来源:
- JStack - https://jstack.app/
- Appwrite 文档 - https://appwrite.io/docs
- Github 仓库 - https://github.com/ChiragAgg5k/jstack-appwrite-template











