Building an Image Gallery with Next.js, Supabase, and Tailwind CSS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
we're going to build an image gallery with next.js superbase and tailwind css that fetches data from a postgres database and displays a grid of optimized lazy loaded images with great performance the finished repository demo link and written walkthrough are all linked in the description for you to reference as you build let's start by running create next app to clone the next.js and tailwind css starter application from the official examples folder this will download and clone the repository locally to a new folder called image gallery and it will automatically set up our application with the latest version of next js and tailwind now we can open our newly created folder inside vs code and run npm run dev to start our local development server at localhost 3000 and we can see our hello world next.js application however let's delete all of this code inside pages slash index and just put a hello world component here called gallery let's start using tailwind to set up the container around the images in our gallery i'll update my gallery component to add some styles to use css grid this will define the layout of the images inside of the gallery which will replace with the image component these styles also set up some padding and define different break points for how the grid will change based on the viewport let's go ahead and paste in some placeholder for an image component and i'll go ahead and update this comment to actually use this new image component now if i hit save i'll see this placeholder image show up on the right in the browser so let's take a look at this image component it's wrapped with an a tag which will allow me to link out to the source of this image and then i also have an image tag as well as some metadata about the image like the name and the twitter user who submitted this image now i'm using a couple cool tailwind tricks here like the aspect ratio plug-in which i'll install in a minute as well as group modifiers so the neat thing about the group modifier is if i hover anywhere over this a tag anywhere inside this component it will actually lower the opacity of the image element by passing the group hover opacity 75 class directly to that component you can see this if i go over the browser and i hover anywhere over the text in the bottom or the actual image the opacity is lowered so as i mentioned we'll want to kill our dev server and install the tailwind css aspect ratio plugin and now we can go into our tailwind config and add this new plugin into the plugins array now if we restart our development server we go back to our browser and we hit reload you'll see that the aspect ratio is maintained of one to one we can ignore that the image is stretched we'll fix that in a minute this image component is a good start but we want to take this further and ensure that we have great performance as defined by core web vinyls or how real users experience the performance of our website and to do that we can use the built-in next.js image component which is going to give us better performance out of the box at the top i've imported image from next image and i renamed the old image component to blur image to prevent a naming collision so i'll also want to update where we're actually consuming this image inside the gallery component inside the blur image you'll see that i've changed a couple things that we were previously using on the native image tag a lot of them are the same like source and alt but i've added this layout mode of fill as well as an object fit of cover now object fit actually just uses the underlying css property of object fit to ensure that we can fix our image being stretched as we can see on the right so let's save and you'll see i get this error on the right that says invalid source property and now this is expected the reason for this is we want to have an allow list of domains that we're telling nextjs hey you can optimize these images this is for good security in our application to prevent people from trying to use our next.js server to optimize any image so let's go into our next.config.js file and we'll add a new key for images to our object and we'll define a list of domains that we want to optimize in this instance we're just using a placeholder image from a link shortener so i'll hit save i will kill our server restart it reload my page on the right in the browser and now you'll see that we've fixed the stretching of our image by using object fit cover and this image if we had a long list would be lazy loaded in as we scroll down the page i'll show an example of this later now i named this component blur image but we're not actually doing a blur up placeholder effect as the image loads right now so let's update this component to do that first we're going to use react state to determine when it started and finished loading second we're going to use this on loading complete prop which will tell react when the image has finished loading and then finally we're going to conditionally add some class names to our image to use css transitions and animation to change the opacity and the easing and the scaling of our image to give it this nice blur effect at the top i've also imported use state and defined a little helper function here to allow us to combine a list of class names that are conditionally added to our component so let's save and let's try this out so now as you noticed on the right when i refresh there's this nice blurring and scaling effect that happens on our image as we load okay now let's actually connect to supabase and actually pull some real data from a database i've already created a superbase account and i have an organization called vercell so i'm going to make a new project called image gallery and i'll add a new password for this database i'll keep the default region of us east as that's also where i'll deploy my briscell application and we can stay on the free tier so i'll hit create new project and we'll actually kick off creating this postgres database as our database is provisioning we're going to copy the secrets and the url that we need to connect to our superbase database so let's copy and reveal this service role as well as this project configuration url which is the restful endpoint that we're going to use to fetch data next back inside our application we'll make a new file.env.local and this is where we'll put the values we copied from supabase so i've went ahead and pasted in the values here and i have two environment variables the first we prefix with next underscore public that would allow us to expose it to the client side in this instance we're just going to be using supabase on the server side but it's still good to know and then i also have this service role key which is a secret that we only want to use on the server side so now that we have the environment variables we can kill our development server we can install the superbase library so we can make a connection on the server and finally inside pages slash index we can paste in some code that will create a new client and use the environment variables that we just created to make a connection to supabase now this or empty string is just appeasing typescript here if we wanted to we could have some better error handling here where if the environment variable wasn't provided we could make the build fail back inside supabase let's go over to the left to our table editor and let's make a new table so that we can add some data to our application we'll call this images and in this instance we don't need to enable row level security because we're only using this on the server side however if we're going to do user authentication or anything on the client side we should definitely use row level security so i'll keep the id i'll keep created at and then let's add a few more columns to define some additional properties so we have name href username and image source and all of these are going to be text types so with that we can hit save that will create this new table images and add six new columns to the table okay our table is good to go now let's add some data we can insert rows using the ui we could import from a spreadsheet or a csv or we can add data using the superbase client instance that we've instantiated inside of our application i've went ahead and imported some data from a csv so that we can have a bunch of images in our image gallery back in our application so back in our editor let's actually fetch this data from supabase so we've already set up our client to create a connection to supabase and we're going to use this new function called git static props to fetch that data on the server side so git static props only ever runs on the server we're able to fetch some data and forward it as props to the default exported react component from our file in this instance the gallery component so with our connection we can do a new query to supa base admin from the images table select everything and order it based on the id and then in the props we're actually going to return a key of images as well as the new data that we've retrieved now if i scroll down to the gallery component you see that we're not actually consuming the data that we've fetched in git static props yet so let's do that first we'll define a type for the image that we're getting back from supabase with the properties that we defined on our table the different columns then we can update the gallery component to take in this image's prop that we retrieved from git static props and this is an array of images then we can iterate over those images or map over each image and forward that information to the blur image component and we'll pass over that entire object as an image now we're getting a typescript error because we haven't defined this yet so let's go back to blur image and do that next so the blur image component will take in this image as a prop and we'll use the type that we defined and instead of using placeholder data it will actually pull off this data from superbase like the image source the name and the username of the person from twitter so now if we hit save we're gonna see the invalid source prop error again because we've changed the domain for where we're optimizing images from so let's go back to next.config.js and we're going to update this file to use the new domain from twitter images so we'll hit save we will restart our dev server reload the page and we see our image gallery complete with all of these images fetched dynamically from supabase now if i resize the page you'll see that my css grid is working and as i scroll you'll notice that the images lazy load in alright so i went ahead and pushed up my repository to github with all my latest changes and over inside versailles you'll see that it automatically recognizes this new repository you can see all my uh all my fun testing repositories here so i'm going to click import and this is going to take me into the import flow i'll keep this project name it automatically picks the framework of next.js and then inside environment variables i need to add the things that we had in our emv.local to connect to superbase okay so i just pasted those in and added both of those environment variables and now we can click deploy all right so it looks like it was done in about 30 some seconds and we see our screenshot that our application was successfully deployed we can click on the image if we want and that will take us out to our new.burcell.app url and our images load perfectly and have our nice blur effect this looks really good because we used git static props we actually generated a completely static site so just some html css and javascript so if we were to go back to supabase and actually change data inside of our database we wouldn't see it reflected on this page unless we went into vercell we went to our dashboard and we redeployed our latest commit or we pushed up some new code with nextgs 12.1 we actually introduced a new feature called on-demand isr or incremental static regeneration that allows you to update your pages after they've been deployed let's add that here let's go back to supabase and on the left we'll click the database tab and then let's click function hooks now function hooks allow us to listen for any changes on any of our database tables and then call some function so let's create a function hook we'll call this update images we're going to listen to this images table that we've created this is where it will watch for changes we're going to watch inserts updates and deletes and we're going to call some external api this is coming soon which should be launched very soon but for now we're just going to use this and we're going to make a post request to our application our deployed.vercell.app url slash api revalidate now this doesn't exist but we're about to create this in a second and we want to add an http query parameter here which we'll call secret and then you can give this some super secret value that you'll store inside your application perfect so let's hit confirm and our function hook is now live and we'll send updates to this api so let's create the api back in our editor we'll reopen dot emb.local and we can paste in the secret that we just created here as revalidate underscore secret so let's use this in our new api route inside pages slash api create next app includes this hello world api route that just returns some json let's rename this to revalidate so we have the slash api slash revalidate like we specified in supabase and then i'll paste in some new code here so let's take a look at what this does first we look at the query parameters to see if the secret that's forwarded from supabase matches what we've set as an environment variable if it doesn't then we just return a 401 and we say this is unauthorized this is important such that we can lock down this api route such that only trusted parties can access it then inside the try block we're going to revalidate our index page so we're actually going to regenerate just that specific page on demand and then return some json saying that revalidated was true and that's it before we deploy though we should go back inside versailles go to our project settings environment variables and we can add that revalidate secret with the value of super secret and add it for all our environments such that the next time we deploy we'll be able to use this value so in vs code or in our terminal we can make a new commit add on demand isr and push this up to our git repository and that's going to automatically trigger a new build inside for cell you see it just automatically shows up without even having to reload the page now this is going to add that new slash api revalidate route and it's going to use the environment variable that we just created okay so we're done deploying now let's try this out back in superbase we'll go to our images table and let's update some data so this first row i'll expand here and let's just change the name from kevin to lee and i'll click save and now i go back to my deployed application i hit reload and immediately you'll see the content update without needing to redeploy that's on demand isr alright that wraps up this tutorial we were able to build a next.js application that displays a list of images fetched dynamically from supabase and we can update our content without needing to redeploy if you enjoyed this video hit subscribe and let me know down below what future videos you'd like to see me make peace
Info
Channel: Lee Robinson
Views: 48,130
Rating: undefined out of 5
Keywords:
Id: BSoRXk1FIw8
Channel Id: undefined
Length: 16min 24sec (984 seconds)
Published: Mon Mar 28 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.