Insta-Next: Introduction & Designs

Insta-Next: Introduction & Designs

Let's build a fullstack Instagram clone using Next.js, Prisma and Mantine

Ā·

7 min read

Play this article

Welcome to Building Instagram Clone with Next.js series!

In this first part, I'll briefly introduce what we'll be building, the tools, and set up of the project.

Disclaimer: This is not a React tutorial, but more focusing on the overall Next.js workflow and a brief touch on other tools used.

Sneak Peek:

Prerequisites

It is expected for you to at least know a little about React, and Tailwind. I also used TypeScript extensively, but should be comprehensible for most.

Introduction to Next.js

You probably know what Next.js is if you're clicking this article. Anyways, here's the description from Vercel, creator of Next.js

Used by some of the world's largest companies, Next.js enables you to create full-stack web applications by extending the latest React features, and integrating powerful Rust-based JavaScript tooling for the fastest builds.

ā€” Vercel Team

The keywords are full-stack web applications, so yeah, it's the dream of all frontend developers, doing backend in frontend, making frontend programmers worthier.

Jokes aside, Next.js is capable of both frontend and backend development, so you can learn a single framework to do fullstack development in a single code base. Also, we can build Single Page Applications (SPA) easily using Next.js.

Disclaimer: You still need to know things like database and design patterns to be a good backend developer.

What are We Building

I'll only be implementing some of the features for this clone, but the list may expand as I go on:

  1. Viewing Story

  2. Post Content

  3. Follower Logic

  4. Viewing Profile

That's it, more than enough for us to get started

Disclaimer: I'm not building a mobile-responsive website

Design

Since it's a fullstack application, let's go over the entire development cycle starting from the design phase including both front and back-end. Jump ahead to the next part if you wish to skip the design phase, but this part will provide a good overview of the app that we're building.

Frontend

Most of the designs will be taken directly from the Instagram website (it's a clone anyways), but I'll doodle some low-fidelity prototypes to better identify the required endpoints and objects to design the backend later.

While the designs don't certainly cover every endpoint required, but they are a good starting point.

Note that these designs also don't cover all components, there are still many missing parts, but our goal right now will be trying to get these basics out first.

Database

From the frontend design, we can at least identify a few entities like User, Post, Story, UserFollower, and PostLike. To visualize these entities, we'll draw a class diagram of them:

It's not the nicest diagram in the world, but it should suffice.

Note that I have a special Image class outside, it's a polymorphic class that'll be attached to Post / Story / User, depending on the type field. Otherwise, it's pretty much done, we can just move on.

And that's basically it, a fresh-baked class diagram ready to be used. In practice, a class diagram is quite helpful when you want to communicate the database design with others (or otherwise others will have to guess the design from database structure / schema file, which might not necessary be bad)

Getting Started

Note: I'll be using yarn due to personal preference, but feel free to use pnpm or npm.

I'll just set up the frontend here for starter, the backend will be set up in their respective articles.

Next.js template

Normally, for large frameworks like Next.js, they usually provide a starter template that bootstraps the project with the necessary tools / configs to get started.

Launch your terminal, cd into the folder, and let's start with the create-next-app

yarn create next-app

Here are the options I used

  1. Project Name: insta-next

  2. TypeScript: I'd recommend you try out TypeScript if you haven't, but feel free to go with vanilla JavaScript

  3. ESLint: Helps to identify your bad code patterns, use it if you wish to take out your bad habits

  4. src/ directory: It's a personal preference, and I came from a background of using src, so yes for me

  5. app/ directory: You can read more here, but since we're building a simple application, I'll skip it, plus it's still experimental anyways

  6. import alias: basically @/ means the root of the repository, without it, the import will be filled with "../../.." which is kinda ugly, so I added it in

Frontend

I'll just set up the UI part here, the specific libraries for state management and usequery hooks will be later in their specific parts.

Component

I have decided to use Mantine because I like its form usage, plus it has a carousel, which is exactly what we're going to use. The best part is that it has tonnes of components, a perfect library. Let's set it up following the docs

yarn add @mantine/core @mantine/hooks @mantine/form @mantine/modals @mantine/nprogress @emotion/react @emotion/server @mantine/carousel @mantine/next

I've also added @mantine/hooks for utility hooks, @mantine/modals for modal management and @mantine/nprogress for the progress bar effect while transitioning.

I'll set up the _app.tsx and _document.tsx following the documentation

// _app.tsx
import { AppProps } from 'next/app';
import Head from 'next/head';
import { MantineProvider } from '@mantine/core';

export default function App(props: AppProps) {
  const { Component, pageProps } = props;

  return (
    <>
      <Head>
        <title>Page title</title>
        <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
      </Head>

      <MantineProvider
        withGlobalStyles
        withNormalizeCSS
        theme={{
          /** Put your mantine theme override here */
          colorScheme: 'light',
        }}
      >
        <Component {...pageProps} />
      </MantineProvider>
    </>
  );
}
// _document.tsx
import { createGetInitialProps } from '@mantine/next';
import Document, { Head, Html, Main, NextScript } from 'next/document';

const getInitialProps = createGetInitialProps();

export default class _Document extends Document {
  static getInitialProps = getInitialProps;

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

Tailwind

Yes, I know it's a bit weird to use Tailwind along with a component library, but the issue with current Mantine is its lack of granularity, like there's only xs, sm, md, lg and xl for sizes, which are insufficient for most cases. Also, Mantine allows us to use classNames to style the components, including the inner parts.

Let's install tailwind

yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

and also update the content in your tailwind.config.js, as all of the codes will lie in the src directory, this pattern will match every React component in it to allow Tailwind to compile CSS files from it

// tailwind.config.js
content: ["./src/**/*.{js,ts,jsx,tsx}"],

and not to forget, remember to update the globals.css for tailwind directives, remove everything, and add these two lines in, which will reset all component styles and allow us to start using Tailwind classes

I know I have missed component, but I'm probably not going to use it in this project, so I'm leaving it aside.

@tailwind base;
@tailwind utilities;

Directory Structure

Now that we're done with the libraries, it's time to organize the folders. We'll be creating the folders under /src directory.

src
|- components  # for storing frontend components
|- features    # for backend features
|- pages       # page routes
|- stores      # for state management later
|- styles      # Global styles
|- utils       # Utility functions if there's any

Page Routes

Next.js uses directory based routing. The location of the page component in the pages folder will indicate its route. For example, /src/pages/index.tsx will be mapped to the route / and /src/pages/auth/register.tsx to /auth/register.

This will make it very convenient to manage the routes compared to the traditional router page.

For dynamic routes, we can wrap the parameter name with [square_brackets]. It can be used in both folder or component. For example, routes like /users/shen_yien or /users/john_doe will be resolved to /src/pages/users/[username].tsx or /src/pages/users/[username]/index.tsx.

Development

When you run yarn dev and visit your localhost:3000 you should see this

Nothing's wrong there, we've removed everything from global, so naturally the styles are gone. Just hang tight there while we develop

Summary

In this article, we have created a simple low-fidelity design, set up the necessities for our frontend development, and started up our development server. In the upcoming articles, we will start with the backend development.

Complete codes for this part: GitHub

Ā