使用Hasura和Next.js搭建舒适的开发环境 – 本地环境搭建部分

你好,我是株式会社H Team Commerce Tech的kazz。

我们正在使用Hasura和Nextjs技术开发一个名为Obremo的宠物食品销售产品。这次我们使用了Hasura和Nextjs的组合来实际操作和配置环境,我想简要总结下步骤作为备忘录。

组成

我们采用了Hasura作为Docker镜像的后端,PostgreSQL作为数据库,Next.js和ApolloClient作为前端。我们将配置Hasura和Next.js环境,并使用ApolloClient实现客户端协作,以将数据库中的数据显示在浏览器上。

这次我们将在HasuraCloud上运行生产环境,并使用Docker镜像在本地环境中运行。我们将以本地环境为例来配置。(在本节中只涉及本地环境)

使用Hasura

Hasura是在后端运行的GraphQL引擎。它可以很方便地开始,无需繁琐的配置。可通过附带的GUI环境在Web客户端上操作数据库和Hasura的便利功能,使开发和运营都变得非常轻松。虽然HasuraCloud作为PaaS非常方便,但您也可以使用官方提供的Docker镜像在本地启动。

本地环境安装和启动

由于公式提供了将PostgreSQL和Hasura一起打包的docker-copose文件,我们将充分利用它。

mkdir hasura-and-nextjs
cd hasura-and-nextjs
curl https://raw.githubusercontent.com/hasura/graphql-engine/stable/install-manifests/docker-compose/docker-compose.yaml -o docker-compose.yml
docker-compose up -d

创建表数据

http://localhost:8080/console 的中文意思是什么?

您可以通过控制台访问,并可以通过数据选项卡对数据库进行各种操作。

スクリーンショット

首先,我们要设置连接的数据库。这次我们将根据设置在docker-compose.yml中的环境变量来获取URL。

スクリーンショット

一旦连接成功后,将创建数据表。

localhost_8080_console_data_postgres_schema_public_table_add.png

我也会添加记录。

スクリーンショット

下一个JS

这是一个与Hasura后端进行合作的Web客户端框架。它使用React进行开发,可以适用于各种多样的场景,例如SPA、SR、SSG、ISR等。

這次我們將使用一個名為ApolloClient的庫來補充Next.js沒有提供的功能。Apollo主要用於連接Next.js和GraphQL。

安装

npx create-next-app@latest --ts
> Ok to proceed? (y) 
> ✔ What is your project named? … front
cd front
npm i
npm run dev

另外,还需要安装所需的库。

npm install @apollo/client graphql cross-fetch @graphql-codegen/cli

http://localhost:3000 – 本地主机端口3000。

当以自然而然的方式对 front/pages/index.tsx 进行修正并尝试启动时。

スクリーンショット 2021-12-13 11.29.53.png

Hasura与客户端的合作

使用Codegen进行架构同步设置

因为有一种名为graphql-codegen的工具,它可以输出可以在Nextjs中使用的类型定义,该工具可以为在Hasura上定义的模式提供输出,所以我们也会引入它。

npx graphql-codegen init

通过执行init命令,可以以对话形式进行设置。

 ◯ Backend - API or server
 ◯ Application built with Angular
❯◉ Application built with React
 ◯ Application built with Stencil
 ◯ Application built with other framework or vanilla JS
? What type of application are you building? Application built with Re
act
? Where is your schema?: (path or url) http://localhost:8080/v1/graphq
l
? Where are your operations and fragments?: queries/**/*.ts
? Pick plugins: TypeScript (required by other typescript plugins), Typ
eScript Operations (operations and fragments), TypeScript React Apollo
 (typed components and HOCs)
? Where to write the output: types/graphqlSchema.tsx
? Do you want to generate an introspection file? No
? How to name the config file? codegen.yml
? What script in package.json should run the codegen? graphql-codegen

按照在这里设置的方式,创建目录。

mkdir queries
mkdir types

在queries中定义了客户端想要执行的GraphQL代码。

import { gql } from "@apollo/client";

export const GET_POSTS = gql`
  query GetPost {
    posts(limit: 10) {
      content
      title
      id
    }
  }
`;

在codegen的初始化时,会在package.json的script中定义codegen的别名,并手动执行它。执行后,会将类型定义等输出到types/graphqlSchema.ts文件中。

npm run graphql-codegen
> graphql-codegen
> graphql-codegen --config codegen.yml

(node:33488) ExperimentalWarning: stream/web is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:33488) ExperimentalWarning: buffer.Blob is an experimental feature. This feature could change at any time
  ✔ Parse configuration
  ✔ Generate outputs

生成的代码中包含了类型定义以及可在APICall时执行的函数等内容。

import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
const defaultOptions =  {}
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: string;
  String: string;
  Boolean: boolean;
  Int: number;
  Float: number;
};

...下に続く

通过ApolloClient执行实际的数据获取并在屏幕上显示

我会参考以下的Nextjs官方示例来进行实现。

请把以下内容用中文进行本地化解释,仅需要一种选项:https://github.com/vercel/next.js/blob/canary/examples/with-apollo/lib/apolloClient.js

我们将创建一个用于生成与ApolloClient协作所需实例的文件。

mkdir libs
touch apolloClient.ts
import {
  ApolloClient,
  HttpLink,
  InMemoryCache,
  NormalizedCacheObject,
} from "@apollo/client";
import "cross-fetch/polyfill";

let apolloClient: ApolloClient<NormalizedCacheObject> | undefined;
const createApolloClient = () => {
  return new ApolloClient({
    ssrMode: typeof window === "undefined",
    link: new HttpLink({
      // .env.development.localに`NEXT_PUBLIC_HASURA_URL='http://localhost:8080/v1/graphql'` と定義しておきます
      uri: process.env.NEXT_PUBLIC_HASURA_URL,
    }),
    cache: new InMemoryCache(),
  });
};
export const initializeApollo = (initialState = null) => {
  const _apolloClient = apolloClient ?? createApolloClient();
  // For SSG and SSR always create a new Apollo Client
  if (typeof window === "undefined") return _apolloClient;
  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient;

  return _apolloClient;
};

在_app.tsx中执行此操作,使其子组件能够使用ApolloClient。

import "../styles/globals.css";
import type { AppProps } from "next/app";
import { ApolloProvider } from "@apollo/client";
import { initializeApollo } from "../libs/apolloClient";

function MyApp({ Component, pageProps }: AppProps) {
  const client = initializeApollo();
  return (
    <ApolloProvider client={client}>
      <Component {...pageProps} />
    </ApolloProvider>
  );
}

export default MyApp;

让我们在index.tsx中实际尝试进行fetch。

import { useQuery } from "@apollo/client";
import type { NextPage } from "next";
import { GET_POSTS } from "../queries/posts";
import { GetPostQuery } from "../types/graphqlSchema";

const Home: NextPage = () => {
  const { data, error } = useQuery<MyQueryQuery>(GET_POSTS);
  return (
    <div>
      {data?.posts.map((post) => (
        <div key={`post-${post.id}`}>
          {post.id} {post.title}
          <br />
          {post.content}
        </div>
      ))}
    </div>
  );
};

export default Home;

打开页面后,数据显示了出来!

スクリーンショット

建立生产环境

Sorry, but I cannot provide you the requested information as “〆” does not have a specific meaning or context in Chinese. Could you please provide more details or a different phrase that needs to be paraphrased?

下一次的节日日历投稿是“不费力地尝试贝叶斯AB测试”的主题。感谢您一直阅读到最后!

广告
将在 10 秒后关闭
bannerAds