Skip to content

Commit

Permalink
Merge pull request #54 from sannajammeh/better-ssr
Browse files Browse the repository at this point in the history
V3 - Better SSR support for Next 14, refactor from deprecated tRPC apis
  • Loading branch information
sannajammeh authored Nov 24, 2023
2 parents 5106cc9 + 5b020a2 commit 43edbb4
Show file tree
Hide file tree
Showing 30 changed files with 2,924 additions and 4,044 deletions.
17 changes: 17 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"mode": "pre",
"tag": "canary",
"initialVersions": {
"app-dir": "0.1.0",
"demo": "0.1.0",
"docs": "0.0.1",
"@trpc-swr/client": "2.0.1",
"config": "1.0.0",
"@trpc-swr/infinite": "2.0.1",
"@trpc-swr/next": "2.0.1",
"@trpc-swr/ssr": "2.0.1",
"e2e": "1.0.0",
"unit": "1.0.0"
},
"changesets": []
}
33 changes: 33 additions & 0 deletions .changeset/tender-ducks-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
"@trpc-swr/infinite": major
"@trpc-swr/client": major
"@trpc-swr/next": major
"@trpc-swr/ssr": major
---

## What:

`@trpc-swr/ssr` - `createProxySSGHelpers` renamed to `createSSRHelpers`

`@trpc-swr/ssr` - Calling `api.endpoint.fetch` is no longer support, use api.endpoint() directly. trpc-swr will now proxy all arguments directly into appRouter.createCaller() instead of calling `caller.query`.
This allows for both mutations and queries to endpoints in React Server Components and other SSR calls

#### Before

```tsx
const data = await rsc.users.byId.fetch({ id: 1 });

const swrFallback = await rsc.dehydrate();
```

#### After

```tsx
const data = await rsc.users.byId({ id: 1 });

// Other supported methods:
const key = rsc.users.byId.getKey(); // Use to manually forward to SWRConfig.
const swrFallback = await rsc.dehydrate();
```

As always both direct access and dehydration into SWR serializable fallback is supported.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: CI
on:
push:
branches: [main, master]
branches: [main, master, canary]
pull_request:
branches: [main, master]
env:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/deploy-canary.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: Publish package
on:
push:
branches: [new-arch]
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [canary]
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This is a monorepo for tRPC-SWR.
## Links

| Description | Link |
|------------------------|---------------------------------------------------------------------|
| ---------------------- | ------------------------------------------------------------------- |
| client | https://github.com/sannajammeh/trpc-swr/tree/main/packages/client |
| next | https://github.com/sannajammeh/trpc-swr/tree/main/packages/next |
| ssr | https://github.com/sannajammeh/trpc-swr/tree/main/packages/ssr |
Expand Down Expand Up @@ -85,8 +85,8 @@ const Profile = (props: { userId: string }) => {
{!data && isLoading
? "loading..."
: data
? data.name
: "User does not exist"}
? data.name
: "User does not exist"}
</div>
);
};
Expand Down Expand Up @@ -118,8 +118,8 @@ const Profile = (props: { userId: string }) => {
{!data && isLoading
? "loading..."
: data
? data.name
: "User does not exist"}
? data.name
: "User does not exist"}
</div>

<button
Expand Down Expand Up @@ -183,10 +183,10 @@ To prefetch data on the server, you must provide a serializable key.
In `server/ssg.ts`

