Reader small image

You're reading from  Full Stack Web Development with Remix

Product typeBook
Published inNov 2023
Reading LevelIntermediate
PublisherPackt
ISBN-139781801075299
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Andre Landgraf
Andre Landgraf
author image
Andre Landgraf

Andre is a full stack developer from Germany. He graduated with an MS in Information Systems from the Technical University of Munich and was also awarded an MS in Computer Science from Sofia University in Palo Alto. Andre currently lives in Cupertino, California, and he works as a Software Engineer at LinkedIn. Andre loves learning, writing, and speaking about all things web. In his free time, he tutors aspiring developers and builds for the web.
Read more about Andre Landgraf

Right arrow

The Era of Full Stack Web Frameworks

“The only constant in life is change.”

– Heraclitus

We live in exciting times for web development. The landscape is changing at an astonishing pace. There have never been more technologies to choose from to develop for the web. It feels like a new framework or library is published every other month. Existing frameworks and libraries release new major versions with new features, breaking changes, and new conventions. The industry’s fast pace can feel overwhelming, but it is also fascinating to see such a high level of innovation.

The larger web development community moves at a much slower pace than the cutting edge does. Most enterprises and developers are waiting to see what technologies stick around before adopting them – creating something we can consider the industry standard. I would count React as part of this standard. However, moving fast and adopting a new technology can be a competitive advantage if it moves the needle far enough. I believe Remix is such a technology.

Since you bought this book, you’ve decided to try Remix – awesome! As a React developer, Remix provides you with many benefits, such as the following:

  • A backend environment for your frontend
  • A full stack data mutation story
  • A declarative approach to error handling
  • Simplified client-side state management
  • Server-side rendering
  • The latest advancements in React, such as streaming
  • An app runtime that can run anywhere, even on the edge
  • Progressive enhancement through an embrace of web standards

With Remix, you can tap into the full capabilities of the web. This book guides you through the process, starting with the basics and progressing to more advanced techniques. In this first chapter, we will go over the following topics:

  • Introducing Remix
  • The philosophy behind Remix
  • Primitives, conventions, and levers
  • Remix behind the scenes

First, we will introduce Remix as a full stack web framework. After that, we will investigate the philosophy behind Remix and introduce a mental model to categorize the different tools Remix provides. Finally, we will look under the hood and learn about the different responsibilities that Remix takes on.

The goal of this first chapter is to introduce you to Remix. Most importantly, we want to showcase the advantages of Remix to your React development. We hope this will motivate you to get going. Therefore, this chapter touches upon several advanced concepts. But fear not; everything mentioned will be studied in detail later in this book.

Introducing Remix

It’s intuitive to think of Remix as another React framework. Still, the team behind Remix stresses that Remix is not a React framework but a full stack web framework – an important distinction.

In this first section, we will summarize what it means that Remix is a full stack web framework. First, we will look at the web framework part and explain why Remix is genuinely a framework for the web. After that, we will highlight why Remix is full stack.

Remix is a web framework

The main reason Remix is a web framework is its deep embrace of the web platform. Remix aims to enable a “fast, slick, and resilient user experience” by using web standards. HTML forms and anchor tags, URLs, cookies, meta tags, HTTP headers, and the Web Fetch API are all first-class citizens in Remix. Remix’s conventions, levers, and primitives are thoughtfully designed abstraction layers of existing web APIs and standards. This sets Remix apart from other popular frameworks that feel more decoupled from the web platform.

The Open Web Platform is the collection of standards defined by the World Wide Web Consortium (W3C). This includes JavaScript web APIs, HTML and CSS, accessibility guidelines, and HTTP. The web standard moves at a much slower pace than the industry standard does. New web standards take a long time and go through many iterations before being released, and it’s even longer before all browsers support them.

As a web developer, your resources are limited. To make the most of your time and energy, it’s essential to focus on learning the core principles of the web, which will be applicable regardless of the tools you choose. Learning the foundations of the web is transferable knowledge that benefits you regardless of what frameworks and libraries you use. When using Remix, you will often refer to the MDN Web Docs instead of the Remix documentation. Learning Remix means learning standard web APIs.

React plays a vital role in Remix. Remix leverages the latest features of React where it makes sense. With React 18, React is becoming more sophisticated. React’s latest features are more tailored to framework authors than app developers. Remix provides necessary abstractions to take advantage of these latest advancements.

