Jamstack中的Prisma案例(附代码示例)

202 阅读10分钟

Jamstack中的Prisma案例

Jamstack方法源于Netlify的首席执行官Matt Biilmann在2016年Smashing杂志的Smashing Conf上发表的演讲。

Jamstack网站通过CDN提供静态的预渲染内容,并通过微服务、API和无服务器功能生成动态内容。它们通常使用JavaScript框架(如Next.js或Gatsby)和静态网站生成器(如Hugo或Jekyll)创建。Jamstack网站通常通过Vercel和Netlify等工具使用基于Git的部署工作流程。这些部署服务可以与无头CMS(如Strapi)一起使用。

使用Jamstack建立网站的目的是创建一个高性能和经济运行的网站。这些网站通过预先渲染尽可能多的内容和在 "边缘 "缓存响应来实现高速运行(又称在尽可能靠近用户的服务器上执行,例如从新加坡的服务器而不是旧金山的服务器为孟买的用户提供服务)。

Jamstack网站的运行更加经济,因为它们不需要使用专用服务器作为主机。相反,他们可以从云服务(PAASs)/主机/CDNs以较低的价格提供使用。这些服务也被设定为以具有成本效益的方式进行扩展,而不需要开发人员改变他们的基础设施和减少他们的工作量。

组成这个组合的另一个工具是Prisma--一个为TypeScript和JavaScript构建的开源ORM(对象关系映射)。

Prisma是一个JavaScript/TypeScript工具,它解释以Prisma标准编写的模式,并生成一个类型安全的模块,提供创建记录、读取记录、更新记录和删除记录(CRUD)的方法。

Prisma处理与数据库的连接(包括池化)和数据库迁移。它可以与使用PostgreSQL、MySQL、SQL Server或SQLite的数据库连接(另外MongoDB的支持也在预览中)。

为了帮助你了解Prisma,这里有一些处理用户CRUD的基本示例代码:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

const user = await prisma.user.create({
  data: {
    name: Sam,
    email: 'sam@sampoder.com',
  },
})

const users = await prisma.user.findMany()

const updateUser = await prisma.user.update({
  where: {
    email: 'sam@sampoder.com',
  },
  data: {
    email: 'deleteme@sampoder.com',
  },
})

const deleteUser = await prisma.user.delete({
  where: {
    email: 'deleteme@sampoder.com',
  },
})

相关项目的Prisma模式看起来会是这样:

datasource db {
  url      = env("DATABASE_URL")
  provider = "postgresql"
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
}

Prisma的使用案例

在了解了Prisma的运作方式后,现在让我们来探讨一下在Jamstack项目中可以在哪里使用它。数据在Jamstack的两个方面很重要:在预渲染静态页面和API路由时。这些任务通常使用JavaScript工具实现,例如静态页面使用Next.js,API路由使用Cloudfare Workers。诚然,这些并不总是用JavaScript实现的--例如,Jekyll使用的是Ruby!所以,也许我应该为基于JavaScript的Jamstack中的Prisma的情况修改一下标题。不管怎么说,开始吧!

Jamstack的一个很常见的用例是博客,其中Prisma将在博客创建一个反应系统时派上用场。你可以在API路由中使用它,其中一个可以获取并返回反应计数,另一个可以注册一个新的反应。为了实现这一点,你可以使用Prisma的createfindMany 方法!

Jamstack的另一个常见用例是登陆页面,没有什么比带有一些很棒的统计数据的登陆页面更好的了在Jamstack中,我们可以用从我们的数据库中提取的统计资料对这些页面进行预渲染,我们可以用Prisma的阅读方法实现。

然而,有时候,Prisma对于某些任务来说可能略显矫枉过正。我建议在只需要一个数据库表的解决方案中避免使用Prisma和一般的关系数据库,因为在这些情况下,它增加了额外的、往往是不必要的开发复杂性。例如,将Prisma用于电子邮件通讯注册箱或联系表是过犹不及的。

替代Prisma的方法

因此,我们可以使用Prisma来完成这些任务,但我们可以使用大量的其他工具来实现这些任务。那么,为什么是Prisma?让我们来看看Prisma的三个替代品,我将试图说服你,Prisma是最好的。