```tsx
import { createProxySSGHelpers } from "@trpc-swr/ssr";
import { createSSRHelpers } from "@trpc-swr/ssr";

export const createSSG = () => {
return createProxySSGHelpers({
return createSSRHelpers({
router: appRouter,
ctx: {},
});
Expand Down Expand Up @@ -221,7 +221,7 @@ const Profile = (props: { userId: string }) => {
export const getServerSideProps = async () => {
const ssg = createSSG();

ssg.user.get.fetch({ id: "1" }); // prefetch data
ssg.user.get({ id: "1" }); // prefetch data

return {
props: {
Expand All @@ -235,4 +235,4 @@ export defualt HomePage;

## Status

[Live E2E Status](https://sannajammeh.github.io/trpc-swr/playwright-report/)
[Live E2E Status](https://sannajammeh.github.io/trpc-swr/playwright-report/)
4 changes: 2 additions & 2 deletions apps/app-dir/app/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSSG } from "@/server/_app";
import { cache } from "react";

export const getNotifications = cache(async () => {
const ssg = createSSG();
const ssg = createSSG();

return await ssg.notifications.all.fetch();
return await ssg.notifications.all();
});
158 changes: 79 additions & 79 deletions apps/app-dir/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Code from "@/components/Code";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
Expand All @@ -17,81 +17,81 @@ import AddNotification from "./AddNotification";
import Notification from "./Notification";

const Page = async () => {
const ssg = createSSG();
const status = await ssg.status.fetch();
const ssg = createSSG();
const status = await ssg.status();

const notifications = await getNotifications();
return (
<div className="container py-12">
<div className="grid grid-cols-[2fr_1fr] mx-auto gap-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
Notifications <Badge variant="blue">RSC</Badge>
</CardTitle>
<CardDescription>Fetching data directly</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="preview">
<TabsList>
<TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger className="flex items-center gap-2" value="code">
<CodeIcon size="16" /> Code
</TabsTrigger>
</TabsList>
<TabsContent value="preview">
<div data-testid="ssg-notifications">
<ScrollArea className="h-72 py-3">
{notifications.map((notification) => (
<Notification
key={notification.id}
notification={notification}
/>
))}
</ScrollArea>
</div>
</TabsContent>
<TabsContent className="w-full" value="code">
<div className="w-full py-4">
<ScrollArea className="w-full max-w-full">
<Code lang="ts">{notificationPreview}</Code>
</ScrollArea>
</div>
</TabsContent>
</Tabs>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
Status <Badge variant="blue">RSC</Badge>
</CardTitle>
<CardDescription>Fetching data directly</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="preview">
<TabsList>
<TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger className="flex items-center gap-2" value="code">
<CodeIcon size="16" /> Code
</TabsTrigger>
</TabsList>
<TabsContent value="preview">
<div data-testid="status">status: {status.status}</div>
</TabsContent>
<TabsContent className="w-full" value="code">
<div>
<Code lang="ts">{statusPreview}</Code>
</div>
</TabsContent>
</Tabs>
</CardContent>
</Card>
<ClientNotifications />
<AddNotification />
</div>
</div>
);
const notifications = await getNotifications();
return (
<div className="container py-12">
<div className="grid grid-cols-[2fr_1fr] mx-auto gap-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
Notifications <Badge variant="blue">RSC</Badge>
</CardTitle>
<CardDescription>Fetching data directly</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="preview">
<TabsList>
<TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger className="flex items-center gap-2" value="code">
<CodeIcon size="16" /> Code
</TabsTrigger>
</TabsList>
<TabsContent value="preview">
<div data-testid="ssg-notifications">
<ScrollArea className="h-72 py-3">
{notifications.map((notification) => (
<Notification
key={notification.id}
notification={notification}
/>
))}
</ScrollArea>
</div>
</TabsContent>
<TabsContent className="w-full" value="code">
<div className="w-full py-4">
<ScrollArea className="w-full max-w-full">
<Code lang="ts">{notificationPreview}</Code>
</ScrollArea>
</div>
</TabsContent>
</Tabs>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
Status <Badge variant="blue">RSC</Badge>
</CardTitle>
<CardDescription>Fetching data directly</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="preview">
<TabsList>
<TabsTrigger value="preview">Preview</TabsTrigger>
<TabsTrigger className="flex items-center gap-2" value="code">
<CodeIcon size="16" /> Code
</TabsTrigger>
</TabsList>
<TabsContent value="preview">
<div data-testid="status">status: {status.status}</div>
</TabsContent>
<TabsContent className="w-full" value="code">
<div>
<Code lang="ts">{statusPreview}</Code>
</div>
</TabsContent>
</Tabs>
</CardContent>
</Card>
<ClientNotifications />
<AddNotification />
</div>
</div>
);
};

export default Page;
Expand Down
5 changes: 1 addition & 4 deletions apps/app-dir/next.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
experimental: {
appDir: true,
},
reactStrictMode: true,
};

module.exports = nextConfig;
56 changes: 28 additions & 28 deletions apps/app-dir/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,44 @@
},
"dependencies": {
"@deepakvishwakarma/ts-util": "^1.1.0",
"@paralleldrive/cuid2": "^2.2.1",
"@paralleldrive/cuid2": "^2.2.2",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-scroll-area": "^1.0.4",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.4",
"@swc/helpers": "^0.4.14",
"@radix-ui/react-toast": "^1.1.5",
"@swc/helpers": "^0.5.3",
"@trpc-swr/client": "workspace:*",
"@trpc-swr/ssr": "workspace:^",
"@trpc/client": "^10.32.0",
"@trpc/server": "^10.32.0",
"@tw-classed/react": "^1.5.1",
"@types/node": "20.3.1",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.6",
"autoprefixer": "10.4.14",
"better-sqlite3": "^8.4.0",
"class-variance-authority": "^0.6.0",
"clsx": "^1.2.1",
"drizzle-orm": "^0.27.0",
"lucide-react": "^0.252.0",
"next": "^13.4.7",
"postcss": "8.4.24",
"@trpc/client": "^10.44.1",
"@trpc/server": "^10.44.1",
"@tw-classed/react": "^1.6.1",
"@types/node": "20.10.0",
"@types/react": "18.2.38",
"@types/react-dom": "18.2.17",
"autoprefixer": "10.4.16",
"better-sqlite3": "^9.1.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"drizzle-orm": "^0.29.0",
"lucide-react": "^0.293.0",
"next": "^14.0.3",
"postcss": "8.4.31",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"shiki": "^0.14.2",
"swr": "^2.2.0",
"tailwind-merge": "^1.13.2",
"tailwindcss": "3.3.2",
"tailwindcss-animate": "^1.0.6",
"typescript": "5.1.3",
"zod": "^3.21.4"
"shiki": "^0.14.5",
"swr": "^2.2.4",
"tailwind-merge": "^2.0.0",
"tailwindcss": "3.3.5",
"tailwindcss-animate": "^1.0.7",
"typescript": "5.3.2",
"zod": "^3.22.4"
},
"devDependencies": {
"@swc-node/register": "^1.6.6",
"@types/better-sqlite3": "^7.6.4",
"drizzle-kit": "^0.19.2"
"@swc-node/register": "^1.6.8",
"@types/better-sqlite3": "^7.6.8",
"drizzle-kit": "^0.20.4"
}
}
Loading

0 comments on commit 43edbb4

Please sign in to comment.