npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@shynome/trpc-sveltekit

v2.1.1

Published

SvelteKit adapter for trpc.io

Downloads

2

Readme

❤️🇺🇦

See below.

Key features

✅ Works with @sveltejs/adapter-node, @sveltejs/adapter-vercel & @sveltejs/adapter-netlify
✅ Works with SvelteKit's load() function for SSR

Example application with Prisma & superjson

👉 tRPC-Sveltekit-Example

TL;DR

Add this in your SvelteKit app hooks:

// src/hooks.ts
import { createTRPCHandle } from 'trpc-sveltekit';
// create your tRPC router...

export const handle = async ({ event, resolve }) => {
  const response = await createTRPCHandle({ // 👈 add this handle
    url: '/trpc',
    router,
    event,
    resolve
  });

  return response;
};

How to use

  1. Install this package

npm install trpc-sveltekit/yarn add trpc-sveltekit

  1. Create your tRPC routes, context and type exports:
// $lib/trpcServer.ts
import type { inferAsyncReturnType } from '@trpc/server';
import * as trpc from '@trpc/server';

// optional
export const createContext = () => {
  // ...
  return {
    /** context data */
  };
};

// optional
export const responseMeta = () => {
  // ...
  return {
    // { headers: ... }
  };
};

export const router = trpc
  .router<inferAsyncReturnType<typeof createContext>>()
  // queries and mutations...
  .query('hello', {
    resolve: () => 'world',
  });

export type Router = typeof router;
  1. Add this handle to your application hooks (src/hooks.ts or src/hooks/index.ts):
// src/hooks.ts or src/hooks/index.ts
import { createContext, responseMeta, router } from '$lib/trpcServer';
import { createTRPCHandle } from 'trpc-sveltekit';

export const handle = async ({ event, resolve }) => {
  const response = await createTRPCHandle({
    url: '/trpc', // optional; defaults to '/trpc'
    router,
    createContext, // optional
    responseMeta, // optional
    event,
    resolve
  });

  return response;
};

Learn more about SvelteKit hooks here.

  1. Create a tRPC client:
// $lib/trpcClient.ts
import type { Router } from '$lib/trpcServer'; // 👈 only the types are imported from the server
import * as trpc from '@trpc/client';

export default trpc.createTRPCClient<Router>({ url: '/trpc' });
  1. Use the client like so:
// page.svelte
import trpcClient from '$lib/trpcClient';

const greeting = await trpcClient.query('hello');
console.log(greeting); // => 👈 world

Recipes & caveats 🛠

Usage with Prisma

When you're building your SvelteKit app for production, you must instantiate your Prisma client like this: ✔️

// $lib/prismaClient.ts
import pkg from '@prisma/client';
const { PrismaClient } = pkg;

const prismaClient = new PrismaClient();
export default prismaClient;

This will not work: ❌

// $lib/prismaClient.ts
import { PrismaClient } from '@prisma/client';

const prismaClient = new PrismaClient();
export default prismaClient;

Configure with superjson & Decimal.js / Prisma.Decimal

❓ If you don't know why you'd want to use superjson, learn more about tRPC data transformers here.

Install trpc-transformer:

Then, configure your tRPC router like so:

// $lib/trpcServer.ts
import trpcTransformer from 'trpc-transformer';
import * as trpc from '@trpc/server';

export const router = trpc
  .router()
  // .merge, .query, .mutation, etc.
  .transformer(trpcTransformer); // 👈

export type Router = typeof router;

...and don't forget to configure your tRPC client:

// $lib/trpcClient.ts
import type { Router } from '$lib/trpcServer';
import transformer from 'trpc-transformer';
import * as trpc from '@trpc/client';

export default trpc.createTRPCClient<Router>({
  url: '/trpc',
  transformer, // 👈
});

Client-side helper types

It is often useful to wrap the functionality of your @trpc/client api within other functions. For this purpose, it's necessary to be able to infer input types, output types, and api paths generated by your @trpc/server router. Using tRPC's inference helpers, you could do something like:

// $lib/trpcClient.ts
import type { Router } from '$lib/trpcServer';
import trpcTransformer from '$lib/trpcTransformer';
import * as trpc from '@trpc/client';
import type { inferProcedureInput, inferProcedureOutput } from '@trpc/server';

export default trpc.createTRPCClient<Router>({
  url: '/trpc',
  transformer: trpcTransformer,
});

type Query = keyof Router['_def']['queries'];
type Mutation = keyof Router['_def']['mutations'];

// Useful types 👇👇👇
export type InferQueryOutput<RouteKey extends Query> = inferProcedureOutput<Router['_def']['queries'][RouteKey]>;
export type InferQueryInput<RouteKey extends Query> = inferProcedureInput<Router['_def']['queries'][RouteKey]>;
export type InferMutationOutput<RouteKey extends Mutation> = inferProcedureOutput<
  Router['_def']['mutations'][RouteKey]
>;
export type InferMutationInput<RouteKey extends Mutation> = inferProcedureInput<Router['_def']['mutations'][RouteKey]>;

Then, you could use the inferred types like so:

// authors.svelte
<script lang="ts">
  let authors: InferQueryOutput<'authors:browse'> = [];

  const loadAuthors = async () => {
    authors = await trpc.query('authors:browse', { genre: 'fantasy' });
  };
</script>

Server-Side Rendering

If you need to use the tRPC client in SvelteKit's load() function for SSR, make sure to initialize it like so:

// $lib/trpcClient.ts
import { browser } from '$app/env';
import type { Router } from '$lib/trpcServer';
import * as trpc from '@trpc/client';

const url = browser ? '/trpc' : 'http://localhost:3000/trpc';
export default (loadFetch?: typeof fetch) =>
  trpc.createTRPCClient<Router>({
    url: loadFetch ? '/trpc' : url,
    transformer: trpcTransformer,
    ...(loadFetch && { fetch: loadFetch })
  });

Then use it like so:

// index.svelte
import trpcClient from '$lib/trpcClient';
import type { Load } from '@sveltejs/kit';

export const load: Load = async ({ fetch }) => { // 👈 make sure to pass in this fetch, not the global fetch
	const authors = await trpcClient(fetch).query('authors:browse', {
		genre: 'fantasy',
	});
	return { props: { authors } };
};

Vercel's Edge Cache for Serverless Functions

Your server responses must satisfy some criteria in order for them to be cached Verced Edge Network, and here's where tRPC's responseMeta() comes in handy. You could initialize your handle in src/hooks.ts like so:

// src/hooks.ts or src/hooks/index.ts
import { router } from '$lib/trpcServer';
import { createTRPCHandle } from 'trpc-sveltekit';

export const handle = async ({ event, resolve }) => {
  const response = await createTRPCHandle({
    url: '/trpc',
    event,
    resolve,
    responseMeta({ type, errors }) {
      if (type === 'query' && errors.length === 0) {
        const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
        return {
          headers: {
            'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`
          }
        };
      }
      return {};
    }
  });

  return response;
};

Example

See an example with Prisma & superjson: ✨

Stand with Ukraine

On 24th of February 2022 Russia unlawfully invaded Ukraine. This is an unjustified, unprovoked attack on the sovereignty of a neighboring country, but also an open affront to international peace and stability that has the potential to degenerate into a nuclear event threatening the very existence of humanity. I am an EU (Romanian) citizen, but I am doing everything in my power to stop this madness. I stand with Ukraine. The entire Svelte community ❤️🇺🇦. Here's how you can show your support.

License

The ISC License.