When paired with React, Remix utilizes client-side routing and data fetching, creating a similar experience to building single-page applications (SPAs) with React. However, Remix has a broader scope than React and addresses additional concerns in web development, such as caching, user sessions, and data mutations. This makes Remix a web framework.

Remix is a full stack framework

Let’s see why Remix is full stack. Remix embraces the client/server model of the web platform. It orchestrates both the frontend and the backend of your web application:

  • On the server, Remix acts as an HTTP request handler
  • On the client, Remix orchestrates a server-side-rendered React application

Remix acts as a frontend and a backend framework. These two frameworks are independent pieces executed in different environments (the browser and the server environment). During your app’s runtime, the two frameworks communicate over the network.

During development, you create one Remix application where the client and server code is nicely co-located in one /app directory. We can even write client and server code in the same files.

The following code example showcases what a page/route file looks like in Remix:

// The route's server-side HTTP action handlerexport async function action({ request }) {
  // Use the web Fetch API Request object (web standard)
  const userId = await requireUserSession(request);
  const form = await request.formData();
  const title = form.get("title");
  return createExpense({ userId, title });
}
// The route's server-side HTTP GET request data loader
export async function loader({ request }) {
  const userId = await requireUserSession(request);
  return getExpenses(userId);
}
// The route's React component
export default function ExpensesPage() {
  // Access the loaded data in React
  const expenses = useLoaderData();
  // Simplify state management with Remix's hooks
  const { state } = useNavigation();
  const isSubmitting = state === "submitting";
  return (
    <>
      <h1>Expenses</h1>
      {expenses.map((project) => (
        <Link to={expense.id}>{expense.title}</Link>
      ))}
      <h2>Add expense</h2>
      <Form method="post">
        <input name="title" />
        <button type="submit" disabled={isSubmitting}>
          {isSubmitting ? "Adding..." : "Add"}
        </button>
      </Form>
    </>
  );
}

In the code example, we use Remix’s route module API to define a loader function for server-side data loading, an action function for mutating data, and the route’s React component for rendering the UI.

Remix co-locates server-side request handlers and the app’s route components. This makes sharing code between the client and server way easier and provides full visibility and control over how our app’s frontend and backend work together.

On the server, we handle incoming HTTP requests and prepare responses using Remix’s action and loader functions. In the code example, the server-side request handlers manage user sessions and load and mutate data. We use web standards such as the Fetch API, FormData, and HTTP cookies.

In the route component, we access the server-side-loaded data and read transition states with Remix’s React hooks. We further use Remix’s Form component to define a data mutation declaratively. On the client, Remix runs JavaScript to enhance the browser’s default experience. This is where we utilize the power of React to compose dynamic UIs.

Remix is a web framework that lets you take advantage of the full stack. Remix truly allows you to unlock the full potential of the web platform for your React development.

Now that we have introduced Remix, let’s dive into its philosophy.

Understanding the philosophy behind Remix

Remix’s mission is to let you build fast, slick, and resilient user experiences. The vision is to let you deliver software that people love. In this section, we will have a closer look into the philosophy behind Remix. You will learn about the creation of Remix and the values that the team promotes.

Remix was created by Ryan Florence and Michael Jackson (@ryanflorance and @mjackson on Twitter and GitHub). Ryan and Michael are React veterans and the authors behind React Router – the most popular routing library for React applications with over 1 billion downloads on npm. Remix’s philosophy is heavily influenced by the lessons Ryan and Michael learned by building and maintaining React Router.

Initially, Remix was intended to be a license-based framework. But in October 2021, the development team behind Remix announced that they had secured seed funding and would make Remix open source. In November 2021, the team released v1 of Remix after 18 months of development. A year later, in October 2022, Shopify acquired Remix. The Remix team is now fully focused on Remix’s development while still pursuing the same mission and vision at Shopify.

Not only is Remix open source, but the Remix team also embraces open development. The team has made the roadmap and all Requests for Comments (RFCs) and proposals available to the public. They also live-stream roadmap meetings and actively encourage community participation and contributions. The goal is to open the development process to the community as much as possible while still fostering the philosophy that guided Ryan and Michael.

Over time, the team behind Remix has mentioned many of the things that are important to them. Above all, Remix is meant to push the web forward. Both Ryan and Michael stress that they want to see better websites. The mission is to provide you with the tools to build great user experiences. They want people to love using your stuff.

