Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[⚠️ wip] Experimental Transport of Async Iterables #369

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 69 additions & 3 deletions examples/hack-the-supergraph-ssr/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,87 @@
import { cookies } from "next/headers";
import { ClientLayout } from "./ClientLayout";
import { registerApolloClient } from "@apollo/client-react-streaming";
import {
gql,
ApolloClient,
InMemoryCache,
HttpLink,
TypedDocumentNode,
} from "@apollo/client";

import { ClientLayout } from "./ClientLayout";
import { ApolloWrapper } from "./ApolloWrapper";

const { PreloadQuery } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
// this needs to be an absolute url, as relative urls cannot be used in SSR
uri: "https://main--hack-the-e-commerce.apollographos.net/graphql",
// you can disable result caching here if you want to
// (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
fetchOptions: { cache: "no-store" },
// fetchOptions: { headers: { "x-custom-delay": "5000" } },
}),
});
});

const ProductCardProductFragment: TypedDocumentNode<{
id: string;
title: string;
description: string;
mediaUrl: string;
}> = gql`
fragment ProductCardProductFragment on Product {
id
title
description
mediaUrl
}
`;

const ReviewsFragment: TypedDocumentNode<{
id: string;
reviews: {
rating: number;
};
}> = gql`
fragment ReviewsFragment on Product {
description
reviews {
rating
}
}
`;

const GET_LATEST_PRODUCTS: TypedDocumentNode<{
products: { id: string }[];
}> = gql`
query HomepageProducts {
products {
id
...ProductCardProductFragment
...ReviewsFragment @defer
}
}
${ProductCardProductFragment}
${ReviewsFragment}
`;

export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const cookieStore = cookies();
const delay = Number(cookieStore.get("apollo-x-custom-delay")?.value ?? 1000);
const delay = Number(cookieStore.get("apollo-x-custom-delay")?.value ?? 5000);