云数据库/服务

像Airtable这样的服务在Jamstack领域非常流行(我自己也用了很多),它们为你提供了一个数据库(像平台),你可以通过REST API访问。它们的使用和原型都很有趣,然而,Prisma可以说是Jamstack项目的一个更好的选择。

首先,由于成本是Jamstack吸引人的一个主要因素,你可能想避免使用其中的一些服务。例如,在Hack Club,我们上个月为我们的小团队花了671.54美元订购了Airtable Pro(哎呀!)。

另一方面,在Heroku的平台上托管一个同等的PostgreSQL数据库,每月花费9美元。基于这些云服务的用户界面和API,当然有一个论点,但我想指出的是Prisma的工作室和上述的JavaScript/TypeScript客户端。

云服务也存在性能问题,特别是考虑到你作为用户,没有能力改变/提高性能。提供数据库的云服务在你的程序和他们所使用的数据库之间设置了一个中间人,减慢了你访问数据库的速度。然而,使用Prisma,你从你的程序中直接调用你的数据库,这减少了查询/修改数据库的时间。

编写纯SQL

那么,如果我们要直接访问我们的PostgreSQL数据库,为什么不直接使用node-postgres模块或--对于许多其他数据库--它们的同等驱动程序?我认为,使用Prisma客户端的开发者经验使它值得稍微增加的负载。

Prisma的闪光点在于它的类型。Prisma为你生成的模块是完全类型安全的--它解释你的Prisma模式中的类型--这有助于你防止数据库的类型错误。此外,对于使用TypeScript的项目,Prisma自动生成了反映你的模型结构的类型定义。Prisma使用这些类型在编译时验证数据库查询,以确保它们是类型安全的。

即使你不使用TypeScript,Prisma也通过其Visual Studio Code扩展提供自动完成/智能提示、提示和格式化。还有社区建立/维护的Emacs(emacs-prisma-mode)、neovim(coc-prisma)、Jetbrains IDE(Prisma支持)和nova(Prisma插件)的插件,实现了Prisma语言服务器以实现代码验证。语法高亮也可以通过插件用于大量的编辑器。

其他ORMs

当然,Prisma不是唯一可用于JavaScript / TypeScript的ORM。例如,TypeORM是另一个用于JavaScript项目的高质量ORM。在这种情况下,这将归结为个人偏好,我鼓励你尝试一系列的ORM来找到你最喜欢的。我个人选择Prisma用于我的项目有三个原因:广泛的文档(尤其是这个CRUD页面,它是一个救星),Prisma生态系统中的额外工具(例如Prisma Migrate和Prisma Studio),以及围绕该工具的活跃社区(例如Prisma Day和Prisma Slack)。

在Jamstack项目中使用Prisma

那么,如果我想在Jamstack项目中使用Prisma,我该怎么做?

Next.js

Next.js正逐渐成为Jamstack领域一个非常受欢迎的框架,而Prisma则是它的最佳选择。下面的例子将作为相当标准的例子,你可以使用不同的JavaScript / TypeScript Jamstack工具转移到其他项目。

在Next.js中使用Prisma的主要规则是,它必须在服务器端设置中使用,这意味着它可以在getStaticPropsgetServerSideProps ,以及API路由(例如api/emojis.js )中使用。

在代码中,它看起来是这样的(例子取自我为2021年Prisma Day的一个演讲所做的演示应用,这是一个虚拟贴纸墙)。

import prisma from '../../../lib/prisma'
import { getSession } from 'next-auth/client'

function getRandomNum(min, max) {
  return Math.random() * (max - min) + min
}

export async function getRedemptions(username) {
  let allRedemptions = await prisma.user.findMany({
    where: {
      name: username,
    },
    select: {
      Redemptions: {
        select: {
          id: true,
          Stickers: {
            select: { nickname: true, imageurl: true, infourl: true },
          },
        },
        distinct: ['stickerId'],
      },
    },
  })
  allRedemptions = allRedemptions[0].Redemptions.map(x => ({
    number: getRandomNum(-30, 30),
    ...x.Stickers,
  }))
  return allRedemptions
}

