The Foundational Setup (Part 1) : Building an E-Commerce Web App from Scratch with NextJS, TailwindCSS, DaisyUI, Prisma, and MongoDB

Welcome to the ultimate guide on building your very own feature-rich E-Commerce Web App! In this comprehensive blog series, we will take you through the step-by-step process of creating a powerful and dynamic online store from scratch using cutting-edge technologies.

In this first part of the series, we will dive deep into the initial setup of the project, laying the groundwork for an exceptional E-Commerce platform. By the end of this post, you'll have a solid foundation to setup your first NextJS application, MongoDB database, configurations for TailwindCSS and setting up Prisma Client for Database Models.


Building an E-Commerce Web App can seem like a daunting task, but fret not! Our guide is crafted with simplicity and clarity in mind. Whether you're a seasoned developer or a coding enthusiast, we've got you covered. We'll walk you through each configuration and provide detailed explanations to ensure a smooth and hassle-free setup process.

Before we embark on this exciting journey, let's take a moment to explore the technologies we'll be using:

  1. NextJS: A powerful React framework that enables server-side rendering, making our app lightning-fast and SEO-friendly.
  2. Tailwind CSS: A utility-first CSS framework that empowers us to design and style with ease and flexibility.
  3. DaisyUI: A delightful plugin for Tailwind CSS, providing a plethora of ready-to-use components and themes for a visually appealing interface.
  4. Prisma: A modern database toolkit that streamlines database operations and data modeling.
  5. MongoDB: A NoSQL database that offers scalability and flexibility, perfect for handling the diverse needs of an E-Commerce platform.

Now, let's roll up our sleeves and embark on the first leg of our journey – the initial setup. By the end of this part, you'll have a fully configured project ready to take shape into a fantastic E-Commerce Web App that stands out in the digital market.

Are you excited? We are too! So, let's get started on transforming your E-Commerce vision into a reality!

Tutorial

Create a new NextJS in your desired directory using the following command in terminal:

npx create-next-app@latest

We will select the following answers for the questions asked after the above command:

What is your project named? ecommerce-store-nextjs
Would you like to use TypeScript?  Yes
Would you like to use ESLint? Yes
Would you like to use Tailwind CSS? Yes
Would you like to use `src/` directory? Yes
Would you like to use App Router? (recommended)Yes
Would you like to customize the default import alias? No 

Now we can open the folder with VS code editor and within the terminal write, npm run dev to open a development server as localhost:3000 which will display the NEXTJS boilerplate page.

Add external packages

Now we can install all the packages that we will be using in this project with this command in the terminal:

npm i daisyui prisma @prisma/client next-auth @auth/prisma-adapter prettier eslint-config-prettier prettier-plugin-tailwindcss zod

Configure Daisy UI, Prettier & ESLint

We’ll be Daisy UI component library to help us focus on the development logic instead of building UI components from scratch. Refer to daisyUI — Tailwind CSS Components for documentation.

Before using it, we’ll need to configure it in the tailwind.config.js file in the following way: Install daisyUI as a Tailwind CSS plugin — Tailwind CSS Components

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],

  plugins: [require("daisyui")],

  daisyui: {
    themes: [
      {
        lightTheme: {
          primary: "#f4aa3a",
          secondary: "#f4f4a1",
          accent: "#1be885",
          neutral: "#272136",
          "base-100": "#ffffff",
          info: "#778ad4",
          success: "#23b893",
          warning: "#f79926",
          error: "#ea535a",
          body: {
            "background-color": "#e3e6e6",
          },
        },
      },
    ],
  },
};

Next, we can remove all the initial styling from the globals.css file in src > app directory and keep the initial imports in the following way:

@tailwind base;
@tailwind components;
@tailwind utilities;

Next, we will create a file called prettier.config.js to configure prettier for tailwindcss in the root directory with the following code:

module.exports = {
  plugins: [require("prettier-plugin-tailwindcss")],
};

This is for the prettier plugin for tailwindcss we install earlier. Source: tailwindlabs/prettier-plugin-tailwindcss: A Prettier plugin for Tailwind CSS that automatically sorts classes based on our recommended class order. (github.com)

Also, make sure you have the Prettier and TailwindCSS Intellisense plugin installed from VS code extensions. Also, set your default formatter to prettier from VS code settings.

Next, we need to add prettier to the eslint configuration in .eslintrc.json file in the root directory in the following way:

// add prettier so that prettier and eslint don't conflict with each other
{
  "extends": ["next/core-web-vitals", "prettier"]
}

Also, install the ESLint and Prisma VS code extensions to be used later.

Next, you’ll need the logo.png and profile-pic-placeholder.png files in your assets folder which can be downloaded from the Github Repository: gupta-karan1/ecommerce-store-nextjs (github.com)

