Bison is a starter repository created out of real-world apps at Echobind. It represents our current "Greenfield Web Stack" that we use when creating web apps for clients.
We're always improving on this, and welcome suggestions from the community!
- Next.js
- TypeScript
- GraphQL API built with Nexus
- Prisma w/ Postgres
- GraphQL Codegen to generate TypeScript types (Schema types and query/mutation hooks)
- Chakra UI
- React Hook Form
- Cypress for E2E tests
- React Testing Library and Jest for unit and API request tests
- Preconfigured for CI using GitHub Actions
- Customizable Hygen Templates to generate new files
- Fully wired up login/signup pages with client and server-side validation.
- Eslint pre-configured with Echobind best practices
- Pre-configured for deployment on Vercel with customizable branch workflow.
- Don't copy/paste files, use generators and Hygen templates. Need to update the generator as your project evolves? they are all in the
_templates
folder. - Use a single command to run Next, generate Nexus types, and GraphQL types for the frontend. By doing this you can ensure your types are always up-to-date.
- Don't manually write types for GraphQL responses... use the generated query hooks from GraphQL Codegen.
- All frontend pages are static by default. If you need something server rendered, just add
getServerSideProps
like you would in any Next app.
- To reduce complexity, Bison avoids yarn workspaces and separate top-level folders. Think of your app a bit more like a traditional monolith, but with a separate frontend and API. This means that folders may be a little more "intermingled" than your used to.
- Currently, Bison only works on Vercel. We plan to add support for Netlify soon.
There are a few other projects that are rapidly maturing in the Full Stack JAMStack space.
RedwoodJS Redwood is a very promising framework we've got our eye on. We took the concept of "Cells" directly from Redwood (though admittedly our version takes a bit more code!).
Blitz.js Blitz is also very promising. Blitz is built on Next.js (which we love!) and takes a very different approach by attempting to "remove" the API layer using conventions provided by Next.js.
We may borrow concepts from Redwood and Blitz over time, and could even switch to one in the future as things continue to mature.
Think of Bison as a bit closer to the metal, but preconfigured for maximum DX and efficiency. The good news is, if you disagree with any of the choices we've made, nothing is hidden from you and you're welcome to adapt the "framework" to fit your needs.
Create a new repo fom the Bison template.
Using yarn:
yarn create bison-app MyApp
Using npx:
npx create-bison-app MyApp
- Setup your local database with
yarn db:setup
. You'll be prompted to create it if it doesn't already exist:
If you'd like to change the database name or schema, change the DATABASE_URL in prisma/.env
.
From the root, run yarn dev
. This:
- runs
next dev
to run the frontend and serverless functions locally - starts a watcher to generate the Prisma client on schema changes
- starts a watcher to generate TypeScript types for GraphQL files
You're not required to follow this exact workflow, but we've found it gives a good developer experience.
- Generate a new GraphQL module using
yarn g:graphql
. - Write a type, query, input, or mutation using Nexus
- Create a new request test using
yarn g:test:request
- Run
yarn test
to start the test watcher - Add tests cases and update schema code accordingly
- The GraphQL playground (localhost:3000/api/graphql) can be helpful to form the proper queries to use in tests.
types.ts
andapi.graphql
should update automatically as you change files. Sometimes it's helpful to open these as a sanity check before moving on to the frontend code.
- Generate a new page using
yarn g:page
- Generate a new component using
yarn g:component
- If you need to fetch data in your component, use a cell. Generate one using
yarn g:cell
(TODO) - To generate a typed GraphQL query, simply add it to the component or page:
export const SIGNUP_MUTATION = gql`
mutation signup($data: SignupInput!) {
signup(data: $data) {
token
user {
id
}
}
}
`;
- Use the newly generated types from codegen instead of the typical
useQuery
oruseMutation
hook. For the example above, that would beuseSignupMutation
. You'll now have a fully typed response to work with!
import { User, useMeQuery } from './types';
// adding this will auto-generate a custom hook in ./types
export const ME_QUERY = gql`
query me {
me {
id
email
}
}
`;
// an example of taking a user as an argument with optional attributes
function noIdea(user: Partial<User>) {
console.log(user.email);
}
function fakeComponent() {
// use the generated hook
const { data, loading, error } = useMeQuery();
if (loading) return <Loading />;
// data.user will be fully typed
return <Success user={data.user}>
}
This project uses GitHub Actions for CI and should work out of the box. Note, as you add ENV vars to your app, you'll want to also add them in GitHub Secrets.
Easiest CI configuration ever, right?
To ensure your project can be deployed using GitHub Actions, you need to add a few ENV vars to GitHub Secrets:
The Vercel project and org id, can be copied from .vercel/project.json
. You can generate a token from https://vercel.com/account/tokens.
After tests pass, the app will deploy to Vercel. By default, every push creates a preview deployment. Merging to the main branch will deploy to staging, and pushing to the production branch will deploy to production.
If you'd like to change these configurations, update the section below:
## For a typical JAMstack flow, this should be your default branch.
## For a traditional flow that auto-deploys staging and deploys prod is as needed, keep as is
if: github.ref != 'refs/heads/production' # every branch EXCEPT production
TypeScript Types for GraphQL types, queries, and mutations are generated automatically and placed in ./types.ts
.
Try reopening VSCode.