Let's Create a Movies app in Next Js using Tmdb API and Tailwind CSS

Let's Create a Movies app in Next Js using Tmdb API and Tailwind CSS

Create A movies app in Next js, tmdb API, and tailwind CSS with proper SEO tags and Sitemaps

In this article, We will create a movies app using next js, tmdb API, and Tailwind CSS with proper SEO and sitemap integration. In past, I had created a project like this and added it to my portfolio

Github link of the project

Live Demo

External Packages I will use

  • Moviestmdb => To interact with tmdb API easily.
  • Tailwind CSS => For styling our app
  • Slugify => To generate slugs (link for our movies).
  • Next Seo => For Seo of the site.

and few others as a dev dependency.

Initial Setup

  npx create-next-app moviesapp

This will create our next js app.

Tailwind CSS setup

  • Installation

    yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest
    

    This will install Tailwind CSS in our app

  • Create postcss.config.file in the root directory and add the following code.

    // postcss.config.js
    module.exports = {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
      }
    }
    
  • Create a config file for tailwind CSS using the following command.

      npx tailwindcss init

replace purge array with the following code in the tailwind.config.js, this will purge the CSS and thus reduce the size of our CSS file.

  purge: ["./pages/**/*.js", "./components/**/*.js"],
  • Add the following styles in global.css
@tailwind base;
@tailwind components;
@tailwind utilities;
  • Finally import tailwind CSS in _app.js
import "tailwindcss/tailwind.css";

Next Js config

  • Add the following code to the next.config.js, this will help next js to enable optimization of images hosted on external sources.
module.exports = {
  images: {
    domains: ["image.tmdb.org"],
  },
};

Moviestmdb and Slugify Setup

  • Installation.
     yarn add slugify moviestmdb
    
  • Get tmdb API key from here
  • Create a .env.local file in the root directory.
  • Paste Your tmdb API key as:

 TMDB_API_KEY="****************************************"
  • create a new folder naming configs in the root directory.
  • create a new file inside naming tmdb.js
  • add the following code .
    import Moviestmdb from "moviestmdb";
    const tmdb = new Moviestmdb(process.env.TMDB_API_KEY);
    export default tmdb;
    

Add the initial setup has been completed now we will work with receiving the data add displaying it.

Index Page

We will fetch popular movies and pass them as props on the index page.

import tmdb from "../configs/tmdb";
//code has been not included to reduce size
export const getStaticProps = async () => {
  const movies = await tmdb.discover("movie", [
    {
      param: "sort_by",
      value: "vote_count.desc",
    },
  ]);
  return {
    props: {
      movies: movies.results,
    },
  };
};
  • getStaticProps will generate build time data.

  • [{param:"sort_by",value:"vote_count.dec}] will return us most popular movies as per the vote count.

Creating the slug for the movie

  • Tmdb returns us the movie data based on its id.
  • So the request would be like
    const movie= tmdb.movie(27205)
    
    this would not beneficial for the SEO purpose as the slug would be like /movies/27205 and search engine crawlers will not understand what it means.

So for this purpose, I have installed the slugify package which will convert the title into the string of slug and we will add id at the end of that slug, then the slug would be like /movies/inception-27205.

While making the request we will split the string into an array and get the last element of the array. Now I will create a utility function for this purpose.

All our utility functions will go inside a new folder naming utils. I will create a new file under the utils directory of the name gen-slug.js with the following code.

import slugify from "slugify";
const slugWithId = (title, id) => {
  const slug = `${slugify(title, {
    lower: true,
    remove: /[*+~.()'"!:@]/g,
  })}-${id}`;

  return slug;
};
export default slugWithId;
  • I am importing the slugify package
  • Then I have created a default export function which takes to argument -> title and id
  • Then using slugify I have converted the title into a slug and removed any unnecessary characters and also added the id of the movie at the end

Parse The slug

While we are in the utils directory let's create a function to parse the slug and return the id from it.

  • Create a file naming parse-slug.js and add the following node.

export default function getIdFromSlug(slug) {
  return slug.split("-").pop();
}
  • this function will take a slug and then split it into an array and return the last element of the array using the.pop() method.
  • .split(separator) method of string converts a string into an array. it takes a separator which is used for splitting the string.
  • .pop() method of the array returns the last element of the array
const id = getIdFromSlug("avengers-infinity-war-299536")
// returns 299536

Movie page

It's time for us to create a single movie page.

  • Create a folder of the name movies inside the page directory.
  • Create a file in this folder naming [slug].js
  • Now add the following code to it.
import tmdb from "../../configs/tmdb";
import getIdFromSlug from "../../utils/parse-slug";
export default function SingleMovie({ moviesData }) {
  return <div>{moviesData.title}</div>;
}

export const getServerSideProps = async (ctx) => {
  const slug = ctx.params !== undefined ? ctx.params.slug : "";
  const id = getIdFromSlug(slug);
   const moviesData = await tmdb.movie(id, {
    append: ["credits"],
  });
  return {
    props: {
      moviesData,
      error: false,
    },
  };
};
  • getServerSideProps will render the page on request time.
  • slug will contain route param example avengers-infinity-war-299536.
  • id will be parsed using getIdFromSlug(slug) function.
  • then we will pass the id into the tmdb. movie() method.
  • we can also get other details such as videos, translations, images, credits, etc by passing them to the appended array.

Tv Shows Page

Same as the movies page now we will add tv shows page. There are few changes in response such as there are no properties as title or original_title instead these are changed into name and original_name

The TV details page for the tv show will be the same as the movies page.

SEO & Sitemap

SEO

  • For the purpose of SEO,I have installed the next-seo package which helps us to include important meta tags
  • I have also included Opengraph data on every page.

Sitemap

Generating sitemap in next-js is quite complex. We will have to create a node js script for generating the sitemap of the site, scripts will go in the scripts directory.

  • First, we will fetch popular movies based on their vote count using the moviestmdb package.

  • Then with the help of the fs module of node js we will generate a JSON file containing an array of movie objects with the property of title, id, slug.

  • After that, we will create another script that will convert the JSON data into the XML format.

  • This step will be repeated for tv shows also with minor changes.

  • The scripts will generate an XML sitemap and JSON file.

  • The reason I am generating the JSON file is that we can use it to generate static movie pages for our site if we ever wanted.

  • you can check the sitemaps at this link

Features You can add

  • Search For movies and tv shows.

  • Improve the UI.

  • Movie page can be more enriched using the data provided by tmdb API see here