Blitz.js的介绍——一个用于Next.js的全栈框架

690 阅读1分钟

Blitz.js的介绍——一个用于Next.js的全栈框架

Blitz.js采用零API的方式,将你的Next.js前端与后端数据存储连接起来。以下是它的工作原理。

Blitz.js是一个新兴的JavaScript框架,建立在ReactNext.js之上。它是一个全栈式的、有主见的框架--这意味着它对如何构建你的JavaScript应用做出了某些假设。也许Blitz最有趣的方面是它所谓的零API方法,其中框架做了连接用户界面和后端数据存储的工作。

让我们亲身体验一下这种有趣而独特的JavaScript应用开发方式。

设置Blitz演示

首先,用以下命令将Blitz添加为一个全局NPM包。npm i blitz@alpha -g.现在,你可以使用工具创建一个新的项目,键入:blitz new demo-app 。清单1显示了我对演示程序的设置。

清单1.创建一个新的Blitz应用程序


$ blitz new demo-app
✔ Pick which language you'd like to use for your new blitz project › Javascript
✔ Pick which template you'd like to use for your new blitz project › full
✔ Install dependencies? … yes
✔ Pick which form you'd like to use for your new blitz project › React Hook Form
Hang tight while we set up your new Blitz app!

在Blitz完成了所有的依赖项的安装后,你可以进入刚刚创建的新目录,cd demo-app ,并通过命令blitz dev ,启动开发服务器。服务器现在运行在localhost:3000,你会得到一个像这里所示的欢迎屏幕。

IDG

图1.Blitz的欢迎屏幕。

你可能注意到的第一件事是,与大多数前端框架不同,Blitz的生成器提供了更精细的全栈脚手架;特别是,它支持用户创建和登录。如果你玩一玩这些功能,你会发现你可以创建一个用户并登录和退出。

添加一个模型

现在让我们按照欢迎页面的建议,通过命令行添加一个模型。转到命令行,按CTRL-C键,停止开发服务器。输入blitz generate all project name:string 。这个命令告诉Blitz添加一个新的模型对象,叫做project ,有一个单独的字符串字段,叫做name

通过Prisma迁移数据库

当提示时,确认你要运行prisma migrate dev 。Blitz已经安装并正在使用基于文件的SQLite数据库,它通过Prisma,即对象关系映射(ORM)层进行映射。SQLite和Prisma是数据对象被持久化的地方和方式。prisma migrate dev 命令通知Prisma更新自己以反映dev 数据库(用于开发的默认数据库)中的变化。

选择你自己的数据库和ORM层

请注意,在Blitz中,数据库和ORM层是模块化的,所以如果你喜欢,你可以改变默认值,使用类似MongoDB的东西。你需要给Blitz的改变起一个名字,用于跟踪。

创建一个新的项目

当生成器完成后,用命令blitz dev ,再次启动服务器。返回到浏览器,访问localhost:3000/projects。你会看到一个新的用户界面,你可以用它来创建一个新项目。(点击创建项目)。

如果你在试图创建一个新项目时没有登录,你会得到这样的信息。"错误。你没有经过认证"。这证实了授权已经开始工作了。

现在以用户身份登录,再次尝试创建项目选项。这一次,你会看到一个包含单一名称字段的表格。你可以创建一些项目,你会发现Blitz正在为你搭建一个合理的RESTful模式。

localhost:3000/projects页面给你一个项目列表,你可以点击它来获得项目的详细信息,地址是*localhost:3000/projects/。*注意,你也可以编辑和删除:一个完整的CRUD往返体验。

Blitz项目的布局

让我们看一下Blitz中的项目布局。这让我们感受到Blitz如何设法为我们做这么多事情。

  • /project-root
    • /db
      • /db.sqlite:SQLite引擎和模式
      • /schema.prisma:Prisma ORM映射
      • /migrations:显示迁移的目录(对回滚很有用)
    • /mailers:包含用于配置邮件的存根,如忘记密码邮件。
    • /jest.config.js:JEST测试框架的配置
    • /next.config.js:Next.js的配置文件
    • /pages:React.js和Next.js的前端文件
      • /api:支持外部(非Blitz)API访问
      • /auth:登录、注销和注册的页面
      • /projects:project 实体的页面。其他对象也遵循同样的模式。
    • /test:测试文件(JEST)
    • /app:应用程序基础设施
      • /blitz-client.js:客户端配置
      • /blitz-server.js:服务器端的配置
        • /core:应用程序的组件、钩子和布局
        • /projects:project 对象的查询、变异和组件。
        • /auth 和 :与认证有关的查询、变异和组件。/user
      • /integrations:第三方集成,如Auth0和Sentry
      • /package.json:Node配置文件,包括Blitz脚本,例如dev
      • /public:静态文件,如favicon

Blitz.js中的RPC