The Remix team did a great job summarizing its philosophy in the Remix documentation. Some of the points that the Remix team has emphasized are as follows:

  • Remix aims to avoid over-abstraction. In Remix, APIs are meant to be a thin abstraction layer on top of the web platform. Simplicity is king. Remix does not reinvent the wheel.
  • Remix looks both forward and backward. It mixes cutting-edge technologies and matches them with battle-proven web standards to create new approaches. Remix takes advantage of HTTP2 streaming and edge deployment but simultaneously embraces HTML forms, cookies, and URLs.
  • Remix progressively enhances the user experience without straying from the browser’s default behavior. The goal is to stay true to the browser’s default behavior and be able to fall back to it whenever possible.
  • Remix is about unlocking the full stack of the web platform – or, as the Remix team phrases it, the client/server model.
  • The team behind Remix deeply cares about the network tab and your app’s bundle size. The goal is to load less and load things as quickly as possible.

Frameworks provide the foundation and framing for your application code. The Remix team also refers to Remix as being center stack (instead of full stack). Remix is meant to be the core, reaching out to both the client and server sides of your application. It is meant to be the centerpiece.

For me, Remix is a powerful tool with great developer experience that lets me build for the web. I value the simplicity and utility of the APIs that Remix provides. I have learned a lot about the web since picking up Remix, all thanks to the emphasis on using the web platform. Remix combines new approaches with old ones. It is refreshing to use and has already started influencing the ecosystem around it. We now truly live in the era of full stack web frameworks.

The Remix team promotes the Remix way of thinking. For instance, Ryan suggests a three-step process for developing web experiences:

  1. Make everything work without JavaScript.
  2. Enhance the experience with JavaScript.
  3. Move as much business logic as possible to the server.

In each step, we build upon the last step to enhance the experience:

  1. First, we focus on building the feature without JavaScript. With Remix, we take advantage of the web platform. We use forms to mutate data and use server-side redirects to communicate feedback. After the feature works without JavaScript, we could possibly publish it and be done.
  2. Next, we use JavaScript on the client to enhance the user experience. We may add optimistic UIs, deferred data loading, and real-time data updates.
  3. Finally, we move as much business logic as possible to the server. This allows for graceful degradation in case client-side JavaScript isn’t loaded. It also decreases the bundle size of your app.

By using Remix and engaging with the Remix community, you are exposed to Remix’s philosophy. Applying Remix’s philosophy to your development process will truly supercharge your React development.

Remix’s philosophy can also be understood by the tools it provides you. In the next section, I want to introduce you to a mental model of framework features.

Primitives, conventions, and levers

In this section, we will categorize the different features Remix offers. A framework provides the foundation and framing for your application. It further exposes tools to you as a developer. We can divide these tools into three categories:

  • Primitives
  • Conventions
  • Levers

Primitives, conventions, and levers can serve as a great mental model to map different features of Remix. Let’s see how the three categories differ.

Primitives

Primitives are used in your application code to interact with the framework layer. They are the wiring that integrates your application into the foundation and framing provided by the framework. Common primitives are functions, hooks, constants, types, classes, and components. The framework exposes these primitives so you can use them in your code. The art is to make primitives easy to understand yet composable enough to enable powerful business logic. Remix has done just that.

Remix provides primitives for both your client and server code. Remix primitives are often just a thin abstraction layer of the web platform and offer similar APIs to the native primitives. For instance, Remix’s Form component accepts the same properties as the native form element but also offers some additional properties to enhance the experience.

Also, Remix’s primitives themselves expose standard web APIs. Most server-side code you write in Remix has access to a Request object that follows the Web Fetch API specification. Remix does not reinvent the wheel.

Conventions

Frameworks also introduce conventions. Common conventions are file and folder naming conventions. In the previous section, we showed a code example of a route file in Remix. Remix’s route files (route modules) allow you to export specific functions that are part of Remix’s route filenaming convention.

Conventions are meant to improve the developer experience. For instance, file-based routing lets you define your application’s route structure as a file and folder hierarchy. Remix compiles your code and infers your route hierarchy, so you don’t have to define your route hierarchy as code.

Intuitive conventions reduce the amount of configuration required to wire an application. They shift the burden toward the framework. Conventions make up the contract between the framework and your application and can significantly reduce the amount of boilerplate code you have to write.

The API of a framework is mainly composed of primitives and conventions. All frameworks include primitives, and many frameworks utilize conventions. However, Remix places a particular emphasis on a third category: levers.

Levers

