Remix

Introduction to Building Better Websites with Remix Framework

Written by Mojtaba Seyedi

Last update: 4/17/2024

In the last couple of years, the front-end world saw a renewed focus on server-side technologies. This was great news for those looking to improve their app's performance. Frameworks like Astro, SvelteKit, Qwik City, and Remix all brought fresh ideas to the table.

Remix was developed by the same team behind React Router and was paid software during beta. But now, it has been open-sourced for everyone to use and contribute to. It's worth mentioning that Remix has been acquired by Shopify recently.

What makes Remix unique is that it introduced a few concepts that were slowly adopted by other frameworks. Remix is also trying to bring old-school web development practices and patterns to the modern JS world.

What is Remix: A Full Stack React Meta framework

So, what exactly is Remix? Simply put, it is a full-stack web framework built on top of React. It embraces web standards and leverages them to provide better user and developer experiences. With Remix, you get a fast and seamless server and browser runtime, which means that you can deliver an amazing user experience without sacrificing performance.

Remix takes a slightly different approach to server-side rendering compared to frameworks like Next.js. While Next.js offers SSG and ISR in addition to SSR for faster performance, Remix focuses solely on SSR with both Node.js and Edge runtimes. This means that Remix is more suited to handling dynamic data, making it ideal for applications with many pages that rely heavily on dynamic data living in a database.

One of Remix's most exciting features is its support for nested routes, which other frameworks adopted later. Additionally, Remix supports file-based routing and can prefetch everything in parallel before the user clicks a link, providing lightning-fast user experience.

Remix Embraces The Server/Client Model

According to this philosophy, you can make your server faster, but you cannot control the user's network. However, you can decrease the amount of stuff you send over the network, such as JavaScript, JSON, and CSS. This philosophy suggests that with today's web infrastructure, static files are not necessary to make your server fast. Instead, having a server to move the code to, and a framework that favors progressive enhancement, can help you send less stuff over the network. By doing so, you can speed up your apps by sending less over the user's network.

Unlike other frameworks that may use SSG or ISG, Remix relies on SSR to provide a fast and efficient experience to users. Remix supports only two runtime strategies: server-side and client-side, which simplifies the development process.

Remix Leverages Web Standards

Remix is also built with a focus on web standards and HTTP/HTML. For example, it uses the Fetch API, which is a standard mechanism for issuing network requests in modern browsers, both on the client and server. By using the same familiar API across the stack, developers can work more efficiently. Additionally, Remix's use of the <link rel="prefetch"> allows for preloading pages when the link to them is visible, even if the page itself is dynamic, which is not possible with other frameworks.

Remix uses the technologies that have been around for a long time. This means that as you get good at Remix, you're getting good at web standards.

Remix Focuses on Progressive Enhancement

Another unique aspect of Remix is its focus on progressive enhancement. With Remix, the data layer of an app can function with or without JavaScript on the page. This is possible since the data is loaded at runtime. This means that even without JavaScript, developers can add or remove data from a data source, like a form. Of course, using JavaScript provides a better experience, but the ability to work without it makes Remix more versatile and accessible.

Nested Routes in Remix

Nested routes in Remix Framework allow you to render parts of a page based on the route the user is on.

The whole idea of nested routing is allowing you to map different components and data dependencies to different segments of a URL, creating a hierarchy of route components. This hierarchy is realized through the use of the <Outlet> component, which is part of React Router DOM.

import { Outlet } from "@remix-run/react";


export default function someRoute() {
  return (
    <div>
      <h1></h1>
      <main>
        <Outlet />
      </main>
    </div>
  );
}

When you have a route nested under a parent, the child route will automatically inherit the UI of the parent. You can think of the <Outlet> component as a placeholder for the child component that will replace it based on the URL you navigate to.

Nested routes also allow Remix to preload the different parts of a page. This enhances user experience and allows you to create complex UI without compromising performance.

It’s best to check the following example to understand nested routing better. The demo is from the Remix official website. You can hover or tap each button to see how each segment of the URL maps to the following three things:

  • A component layout
  • A JavaScript bundle
  • A piece of data
[@portabletext/react] Unknown block type "iframe", specify a component for it in the `components.types` prop

Note that nested routes were later adopted by other frameworks like Next.js too.

Form Component and Action Function in Remix

Remix has a built-in <Form /> component that functions similarly to a regular form when JavaScript is not available. However, when JavaScript is enabled, the <Form /> component is "progressively enhanced" to make a fetch request rather than causing a full-page reload. This enhancement results in a smoother user experience and better performance.