Setting Up MongoDB Atlas

First create an account on MongoDB Atlas on MongoDB: The Developer Data Platform | MongoDB and then you’ll be taken to your blank dashboard.

Here you can click on projects on the top left corner button and create new project. You’ll be asked for the project’s name and permissions which you can decide for yourself.

Once the project is created, you need to click on Build a Database button at the center of the dashboard to begin creating your first NoSQL database. Then you’ll need to select the Cluster to begin with. You can go for M0 Cluster which is free of cost and perfect for practice apps or small production apps. You can keep the default settings or choose a server closest to your location for better performance.

Next, you’ll be asked to create a username and password for your database which is very important because it will be used to connect to the service via your app. So please note the password in some secure location. Don’t worry, you can change the credentials later on also.

You’ll also need to add the local IP address which needs to access this database. It will automatically detect your IP address and add it to the list. For now, you’ll be connecting it locally on your machine but later on when in production or testing you can change the Network access settings to make it available to other users.

Once this is done, and you’ve submitted the details, it will take some 10-15 minutes to generate the cluster for the first time. So you can now have a coffee break for completing the initial setup.

Create a sample collection

Go the Collections tab in your dashboard and over there, click on ‘Add My Own Data’ to create the first collection manually. You can name the database as ‘ecommerce’ and the collection as ‘products’ because we will be displaying products to the customers.

Next, we will add some dummy data to the first document we will create in this collection. Make sure the field names are correct because we will be using these field names to build the Prisma schema later on in the code.

_id: ObjectId(64bd4aad73fe67e8ebaaebf7)
name: "Product Name"
description: "Product Description"
imageUrl: "<https://product-image.com>"
price : 999

Make sure you have the correct data types for each field in the document as displayed above in the image.

Setting Up Prisma

Prisma is an open source next-generation ORM. It consists of the following parts: Prisma Client: Auto-generated and type-safe query builder for Node.js & TypeScript Prisma Migrate: Migration system Prisma Studio: GUI to view and edit data in your database. Prisma Studio is the only part of Prisma ORM that is not open source. You can only run Prisma Studio locally. Prisma Studio is also integrated in our commercial offering Prisma Data Platform under the name Data Browser. In Data Browser, you can view and edit data for each project and other team members can do the same after you grant them permissions with an appropriate role. Prisma Client can be used in any Node.js (supported versions) or TypeScript backend application (including serverless applications and microservices). This can be a REST API, a GraphQL API, a gRPC API, or anything else that needs a database.

Source: Prisma | Next-generation ORM for Node.js & TypeScript

Since we have already installed Prisma earlier, we need to now add Prisma to the Project. Add Prisma to an existing MongoDB project (15 min) | typescript-mongodb

We’ll use the following command to execute Prisma in the terminal:

npx prisma init

This will create a .env file in the root directory which will have some placeholder code we need to replace with our own connection string from MongoDB.

Getting the Connection String from MongoDB Cluster

Go to your MongoDB Dashboard ⇒ Click on the ‘Connect’ button at the top right ⇒ Choose ‘Drivers’ within the modal box ⇒ Copy the connection string from the modal page.

Paste this connection string in the .env file in your root directory in the following way:

# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: <https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema>

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: <https://pris.ly/d/connection-strings>

DATABASE_URL="mongodb+srv://d22124440:<password>@cluster0.49swqm8.mongodb.net/ecommerce?retryWrites=true&w=majority"

Remember to use your own username and replace the password field with your database password.

Also, you’ll need to add the database name of ‘ecommerce’ that we created earlier within the connection string otherwise it will create a new database.

Next, we’ll add this .env file name within our .gitignore file in the root directory so that our configuration credentials don’t get pushed to our Github Repository making them publically available for everyone to see and misuse. Add the name to .gitignore like this:

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

.env

Now, when we gave the prisma init command earlier, it created a prisma folder within the root directory with a file called schema.prisma where we will create the schema for our data.

Make the following changes to schema.prisma to make it work with MongoDB:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

The url is the one that makes prisma look into the .env file for the connection string from MongoDB.

Now, we will use the existing sample data that we created in the MongoDB collection to build the schema within the schema.prisma file automatically using the following terminal command:

npx prisma db pull

This will create the schema within the shema.prisma file like this:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model products {
  id          String @id @default(auto()) @map("_id") @db.ObjectId
  description String
  imageUrl    String
  name        String
  price       Int
}

Now we will make some changes to the schema within this file and push them to the MongoDB collection.

First, we’ll make the following changes to the above file:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model Product { // This is the name of the model
  id          String @id @default(auto()) @map("_id") @db.ObjectId
  description String
  imageUrl    String
  name        String
  price       Int
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@map("products") // This is the name of the collection in the database
}