Levers can be interpreted as options. Ryan coined the metaphor in one of his first conference talks about Remix. Ryan emphasizes that Remix is just a thin abstraction layer on top of the web platform. Remix lets you decide what web vitals to optimize for. Time to First Byte (TTFB) or Cumulative Layout Shift (CLS)? Loading spinners or slower page loads? Optimizing for different web vitals can be conflicting goals. Remix offers levers so that you can stir your web app in the direction that is right and important for you.

With levers comes utility but also responsibility. Remix provides the primitives, but you must decide how to design your application. I believe this power makes you a better web developer. But more importantly, it unlocks the full potential of the web platform. There are many things to optimize for, and Remix provides the levers. This sets Remix apart from other frameworks that don’t give you the same kind of flexibility and control.

Now that we’ve prepared a mental model for how to categorize Remix’s features, we will have a look behind the scenes. Remix offers many great features and comes with many quality-of-life improvements. This is because it takes on several responsibilities at once. Let’s peek under the hood to understand what that means.

Remix behind the scenes

So, how does Remix work behind the scenes? Based on what we have learned so far, Remix seems to do quite a lot. In this section, we will have a look behind the curtain. This will help you understand some of the responsibilities Remix takes on.

Remix offers a fantastic developer experience but can also feel like magic. A bit of magic goes a long way, but it can also be overwhelming when one doesn’t understand what is happening. Magic is also hard to troubleshoot if something goes wrong. That is why I want to reveal some of Remix’s inner workings even before creating our first Remix project.

We can identify three distinct responsibilities that Remix takes on:

  • Remix bundles your code
  • Remix manages routing in your application
  • Remix handles incoming HTTP requests

Based on the identified responsibilities, Remix can be broken down into three main components: a compiler, a router, and a runtime. In the following sections, we will examine each component. To start, let’s take a closer look at how Remix operates as a compiler.

Remix is a compiler

Remix compiles your file-based route modules into code. It infers the route structure from the file and folder hierarchy. For each route module, Remix inspects what functions it exports and translates the routes folder into a data structure used during runtime. This makes Remix a compiler.

One thing you will notice while working with Remix is the speed of its build step. This is thanks to esbuild, the build tool used by Remix. Remix doesn’t expose esbuild. Hence, Remix can adapt how it bundles your code and be competitive in the future by using the latest and greatest build tools. If an even faster, more powerful build tool is released, Remix could switch out esbuild tomorrow.

Remix builds on top of esbuild to bundle your JavaScript files into the following:

  • A server bundle
  • A client bundle
  • An asset manifest

Remix’s command-line interface (CLI) builds your code into a client and server bundle. The server bundle contains Remix’s HTTP handler and adapter logic. This is the code that runs on the server. The client build contains client-side scripts that operate Remix’s client-side React application.

Remix also compiles an asset manifest based on your route hierarchy. Both the client and server use the asset manifest, which includes information about the dependency graph of your application. The manifest tells Remix what to load and allows prefetching assets and application data for page transitions.

Speaking of page transitions…

Remix is a router

Remix implements a router for both your client and server code. This eases the server-to-client handoff. The deep integration between the frontend and backend makes Remix bridge the network gap. This allows Remix to do some neat things. For instance, Remix calls your route loader functions in parallel to avoid request waterfalls.

We can simplify things and say that Remix uses React Router under the hood. To be more specific, Remix uses both react-router-dom and @remix-run/router. @remix-run/router is a frontend library/framework-agnostic package used by React Router v6 and Remix. React Router and Remix have been aligned and share a similar API surface. In many ways, you can think of Remix as a compiler for its underlying routing solution.

Remix has a client-side and a server-side part, as does its routing solution. The React components exposed by Remix make sure your application feels like an SPA. Remix handles form submissions and link clicks. It prevents the browser’s default behavior if JavaScript is loaded but can fall back to full page loads if necessary. All that is managed by Remix’s router at runtime.

Speaking of runtimes…

Remix is a runtime

Remix runs on an existing server, such as an Express.js Node server. Remix provides adapters to create combability with different server-side JavaScript environments. This enables Remix’s HTTP handler to be agnostic to the underlying server.

The adapter translates incoming requests from the server environment to standard Request objects and reverts the HTTP handler’s responses back to the server environment’s response implementation.

Remix receives HTTP requests via the JavaScript server and prepares the responses. Remix’s router knows what route modules to load and render and which assets to fetch. On the client, Remix hydrates your React application and orchestrates the routing and data fetching. As a framework, Remix provides the foundation for your application and executes your application’s code. Next, let’s have a look at what Remix is not.

What Remix is not