Also, in Remix, you can use actions to handle form submissions. Actions are server-only functions that handle data mutations and requests made to your route.

This is a simple example of how you can use the From component and the Action function in Remix:

import { Form } from "@remix-run/react";
import { redirect } from "@remix-run/node";


// This handles the form POST
export const action = async ({ request }) => {
  const formData = await request.formData()
  
  const title = formData.get("title")
  const slug = formData.get("slug")


  // This knows how to save the post
  await addPost({ title, slug })


  return redirect("/somewhere")
}


export default function NewBlog() {
  return (
    <Form method="post">
      <label>Title: <input type="text" name="title" /></label>
      <label>Slug: <input type="text" name="slug" /></label>    
      <button type="submit">Add Post</button>
    </Form>
  );
}

Also, you can use the useNavigation hook to know the status of the request.

That's it. Remix, and the browser will take care of the rest. You no longer need to worry about manually sending form values to the action with the correct method or handling loading states and aborting requests. The framework takes care of these tasks for you.

[@portabletext/react] Unknown block type "message", specify a component for it in the `components.types` prop

Remix File Structure

The basic type of a Remix project has the following structure:

my-app
├── public
│   └── favicon.svg
├── app
│   ├── root.jsx
│   └── routes
│       └── index.jsx
├── remix.config.js
└── package.json
  • public: This folder contains static assets like images, fonts, etc.
  • app: This is where all your Remix app code lives.
  • app/root.jsx: Contains the root component of your app. You render the <html> element here.
  • app/routes: This is where you define all your pages. Remix uses all the files in this directory to create the URL routes based on the name of them.
  • app/routes/index.jsx: This is basically your homepage.
  • remix.config.js: Remix configuration options are going to be in this file.

Remix Ecosystem

The Remix community is thriving and can provide you with plenty of resources to help you make the most out of the framework.

For starters, the official Remix Discord server is a fantastic place to connect with other developers, get help with specific issues, and stay up to date on the latest news and developments in the community.

If you're looking for examples to learn from, Remix has an extensive collection that covers everything from simple apps to complex e-commerce sites.

One of the things that makes Remix so flexible is its adapter system, which lets you easily integrate the framework with different back-end systems like databases and APIs. There are adapters available for popular services like MongoDB and Firebase, among others.

And if you have any questions or ideas to share, the Remix GitHub Discussions page is a great place to start.

Finally, if you're looking for more in-depth information, the Remix Guide Collection has a series of guides that cover different aspects of using the framework.

Showcase

[@portabletext/react] Unknown block type "showcase", specify a component for it in the `components.types` prop

How to get started With Remix?

You can start a new Remix project by the following command:

npx create-remix@latest

This will prompt you to answer a few questions:

Also, Remix CLI allows you to use an official Remix stack to initial your project. This is possible by adding the –template flag to the previous command:

npx create-remix@latest --template blues-stack

In case you want to have a custom stack, you can simply give your stack address as an option to --template flag:

npx create-remix@latest --template github-username/repo-name

Once you are done with the installation, you can go to your specified directory and run the project locally:

cd your-project

npm run dev

Now your project is live on localhost:3000, so you can rock and roll!

Deploying Remix

When you initialize your project, Remix gives you options to pick a deployment target, such as Netlify, Vercel, etc. Each target has its own steps for you to deploy your project, and the best way to learn about them is to read the README.md file that Remix generates for you right from the start.

Additionally, if you are familiar with deploying node applications, the built-in Remix app server is production-ready.

First you need to build your app running the following command:

npm run build

Also you can run your project in production mode:

npm start

Finally you can deploy the output of Remix build, which is in both the build and public/build directories on your server:

  • build/
  • public/build/

Also, regarding edge computing, note that Remix is an edge native framework. This means Remix is deployable to edge providers like CloudFlare Workers, Lambda@Edge, and Netlify Edge Functions.

Final Thoughts

Remix is a promising full-stack web framework that leverages web standards and embraces progressive enhancement. Its unique approach to server-side rendering, nested routes, and support for multiple front-end technologies make it a flexible and powerful option for building complex and dynamic web applications. By utilizing modern web technologies and focusing on performance, Remix enables developers to deliver fast, high-performing apps that provide a seamless user experience. Whether you're an experienced developer or just starting out, Remix is definitely worth checking out as it can help improve your skills in web standards.

[@portabletext/react] Unknown block type "message", specify a component for it in the `components.types` prop
[@portabletext/react] Unknown block type "prosCons", specify a component for it in the `components.types` prop