Compare commits

..

16 Commits

Author SHA1 Message Date
Robert Soriano
ebb6637238 chore: release v0.4.0-beta.4 2022-10-30 13:02:11 -07:00
Robert Soriano
0c83ade918 update release script 2022-10-30 13:02:01 -07:00
Robert Soriano
97d9b3ddf8 import useAsyncData and useState from #app 2022-10-30 12:57:57 -07:00
Robert Soriano
eaa61f3700 bump local pnpm to 7.14.1 2022-10-30 12:35:30 -07:00
Robert Soriano
a5a9f430d5 chore: release v0.4.0-beta.3 2022-10-30 12:34:40 -07:00
Robert Soriano
94f59c396a update local deps 2022-10-30 12:30:03 -07:00
Robert Soriano
fe4c10ae25 remove outDir 2022-10-30 12:29:01 -07:00
Robert Soriano
7a97127353 update directory structure 2022-10-30 12:25:28 -07:00
Robert Soriano
0c4a43ec19 update playground 2022-10-30 12:19:57 -07:00
Robert Soriano
da6d738406 update docs 2022-10-30 12:00:21 -07:00
Robert Soriano
70c0b35c48 complete usage docs 2022-10-30 11:18:57 -07:00
Robert Soriano
da52b350ba add initial docs 2022-10-30 11:00:09 -07:00
Robert Soriano
b45c613ce7 immediately execute mutations 2022-10-30 01:52:20 -07:00
Robert Soriano
025ce7e028 chore: release v0.4.0-beta.2 2022-10-29 23:10:16 -07:00
Robert Soriano
4e637a4ec3 add root tsconfig 2022-10-29 23:09:44 -07:00
Robert Soriano
2b5daf54fa chore: release v0.4.0-beta.1 2022-10-29 22:52:42 -07:00
40 changed files with 4354 additions and 647 deletions

1
client.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
export * from './dist/client/index'

1
docs/README.md Normal file
View File

@@ -0,0 +1 @@
docs

5
docs/app.config.ts Normal file
View File

@@ -0,0 +1,5 @@
export default defineAppConfig({
docus: {
title: 'tRPC Nuxt',
},
})

View File

