From 7094b5fc0426272153abca35798a69bda8c9bc91 Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 10:04:01 +0700 Subject: [PATCH 1/7] rename --- playgrounds/nextjs/src/lib/orpc.ts | 4 ++-- playgrounds/nextjs/src/playground-client.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/playgrounds/nextjs/src/lib/orpc.ts b/playgrounds/nextjs/src/lib/orpc.ts index 56abf45e9..8dbefa9e4 100644 --- a/playgrounds/nextjs/src/lib/orpc.ts +++ b/playgrounds/nextjs/src/lib/orpc.ts @@ -20,6 +20,6 @@ const rpcLink = new RPCLink({ ], }) -export const orpcClient: RouterClient = createORPCClient(rpcLink) +export const client: RouterClient = createORPCClient(rpcLink) -export const orpc = createORPCReactQueryUtils(orpcClient) +export const orpc = createORPCReactQueryUtils(client) diff --git a/playgrounds/nextjs/src/playground-client.ts b/playgrounds/nextjs/src/playground-client.ts index d33cddadf..cff6aa13b 100644 --- a/playgrounds/nextjs/src/playground-client.ts +++ b/playgrounds/nextjs/src/playground-client.ts @@ -1,4 +1,4 @@ -import { orpcClient as orpc } from '@/lib/orpc' +import { client as orpc } from '@/lib/orpc' import { safe } from '@orpc/client' const token = await orpc.auth.signin({ From f6bc64a2eb651154d21b5623e6055097b4eb303b Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 10:09:38 +0700 Subject: [PATCH 2/7] rename --- CONTRIBUTING.md | 2 +- apps/content/docs/playgrounds.md | 4 ++-- playgrounds/{nextjs => next}/.gitignore | 0 playgrounds/{nextjs => next}/.vscode/settings.json | 0 playgrounds/{nextjs => next}/README.md | 0 playgrounds/{nextjs => next}/next.config.ts | 0 playgrounds/{nextjs => next}/package.json | 2 +- playgrounds/{nextjs => next}/public/file.svg | 0 playgrounds/{nextjs => next}/public/globe.svg | 0 playgrounds/{nextjs => next}/public/next.svg | 0 playgrounds/{nextjs => next}/public/vercel.svg | 0 playgrounds/{nextjs => next}/public/window.svg | 0 playgrounds/{nextjs => next}/src/app/actions.ts | 0 .../src/app/api/[[...rest]]/route.ts | 0 playgrounds/{nextjs => next}/src/app/error.tsx | 0 playgrounds/{nextjs => next}/src/app/favicon.ico | Bin playgrounds/{nextjs => next}/src/app/layout.tsx | 0 playgrounds/{nextjs => next}/src/app/loading.tsx | 0 .../{nextjs => next}/src/app/orpc-mutation.tsx | 0 playgrounds/{nextjs => next}/src/app/orpc-query.tsx | 0 .../{nextjs => next}/src/app/orpc-server-action.tsx | 0 playgrounds/{nextjs => next}/src/app/page.tsx | 0 playgrounds/{nextjs => next}/src/app/providers.tsx | 0 .../src/app/rpc/[[...rest]]/route.ts | 0 playgrounds/{nextjs => next}/src/lib/orpc.ts | 0 .../{nextjs => next}/src/middlewares/auth.ts | 0 playgrounds/{nextjs => next}/src/middlewares/db.ts | 0 .../{nextjs => next}/src/middlewares/retry.ts | 0 playgrounds/{nextjs => next}/src/orpc.ts | 0 .../{nextjs => next}/src/playground-client.ts | 0 .../{nextjs => next}/src/playground-query.ts | 0 playgrounds/{nextjs => next}/src/polyfill.ts | 0 playgrounds/{nextjs => next}/src/router/auth.ts | 0 playgrounds/{nextjs => next}/src/router/index.ts | 0 playgrounds/{nextjs => next}/src/router/planet.ts | 0 playgrounds/{nextjs => next}/src/router/sse.ts | 0 playgrounds/{nextjs => next}/src/schemas/auth.ts | 0 playgrounds/{nextjs => next}/src/schemas/planet.ts | 0 playgrounds/{nextjs => next}/src/schemas/user.ts | 0 playgrounds/{nextjs => next}/tsconfig.json | 0 40 files changed, 4 insertions(+), 4 deletions(-) rename playgrounds/{nextjs => next}/.gitignore (100%) rename playgrounds/{nextjs => next}/.vscode/settings.json (100%) rename playgrounds/{nextjs => next}/README.md (100%) rename playgrounds/{nextjs => next}/next.config.ts (100%) rename playgrounds/{nextjs => next}/package.json (94%) rename playgrounds/{nextjs => next}/public/file.svg (100%) rename playgrounds/{nextjs => next}/public/globe.svg (100%) rename playgrounds/{nextjs => next}/public/next.svg (100%) rename playgrounds/{nextjs => next}/public/vercel.svg (100%) rename playgrounds/{nextjs => next}/public/window.svg (100%) rename playgrounds/{nextjs => next}/src/app/actions.ts (100%) rename playgrounds/{nextjs => next}/src/app/api/[[...rest]]/route.ts (100%) rename playgrounds/{nextjs => next}/src/app/error.tsx (100%) rename playgrounds/{nextjs => next}/src/app/favicon.ico (100%) rename playgrounds/{nextjs => next}/src/app/layout.tsx (100%) rename playgrounds/{nextjs => next}/src/app/loading.tsx (100%) rename playgrounds/{nextjs => next}/src/app/orpc-mutation.tsx (100%) rename playgrounds/{nextjs => next}/src/app/orpc-query.tsx (100%) rename playgrounds/{nextjs => next}/src/app/orpc-server-action.tsx (100%) rename playgrounds/{nextjs => next}/src/app/page.tsx (100%) rename playgrounds/{nextjs => next}/src/app/providers.tsx (100%) rename playgrounds/{nextjs => next}/src/app/rpc/[[...rest]]/route.ts (100%) rename playgrounds/{nextjs => next}/src/lib/orpc.ts (100%) rename playgrounds/{nextjs => next}/src/middlewares/auth.ts (100%) rename playgrounds/{nextjs => next}/src/middlewares/db.ts (100%) rename playgrounds/{nextjs => next}/src/middlewares/retry.ts (100%) rename playgrounds/{nextjs => next}/src/orpc.ts (100%) rename playgrounds/{nextjs => next}/src/playground-client.ts (100%) rename playgrounds/{nextjs => next}/src/playground-query.ts (100%) rename playgrounds/{nextjs => next}/src/polyfill.ts (100%) rename playgrounds/{nextjs => next}/src/router/auth.ts (100%) rename playgrounds/{nextjs => next}/src/router/index.ts (100%) rename playgrounds/{nextjs => next}/src/router/planet.ts (100%) rename playgrounds/{nextjs => next}/src/router/sse.ts (100%) rename playgrounds/{nextjs => next}/src/schemas/auth.ts (100%) rename playgrounds/{nextjs => next}/src/schemas/planet.ts (100%) rename playgrounds/{nextjs => next}/src/schemas/user.ts (100%) rename playgrounds/{nextjs => next}/tsconfig.json (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b73273588..0aebdc9e1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ We use **Vitest** for testing and **ESLint** with [@antfu/eslint-config](https:/ 5. **Code**: Make your changes. 6. **Test**: Manually verify in a playground, e.g.: ```bash - cd playgrounds/nextjs + cd playgrounds/next pnpm dev ``` 7. **Tests**: Add or update tests: diff --git a/apps/content/docs/playgrounds.md b/apps/content/docs/playgrounds.md index f87e7eecf..a4716e709 100644 --- a/apps/content/docs/playgrounds.md +++ b/apps/content/docs/playgrounds.md @@ -12,7 +12,7 @@ featuring pre-configured examples accessible instantly via StackBlitz or local s | Environment | StackBlitz | GitHub Source | | ------------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -| Next.js Playground | [Open in StackBlitz](https://stackblitz.com/github/unnoq/orpc/tree/main/playgrounds/nextjs) | [View Source](https://github.com/unnoq/orpc/tree/main/playgrounds/nextjs) | +| Next.js Playground | [Open in StackBlitz](https://stackblitz.com/github/unnoq/orpc/tree/main/playgrounds/next) | [View Source](https://github.com/unnoq/orpc/tree/main/playgrounds/next) | | TanStack Start Playground | [Open in StackBlitz](https://stackblitz.com/github/unnoq/orpc/tree/main/playgrounds/tanstack-start) | [View Source](https://github.com/unnoq/orpc/tree/main/playgrounds/tanstack-start) | | Nuxt.js Playground | [Open in StackBlitz](https://stackblitz.com/github/unnoq/orpc/tree/main/playgrounds/nuxt) | [View Source](https://github.com/unnoq/orpc/tree/main/playgrounds/nuxt) | | Solid Start Playground | [Open in StackBlitz](https://stackblitz.com/github/unnoq/orpc/tree/main/playgrounds/solid-start) | [View Source](https://github.com/unnoq/orpc/tree/main/playgrounds/solid-start) | @@ -29,7 +29,7 @@ StackBlitz has own limitations, so some features may not work as expected. If you prefer working locally, you can clone any playground using the following commands: ```bash -npx degit unnoq/orpc/playgrounds/nextjs orpc-nextjs-playground +npx degit unnoq/orpc/playgrounds/next orpc-next-playground npx degit unnoq/orpc/playgrounds/tanstack-start orpc-tanstack-start-playground npx degit unnoq/orpc/playgrounds/nuxt orpc-nuxt-playground npx degit unnoq/orpc/playgrounds/solid-start orpc-solid-start-playground diff --git a/playgrounds/nextjs/.gitignore b/playgrounds/next/.gitignore similarity index 100% rename from playgrounds/nextjs/.gitignore rename to playgrounds/next/.gitignore diff --git a/playgrounds/nextjs/.vscode/settings.json b/playgrounds/next/.vscode/settings.json similarity index 100% rename from playgrounds/nextjs/.vscode/settings.json rename to playgrounds/next/.vscode/settings.json diff --git a/playgrounds/nextjs/README.md b/playgrounds/next/README.md similarity index 100% rename from playgrounds/nextjs/README.md rename to playgrounds/next/README.md diff --git a/playgrounds/nextjs/next.config.ts b/playgrounds/next/next.config.ts similarity index 100% rename from playgrounds/nextjs/next.config.ts rename to playgrounds/next/next.config.ts diff --git a/playgrounds/nextjs/package.json b/playgrounds/next/package.json similarity index 94% rename from playgrounds/nextjs/package.json rename to playgrounds/next/package.json index 8641cd9a4..e108e12da 100644 --- a/playgrounds/nextjs/package.json +++ b/playgrounds/next/package.json @@ -1,5 +1,5 @@ { - "name": "@orpc/nextjs-playground", + "name": "@orpc/next-playground", "version": "1.2.0", "private": true, "scripts": { diff --git a/playgrounds/nextjs/public/file.svg b/playgrounds/next/public/file.svg similarity index 100% rename from playgrounds/nextjs/public/file.svg rename to playgrounds/next/public/file.svg diff --git a/playgrounds/nextjs/public/globe.svg b/playgrounds/next/public/globe.svg similarity index 100% rename from playgrounds/nextjs/public/globe.svg rename to playgrounds/next/public/globe.svg diff --git a/playgrounds/nextjs/public/next.svg b/playgrounds/next/public/next.svg similarity index 100% rename from playgrounds/nextjs/public/next.svg rename to playgrounds/next/public/next.svg diff --git a/playgrounds/nextjs/public/vercel.svg b/playgrounds/next/public/vercel.svg similarity index 100% rename from playgrounds/nextjs/public/vercel.svg rename to playgrounds/next/public/vercel.svg diff --git a/playgrounds/nextjs/public/window.svg b/playgrounds/next/public/window.svg similarity index 100% rename from playgrounds/nextjs/public/window.svg rename to playgrounds/next/public/window.svg diff --git a/playgrounds/nextjs/src/app/actions.ts b/playgrounds/next/src/app/actions.ts similarity index 100% rename from playgrounds/nextjs/src/app/actions.ts rename to playgrounds/next/src/app/actions.ts diff --git a/playgrounds/nextjs/src/app/api/[[...rest]]/route.ts b/playgrounds/next/src/app/api/[[...rest]]/route.ts similarity index 100% rename from playgrounds/nextjs/src/app/api/[[...rest]]/route.ts rename to playgrounds/next/src/app/api/[[...rest]]/route.ts diff --git a/playgrounds/nextjs/src/app/error.tsx b/playgrounds/next/src/app/error.tsx similarity index 100% rename from playgrounds/nextjs/src/app/error.tsx rename to playgrounds/next/src/app/error.tsx diff --git a/playgrounds/nextjs/src/app/favicon.ico b/playgrounds/next/src/app/favicon.ico similarity index 100% rename from playgrounds/nextjs/src/app/favicon.ico rename to playgrounds/next/src/app/favicon.ico diff --git a/playgrounds/nextjs/src/app/layout.tsx b/playgrounds/next/src/app/layout.tsx similarity index 100% rename from playgrounds/nextjs/src/app/layout.tsx rename to playgrounds/next/src/app/layout.tsx diff --git a/playgrounds/nextjs/src/app/loading.tsx b/playgrounds/next/src/app/loading.tsx similarity index 100% rename from playgrounds/nextjs/src/app/loading.tsx rename to playgrounds/next/src/app/loading.tsx diff --git a/playgrounds/nextjs/src/app/orpc-mutation.tsx b/playgrounds/next/src/app/orpc-mutation.tsx similarity index 100% rename from playgrounds/nextjs/src/app/orpc-mutation.tsx rename to playgrounds/next/src/app/orpc-mutation.tsx diff --git a/playgrounds/nextjs/src/app/orpc-query.tsx b/playgrounds/next/src/app/orpc-query.tsx similarity index 100% rename from playgrounds/nextjs/src/app/orpc-query.tsx rename to playgrounds/next/src/app/orpc-query.tsx diff --git a/playgrounds/nextjs/src/app/orpc-server-action.tsx b/playgrounds/next/src/app/orpc-server-action.tsx similarity index 100% rename from playgrounds/nextjs/src/app/orpc-server-action.tsx rename to playgrounds/next/src/app/orpc-server-action.tsx diff --git a/playgrounds/nextjs/src/app/page.tsx b/playgrounds/next/src/app/page.tsx similarity index 100% rename from playgrounds/nextjs/src/app/page.tsx rename to playgrounds/next/src/app/page.tsx diff --git a/playgrounds/nextjs/src/app/providers.tsx b/playgrounds/next/src/app/providers.tsx similarity index 100% rename from playgrounds/nextjs/src/app/providers.tsx rename to playgrounds/next/src/app/providers.tsx diff --git a/playgrounds/nextjs/src/app/rpc/[[...rest]]/route.ts b/playgrounds/next/src/app/rpc/[[...rest]]/route.ts similarity index 100% rename from playgrounds/nextjs/src/app/rpc/[[...rest]]/route.ts rename to playgrounds/next/src/app/rpc/[[...rest]]/route.ts diff --git a/playgrounds/nextjs/src/lib/orpc.ts b/playgrounds/next/src/lib/orpc.ts similarity index 100% rename from playgrounds/nextjs/src/lib/orpc.ts rename to playgrounds/next/src/lib/orpc.ts diff --git a/playgrounds/nextjs/src/middlewares/auth.ts b/playgrounds/next/src/middlewares/auth.ts similarity index 100% rename from playgrounds/nextjs/src/middlewares/auth.ts rename to playgrounds/next/src/middlewares/auth.ts diff --git a/playgrounds/nextjs/src/middlewares/db.ts b/playgrounds/next/src/middlewares/db.ts similarity index 100% rename from playgrounds/nextjs/src/middlewares/db.ts rename to playgrounds/next/src/middlewares/db.ts diff --git a/playgrounds/nextjs/src/middlewares/retry.ts b/playgrounds/next/src/middlewares/retry.ts similarity index 100% rename from playgrounds/nextjs/src/middlewares/retry.ts rename to playgrounds/next/src/middlewares/retry.ts diff --git a/playgrounds/nextjs/src/orpc.ts b/playgrounds/next/src/orpc.ts similarity index 100% rename from playgrounds/nextjs/src/orpc.ts rename to playgrounds/next/src/orpc.ts diff --git a/playgrounds/nextjs/src/playground-client.ts b/playgrounds/next/src/playground-client.ts similarity index 100% rename from playgrounds/nextjs/src/playground-client.ts rename to playgrounds/next/src/playground-client.ts diff --git a/playgrounds/nextjs/src/playground-query.ts b/playgrounds/next/src/playground-query.ts similarity index 100% rename from playgrounds/nextjs/src/playground-query.ts rename to playgrounds/next/src/playground-query.ts diff --git a/playgrounds/nextjs/src/polyfill.ts b/playgrounds/next/src/polyfill.ts similarity index 100% rename from playgrounds/nextjs/src/polyfill.ts rename to playgrounds/next/src/polyfill.ts diff --git a/playgrounds/nextjs/src/router/auth.ts b/playgrounds/next/src/router/auth.ts similarity index 100% rename from playgrounds/nextjs/src/router/auth.ts rename to playgrounds/next/src/router/auth.ts diff --git a/playgrounds/nextjs/src/router/index.ts b/playgrounds/next/src/router/index.ts similarity index 100% rename from playgrounds/nextjs/src/router/index.ts rename to playgrounds/next/src/router/index.ts diff --git a/playgrounds/nextjs/src/router/planet.ts b/playgrounds/next/src/router/planet.ts similarity index 100% rename from playgrounds/nextjs/src/router/planet.ts rename to playgrounds/next/src/router/planet.ts diff --git a/playgrounds/nextjs/src/router/sse.ts b/playgrounds/next/src/router/sse.ts similarity index 100% rename from playgrounds/nextjs/src/router/sse.ts rename to playgrounds/next/src/router/sse.ts diff --git a/playgrounds/nextjs/src/schemas/auth.ts b/playgrounds/next/src/schemas/auth.ts similarity index 100% rename from playgrounds/nextjs/src/schemas/auth.ts rename to playgrounds/next/src/schemas/auth.ts diff --git a/playgrounds/nextjs/src/schemas/planet.ts b/playgrounds/next/src/schemas/planet.ts similarity index 100% rename from playgrounds/nextjs/src/schemas/planet.ts rename to playgrounds/next/src/schemas/planet.ts diff --git a/playgrounds/nextjs/src/schemas/user.ts b/playgrounds/next/src/schemas/user.ts similarity index 100% rename from playgrounds/nextjs/src/schemas/user.ts rename to playgrounds/next/src/schemas/user.ts diff --git a/playgrounds/nextjs/tsconfig.json b/playgrounds/next/tsconfig.json similarity index 100% rename from playgrounds/nextjs/tsconfig.json rename to playgrounds/next/tsconfig.json From 4a368571c63f9cc3bc1c6ee1b1717ec871878a3e Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 10:10:44 +0700 Subject: [PATCH 3/7] update pnpm lock --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe81a5190..5580b184f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -731,7 +731,7 @@ importers: specifier: ^3.24.4 version: 3.24.4 - playgrounds/nextjs: + playgrounds/next: devDependencies: '@orpc/client': specifier: next From e0b520a77a6b55f0183073535dc94a538c225444 Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 10:12:59 +0700 Subject: [PATCH 4/7] rename --- apps/content/.vitepress/config.ts | 2 +- apps/content/docs/integrations/{nextjs.md => next.md} | 0 apps/content/public/_redirects | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) rename apps/content/docs/integrations/{nextjs.md => next.md} (100%) diff --git a/apps/content/.vitepress/config.ts b/apps/content/.vitepress/config.ts index 5c7b2b9a8..c57cf534f 100644 --- a/apps/content/.vitepress/config.ts +++ b/apps/content/.vitepress/config.ts @@ -97,7 +97,7 @@ export default defineConfig({ items: [ { text: 'Express', link: '/docs/integrations/express' }, { text: 'Fastify', link: '/docs/integrations/fastify' }, - { text: 'Next.js', link: '/docs/integrations/nextjs' }, + { text: 'Next.js', link: '/docs/integrations/next' }, { text: 'Nuxt', link: '/docs/integrations/nuxt' }, { text: 'Hono', link: '/docs/integrations/hono' }, { text: 'Tanstack Start', link: '/docs/integrations/tanstack-start' }, diff --git a/apps/content/docs/integrations/nextjs.md b/apps/content/docs/integrations/next.md similarity index 100% rename from apps/content/docs/integrations/nextjs.md rename to apps/content/docs/integrations/next.md diff --git a/apps/content/public/_redirects b/apps/content/public/_redirects index 70507ff95..3917e5f8d 100644 --- a/apps/content/public/_redirects +++ b/apps/content/public/_redirects @@ -1,3 +1,4 @@ /docs /docs/getting-started 301 /docs/openapi /docs/openapi/getting-started 301 -/sponsor https://github.com/sponsors/unnoq 301 \ No newline at end of file +/sponsor https://github.com/sponsors/unnoq 301 +/docs/integrations/nextjs /docs/integrations/next 301 \ No newline at end of file From b01821c490416f7987bce811aef2b952194ea614 Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 10:46:35 +0700 Subject: [PATCH 5/7] wip --- apps/content/docs/integrations/next.md | 118 +++++++++++++++++++++--- playgrounds/next/src/app/layout.tsx | 2 + playgrounds/next/src/app/orpc-query.tsx | 8 +- playgrounds/next/src/lib/orpc.server.ts | 5 + playgrounds/next/src/lib/orpc.ts | 17 +++- 5 files changed, 127 insertions(+), 23 deletions(-) create mode 100644 playgrounds/next/src/lib/orpc.server.ts diff --git a/apps/content/docs/integrations/next.md b/apps/content/docs/integrations/next.md index adec8c2dd..f7ca3304a 100644 --- a/apps/content/docs/integrations/next.md +++ b/apps/content/docs/integrations/next.md @@ -8,12 +8,12 @@ description: Seamlessly integrate oRPC with Next.js [Next.js](https://nextjs.org/) is a leading React framework for server-rendered apps. oRPC works with both the [App Router](https://nextjs.org/docs/app/getting-started/installation) and [Pages Router](https://nextjs.org/docs/pages/getting-started/installation). For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide. ::: info -oRPC also supports [Server Action](/docs/server-action) out-of-the-box. +oRPC also supports [Server Action](/docs/server-action) out-of-the-box without any extra configuration. ::: -## App Router +## Server -::: code-group +You can integrate oRPC with TanStack Start using its [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers). ```ts [app/rpc/[[...rest]]/route.ts] import { RPCHandler } from '@orpc/server/fetch' @@ -29,6 +29,7 @@ async function handleRequest(request: Request) { return response ?? new Response('Not found', { status: 404 }) } +export const HEAD = handleRequest export const GET = handleRequest export const POST = handleRequest export const PUT = handleRequest @@ -36,15 +37,11 @@ export const PATCH = handleRequest export const DELETE = handleRequest ``` -::: - ::: info The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler. ::: -## Pages Router - -::: code-group +::: details Pages Router Support? ```ts [pages/rpc/[[...rest]].ts] import { RPCHandler } from '@orpc/server/node' @@ -72,9 +69,8 @@ export default async (req, res) => { } ``` -::: - ::: warning + Next.js default [body parser](https://nextjs.org/docs/pages/building-your-application/routing/api-routes#custom-config) blocks oRPC raw‑request handling. Ensure `bodyParser` is disabled in your API route: ```ts @@ -87,6 +83,104 @@ export const config = { ::: -::: info -The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler. +## Client + +On the client, to make client friendly with SSR, because Next.js does not built-in support `Isomorphic Functions` so need need some tricks to achieve it by using `globalThis.$headers` on ssr. Alternative you can use react context like the approach mention in [discussions#330](https://github.com/unnoq/orpc/discussions/330#discussioncomment-12727779) + +::: code-group + +```ts [lib/orpc.ts] +import type { headers } from 'next/headers' + +declare global { + var $headers: typeof headers +} + +const link = new RPCLink({ + url: new URL('/rpc', typeof window !== 'undefined' ? window.location.href : 'http://localhost:3000'), + headers: async () => { + return globalThis.$headers + ? Object.fromEntries(await globalThis.$headers()) // use this on ssr + : {} // use this on browser + }, +}) +``` + +```ts [lib/orpc.server.ts] +'server only' + +import { headers } from 'next/headers' + +globalThis.$headers = headers +``` + +```ts [app/layout.tsx] +import '../lib/orpc.server' + +// Rest of the code +``` + +::: + +:::info +This only shows how to configure the link. For full client examples, see [Client-Side Clients](/docs/client/client-side). +::: + +## Optimize SSR + +To reduce HTTP requests and improve latency during SSR, you can utilize a [Server-Side Client](/docs/client/server-side) during SSR. Below is a quick setup, see [Optimize SSR](/docs/best-practices/optimize-ssr) for a more details. + +::: code-group + +```ts [lib/orpc.ts] +import type { RouterClient } from '@orpc/server' +import { RPCLink } from '@orpc/client/fetch' +import { createORPCClient } from '@orpc/client' + +declare global { + var $client: RouterClient | undefined +} + +const link = new RPCLink({ + url: () => { + if (typeof window === 'undefined') { + throw new Error('RPCLink is not allowed on the server side.') + } + + return new URL('/rpc', window.location.href) + }, +}) + +/** + * Fallback to client-side client if server-side client is not available. + */ +export const client: RouterClient = globalThis.$client ?? createORPCClient(link) +``` + +```ts [lib/orpc.server.ts] +'server only' + +import { headers } from 'next/headers' +import { createRouterClient } from '@orpc/server' + +globalThis.$client = createRouterClient(router, { + /** + * Provide initial context if needed. + * + * Because this client instance is shared across all requests, + * only include context that's safe to reuse globally. + * For per-request context, use middleware context or pass a function as the initial context. + */ + context: async () => ({ + headers: await headers(), + }), +}) +``` + +```ts [app/layout.tsx] +import '../lib/orpc.server' + +// Rest of the code +``` + ::: diff --git a/playgrounds/next/src/app/layout.tsx b/playgrounds/next/src/app/layout.tsx index f3a134440..ab470b583 100644 --- a/playgrounds/next/src/app/layout.tsx +++ b/playgrounds/next/src/app/layout.tsx @@ -1,3 +1,5 @@ +import '../lib/orpc.server' + import type { Metadata } from 'next' import { Providers } from './providers' diff --git a/playgrounds/next/src/app/orpc-query.tsx b/playgrounds/next/src/app/orpc-query.tsx index 34c4d1ab6..dbddee78c 100644 --- a/playgrounds/next/src/app/orpc-query.tsx +++ b/playgrounds/next/src/app/orpc-query.tsx @@ -1,10 +1,10 @@ 'use client' import { orpc } from '@/lib/orpc' -import { useInfiniteQuery } from '@tanstack/react-query' +import { useSuspenseInfiniteQuery } from '@tanstack/react-query' export function ListPlanetsQuery() { - const { data, refetch, fetchNextPage, hasNextPage, status } = useInfiniteQuery( + const { data, refetch, fetchNextPage, hasNextPage, status } = useSuspenseInfiniteQuery( orpc.planet.list.infiniteOptions({ input: cursor => ({ cursor, limit: 10 }), getNextPageParam: lastPage => lastPage.length === 10 ? lastPage.at(-1)?.id : null, @@ -12,10 +12,6 @@ export function ListPlanetsQuery() { }), ) - if (status === 'pending') { - return

Loading...

- } - if (status === 'error') { return (

diff --git a/playgrounds/next/src/lib/orpc.server.ts b/playgrounds/next/src/lib/orpc.server.ts new file mode 100644 index 000000000..48a377ff7 --- /dev/null +++ b/playgrounds/next/src/lib/orpc.server.ts @@ -0,0 +1,5 @@ +'server only' + +import { headers } from 'next/headers' + +globalThis.$headers = headers diff --git a/playgrounds/next/src/lib/orpc.ts b/playgrounds/next/src/lib/orpc.ts index 8dbefa9e4..502c516c5 100644 --- a/playgrounds/next/src/lib/orpc.ts +++ b/playgrounds/next/src/lib/orpc.ts @@ -4,12 +4,19 @@ import { createORPCClient } from '@orpc/client' import { RPCLink } from '@orpc/client/fetch' import { createORPCReactQueryUtils } from '@orpc/react-query' import { BatchLinkPlugin } from '@orpc/client/plugins' +import type { headers } from 'next/headers' -const rpcLink = new RPCLink({ +declare global { + var $headers: typeof headers +} + +const link = new RPCLink({ url: new URL('/rpc', typeof window !== 'undefined' ? window.location.href : 'http://localhost:3000'), - headers: () => ({ - Authorization: 'Bearer default-token', - }), + headers: async () => { + return globalThis.$headers + ? Object.fromEntries(await globalThis.$headers()) + : {} + }, plugins: [ new BatchLinkPlugin({ groups: [{ @@ -20,6 +27,6 @@ const rpcLink = new RPCLink({ ], }) -export const client: RouterClient = createORPCClient(rpcLink) +export const client: RouterClient = createORPCClient(link) export const orpc = createORPCReactQueryUtils(client) From fbb2129c13c846e0fefe26754f9e99c5f8c85700 Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 10:59:10 +0700 Subject: [PATCH 6/7] wip --- apps/content/docs/integrations/next.md | 4 ++++ .../next/src/app/api/[[...rest]]/route.ts | 1 + .../next/src/app/rpc/[[...rest]]/route.ts | 1 + playgrounds/next/src/lib/orpc.server.ts | 20 ++++++++++++++++++- playgrounds/next/src/lib/orpc.ts | 15 +++++++------- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/content/docs/integrations/next.md b/apps/content/docs/integrations/next.md index f7ca3304a..7dffec485 100644 --- a/apps/content/docs/integrations/next.md +++ b/apps/content/docs/integrations/next.md @@ -15,6 +15,8 @@ oRPC also supports [Server Action](/docs/server-action) out-of-the-box without a You can integrate oRPC with TanStack Start using its [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers). +::: code-group + ```ts [app/rpc/[[...rest]]/route.ts] import { RPCHandler } from '@orpc/server/fetch' @@ -37,6 +39,8 @@ export const PATCH = handleRequest export const DELETE = handleRequest ``` +::: + ::: info The `handler` can be any supported oRPC handler, such as [RPCHandler](/docs/rpc-handler), [OpenAPIHandler](/docs/openapi/openapi-handler), or another custom handler. ::: diff --git a/playgrounds/next/src/app/api/[[...rest]]/route.ts b/playgrounds/next/src/app/api/[[...rest]]/route.ts index 67e383825..f8f811549 100644 --- a/playgrounds/next/src/app/api/[[...rest]]/route.ts +++ b/playgrounds/next/src/app/api/[[...rest]]/route.ts @@ -45,6 +45,7 @@ async function handleRequest(request: Request) { return response ?? new Response('Not found', { status: 404 }) } +export const HEAD = handleRequest export const GET = handleRequest export const POST = handleRequest export const PUT = handleRequest diff --git a/playgrounds/next/src/app/rpc/[[...rest]]/route.ts b/playgrounds/next/src/app/rpc/[[...rest]]/route.ts index 24d6ead37..3eccf1bf3 100644 --- a/playgrounds/next/src/app/rpc/[[...rest]]/route.ts +++ b/playgrounds/next/src/app/rpc/[[...rest]]/route.ts @@ -24,6 +24,7 @@ async function handleRequest(request: Request) { return response ?? new Response('Not found', { status: 404 }) } +export const HEAD = handleRequest export const GET = handleRequest export const POST = handleRequest export const PUT = handleRequest diff --git a/playgrounds/next/src/lib/orpc.server.ts b/playgrounds/next/src/lib/orpc.server.ts index 48a377ff7..aea732baa 100644 --- a/playgrounds/next/src/lib/orpc.server.ts +++ b/playgrounds/next/src/lib/orpc.server.ts @@ -1,5 +1,23 @@ 'server only' +import { router } from '@/router' +import { createRouterClient } from '@orpc/server' import { headers } from 'next/headers' -globalThis.$headers = headers +/** + * This is part of the Optimize SSR setup. + * + * @see {@link https://orpc.unnoq.com/docs/integrations/next#optimize-ssr} + */ +globalThis.$client = createRouterClient(router, { + /** + * Provide initial context if needed. + * + * Because this client instance is shared across all requests, + * only include context that's safe to reuse globally. + * For per-request context, use middleware context or pass a function as the initial context. + */ + context: async () => ({ + headers: await headers(), + }), +}) diff --git a/playgrounds/next/src/lib/orpc.ts b/playgrounds/next/src/lib/orpc.ts index 502c516c5..038786ca2 100644 --- a/playgrounds/next/src/lib/orpc.ts +++ b/playgrounds/next/src/lib/orpc.ts @@ -4,19 +4,18 @@ import { createORPCClient } from '@orpc/client' import { RPCLink } from '@orpc/client/fetch' import { createORPCReactQueryUtils } from '@orpc/react-query' import { BatchLinkPlugin } from '@orpc/client/plugins' -import type { headers } from 'next/headers' +/** + * This is part of the Optimize SSR setup. + * + * @see {@link https://orpc.unnoq.com/docs/integrations/next#optimize-ssr} + */ declare global { - var $headers: typeof headers + var $client: RouterClient | undefined } const link = new RPCLink({ url: new URL('/rpc', typeof window !== 'undefined' ? window.location.href : 'http://localhost:3000'), - headers: async () => { - return globalThis.$headers - ? Object.fromEntries(await globalThis.$headers()) - : {} - }, plugins: [ new BatchLinkPlugin({ groups: [{ @@ -27,6 +26,6 @@ const link = new RPCLink({ ], }) -export const client: RouterClient = createORPCClient(link) +export const client: RouterClient = globalThis.$client ?? createORPCClient(link) export const orpc = createORPCReactQueryUtils(client) From 2dc37ed3bf805b57a45176151a5edb1ac5be9bd0 Mon Sep 17 00:00:00 2001 From: unnoq Date: Mon, 12 May 2025 11:06:35 +0700 Subject: [PATCH 7/7] docs --- apps/content/docs/integrations/next.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/content/docs/integrations/next.md b/apps/content/docs/integrations/next.md index 7dffec485..8478aaedc 100644 --- a/apps/content/docs/integrations/next.md +++ b/apps/content/docs/integrations/next.md @@ -8,7 +8,7 @@ description: Seamlessly integrate oRPC with Next.js [Next.js](https://nextjs.org/) is a leading React framework for server-rendered apps. oRPC works with both the [App Router](https://nextjs.org/docs/app/getting-started/installation) and [Pages Router](https://nextjs.org/docs/pages/getting-started/installation). For additional context, refer to the [HTTP Adapter](/docs/adapters/http) guide. ::: info -oRPC also supports [Server Action](/docs/server-action) out-of-the-box without any extra configuration. +oRPC also provides out-of-the-box support for [Server Action](/docs/server-action) with no additional configuration required. ::: ## Server @@ -89,7 +89,7 @@ export const config = { ## Client -On the client, to make client friendly with SSR, because Next.js does not built-in support `Isomorphic Functions` so need need some tricks to achieve it by using `globalThis.$headers` on ssr. Alternative you can use react context like the approach mention in [discussions#330](https://github.com/unnoq/orpc/discussions/330#discussioncomment-12727779) +Next.js doesn’t natively support isomorphic functions, so you need a workaround to make client-side code compatible with SSR. This example uses `globalThis.$headers` as that workaround. Alternatively, you can use React Context like the approach mentioned in [discussions#330](https://github.com/unnoq/orpc/discussions/330#discussioncomment-12727779). ::: code-group