Creating Your Own JAMStack Blog in No Time with Next.js and Bison

mcavaliere

Mike Cavaliere

Posted on October 20, 2020

Creating Your Own JAMStack Blog in No Time with Next.js and Bison

Next.js is a fantastic framework for building fast and powerful JAMStack web applications — that’s one reason among many that it’s our go-to JavaScript framework at Echobind. We’ve wrapped Next.js with a set of tools we regularly use into a JAMStack generator called Bison, which makes Next.js even more powerful. In this article, I’ll show you the steps to building a custom blog with Bison and Next.js.

If you want to jump right to the code, here’s the repo on GitHub.

Run the Bison Generator

yarn create bison-app bison-blog
Enter fullscreen mode Exit fullscreen mode

This will generate your app skeleton, run yarn installand create a Git repo automatically.

Set up your database

You’ll want to check the latest README for full steps, but it’s as simple as making sure PostgresSQL is running (I highly recommend Postgres.app) and running yarn db:setup .

You’ll be asked a few questions during setup, and it’ll do the rest of the work for you.

Start the app

Run yarn dev from the directory you just created, and visit http://localhost:3000. Your app is running, and you should see a screen like the one below. We’re in business.

Create a user account

Bison comes pre-packaged with a simple user authentication mechanism, so signing in or signing up is a cinch.

First, tap Login to get to the login screen, then click Sign Up.

Fill out the form and submit, and you’ll be logged in and redirected to the home page.

Add some database tables

We’ll need a Posts table and model to create and list posts. Edit schema.prisma which is the source of truth for the data model. Adding a Post model is pretty easy.

Then run yarn prisma migrate save --experimental, to generate a database migration for it.

Now run the migration using yarn db:migrate .

If you look at your database using Postico or psql, you’ll see the resulting table and columns.

Generate a page for creating posts

Use Bison’s page generator to stub the /posts/new page:

yarn g:page posts/new

Generate components

We’ll need 2 React components for creating and showing posts PostList and PostForm, so we’ll generate them with Bison’s CLI commands. These wrap 👍some pre-packaged Hygen generators that Bison comes with.

yarn g:component PostList
yarn g:component PostForm
Enter fullscreen mode Exit fullscreen mode

Now you’ll see these 4 new files in your folder tree:

All rightie! Let’s add some code.

Create the “New Post” form

The page container for /posts/new.tsx is quite simple; aside from styling, we add the component which we’ll build immediately after.

    import React from 'react';
    import Head from 'next/head';
    import { Heading, Flex } from '@chakra-ui/core';

    import { PostForm } from '../../components/PostForm';

    function PostsNewPage() {
      return (
        <>
          <Head>
            <title>PostsNewPage</title>
          </Head>

          <Flex direction="column" justify="center">
            <Heading size="lg">New Post</Heading>

            <PostForm />
          </Flex>
        </>
      );
    }

    export default PostsNewPage;
Enter fullscreen mode Exit fullscreen mode

Create the component

Full code is here. Here are some highlights.

Bison comes packaged withreact-hook-form, so we build the form out like this:

    <form onSubmit={handleSubmit(onSubmit)}>
          <FormControl isInvalid={errors.title}>
            <FormLabel htmlFor="title">Post Title</FormLabel>
            <Input type="text" name="title" id="title" ref={register({ required: true })} />
            <FormErrorMessage>{errors.title && <span>This field is required</span>}</FormErrorMessage>
          </FormControl>

          <FormControl isInvalid={errors.body}>
            <FormLabel htmlFor="body">Post Body</FormLabel>
            <Textarea name="body" id="body" ref={register({ required: true })} />
            <FormErrorMessage>{errors.body && <span>This field is required</span>}</FormErrorMessage>
          </FormControl>

          <Button type="submit">Submit</Button>
        </form>
Enter fullscreen mode Exit fullscreen mode

Because Bison also sets up nexus-plugin-prismafor us, We add a mutation to create a post like so:

    export const CREATE_POST_MUTATION = gql`
      mutation CreatePost($data: PostCreateInput!) {
        createOnePost(data: $data) {
          id
          title
          body
        }
      }
    `;
Enter fullscreen mode Exit fullscreen mode

In turn, Bison’s graphql-codegen configuration sees the above and generates a nice React hook for us to plug into 🎉:

    import { useCreatePostMutation } from '../types';
Enter fullscreen mode Exit fullscreen mode

We use this and a few other hooks to get our data into the form component:

    export function PostForm() {
      const { register, handleSubmit, errors } = useForm();
      const [createPost] = useCreatePostMutation();
      const router = useRouter();

      const { user: { id: userId } = {} } = useAuth();
      // ...
    }
Enter fullscreen mode Exit fullscreen mode

And here’s the onSubmit handler which triggers the createPost mutation and redirects back to the homepage upon success:

    const onSubmit = async (data) => {
        // Create the post
        await createPost({
          variables: {
            data: {
              ...data,
              author: {
                connect: {
                  id: userId,
                },
              },
            },
          },
        });

        // Redirect to homepage
        await router.replace('/');
      };
Enter fullscreen mode Exit fullscreen mode

Now we’ve got a form that saves a post to the database. Voila. 🚀

Create the component

Now that we’ve got data, let’s display it.

If you remember, we already ran the generator for the component. So we start by importing the into the homepage and displaying it like so:

Now we’ll need to fetch and display the posts. When fetching data with Bison, we recommend something called a “cell.” A cell is a concept borrowed from Redwood.js. It’s a declarative way of wrapping the GraphQL query together with loading, success, and error states.

yarn g:cell FetchPosts will create /cells/FetchPosts.tsx as below.

Now we’ll fill the cell out with the correct query and some formatting for the rendered posts.

Full code here. Important snips:

    export const POSTS_QUERY = gql`
      query posts {
        posts {
          id
          title
          body
        }
      }
    `;

    export const Success = ({ posts }: PostsQuery) => {
      return (
        <Stack>
          {posts.map((p) => (
            <Box p={5} shadow="md" key={p.id}>
              <Heading>{p.title}</Heading>
              {p.body}
            </Box>
          ))}
        </Stack>
      );
    };
Enter fullscreen mode Exit fullscreen mode

Don’t forget to include the cell in the component:

    export function PostList() {  return <FetchPostsCell />;}
Enter fullscreen mode Exit fullscreen mode

And we’re done. You now have a (very simple and basic but functioning) blog built in Next.js. Add some data and start having fun.

Conclusion

Bison is in its early stages, but is already a useful tool for kickstarting your Next.js project quickly with great stuff like Prisma, Nexus, and Hygen built-in.

If you try out this tutorial, please drop me a line with any feedback or questions. Or comment right here.

Contributor’s Bio

Mike Cavaliere is a web development veteran, personal development devotee, and ADHD/brain improvement aficionado who works as a Senior Software Engineer at Echobind.

He also blogs about software at MikeCavaliere.com and brain improvement at ADHDTechies.com.

--

This post originally appeared on the Echobind blog.

💖 💪 🙅 🚩
mcavaliere
Mike Cavaliere

Posted on October 20, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related