Blitz最不寻常的地方是它对远程过程调用的使用,即RPC。你没有使用REST或GraphQL API,而是将服务器端的代码直接导入客户端的JavaScript中。然后Blitz将服务器端的代码转换为RPC调用。你可以直接从你的客户端JavaScript访问服务器端代码,而Blitz会将网络交互连接起来,使其全部工作。

现在,让我们打开这个文件:blitz-demo/pages/projects/[projectId]/edit.js 。注意,方括号的语法是Next.js处理路径衔接的方式。(projectID 变量将被暴露给处理请求的页面,持有路径中该位置的参数值)。

清单2有Blitz演示的主要重要部分。

清单2.项目 edit.js


import { Suspense } from "react";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { useQuery, useMutation } from "@blitzjs/rpc";
import { useParam } from "@blitzjs/next";
import Layout from "app/core/layouts/Layout";
import getProject from "app/projects/queries/getProject";
import updateProject from "app/projects/mutations/updateProject";
import { ProjectForm, FORM_ERROR } from "app/projects/components/ProjectForm";
export const EditProject = () => {
  const router = useRouter();
  const projectId = useParam("projectId", "number");
  const [project, { setQueryData }] = useQuery(
    getProject,
    { id: projectId },
    { staleTime: Infinity }
  );
  const [updateProjectMutation] = useMutation(updateProject);
  return (
    <>
      <Head>
        <title>Edit Project {project.id}</title>
      </Head>

      <div>
        <h1>Edit Project {project.id}</h1>
        <pre>{JSON.stringify(project, null, 2)}</pre>

        <ProjectForm
          submitText="Update Project" initialValues={project}
          onSubmit={async (values) => {
            try {
              const updated = await updateProjectMutation({
                id: project.id,
                ...values,
              });
              await setQueryData(updated);
              router.push({
                pathname: `/projects/[projectId]`,
                query: {
                  projectId: updated.id,
                },
              });
            } catch (error) {
              console.error(error);
              return {
                [FORM_ERROR]: error.toString(),
              };
            }
          }}
        />
      </div>
    </>
  );
};

const EditProjectPage = () => {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <EditProject />
      </Suspense>

      <p>
        <Link
          href={{
            pathname: "/projects",
          }}
        >
          <a>Projects</a>
        </Link>
      </p>
    </div>
  );
};

EditProjectPage.authenticate = true;

EditProjectPage.getLayout = (page) => <Layout>{page}</Layout>;

export default EditProjectPage;

首先,注意到import 行让我们很好地了解了Blitz的工作方式:该演示导入了React.js、Next.js和Blitz.js库的混合体,以及项目专用组件和Blitz生成的RPC。

表单本身是从app/projects/components/ProjectForm.js ,它从app/core/components/Form.js 下来。Form.js 扩展了react-hook-form 库,它完成了使表单工作的重任。另外,注意到表单是用属性预填充的:initialValues={project} 。页面是如何首先获得project 对象的?

project 对象是通过useQuery 钩子(来自 Blitz)填充的,行数是const [project, { setQueryData }] = useQuery{...} 。项目变量被设置为最终将持有useQuery 钩子的结果。setQueryData 是一个来自Blitz的函数,用于更新对象的缓存,使其执行。

关于查询的更多信息

关于useQuerysetQueryData 的更多信息,请参见Blitz文档

useQuery 钩子依赖于getProject 函数,用路径中的projectId 值作为参数。getProject 函数来自于app/projects/queries/getProject.js 。如果你跟着线程走,你会看到getProject.js 依赖于对db 对象的调用,Blitz在/d 目录下创建并导出该对象。清单3显示了getProject 的调用是如何实现的。

清单3. getProject.js


import db from "db";
//...
const project = await db.project.findFirst({
    where: {
      id: input.id,
    },
  })

所以,db 对象暴露了一个关于项目成员的查询API。在这里,我们使用它来通过标准API找到项目,使用我们传回的那个projectId 参数。db API主要是Prisma库,Blitz用一些辅助工具来装饰它。

突变对象的过程与创建和查询对象的过程类似,视图依赖于Blitz的基础设施,它将前端与后端联系起来,而不需要明确的API调用。

认证

如果你看一下projects/create.js ,看看那里是如何处理认证的,你会注意到导出的页面被设置了一个authenticate 字段,设置为true ,如清单4所示。

清单4.确保一个页面的安全


NewProjectPage.authenticate = true;
export default NewProjectPage;

再一次,Blitz向我们隐藏了很多工作和细节。类似地,在主pages/index.js ,当前用户是由useCurrentUser 钩子检索的。在查询和突变的情况下,ctx 对象被自动作为一个参数传入,持有会话对象。你可以通过queries/getProject.js 文件看到后面这个功能的作用,它通过检查ctx.session.$isAuthorized() 来保证调用的安全性。

总结

Blitz是一个独特而强大的全栈框架。它在引擎盖下做了大量的工作,而没有完全混淆这些底层操作。一旦你理解了Blitz.js和它的习性,开发就可以沿着许多快乐的路径快速进行,比如围绕基本对象图构建CRUD和执行简单的授权。