return (
<html lang="en">
<body>
<ApolloWrapper delay={delay}>
<ClientLayout>{children}</ClientLayout>
<PreloadQuery query={GET_LATEST_PRODUCTS}>
<ClientLayout>{children}</ClientLayout>
</PreloadQuery>
</ApolloWrapper>
</body>
</html>
Expand Down
7 changes: 2 additions & 5 deletions examples/hack-the-supergraph-ssr/app/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ import Error from "./error";
import Link from "next/link";

export const Fallback = () => (
<Error code="404" error="This page could not be found">
<Button as={Link} href="/">
Home
</Button>
</Error>
<div>hi</div>
// <Error error={new Error("This page could not be found")} />
);

export default Fallback;
9 changes: 5 additions & 4 deletions examples/hack-the-supergraph-ssr/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import ProductCard from "../components/ProductCard";
import ProductCard, { Reviews } from "../components/ProductCard";
import { Heading, SimpleGrid, Stack, Text, VStack } from "@chakra-ui/react";
import { useSuspenseQuery, gql, TypedDocumentNode } from "@apollo/client";

Expand All @@ -11,14 +11,15 @@ const GET_LATEST_PRODUCTS: TypedDocumentNode<{
products {
id
...ProductCardProductFragment
...ReviewsFragment @defer
}
}
${ProductCard.fragments.ProductCardProductFragment}
${Reviews.fragments.ReviewsFragment}
`;
export default function HomePage() {
const { data } = useSuspenseQuery(GET_LATEST_PRODUCTS, {
fetchPolicy: "cache-first",
});
const { data } = useSuspenseQuery(GET_LATEST_PRODUCTS);

return (
<Stack direction="column" spacing="12">
<VStack direction="column" spacing="2" py="10">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const GET_PRODUCT_DETAILS: TypedDocumentNode<{
};
}> = gql`
fragment ProductFragment on Product {
averageRating
reviews {
content
rating
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function DelaySlider() {
<Heading fontSize="md">
Custom <code>@defer</code> Delay: {delay}ms
</Heading>
<Slider min={0} max={500} value={delay} onChange={setDelay}>
<Slider min={0} max={5000} value={delay} onChange={setDelay}>
<SliderTrack>
<SliderFilledTrack />
</SliderTrack>
Expand Down
76 changes: 58 additions & 18 deletions examples/hack-the-supergraph-ssr/components/ProductCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Suspense } from "react";
import Button from "./Button";
import ReviewRating from "./ReviewRating";
import {
Expand All @@ -9,30 +10,41 @@ import {
usePrefersReducedMotion,
} from "@chakra-ui/react";
import Link from "next/link";
import { useFragment, TypedDocumentNode, gql } from "@apollo/client";
import { useSuspenseFragment, TypedDocumentNode, gql } from "@apollo/client";

const ProductCardProductFragment: TypedDocumentNode<{
id: string;
title: string;
description: string;
mediaUrl: string;
averageRating: number;
}> = gql`
fragment ProductCardProductFragment on Product {
id
title
description
mediaUrl
... @defer {
averageRating
}
`;

const ReviewsFragment: TypedDocumentNode<{
id: string;
description: string;
reviews: Array<{
rating: number;
}>;
}> = gql`
fragment ReviewsFragment on Product {
description
reviews {
rating
}
}
`;

function ProductCard({ id }: { id: string }) {
const prefersReducedMotion = usePrefersReducedMotion();

const { data } = useFragment({
const { data } = useSuspenseFragment({
fragment: ProductCardProductFragment,
from: `Product:${id}`,
});
Expand Down Expand Up @@ -60,24 +72,52 @@ function ProductCard({ id }: { id: string }) {
<Heading as="h2" size="md" my="4">
{data?.title}
</Heading>
{data?.averageRating ? (
<Flex direction="column" minH="100px" justify="space-between">
<Text as="i" noOfLines={2}>{`"${data?.description}"`}</Text>
<Flex direction="row" py="4" justify="space-between">
<ReviewRating isHalf rating={data?.averageRating} size={20} />
<Button>Read More</Button>
</Flex>
</Flex>
) : (
<Flex direction="row" justify="right">
<Button>Leave a Review</Button>
</Flex>
)}
<Suspense fallback="Loading">
<Reviews id={data?.id} />
</Suspense>
</Flex>
</Box>
);
}

export function Reviews({ id }: { id: string }) {
const { data } = useSuspenseFragment({
fragment: ReviewsFragment,
from: `Product:${id}`,
});

// console.log({ data });

const average = (array: Array<number>) =>
array.reduce((a, b) => a + b) / array.length;

const averageRating = data.reviews.length
? average(data.reviews.map((review) => review.rating))
: 0;

// console.log({ averageRating });

return (
<>
{averageRating ? (
<Flex direction="column" minH="100px" justify="space-between">
<Text as="i" noOfLines={2}>{`"${data?.description}"`}</Text>
<Flex direction="row" py="4" justify="space-between">
<ReviewRating isHalf rating={averageRating} size={20} />
<Button>Read More</Button>
</Flex>
</Flex>
) : (
<Flex direction="row" justify="right">
<Button>Leave a Review</Button>
</Flex>
)}
</>
);
}

Reviews.fragments = { ReviewsFragment };

ProductCard.fragments = {
ProductCardProductFragment,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use client";
import DelaySlider from "./DelaySlider";
import {
Button,
Expand Down
5 changes: 3 additions & 2 deletions examples/hack-the-supergraph-ssr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
"private": true,
"scripts": {
"dev": "next dev",
"prebuild": "yarn workspace @apollo/experimental-nextjs-app-support run build",
"prebuild": "yarn workspace @apollo/experimental-nextjs-app-support run build && yarn workspace @apollo/client-react-streaming run build",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@apollo/client": "3.10.4",
"@apollo/client": "https://pkg.pr.new/@apollo/client@12066",
"@apollo/client-react-streaming": "workspace:^",
"@apollo/experimental-nextjs-app-support": "workspace:^",
"@apollo/space-kit": "^9.11.0",
"@chakra-ui/next-js": "^2.1.2",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"build:docmodel": "yarn workspaces foreach --all --include \"@apollo/*\" exec api-extractor run"
},
"resolutions": {
"@apollo/client": "https://pkg.pr.new/@apollo/client@12066",
"react": "19.0.0-rc-935180c7e0-20240524",
"react-dom": "19.0.0-rc-935180c7e0-20240524",
"react-server-dom-webpack": "19.0.0-beta-94eed63c49-20240425",
Expand Down
Loading
Loading