Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ src/graphql/schemaImportMap.tsx
src/prisma/pothos-types.ts
src/prisma/prisma-client/
tsconfig.tsbuildinfo
dist/
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,20 @@ You need to build your own authentication flow in your client using [Better Auth

The sample data in this repository is insecure demo data. Before deploying a server built using this template, make sure to at least change the passwords for the seed users and the authentication secret in the `.env` file.

## Deployment to serverless

This template can also be deployed to serverless hosting platforms like Vercel. To increase portability, we strip all TypeScript types and bundle the app via [tsdown](https://tsdown.dev/) into a single file at `dist/index.js`.

To deploy on Vercel with the default configurations, specify the following options for the project:

- **Framework Preset**: Hono
- **Build Command**: `npm run build`
- **Output Directory**: `dist`

Be sure to add the necessary environment variables.

After which, the GraphQL endpoint can be accessed at `https://yourdomain.vercel.app/graphql`.

## Building a client

This template is designed to be used with [Relay](https://relay.dev/) as the client. Relay is a mature choice for a GraphQL client for TypeScript apps. The CORS policy expects the client to run at `http://localhost:5173` during development. If you are using a different port, change the `DEVELOPMENT_DOMAIN` in `.env`.
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
"author": "Christoph Nakazawa <christoph.pojer@gmail.com>",
"type": "module",
"scripts": {
"build": "tsdown",
"dev": "NODE_ENV=development node_modules/.bin/nodemon -q -I --exec node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm --env-file .env src/index.tsx",
"dev:setup": "pnpm prisma generate && pnpm generate-graphql",
"format": "prettier --experimental-cli --write .",
"generate-graphql": "node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./scripts/generate-graphql.tsx",
"preinstall": "command -v git >/dev/null 2>&1 && git config core.hooksPath git-hooks || exit 0",
"postinstall": "pnpm dev:setup",
"lint": "eslint --cache .",
"lint:format": "prettier --experimental-cli --cache --check .",
"test": "npm-run-all --parallel tsc:check vitest:run lint lint:format",
Expand All @@ -36,7 +38,8 @@
"@pothos/plugin-prisma": "^4.12.0",
"@pothos/plugin-relay": "^4.6.2",
"@pothos/plugin-scope-auth": "^4.1.6",
"@prisma/client": "^6.17.1",
"@prisma/adapter-pg": "^6.18.0",
"@prisma/client": "^6.18.0",
"array-shuffle": "^4.0.0",
"better-auth": "^1.3.28",
"graphql": "^16.11.0",
Expand All @@ -56,14 +59,15 @@
"npm-run-all2": "^8.0.4",
"prettier": "^3.6.2",
"prettier-plugin-packagejson": "^2.5.19",
"prisma": "^6.17.1",
"prisma": "^6.18.0",
"prisma-json-types-generator": "^3.6.2",
"ts-node": "^10.9.2",
"tsdown": "^0.15.9",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
},
"engines": {
"node": ">=24.0.0",
"node": ">=22.0.0",
"pnpm": ">=10.0.0"
}
}
562 changes: 515 additions & 47 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/graphql/builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DirectivesPlugin from '@pothos/plugin-directives';
import PrismaPlugin from '@pothos/plugin-prisma';
import RelayPlugin from '@pothos/plugin-relay';
import ScopeAuthPlugin from '@pothos/plugin-scope-auth';
import PrismaTypes from '../prisma/pothos-types.ts';
import PrismaTypes, { getDatamodel } from '../prisma/pothos-types.ts';
import prisma from '../prisma/prisma.tsx';
import isAdmin from '../user/isAdmin.tsx';
import { Context } from './context.tsx';
Expand Down Expand Up @@ -44,6 +44,7 @@ const builder = new SchemaBuilder<PothosTypes>({
],
prisma: {
client: prisma,
dmmf: getDatamodel(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is safe to add regardless of deployment runtime. cc @hayes correct me if I'm wrong

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to https://pothos-graphql.dev/docs/plugins/prisma/setup#set-up-the-builder:

This give pothos information about your tables, relations, and indexes to help it generate optimal queries at runtime. This used to be attached to the prisma client, but has been removed in most runtimes/modes to reduce bundle size.

exposeDescriptions: false,
filterConnectionTotalCount: true,
maxConnectionSize: 120,
Expand Down
61 changes: 32 additions & 29 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,7 @@ try {
process.exit(1);
}

const name = 'Pothos GraphQL Server';

const {
values: { port: portArg },
} = parseArgs({
options: {
port: {
default: '9000',
short: 'p',
type: 'string',
},
},
});

const origin = env('CLIENT_DOMAIN');
const port = (portArg && parseInteger(portArg)) || 9000;
const app = new Hono();

app.use(
Expand Down Expand Up @@ -69,18 +54,36 @@ app.on(['POST', 'GET', 'OPTIONS'], '/graphql/*', async (context) => {

app.all('/*', (context) => context.redirect(origin));

serve({ fetch: app.fetch, port }, () =>
console.log(
`${styleText(['green', 'bold'], `${name}\n ➜`)} Server running on port ${styleText('bold', String(port))}.\n`,
),
);
if (process.env.npm_lifecycle_event === 'dev') {
const name = 'Pothos GraphQL Server';
const {
values: { port: portArg },
} = parseArgs({
options: {
port: {
default: '9000',
short: 'p',
type: 'string',
},
},
});

const port = (portArg && parseInteger(portArg)) || 9000;
serve({ fetch: app.fetch, port }, () =>
console.log(
`${styleText(['green', 'bold'], `${name}\n ➜`)} Server running on port ${styleText('bold', String(port))}.\n`,
),
);

const setTitle = (title: string) => {
process.title = title;
if (process.stdout.isTTY) {
process.stdout.write(
`${String.fromCharCode(27)}]0;🚀 ${title}${String.fromCharCode(7)}`,
);
}
};
setTimeout(() => setTitle(name), 0);
}

const setTitle = (title: string) => {
process.title = title;
if (process.stdout.isTTY) {
process.stdout.write(
`${String.fromCharCode(27)}]0;🚀 ${title}${String.fromCharCode(7)}`,
);
}
};
setTimeout(() => setTitle(name), 0);
export default app;
5 changes: 4 additions & 1 deletion src/prisma/prisma.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from './prisma-client/client.ts';

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


declare global {
namespace PrismaJson {
type PokemonStats = Readonly<{
Expand All @@ -14,4 +17,4 @@ declare global {
}
}

export default new PrismaClient();
export default new PrismaClient({ adapter });
1 change: 1 addition & 0 deletions src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ generator client {
importFileExtension = "ts"
output = "./prisma-client"
provider = "prisma-client"
engineType = "client"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

generator pothos {
Expand Down
5 changes: 5 additions & 0 deletions tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
entry: ['./src/index.tsx'],
});