We’ll now push these changes to the database using the command:

npx prisma db push

It will most likely say: The database is already in sync with the Prisma schema.

After this we will run another command:

npx prisma generate

This will create the prisma client which we can use in our code to access the schema model we’ve just created.

Storing Prisma Client

First we will create a folder called lib in the src folder, within which we will create a db folder where we will create a prisma.ts file. Here we need to follow some best practices from Best practice for instantiating PrismaClient with Next.js to ensure the prisma client isn’t created multiple times when working in development server in NextJS.

We can simply copy and paste the code from the documentation within our prisma.ts file in the following way:

import { PrismaClient } from '@prisma/client'

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}

export const prisma = globalForPrisma.prisma ?? new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

This will instantiate a single instance PrismaClient and save it on the [globalThis](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis>) object. Then we keep a check to only instantiate PrismaClient if it's not on the globalThis object otherwise use the same instance again if already present to prevent instantiating extra PrismaClient instances.

The above code snippet is a part of a TypeScript module that uses the Prisma client, a powerful ORM (Object-Relational Mapping) tool used for working with databases. Let's break down what each part of the code does:

  1. import { PrismaClient } from '@prisma/client': This line imports the PrismaClient class from the '@prisma/client' package, which is the client library provided by Prisma to interact with the database.
  2. const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined }: This creates a variable globalForPrisma, which is a type assertion (as) to convert the globalThis object to an object with a property prisma that can hold an instance of the PrismaClient or undefined. globalThis represents the global object in the current environment (e.g., window in browsers and global in Node.js).
  3. export const prisma = globalForPrisma.prisma ?? new PrismaClient(): This line exports a constant named prisma, which will be used to interact with the Prisma client throughout the application. It assigns the value of globalForPrisma.prisma if it exists (i.e., it was initialized previously). Otherwise, it creates a new instance of the PrismaClient using new PrismaClient().
  4. if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma: This conditional statement sets globalForPrisma.prisma to the current prisma instance only if the NODE_ENV environment variable is not equal to 'production'. This condition likely ensures that only one instance of the Prisma client is used during development to avoid unnecessary connections to the database.

The code aims to ensure that there is only one instance of the Prisma client throughout the application's lifetime. When the prisma constant is imported into multiple modules, they all refer to the same prisma instance, making it more efficient and avoiding redundant connections to the database.

Once this is done, we can use the prisma client in our other files without any errors.

Before moving on to the development, we need to delete the document we created earlier from the MongoDB collection which was only to create the prisma schema. We can go to the collection of products and click on the trash icon next to the document to delete the document.

Conclusion to Part 1

Congratulations on completing the initial setup of your E-Commerce Web App! In this first part of our blog series, we've laid the essential groundwork that will serve as the backbone for your online store's success. You've now armed yourself with Next.js, Tailwind CSS, DaisyUI, Prisma, and MongoDB – a powerful arsenal of tools to build a feature-rich and visually stunning platform.

Throughout this journey, we've taken the time to explain each step in detail, ensuring that you have a clear understanding of the configurations and technologies involved. Whether you're a seasoned developer or a coding enthusiast, we hope this guide has been approachable and informative, making the process enjoyable and rewarding.

As you continue with the subsequent parts of this series, we encourage you to let your creativity flow and customize your E-Commerce Web App to reflect your brand's unique identity. From crafting engaging product pages to implementing seamless checkout experiences, the possibilities are endless, and the potential for growth is immense.

Keep in mind that building a successful E-Commerce platform requires dedication, perseverance, and a deep understanding of your target audience's needs. As you move forward, don't hesitate to explore additional resources, join developer communities, and seek assistance if needed. Learning from others and sharing your knowledge will undoubtedly accelerate your progress.

In the next part of this series, we will delve into the exciting process of designing the user interface and integrating various components to create a captivating shopping experience. From stunning visuals to intuitive navigation, we'll cover it all to make your E-Commerce Web App stand out from the crowd.

Thank you for joining us on this adventure to create an exceptional E-Commerce Web App. Stay tuned for the upcoming posts, and remember, the path to success may have its challenges, but with dedication and the right tools at your disposal, you can turn your dream into a thriving reality. Happy coding!

Popular Posts

Perform CRUD (Create, Read, Update, Delete) Operations using PHP, MySQL and MAMP : Part 4. My First Angular-15 Ionic-7 App

Visualize Your Data: Showcasing Interactive Charts for Numerical Data using Charts JS Library (Part 23) in Your Angular-15 Ionic-7 App

How to Build a Unit Converter for Your Baking Needs with HTML, CSS & Vanilla JavaScript