@@ -0,0 +1,90 @@
---
title: Installation
description: tRPC-Nuxt provides first class integration with tRPC.
---
# Installation
## 1. Add to existing Nuxt project
::code-group
```bash [pnpm]
pnpm add @trpc/server@next @trpc/client@next trpc-nuxt@next zod
```
```bash [npm]
npm install @trpc/server@next @trpc/client@next trpc-nuxt@next zod
```
```bash [yarn]
yarn add @trpc/server@next @trpc/client@next trpc-nuxt@next zod
```
::
#### Why @trpc/server?
For implementing tRPC endpoints and routers.
#### Why @trpc/client?
For making typesafe API calls from your client.
#### Why zod?
Most examples use [Zod](https://github.com/colinhacks/zod) for input validation and tRPC.io highly recommends it, though it isn't required.
## 2. Enable strict mode
If you want to use Zod for input validation, make sure you have enabled strict mode:
::code-group
```json [tsconfig.json]
{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strict": true
}
}
```
```ts [nuxt.config.ts]
export default defineNuxtConfig({
typescript: {
strict: true
}
})
```
::
If strict mode is too much, at least enable `strictNullChecks`:
::code-group
```json [tsconfig.json]
{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strictNullChecks": true
}
}
```
```ts [nuxt.config.ts]
export default defineNuxtConfig({
typescript: {
tsConfig: {
strictNullChecks: true
}
}
})
```
::
## Next Steps
Now that you've installed the required dependencies, you are ready to start building your application.

View File

@@ -0,0 +1,140 @@
---
title: Usage
description: tRPC-Nuxt provides first class integration with tRPC.
---
# Usage
## Recommended file structure
Recommended but not enforced file structure. This is what you get when starting from [the examples](../main/example-apps.md).
```graphql
.
server
api
trpc
[trpc].ts # <-- tRPC HTTP handler
[..]
trpc
routers
index.ts # <-- main app router
todo.ts # <-- sub routers
[..]
context.ts # <-- create app context
trpc.ts # <-- procedure helpers
plugins
client.ts # <-- tRPC Client as a plugin
[..]
```
## 1. Create a tRPC router
Initialize your tRPC backend using the `initTRPC` function and create your first router.
::code-group
```ts [server/trpc/trpc.ts]
import { TRPCError, initTRPC } from '@trpc/server'
// Avoid exporting the entire t-object since it's not very
// descriptive and can be confusing to newcomers used to t
// meaning translation in i18n libraries.
const t = initTRPC.create()
// Base router and procedure helpers
export const router = t.router
export const publicProcedure = t.procedure
```
```ts [server/trpc/routers/index.ts]
import { z } from 'zod'
import { publicProcedure, router } from '..'
export const appRouter = router({
hello: publicProcedure
.input(
z.object({
text: z.string().nullish(),
}),
)
.query(({ input }) => {
return {
greeting: `hello ${input?.text ?? 'world'}`,
}
}),
})
// export type definition of API
export type AppRouter = typeof appRouter
```
```ts [server/api/trpc/[trpc].ts]
import { createNuxtApiHandler } from 'trpc-nuxt'
import { appRouter } from '../../trpc/routers'
// export API handler
export default createNuxtApiHandler({
router: appRouter,
createContext: () => ({}),
})
```
::
::alert{type=info}
If you need to split your router into several subrouters, you can implement them in the `server/trpc/routers` directory and import and [merge them](https://trpc.io/docs/v10/merging-routers) to a single root `appRouter`.
::
## 2. Create tRPC client plugin
Create a set of strongly-typed composables using your API's type signature.
```ts [plugins/client.ts]
import { httpBatchLink } from '@trpc/client'
import { createTRPCNuxtProxyClient } from 'trpc-nuxt/client'
import type { AppRouter } from '~~/server/trpc/routers'
export default defineNuxtPlugin(() => {
const client = createTRPCNuxtProxyClient<AppRouter>({
links: [
httpBatchLink({
/**
* If you want to use SSR, you need to use the server's full URL
* @link https://trpc.io/docs/ssr
**/
url: 'http://localhost:3000/api/trpc',
}),
],
})
return {
provide: {
client,
},
}
})
```
## 3. Make API requests
```vue [pages/index.vue]
<script setup lang="ts">
const { $client } = useNuxtApp()
// query and mutate uses useAsyncData under the hood
const { data, pending, error } = await $client.hello.query({ text: 'client' })
</script>
<template>
<div v-if="pending">
Loading...
</div>
<div v-else-if="error?.data?.code">
Error: {{ error.data.code }}
</div>
<div v-else>
<p>{{ hello.data?.greeting }}</p>
</div>
</template>
```

View File

@@ -0,0 +1,6 @@
---
title: Basic
description: tRPC-Nuxt provides first class integration with tRPC.
---
# Basic Example

View File

@@ -0,0 +1,6 @@
---
title: Multiple Routers
description: tRPC-Nuxt provides first class integration with tRPC.
---
# Multi Routers

31
docs/content/index.md Normal file
View File

@@ -0,0 +1,31 @@
---
title: "tRPC Nuxt"
description: "A supa simple wrapper arousnd supabase-js to enable usage and integration within Nuxt."
navigation: false
layout: page
---
::block-hero
---
cta:
- Get Started
- /get-started/installation
secondary:
- Star on GitHub ->
- https://github.com/wobsoriano/trpc-nuxt
snippet: npm install trpc-nuxt@next
---
#title
tRPC [Nuxt]{.text-primary-500}
#description
End-to-end typesafe APIs in Nuxt applications.
#extra
::list
- Automatic typesafety
- Snappy DX
- Autocompletion
::
::

16
docs/nuxt.config.ts Normal file
View File

@@ -0,0 +1,16 @@
export default defineNuxtConfig({
app: {
pageTransition: false,
layoutTransition: false,
},
extends: '@nuxt-themes/docus',
build: {
transpile: [/content-edge/],
},
nitro: {
prerender: {
crawlLinks: true,
routes: ['/'],
},
},
})

17
docs/package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "docs",
"description": "Docs for TRPC-Nuxt",
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"generate": "nuxi build",
"preview": "nuxi preview"
},
"devDependencies": {
"@docus/github": "npm:@docus/github-edge@latest",
"@nuxt-themes/docus": "npm:@nuxt-themes/docus-edge@0.1.0-2a7c428",
"@nuxt-themes/website": "0.1.7",
"nuxt": "^3.0.0-rc.12",
"vue-plausible": "^1.3.2"
}
}

