A monorepo built for rapid full stack web development using KeystoneJS and tRPC. This repository contains a CMS, UI component library and end-to-end tests. The packages are organized by their functionalities and can be developed and tested independently.
cms
: KeystoneJS CMSapp
: Screens with data fetching with UI componentsui
: UI library with twin.macro and stitchese2e
: End-to-end tests using Playwright
The monorepo also includes client applications
astro-app
: Astro web applicationnext-app
: Next.js web application
Install all packages and dependencies using:
git clone https://github.com/lachlanhawthorne/keystone-t3.git
pnpm
You can run all apps and packages simultaneously from the root directory or individually using:
pnpm dev
pnpm cms:dev
pnpm ui:dev
pnpm astro-app:dev
pnpm next-app:dev
pnpm remix-app:dev
pnpm qwick-app:dev
pnpm vite-app:dev
You can quickly generate new components with Storybook stories and tests using:
pnpm ui:new
For more information on generating styled components, follow the guidelines outlined in the twin.macro documentation.
The ui
package is configured to use Storybook for component development. You can run Storybook using:
pnpm storybook:dev
The e2e
package contains an adapter create a tRPC server and client using KeystoneJS. This allows you to use KeystoneJS as a data source for your tRPC API.
To link a new KeystoneJS project to the tRPC server, add the following to your KeystoneJS schema.ts
file:
import { KeystoneContext } from '@keystone-next/types';
import { createKeystoneAdapter } from '@keystone-next-trpc-twin.macro/e2e';
export const keystone = new Keystone({
adapter: createKeystoneAdapter({
context: KeystoneContext,
schemaName: 'public',
}),
});
To link a new Next.js project to the tRPC client, add the following to your Next.js pages/api/trpc/[trpc].ts
file:
import { createNextApiHandler } from '@keystone-next-trpc-twin.macro/e2e';
export default createNextApiHandler();
To create a new tRPC route, add a new file to the e2e/routes
directory. The file should export a function that returns a tRPC route. For example:
import { createRouter } from '@trpc/server';
import { createContext } from '@keystone-next-trpc-twin.macro/e2e';
export const createRoutes = () =>
createRouter()
.query('hello', {
resolve() {
return 'Hello World!';
},
})
.mutation('createUser', {
input: z.object({
name: z.string(),
}),
resolve({ input }) {
return createContext().db.user.create({
data: {
name: input.name,
},
});
},
});
To use a tRPC route, import the useQuery
or useMutation
hook from @trpc/react
and pass the route name as the first argument. For example:
import { useQuery, useMutation } from '@trpc/react';
const { data } = useQuery('hello');
const [createUser] = useMutation('createUser');
To add access control to a tRPC route, add a middleware
function to the route. For example:
import { createRouter } from '@trpc/server';
import { createContext } from '@keystone-next-trpc-twin.macro/e2e';
export const createRoutes = () =>
createRouter()
.query('hello', {
resolve() {
return 'Hello World!';
},
})
.mutation('updateUser', {
input: z.object({
id: z.string(),
name: z.string(),
}),
resolve({ input }) {
return createContext().db.user.update({
where: {
id: input.id,
},
data: {
name: input.name,
},
});
},
}
.middleware(async ({ ctx, next }) => {
if (!ctx.session?.data?.userId) {
throw new Error('Not authenticated');
}
return next();
});
You tests for all apps and packages simultaneously or individually using:
pnpm test
pnpm cms:test
pnpm web:test
pnpm ui:test
pnpm e2e:test
To build a production version of the cms
or web
application, navigate to the respective directory and run pnpm build
. This will build the application and output the files to the build
directory. You can build all apps and packages using:
pnpm build
Refer to the KeystoneJS documentation and the NextJS documentation for further deployment instructions.
This repository is configured to use GitHub CI for continuous integration. Any changes pushed to the master
branch will trigger a build and test run.
Any changes to the UI package will trigger