使用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。
一旦连接成功后,将创建数据表。
我也会添加记录。
下一个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 进行修正并尝试启动时。
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测试”的主题。感谢您一直阅读到最后!