25
docs/tokens.config.ts Normal file
View File

@@ -0,0 +1,25 @@
import { defineTheme } from 'pinceau'
export default defineTheme({
title: 'asddsasda 3s',
cover: {
src: 'https://res.cloudinary.com/nuxt/image/upload/v1650870623/nuxt3-rc-social_z6qh3m.png',
alt: 'Nuxt 3 cover image',
},
aside: {
level: 1,
},
// colors: {
// primary: {
// 100: '#77b0db',
// 200: '#589ed3',
// 300: '#4e98d0',
// 400: '#398ccb',
// 500: '#398ccb',
// 600: '#2BAB71',
// 700: '#317eb9',
// 800: '#2e77af',
// 900: '#266290',
// },
// },
})

3
docs/tsconfig.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "./.nuxt/tsconfig.json"
}

View File

@@ -1,15 +1,55 @@
{
"name": "trpc-nuxt-workspace",
"packageManager": "pnpm@7.5.0",
"name": "trpc-nuxt",
"version": "0.4.0-beta.4",
"packageManager": "pnpm@7.14.1",
"license": "MIT",
"sideEffects": false,
"exports": {
"./package.json": "./package.json",
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./client": {
"require": "./dist/client/index.js",
"import": "./dist/client/index.mjs"
}
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist",
"client.d.ts"
],
"scripts": {
"prepublishOnly": "nr build",
"build": "tsup",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
"lint:fix": "eslint . --fix",
"release": "bumpp && npm publish"
},
"peerDependencies": {
"@trpc/client": "^10.0.0-proxy-beta.21",
"@trpc/server": "^10.0.0-proxy-beta.21",
"nuxt": "^3.0.0-rc.12"
},
"dependencies": {
"h3": "^0.8.5",
"ohash": "^0.1.5",
"ufo": "^0.8.6"
},
"devDependencies": {
"@antfu/eslint-config": "^0.27.0",
"@antfu/ni": "^0.18.3",
"@trpc/client": "10.0.0-rc.2",
"@trpc/server": "10.0.0-rc.2",
"bumpp": "^8.2.1",
"eslint": "^8.25.0",
"pnpm": "^7.5.0"
"nuxt": "3.0.0-rc.12",
"pnpm": "^7.14.1",
"tsup": "6.0.1",
"typescript": "^4.7.4"
},
"eslintConfig": {
"extends": "@antfu",

View File

@@ -1 +0,0 @@
export * from './dist/client'

View File

@@ -1,58 +0,0 @@
{
"name": "trpc-nuxt",
"version": "0.4.0-beta.0",
"packageManager": "pnpm@7.5.0",
"license": "MIT",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./client": {
"types": "./dist/client.d.ts",
"require": "./dist/client.js",
"import": "./dist/client.mjs"
}
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist",
"*.d.ts"
],
"scripts": {
"prepublishOnly": "nr build",
"build": "tsup",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"release": "bumpp --commit --push --tag && npm publish"
},
"peerDependencies": {
"@trpc/client": "^10.0.0-proxy-beta.21",
"@trpc/server": "^10.0.0-proxy-beta.21",
"nuxt": "^3.0.0-rc.12"
},
"dependencies": {
"h3": "^0.8.5",
"ohash": "^0.1.5",
"ohmyfetch": "^0.4.20",
"ufo": "^0.8.6"
},
"devDependencies": {
"@trpc/client": "10.0.0-rc.1",
"@trpc/server": "10.0.0-rc.1",
"bumpp": "^8.2.1",
"nuxt": "3.0.0-rc.12",
"tsup": "^6.3.0",
"typescript": "4.5.4"
},
"eslintConfig": {
"extends": "@antfu",
"rules": {
"no-console": "warn"
}
}
}

View File

