Let's Checkout Remix ... And Compare It To Next.js
In this video we are going to checkout Remix. I’ve been playing around with Remix for the last couple of days. This video is mostly going to be about that journey and how Remix compares to Next.js.
Remix is a React framework similar to Next.js and I would say that it’s the only real competitor to Next.
It is focused on web standards and modern web app UX. Although Remix is pretty new to Open Source, it has been around for about two years now, but as a payed software that was recently Open Sourced.
The main selling point of Remix is that it embraces web standards and tries to leverage them to provide great user and developer experience.
Remix is trying to bring old school web development practices and patterns to the modern JS world. So if you are and old school developer like me these things are going to be pretty familiar to you.
Remix philosophy consists of few parts:
Embracing Server/Client model - which means that if you are doing things Remix way, most of your data is going to be coming from the server - there is no Static Site Generation or Incremental Static Generation in Remix, only server side rendering, for which Remix provides very nice APIs to make your life as a developer easier.
If you wanna make your site faster this may sound a bit counter intuitive, but since you can transform your data on the server this means that you are sending only the data that the user needs on every request, so your payloads can be pretty small.
If you are using modern web infrastructure combined with native web features like
prefetch this can make your site very fast even without serving mostly static content.
Remix is very easy to deploy and plays nicely with Vercel, Cloudflare Pages, Cloudflare workers, Fly.io and many others, so you can easily serve your Remix site from the servers that are closest to your users using CDNs.
Another core philosophy is that it embraces native web standards like HTML, HTTP, Web Fetch API, Request, Response, URLSearchParams and others that already live in your browser.
Progressive Enhancement is another big thing for Remix, and because of it, data layer of Remix can function with or without JS. It uses JS to provide nicer User Experience but you can add or remove data from your data source without using JS at all, because Remix knows how to work with the lowly
<form> tag that has been around for 20+ years, and it can send the data to server without JS. Of course as you will see in this video Remix augmented the
<Form> tag for 21 century, but it can also function like it’s 1999.
So now that you have general idea what Remix is, let’s get our feet wet and let me show you how I remade the site from Directus and Next series in Remix.
Installation of Remix was breeze, I managed to get most of the functionality that we have in that app in just four to five hours.
Keep in mind that I already had a lot of code that I could reuse from that app, and I skipped the mini cart and sign in functionality because i didn’t wanna learn another library for authentication. Since we used Next Auth in Directus Next series, and it can only be used with Next.js.
However there is a library called Remix Auth that you can use for that, and it seems pretty similar to Next Auth. So if you need authentication in your app you can check that out.
The only thing I installed when remaking this app was Tailwind, so that I can have the same design that we had in DIrectus Next app.
To install Tailwind you can just follow a quick guide on Tailwinds website, and you’ll be good to go in no time.
When you open the app in your editor you will see a folder structure that is similar to Next.js except all the important stuff is in the
app folder. And in
app folder you only have routes directory. Which is very similar to the pages directory in Next.js, because just like Next - Remix uses page based routing. So whatever you add in there will automatically get its own route.
This is the folder structure that I ended up with when the app was finished.
Styles directory is generated by Tailwind, and all the other folders are pretty much just copy and paste from the Next.js site, except I needed to save them into
app folder as opposed to the root folder of Next.js app.
If you wanna see all the code there will be a link in the description to the GitHub repo that you can browse through.
Products, categories, and Filters.
First thing I wanted to do was setup the homepage. And on the homepage we have few interesting functionalities. One is getting all of our products from Directus, getting all the categories for the Filter and also filtering functionality itself.
Homepage is of course
index.jsx file in the
routes folder. Now, my Next app uses React Query to get the data and to filter it. However this is not the Remix way, because, remember Remix respects the Server/Client philosophy, so it would be nice to embrace that and get the data from the server instead from the client.
So I removed the React Query part of the code, and leaned in to the server.
And this is not anything new, because Next.js does the similar thing with
getServerSideProps just here it works a bit differently.
First you create
models directory and in it I created a file called
index.server.js here I added all of the getter functions for my data.
And if you have been following my Directus Next series you can see that here I’m pretty much using the same functions for getting the data. And also the same GraphQL queries that I have been using on the Directus Next site.
You can return whatever you need from those functions. I’m exporting functions for getting all of my products, categories, and a function for getting my filtered products that accepts an array of category IDs to filter those products.
Now back in
index.jsx you need to export a
loader function that will talk to the server and get your actual data.
For categories it’s easy, you can just use
useLoderData Remix hook and get it from there. Products are a bit more complicated because we need to filter them.
So for that I’m using the
useFetcher Remix hook which will allow me to first of all display all the products. But when user selects a category it will send the category IDs to the loader function which will run a different different getter function to get my filtered data.
Our fetcher is called products in this case, and the fetcher has a submit method on it. So whenever the state of the selected categories change it will submit it to the loader.
And loader will receive a
get request which we can parse, and then call the
getFilteredProducts function with an array of IDs as a parameter to get the filtered products.
This Workflow is very similar to the Directus Next app, except here all the data fetching is happening on the server and without the need for ReactQuery.
And if we check our front page everything is working as expected.
There is also a difference how Remix handles meta tags compared to Next.js. In Next you would import
Head component, add it to the beginning of the layout on your page and then add the actual tags there, like
<description> and whatever else you need.
In Remix you would export
meta function for every page, and that would overwrite all the default tags that you can define in
root.jsx is similar to
_app.jsx in Next.
Also you can add dynamic data to it, by passing in the
data variable which will then have access to all the data that you get from the
loader function on that page.
I’m doing that on the single product page to set the title of that page to be the name of the product.
Now, to Link the product to the product page you first need to define that page. You can do that almost identically to Next.js, except you would use dollar sign notation for defining dynamic parts of your route instead of square brackets.
In Next you would get the page by slug by writing
[slug].jsx but in Remix that page would be called
Now, my case is a bit more complicated because I don’t just wanna display the name of product in the URL but I also wanna display a category. So I would have:
In Next and in Remix you could create a folder called products, and in it you would create another folder called
[catgegory] and in it you would add a file called
[slug].jsx for Next.js. So this is almost the same in both frameworks.
But, in Remix you could also just create a file with the name:
products.$category.$slug.jsx and you would get the same thing, which is cool. So I decided to go with that for my single product page.
Also I suggest to read up about Nested Routing in Remix which is really cool. You can do that on this address. https://remix.run/docs/en/v1/guides/routing
To link my products to the single product page, I used the
Link component, which is also similar to the
Link component in Next. Except in remix you don’t have
href property but instead you use
to property. And also you don’t need to wrap
Link component around anchor tag like you need to do it Next.js.
You can see the link to my products in the
ProductCard.jsx and you can see the difference between Next and Remix. It’s very similar for the most part. The only difference is the
href property and the missing anchor tag.
In Next.js I added the Header component which holds the Logo of the shop and navigation in
_app.jsx . As mentioned before Remix has a file called
root.jsx that serves the same purpose. So we can add
Header component that is visible throughout the site there.
And there is just one more thing that I wanna show you, and that is the
Form component. Which I already talked a bit about at the beginning, and said how it embraces web standards and old school way of dealing with forms.
On Sign up page you can register and create a new user in Directus. To do that in Next we used
useMutation hook from React Query, and we would get the data from the form by creating
handleSubmit function, for which we would prevent default functionality of the form and then send the data to the server from there.
This is the usual React pattern.
But since Remix embraces the
form we can do things a bit differently. So first of all I changed
form to be
Form with capital F. Fun fact here is that you could leave it as just
form with lower case F, and it would also work, it would just reload the page on sending the data, because that is what forms do, and that is the reason we need to use
preventDefault in the Next version.
In Remix I just added the method of
post to the form, and I want it to do an action that is defined on the page it is on. But you could also add an action that will get instructions from another page.
Then you need to define the action by exporting
action function to which you pass a
request object. And then you can easily access the data from the form by using
When the data is defined I just send it to the server with
createUser function, which I defined in the
user.server.js file in
models folder. Function for sending the data is the same as in Next.js version of the site.
Now I’m waiting for the response from the server, and if I get
create_users_item to be equal to
null I can return an error. Since I’m using Directus this means that the user already exists.
If the user does not exist then I can just redirect the user to the thank you page after it’s created on Directus API.
Now if we get an error we can get that information by using
useActionData Remix hook. And then we can display an error in our layout like this.
Of course there are a lot more things to cover about Remix but I cant do that in one video. This video is just for you to get a taste of what is possible in Remix and how it works.
My time with the framework was for the most part very enjoyable.
I think it’s an all around great framework that is just going to get better with time, and is a real competitor to Nextjs. And competition is going to be great for us developers.
If you wanna take a look at the code I used in this video you can check it out on Github.
Like This Video?
Consider supporting me on Patreon.
...or you can share this video, that also helps ;)