Earlier in this chapter, we introduced Remix and explored many of the tools and features that it provides. Remix is a full stack web framework, but it is also essential to understand what Remix is not. Most importantly, Remix is not one of the following:

  • A JavaScript server
  • A database
  • An Object Relation Mapper (ORM)
  • A cloud provider
  • A styling or theming library
  • A magic crystal ball

Remix is neither a server nor a JavaScript engine. Remix runs on a JavaScript environment such as Node.js and uses adapters to communicate with a web server such as Express.js. Remix also provides no solutions for the data layer of your application. It helps you load and mutate data, but it is your job to implement those data loaders and actions. It is your job to select a database solution that fits your use case. Remix is also not an ORM. Hence, you must query your data in your actions and loaders, define your data types, or use third-party libraries for support.

The company behind Remix does not act as a cloud provider or offer a cloud hosting service. You can host your Remix application almost anywhere where JavaScript can be executed. Many cloud services support Remix out of the box, but Remix as a company does not offer any hosting services.

Remix is also not a styling or theming library. Remix is opinionated on how to work with CSS, but its solution is generic. Remix provides no tools for styling or theming other than utilities to load your stylesheets on a prefix route level.

Most things listed are out of scope for Remix, but some might be up for change in the future. For now, let’s focus on the present. In this first chapter, we have learned a lot about the many features Remix has to offer. Most of the things mentioned happen behind the scenes. This book will guide you through each aspect of Remix step by step. Each chapter will focus on a specific topic, such as routing, data fetching and mutation, error handling, and state management. By examining these topics one by one, we will explore the significance of Remix. I am certainly excited to start coding!

Summary

In this first chapter, we introduced Remix as a full stack web framework. Remix promotes the usage of the web platform and lets you take advantage of standard web APIs. It bridges the network gap by tightly integrating the frontend and the backend. This allows Remix to do some cool things.

We also looked at the philosophy behind Remix. The team behind Remix emphasizes avoidance of over-abstraction. Its mission is to let you build fast, slick, and resilient user experiences. The vision is to let you deliver software that people will love.

We introduced the terms primitives, conventions, and levers to categorize Remix’s different features. Primitives are the exposed utilities that can be imported and used in our code. Conventions are contracts such as file and folder naming conventions that are used to avoid tedious configuration. Levers are options provided by Remix that allow us to optimize our application for what’s important to us.

You also learned more about what Remix does behind the scenes. Remix takes on three distinct responsibilities. It is a compiler, a router, and a runtime. Combining those three responsibilities in one framework enables great things, such as flattening request waterfalls and avoiding the frontend-backend split by co-locating client and server code.

In this chapter, we touched upon many concepts, such as server-side rendering, prefetching, and client-side routing. We will revisit all the mentioned concepts throughout this book. In the next chapter, we start our Remix development journey and create a “Hello World” Remix app.

Further reading

If you haven’t looked through Remix’s home page (https://remix.run), I encourage you to do so. The team behind Remix has done a great job of breaking down its value proposition and pitching its solutions. Also, it looks awesome.

The same goes for the Remix documentation. I encourage you to familiarize yourself with Remix's documentation as you work through the chapters of this book. For example, the team behind Remix has done a fantastic job of summarizing its philosophy. You can read more about it here: https://remix.run/docs/en/v1/pages/philosophy.

Are you interested in more in-depth explanations about Remix? You can find an in-depth technical explanation about Remix here: https://remix.run/docs/en/2/pages/technical-explanation.

You can find the official announcement of Remix joining forces with Shopify here: https://remix.run/blog/remixing-shopify.

The public roadmap and most other planning documents are located on GitHub. The roadmap can be found here: https://github.com/orgs/remix-run/projects/5.

If you want to learn more about Remix’s approach compared to alternative technologies, check out this blog post: https://remix.run/blog/remix-and-the-edge. If you want more context around alternative solutions, I recommend the following blog post: https://frontendmastery.com/posts/the-new-wave-of-javascript-web-frameworks.

You have been reading a chapter from
Full Stack Web Development with Remix
Published in: Nov 2023Publisher: PacktISBN-13: 9781801075299
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime

Author (1)

author image
Andre Landgraf

Andre is a full stack developer from Germany. He graduated with an MS in Information Systems from the Technical University of Munich and was also awarded an MS in Computer Science from Sofia University in Palo Alto. Andre currently lives in Cupertino, California, and he works as a Software Engineer at LinkedIn. Andre loves learning, writing, and speaking about all things web. In his free time, he tutors aspiring developers and builds for the web.
Read more about Andre Landgraf