跳转到主要内容

Blitz.js采用零API方法将Next.js前端连接到后端数据存储。以下是它的工作原理

Blitz.js是一个基于React和Next.js的新兴JavaScript框架。它是一个全栈的、有主见的框架,这意味着它对如何构建JavaScript应用程序做出了某些假设。Blitz最有趣的方面可能是所谓的零API方法,其中框架完成将用户界面连接到后端数据存储的工作。

让我们亲身体验一下JavaScript应用程序开发的这一有趣而独特的观点。

目录

  • 设置闪电战演示
  • 创建新项目
  • Blitz.js中的RPC
  • 身份验证
  • 结论

设置闪电战演示

首先,使用以下命令将Blitz添加为全局NPM包:NPM iblitz@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上,您将看到一个欢迎屏幕,如下图所示:

The Blitz.js welcome screen.

图1。闪电战欢迎屏幕。

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

添加模型

现在,让我们按照欢迎页面的建议,通过命令行添加一个模型。转到命令行并点击CTRL-C以停止开发服务器。输入blitz generate all项目名称:string。这个命令告诉Blitz添加一个新的模型对象,称为project,并使用一个名为name的字符串字段。

通过Prisma迁移数据库

出现提示时,确认要运行prisma migrate dev.Blitz已安装并正在使用基于文件的SQLite数据库,该数据库通过对象关系映射(ORM)层prisma进行映射。SQLite和Prisma是数据对象持久化的位置和方式。prisma migrate dev命令通知prisma更新自身以反映dev数据库(用于开发的默认数据库)中的更改。

2024年IT最佳工作场所提名开放

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

请注意,Blitz中的数据库和ORM层是模块化的,因此如果您愿意,可以更改默认值并使用MongoDB之类的东西。您需要为Blitz的更改提供一个名称,用于跟踪目的。

创建新项目

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

如果您在尝试创建新项目时未登录,则会收到消息:“错误:您未通过身份验证。”这将确认授权已在工作。

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

localhost:3000/projects页面为您提供了一个项目列表,您可以单击该列表在localhost:3000-projects/<ID>上获取项目详细信息。请注意,您还可以编辑和删除:一个完整的CRUD往返体验。

闪电战项目的布局

让我们来看看Blitz中的项目布局。这让我们感觉到闪电战是如何为我们做这么多的。

  • /project-root
    • /db
      • /db.sqlite: The SQLite engine and schema
      • /schema.prisma: The Prisma ORM mappings
      • /migrations: The directory showing the migrations (useful for rollbacks)
    • /mailers: Contains stubs for configuring mailers like the Forgot Password mailer
    • /jest.config.js: The JEST testing framework config
    • /next.config.js: The Next.js config file
    • /pages: The React.js and Next.js front-end files
      • /api: Support for external (non-Blitz) API access
      • /auth: The log in, log out, and signup pages
      • /projects: Pages for the project entity. Other objects follow the same pattern.
    • /test: Test files (JEST)
    • /app: App infrastructure
      • /blitz-client.js: The client-side config
      • /blitz-server.js: The server-side config
        • /core: The components, hooks, and layouts for the application
        • /projects: The queries, mutations, and components for the project object
        • /auth and /user: Auth related queries, mutations, and components
      • /integrations: Third-party integrations like Auth0 and Sentry
      • /package.json: The Node config file including Blitz scripts like dev
      • /public: Static files like 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。项目编辑.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;

首先,请注意,导入行让我们很好地了解了Blitz的工作原理:该演示导入了React.js、Next.js和Blitz.js库的混合,以及项目特定组件和Blitz生成的RPC。

表单本身是从app/projects/components/ProjectForm.js中提取的,它是从app/core/components/form.js派生而来的。form.js扩展了react钩子表单库,它完成了使表单工作的重任。此外,请注意,表单中预先填充了以下属性:initialValues={project}。页面是如何首先获得项目对象的?

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

有关查询的详细信息

有关useQuery和setQueryData的更多信息,请参阅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参数。dbneneneba API主要是Prisma库,Blitz用一些助手对其进行了装饰。

对象的突变与对象的创建和查询类似,视图依赖于Blitz基础设施,该基础设施将前端与后端连接起来,而不需要显式的API调用。

身份验证

如果您查看projects/create.js以了解如何在那里处理身份验证,您会注意到导出的页面设置了一个authenticate字段,该字段设置为true,如清单4所示。

清单4。保护页面

NewProjectPage.authenticate = true;
export default NewProjectPage;

Blitz再一次向我们隐藏了很多工作和细节。同样,在主页面/index.js中,当前用户是通过useCurrentUser钩子检索的。在查询和突变的情况下,ctx对象会自动作为参数传入,其中包含会话对象。您可以在稍后的querys/getProject.js文件中看到这一功能,该文件通过检查ctx.session.$isAuthorized()来保护调用。

结论

Blitz是对全栈框架的一种独特而强大的表现。它在幕后做了大量的工作,而没有完全混淆这些底层操作。一旦您了解了Blitz.js及其惯用语,开发就可以沿着许多愉快的道路快速进行,比如围绕基本对象图构建CRUD和执行直接的授权。

 

文章链接