export default async function RedeemCodeReq(req, res) {
  let data = await getRedemptions(req.query.username)
  res.send(data)
}

正如你所看到的,它能很好地整合到Next.js项目中。但你可能会注意到一些有趣的事情:'../../../lib/prisma' 。以前,我们像这样导入Prisma。

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

不幸的是,这是由于Next.js的实时刷新系统中的一个怪癖造成的。所以,Prisma建议你把这个代码片段粘贴到一个文件中,然后把代码导入到每个文件中。

红木

Redwood在本节中有点反常,因为它不一定是一个Jamstack框架。它一开始是打着为Jamstack带来全栈的旗号,但现在已经过渡到受Jamstack的启发。然而,我选择把它放在这里,因为它采取了一种有趣的方法,将Prisma纳入框架中。

像往常一样,它从创建Prisma模式开始,这次是在api/db/schema.prisma (Redwood为每个新项目添加了这个功能)。然而,为了查询和修改数据库,你并没有使用Prisma的默认客户端。相反,在Redwood中,使用GraphQL突变和查询。例如,在Redwood的示例todo应用程序中,这是用于创建一个新todo的GraphQL突变。

const CREATE_TODO = gql`
  mutation AddTodo_CreateTodo($body: String!) {
    createTodo(body: $body) {
      id
      __typename
      body
      status
    }
  }
`

在这种情况下,Todo的Prisma模型是。

model Todo {
  id     Int    @id @default(autoincrement())
  body   String
  status String @default("off")
}

为了触发GraphQL突变,我们使用useMutation 函数,该函数是基于从@redwoodjs/web 中导入的Apollo的GraphQL客户端。

const [createTodo] = useMutation(CREATE_TODO, {
    //  Updates Apollo's cache, re-rendering affected components
    update: (cache, { data: { createTodo } }) => {
      const { todos } = cache.readQuery({ query: TODOS })
      cache.writeQuery({
        query: TODOS,
        data: { todos: todos.concat([createTodo]) },
      })
    },
  })

  const submitTodo = (body) => {
    createTodo({
      variables: { body },
      optimisticResponse: {
        __typename: 'Mutation',
        createTodo: { __typename: 'Todo', id: 0, body, status: 'loading' },
      },
    })
  }

使用Redwood,你不需要担心在创建Prisma模式后设置GraphQL模式/SDL,因为你可以使用Redwood的scaffold 命令将Prisma模式转换为GraphQL SDL和服务 -yarn rw g sdl Todo ,例如。

Cloudfare Workers

Cloudfare Workers是托管Jamstack API的流行平台,因为它将你的代码放在 "边缘"。然而,该平台有其局限性,包括缺乏TCP支持,而传统的Prisma客户端使用TCP。虽然现在,通过Prisma数据代理,可以做到这一点。

要使用它,你需要一个Prisma云平台账户,目前是免费的。一旦你完成了设置过程(确保启用Prisma数据代理),你将得到一个以prisma:// 开始的连接字符串。 你可以在你的.env 文件中使用该Prisma连接字符串,代替传统的数据库URL。

DATABASE_URL="prisma://aws-us-east-1.prisma-data.com/?api_key=•••••••••••••••••"

然后,不要使用npx prisma generate ,而是使用这个命令来生成一个Prisma客户端。

PRISMA_CLIENT_ENGINE_TYPE=dataproxy npx prisma generate

你的数据库请求将被代理通过,你可以像平常一样使用Prisma客户端。这不是一个完美的设置,但对于那些在Cloudfare Workers上寻找数据库连接的人来说,这是一个相对不错的解决方案。

结论

总而言之,如果你正在寻找一种方法来连接Jamstack应用程序和数据库,我不会再找Prisma了。它的开发者经验、广泛的工具和性能使它成为完美的选择。Next.js、Redwood和Cloudfare Workers--每一个都有独特的使用Prisma的方式,但它在所有这些中仍然非常好用。

我希望你喜欢和我一起探索Prisma,谢谢你