Build a Fullstack Music App with Next.js
A second version of this course released using Next 13+, but this course is great if you want to see another example fullstack project. We now recommend you take the Build a Fullstack App with Next.js, v2 course.
Table of Contents
IntroductionScott Moss introduces the course by providing personal background information and reasoning behind creating this course. A brief overview of the course project is also covered in this segment.
SetupScott briefly walks through the materials utilized in this course, including Node.js, React.js, Postgres, Prisma, Next.js, Vercel, Heroku, and various component libraries. A walkthrough of the finished application is also provided in this segment.
Setup Next.js, ESLint, & TypescriptScott walks through setting up the base for the course project, the code included in a next.js app, and installing the config files and dependencies. Updating file types to TypeScript and a student's question regarding the difference between _app.tsx and index.tsx are also covered in this segment.
Course App OverviewScott discusses an overview of the design layout of the course application and the different components that it is comprised of. Reusable components to look out for when viewing design specifications are also discussed in this segment.
Setup Chakra UIScott briefly discusses the page rendering options of Next.js and walks through setting up a layout with Chakra UI. Editing the base stylings provided with Chakra UI and extending the theme over the component are also demonstrated in this segment.
Creating Player LayoutScott demonstrates creating the layout for the player component of the course application and briefly discusses Chakra UI's use of box compared to the usual div tag. Wrapping components in the layout avoids the layout being reloaded on page change.
Creating the SidebarScott walks through implementing the sidebar component, discusses using Chakra's List component to display items, and demonstrates using React Icons to import icon packs as components. Importing all of the Sidebar's needed Chakra and icon components is also shown in this segment.
Adding the LogoScott demonstrates mocking up the playlist layout to include the playlist container and the provided application logo using NextImage. NextImage is an image component optimized by Next.js and includes image compression. A student's question regarding why height and width for NextImage are set in curly braces and not in quotes is also covered in this segment.
Create a List Nav with LinkBoxScott walks through creating the navigation list in the sidebar using List, ListItem, LinkBox, NextLink, LinkOverlay, and ListIcon. Student questions regarding whether creating objects or code repetition is better for menu items and how NextImage optimizes images are also covered in this segment.
Create Playlist MenuScott demonstrates creating the music menu, a scrolling playlist menu, and a divider to separate the navigation and music menu from the playlist. The playlist and container must have a height for the application to know where the array is overflowing the container and adequately scroll.
Setup Prisma & PostgreSQL on HerokuScott walks through setting up a PostgreSQL database on Heroku and provides a brief overview of the setup at the end of the segment. Student questions regarding if Prisma works for both SQL and non-SQL databases simultaneously and the need for the shadow database are also covered in this segment.
Prisma SchemaScott demonstrates the syntax of Prisma's schema by setting up a user model with fields, types, and defaults.
Data ModelingScott demonstrates identifying components and secondary data needed to complete the specified application design. Creating the Song and Artist models are also shown in this segment.
Creating Schema & Migrations with PrismaScott discusses defining the relations between the previously created models in the Prisma schema. There is a one-to-many relation between User and Playlists due to one user having many playlists. Confirming the changes to the database with an initial migration using Prisma is also covered in this segment.
Seeding DataScott walks through creating a seed script to populate the database with playlist data and prepare the application for user authentication. Prisma allows the use of nested inserts to avoid multiple database calls. Students' questions regarding the use of Int? for userId and if it is best practice to separate backend code and frontend code are also covered in this segment.
Running the Seed ScriptScott walks through how to run the seed script to populate the application's database. A demonstration of using Prisma studio to view the database in a browser application is also provided in this segment.
Seeding User DataScott demonstrates how to salt and hash users' passwords using bcrypt for encryption. A student's question regarding if the Prisma code gets shipped to the client is also covered in this segment.
Seeding Playlist DataScott live codes the seed script for new playlist arrays to populate the playlist data in the database. This seed script will also connect the playlists to a user.
Seeding Playlist Data Q&AScott answers student questions regarding when the run function gets executed and if running the seed script clears the previous data in the database.
Serverless API OverviewScott discusses the benefits and drawbacks of building out database routes frontend first, backend first, and by feature. A demonstration of API routes corresponding to files in the pages/api folder and discussion of serverless functions being functions that are executed based on an event are also covered in this segment.
Signup API RouteScott walks through creating a serverless signup function for user account creation and authentication. Student questions regarding if Prisma can generate and validate CSRF tokens and how serverless functions execute in production are also covered in this segment.
Signup API Route Recap & TestScott walks through the previously completed signup API route and tests to verify that the route creates a user and erroring when creating an already existing user.
Signin API RouteScott live codes and tests the serverless signin function, allowing users to sign in to their account by comparing the user email and password to the data stored in the database. This function will also respond to an incorrect username or password input with an error.
Fetcher & Auth MutationScott creates a fetcher function to abstract the HTTP fetching mechanism and an auth mutation function to make an API call to sign in or sign up using the fetcher function. Scott also creates a mutations file to hold the various functions mutating the application's state.
Auth PagesScott walks through building an authForm component to toggle between modes based on the user login status and demonstrates opting out of the global player layout for just the login page. This form is created using useRouter to access the Next.js router and userSWRConfig, which can handle data fetching, caching, optimistic updates, re-fetching, and re-caching.
Sign In & Sign UpScott live codes the authForm inputs, submission button, form styling, and logo for signin and signup. Implementing the forms to allow users to sign in and signup is also covered in this segment.
Protected Route HandlerScott demonstrates only allowing authorized users, protecting API routes using middleware, and discussing protecting pages utilizing edge functions. Student questions regarding why the user is added for the handler argument and a reason for not using NextAuth for authentication are also covered in this segment.
Middleware Edge FunctionsScott walks through creating an edge function that checks the cookie to see if the user has a valid access token and redirects to the sign in page if no token is found. Student questions regarding ending test edge functions on localhost, if _app.tsx runs before _middleware.tsx, and if NextResponse is replacing res.
Middleware Q&AScott answers student questions regarding limited options for deploying a Next.js application and ways to redirect 404 pages. A student's question regarding if there is any relation between middleware functions and Angular interceptors is also covered in this segment.
Custom Hooks for Fetching DataScott demonstrates creating custom hooks with SWR to handle fetching the user and playlists data from the server and setting the correct loading state. A student's question regarding if the word "use" has to be in the function name is also covered in this segment.
Fetch & Render Data into ComponentsScott walks through using the custom usePlaylist hook to fetch the playlist data, allowing a user's playlists to be rendered in the sidebar component. The usePlaylist hook can be used to avoid making multiple calls for every page that includes playlists.
Gradient Background & Image BoxScott live codes a gradient page component for the homepage and playlist gradient background using Chakra UI's Box and Flex components. Creating a flexible image box for the user profile picture and playlist image is also covered in the segment.
Title & Subtitle UI LayoutScott demonstrates using Chakra UI's Text component to abstract away from heading, paragraph, or span tags being used for text. The Text component will default to a paragraph tag but can be changed to an alternate tag by setting the "as" property value.
Load Artists DataScott demonstrates retrieving data from the server by exporting the getServerSideProps function from Next.js. Despite being located in a page component, the getServerSideProps function only runs server-side and never runs on the browser. A student's question regarding the difference between getStaticProps and getServerSideProps is also covered in this segment.
Artists List UI LayoutScott walks through implementing the layout and styling for the artists list, including rendering the artists data previously retrieved from the server. Each artist card will include a placeholder image, artist name, and " Artist " label.
Seed User DataScott walks through resetting the database to include new user data and pulling in the user data to replace the application's hard-coded data. Populating the user playlist count is also covered in this segment.
Build Dynamic Playlist PagesScott live codes a dynamic route for playlist pages that will render and authenticate a page for each user's playlists. The server request will also get the songs and artists in each playlist. Student questions regarding if the include keyword is similar to a join and if the playlist request returns everything about songs unless specified are also covered in this segment.
Playlist Page UIScott continues to work on the playlist page by implementing the previously created gradient layout, a random background color generator, and a random playlist image.
Songs Table UIScott walks through starting to build out the songs table to hold the songs in the user's playlists, including the layout of the play button and completion of the table header. The Chakra UI Table component is imported and used to build the songs table.
Song UI & Time formatScott demonstrates inserting song data into the songs table, including song number, title, date added, and song duration. The formatting functions used to format date added and song duration into appropriate time formats are built using the Format Duration library. Student questions regarding if getServerSideProps has to be named exactly that and if edge functions compared to lambda functions are expensive to hold on a live CDN
Auth Error HandlingScott discusses the scope of what will be covered regarding the player component and how to handle auth errors with an expired jwt by redirecting a user to the login page.
Player UI ContainerScott walks through creating the container layout for the application's player bar component using Chakra UI's Box, Flex, and Text components.
Player State with Easy PeasyScott demonstrates creating a store and player state using the Easy Peasy library to handle the active playlist and song state.
Player Controls UIScott live codes importing components for the seek bar and the controls for the player bar using Chakra UI, React, React Howler, React Material Design Icons, and Easy Peasy to access the application's store. The shuffle, previous, play, pause, and next buttons are laid out in this segment.
Seek Bar UIScott walks through implementing the sidebar component, discusses using Chakra's List component to display items, and demonstrates using React Icons to import icon packs as components. Importing all of the sidebar's needed Chakra and icon components is also demonstrated in this segment.
Player Controls StateScott walks through setting up state for the player using Easy Peasy, including shuffle, repeat, play, current duration, seek bar value, seeking, and currently playing song. Student questions regarding if useReducer is used to eliminate the state, if the playState wrapper is redundant, and why setPlayState does not follow the onShuffle/onRepeat naming convention are also covered in this segment.
Playing Songs StateScott demonstrates how to import and set the player's active song, conditionally render the artist box and player component, and render the current song and artist names.
Seek Bar ControlsScott implements seek bar controls, including the onEnd, onLoad, and the range slider functions to handle the seek bar functions. Student questions regarding if the seek bar controls could be used for the volume slider and if the player would be a good candidate for Xstate are also covered in this segment.
requestAnimationFrame & Synching UIScott demonstrates updating the UI to be responsive to changes using the requestAnimationFrame method, which tells the browser that an animation wishes to be performed and requests that the browser calls a specified function to update an animation before the next repaint. Updating the range slider and the current song duration are covered in this segment.
End Song & Repeat HandlersScott walks through implementing and debugging the player's next, previous, repeat, and shuffle functions. Using a reference instead of hooks with callbacks can help avoid getting caught in closures.
Deployment & Testing
Deploying with VercelScott discusses a brief overview of the completed application and walks through the deployment process with Vercel. If Vercel is connected to a GitHub repository, it will automatically redeploy on a new push to that repository.
Testing & CIScott discusses different options for adding testing and CI to the application, including Jest, Cypress, and GitHub Actions. Student questions regarding if Next.js has a configuration to do a static build for all pages, opinions on React testing library, and if user details can be server-side rendered with SWR are also covered in this segment.