@@ -9,6 +9,8 @@
"postinstall": "nuxt prepare"
},
"dependencies": {
"@trpc/client": "10.0.0-rc.2",
"@trpc/server": "10.0.0-rc.2",
"superjson": "^1.11.0",
"trpc-nuxt": "workspace:*",
"zod": "^3.19.1"

View File

@@ -11,14 +11,13 @@ const addTodo = async () => {
const title = Math.random().toString(36).slice(2, 7)
try {
const result = await $client.todo.addTodo.mutate({
const x = await $client.todo.addTodo.mutate({
id: Date.now(),
userId: 69,
title,
completed: false,
})
await result.execute()
console.log('Todo: ', result.data.value)
console.log(x.data.value)
}
catch (e) {
console.log(e)

View File

@@ -1,4 +1,4 @@
import { router } from '..'
import { router } from '../trpc'
import { todoRouter } from './todo'
import { userRouter } from './user'

View File

@@ -1,5 +1,5 @@
import { z } from 'zod'
import { publicProcedure, router } from '..'
import { publicProcedure, router } from '../trpc'
const baseURL = 'https://jsonplaceholder.typicode.com'

View File

@@ -1,5 +1,5 @@
import { z } from 'zod'
import { publicProcedure, router } from '..'
import { publicProcedure, router } from '../trpc'
const baseURL = 'https://jsonplaceholder.typicode.com'

4503
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,3 @@
packages:
- packages/*
- playground
- docs

View File

@@ -1,12 +1,13 @@
import type { CreateTRPCClientOptions, inferRouterProxyClient } from '@trpc/client'
import { createTRPCProxyClient } from '@trpc/client'
import { FetchError } from 'ohmyfetch'
import type {
AnyRouter,
} from '@trpc/server'
import { createFlatProxy, createRecursiveProxy } from '@trpc/server/shared'
import { hash } from 'ohash'
import type { DecoratedProcedureRecord } from './types'
// @ts-ignore: nuxt internal
import { useAsyncData, useState } from '#app'
/**
* Calculates the key used for `useAsyncData` call
@@ -28,7 +29,7 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter>(name: strin
const pathCopy = [name, ...opts.path]
// The last arg is for instance `.mutate` or `.query()`
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const lastArg = pathCopy.pop()!
const path = pathCopy.join('.')
@@ -37,13 +38,6 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter>(name: strin
const queryKey = getQueryKey(path, input)
if (lastArg === 'mutate') {
return useAsyncDataWithError(queryKey, () => (client as any)[path][lastArg](input), {
...asyncDataOptions as Record<string, any>,
immediate: false,
})
}
return useAsyncDataWithError(queryKey, () => (client as any)[path][lastArg](input), asyncDataOptions)
})
}
@@ -52,9 +46,7 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter>(name: strin
* Custom useAsyncData to add server error to client
*/
async function useAsyncDataWithError(queryKey: string, cb: any, asyncDataOptions: any) {
// @ts-ignore: nuxt internal
const serverError = useState(`error-${queryKey}`, () => null)
// @ts-ignore: nuxt internal
const { error, data, ...rest } = await useAsyncData(queryKey, cb, asyncDataOptions)
if (error.value && !serverError.value)
@@ -79,17 +71,3 @@ export function createTRPCNuxtProxyClient<TRouter extends AnyRouter>(opts: Creat
return decoratedClient
}
export function customFetch(input: RequestInfo | URL, options?: RequestInit) {
return globalThis.$fetch.raw(input.toString(), options)
.catch((e) => {
if (e instanceof FetchError && e.response)
return e.response
throw e
})
.then(response => ({
...response,
json: () => Promise.resolve(response._data),
}))
}

View File

@@ -10,7 +10,7 @@
"noImplicitAny": true,
"allowJs": true,
"noEmit": true,
"outDir": "dist",
"resolveJsonModule": true
"resolveJsonModule": true,
"skipDefaultLibCheck": true
}
}

View File

@@ -1,7 +1,7 @@
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts', 'src/client.ts'],
entry: ['src/index.ts', 'src/client/index.ts'],
format: ['cjs', 'esm'],
splitting: false,
clean: true,