Skip to content

This Dot Blog

This Dot provides teams with technical leaders who bring deep knowledge of the web platform. We help teams set new standards, and deliver results predictably.

Newest First
Remix's evolution to a Vite plugin cover image

Remix's evolution to a Vite plugin

As Remix evolves into a Vite plugin, the story of React Router continues, promising exciting developments in the React Server Components era....

Choosing Remix: The JavaScript Fullstack Framework and Building Your First Application cover image

Choosing Remix: The JavaScript Fullstack Framework and Building Your First Application

Remix is a React framework for building server-side rendering full-stack applications. It focuses on using web standards to build modern user interfaces. Remix was created by the team behind React Router, and was recently open-sourced for the community. Remix extends most of the core functionality of React and React Router with server-side rendering, server requests, and backend optimization. But why start using Remix? Remix comes with a number of advantages: - Nested routes - nested routes help eliminate nearly every loading state by using React Router’s outlet to render nested routes from directories and subdirectories. - Setup is easy! Spinning up a remix project takes just a few minutes and gets you productive immediately. - Remix uses server side progressive enhancement which means only necessary JavaScript, JSON, and CSS content is sent to the browser. - Remix focuses on server-side rendering. - File-system-based routing automatically generates the router configuration based on your file directory. - Remix is built on React which makes it easy to use if you know React. Key Features Let’s highlight a few key features of Remix you should be aware of. Nested Route Routes in Remix are file-system-based. Any component in the route directory is handled as a route and rendered to its parent outlet components. If you define a parent component inside the routes directory, and then different routes inside a directory with the same name as the parent component, the latter will be nested within the first one. Error boundaries Error handling with applications is critical. In many cases, a single error can cause the entire application to be affected. With Remix, when you get an error in a Remix component or a nested route, the errors are limited to the component and the component will fail to render or it will display the error without disrupting the entire application’s functionality. Loading State Remix handles loading states in parallel on the server and sends the fully formed HTML document to the browser; this eliminates the need to use a loading skeleton or spinner when fetching data or submitting form data. Loaders and Actions Among the most exciting features of Remix are Loaders and Actions. These are special functions: Loaders are functions (Hooks) that retrieve dynamic data from the database or API using the native fetch API. You can add loaders to a component by calling the useLoaderData() hook. Actions are functions used to mutate data. Actions are mostly used to send form data to the API or database, to make changes to an API, or perform a delete action. Building Your First Remix App The next portion of this blog post will show you how to build your first Remix app! We will be building a small blog app with primsa’s SQLite to store the posts. To start a Remix project the prerequisites are: - A familiarity with JavaScript and React - Node.js installed - A code editor i.e VSCode Open your system terminal and run: ` You can accept the default prompts or use your own preferences. Remix will install all the dependencies it requires and scaffold the application with directories and files. In the project’s directory let install the other dependencies we will be using, run: ` You should use something like the directory in the image. File structure walk through The app directory contains the main building files for our Remix application. The route directory holds all the routes that expose the exported default function as the route handler from the file. entry.client.jsx and entry.server.jsx are core Remix’s files. Remix uses entry.client.jsx as the entry point for the browser bundle, and uses entry.server.jsx to generate the HTTP response when rendering on the server. root.jsx is the root component of Remix application, the default export is the layout component that renders the rest of the app in an These are the files we really want to touch on in our project. To learn more about the file directory, check out Remix’s API conventions. Project set up Open the root.jsx file and replace the code with: ` Since we are using bootstrap for styling we imported the minified library, Remix uses the to add stylesheet at component level using the Route Module links export. The links function defines which elements to add to the page when the user visits the route. Visit Remix Styles to learn more about stylesheets in Remix. Similar to the stylesheet, Remix can add the Meta tags to the route header by calling Meta Module. The meta function defines which meta elements you can add to the routes. This is a huge plus for your application’s SEO. The app file has three components with a default export of the App component. Here, we declared a Document Component for the HTML document template, a Layout Component to further improve the template layout for rendering components, and added the {process.env.NODE_ENV === "development" ? : null} for Hot reload when changing things in the file during development. One important note is to not confuse Links with Link. The latter, Link, is a router component for matching routes in Remix’s apps. We will handle the components to match our routes below. To test out the application: ` You should have a similar app as shown below: Let’s configure the db we will use for the app. We will use primsa SQLite to store the posts. Install the Prisma packages in your project: ` Now let’s initialize the prisma SQlite in project: ` This will add a Prisma directory to the project. Open prisma/schema.prisma and add the following code at the end of the file: ` This is the schema for the blog database. Simply, the schema is identifying that we will need a slug which will be a unique string and used for our blog’s unique route. The title property is also a string type for the title of our blog. The body type of string will hold the body, and finally we want to have the dates created and updated. Now, let’s push the schema to Prisma: ` Prisma will create a dev.db in the Prisma directory. Now let's seed our database with a couple posts. Create prisma/seed.js and add this to the file. ` Now edit the package.json file just before the script property and add this: ` Now, to seed the db with Prisma, run: ` Our database setup is now done. There is just one more thing for database connection, We need to create a typescript file app/utils/db.server.ts. We specify a server file by appending .server at the end of the file name, Remix will compile and deploy this file on the server.. Add the code below to the file: ` Now, go back to the code editor and create post.jsx in the route directory, and add the following code: ` All we are doing is rendering our nested routes of posts here, nothing crazy. Now create routes/posts/index.jsx ` Here, we are declaring the loader and fetching all the posts from the database with a limit of 20 and destructuring the posts from the useLoaderData hook, then finally looping through the returned posts. Dynamic Routes Remix dynamic routes are defined with a $ sign and the id key. We will want to use the slugs properties as our dynamic routes for the blogs. To do this, create app/routes/posts/$postSlug.jsx ` Here, the loader is fetching from the database using the unique slug we provided and rendering the article. To add where to post new blogs, create app/routes/posts/new.jsx, and the following code: ` We created an action function to handle the form post request, and Remix will catch all the formData by passing the request. And there you have it! You’ve created a functional blog application. Conclusion In this article, we learned why Remix is a great choice for building your next application, and why it’s becoming a more popular framework to use amongst developers. We also explored the core features of Remix and learned how to build a sample blog application using a database....

Remix Deployment with Architecture cover image

Remix Deployment with Architecture

Intro Today’s article, will give a brief overview of the Architect framework and how to deploy a Remix app. I’ll cover a few different topics, such as what Architect is, why it’s good to use, and the issues I ran into while using it. It is a straightforward process, and I recommend using it with the Grunge Stack offered by Remix. So let’s jump on in and start talking about Architect. Prerequisites There are a few prerequisites and also some basic understandings that are expected going into this. The first is to have a GitHub account, then an AWS account, and finally some basic understanding of how to deploy. I also recommend checking out the *Grunge Stack* here if you run into any issues when we progress further. What is Architect? First off, Architect is a simple framework for Functional Web Apps (FWAs) on AWS. Now you might be wondering, "why Architect?" It offers the best developer experience, works locally, has infrastructure as code, is secured to the least privilege by default, and is open-source. Architect prioritizes speed, smart configurable defaults, and flexible infrastructure. It also allows users to test things and debug locally. It defines a high-level manifest, and turns a complex cloud infrastructure into a build artifact. It complies the manifest into AWS CloudFormation and deploys it. Since it’s open-source, Architect prioritizes a regular release schedule, and backwards compatibility. Remix deployment Deploying Remix with Architect is rather straightforward, and I recommend using the Grunge Stack to do it. First, we’re going to head on over to the terminal and run *npx create-remix --template remix-run/grunge-stack*. That will get you a Remix template with almost everything you need. *Generating remix template* For the next couple of steps, you need to add your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to your repo’s secrets. You’ll need to create the secrets on your AWS account, and then add them to your repo. *AWS secrets* *GitHub secrets* The last steps before deploying include giving CloudFormation a SESSION_SECRET of its own for both staging and production environments. Then you need to add an ARC_APP_SECRET. *Adding env variables* ` With all of that out of the way, you need to run *npx arc deploy*, which will deploy your build to the staging environment. You could also do *npx arc deploy —-dry-run* beforehand to verify everything is fine. Issues I Had in My Own Project Now let's cover some issues I had, and my solution for my own project. So, I had a project far into development, and while looking at the Grunge Stack, I was scratching my head, trying to figure out what was necessary to bring over to my existing project. I had several instances of trial and error as I plugged in the Architect related items. For instance: the arc file, which has the app name, HTTP routes, static assets for S3 buckets, and the AWS configuration. I also had to change things like the *remix.config* file, adding a *server.ts* file, and adding Architect related dependencies in the package.json. During this process, I would get errors about missing files or missing certain function dirs(), and I dumped a good chunk of time into it. So while continuing to get those errors, I concluded that I would follow the Grunge Stack, and their instructions for a new project. Then I would merge my old project with the new project; and that resolved my issues. While not the best way, it did get me going, and did not waste any more time. That resolved my immediate issues of trying to get my Remix app deployed to AWS, but then I had to figure out what got pushed. That was easy, since it created a lambda, API gateway, and bucket based on the items in my arc file. Then I realized, while testing it out live, that my environmental variables hadn’t carried over, so I had to tweak those on AWS. My project also used a GitHub OAuth app. So that needed to be tweaked with the new URL. Then it was up and running. Conclusion Today’s article covered a brief overview of what Architect is, why it’s good to use, how to deploy a Remix app and the issues you might have. I hope it was useful and will give others a good starting point....

Introduction to Remix cover image

Introduction to Remix

What is Remix? Remix is a full stack web framework based on web fundamentals and modern UX. It was created by the team, founded by Ryan Florence and Michael Jackson. They are the creators of React Router. Remix is a seamless server and browser runtime. It has no static site support, and always relies on a server. Remix aims to provide fast page load times and instant UI transitions. Remix is built on the Web Fetch API, which allows it to run anywhere. It can be deployed in a serverless environment or in a Node.js server environment. Remix features Fast data fetching Fetching data is so fast with Remix that there is no need for transitional spinners. Rather than fetching data via a series of requests from components, Remix will load data in parallel on the server. It will then send the browser an HTML document that contains the data, ready to be displayed. Making use of its own cache, Remix makes page reloads really fast. Remix will reload unchanged data from the cache, and only fetch new data. Forms Remix has a Form component, which is an enhanced HTML form component. Remix's Form component requires no onChange, onClick, or onSubmit events on the form or its fields. Contrary to traditional React forms, there is also no need for useState fields per form input. Remix's Form component will automatically do a POST request to the current page route with all the form's data submitted. It can be configured to do PUT and DELETE requests as well. To handle requests from a form, a simple action method is needed. Forms have traditionally been a point of frustration with React apps. Remix's approach to forms allows developers to create forms without having to write lines and lines of boilerplate code. Routing Similar to Next.js, Remix uses the file system to define page routes. Remix is built on top of React Router v6. This means that all the React Router APIs can be used in a Remix application. Anything that works with React Router will work within Remix. When navigating using a Link tag, the Outlet tag from React Router will automatically render the link's content on the page. This makes it easy to build a hierarchy of nested routes. Nested routes Nested routes allow Remix to make apps really fast. Remix will only load the nested routes that change. Remix will also only update the single nested component that was updated by some user interaction. Nested Routes also provide nested CSS styling. This allows CSS to be loaded on a per page basis. When a user navigates away from a certain page, that page's stylesheet is removed. Error handling When a route in a Remix app throws an error in its action method, loader, or component, it will be caught automatically. Remix won't try to render the component. It will render the route's ErrorBoundary instead. An ErrorBoundary is a special component that handles runtime errors. It's almost like a configurable try/catch block. If a given route has no ErrorBoundary, then the error that occured will bubble up to the routes above until it reaches the ErrorBoundary of the App component in the root.tsx file (assuming TypeScript is used). Error handling is built into Remix to make it easier to do. If an error is thrown on the client side or on the server side, the error boundary will be displayed instead of the default component. This graceful degradation improves the user experience. Project setup Creating a new Remix project is as easy as using the following command in a terminal window. ` You'll be asked to pick a folder name for your app. You'll also be asked where you want to deploy. Select *Remix App server*. > Remix can be deployed in several environments. The "Remix App Server" is a Node.js server based on Express. It's the simplest option to get up and running with Remix. You'll then be asked to choose between TypeScript or JavaScript. The last step will ask you if you want to run npm install. Say yes. Once installed, Remix can be run locally by using the following terminal commands. ` Once Remix is running, you can go to localhost:3000 in your browser to see if the default Remix installation worked. You should see the following. Project structure Let's explore the project structure that Remix created for us. - The public/ folder is for static assets such as images and fonts. - The app/ folder contains the Remix app's code. - The app/root.tsx file contains the root component for the app. - The app/entry.client.tsx file runs when the app loads in the browser. It hydrates React components. - The app/entry.server.tsx generates a HTTP response when rendering on the server. It will run when a request hits the server. Remix will handle loading the necessary data and we must handle the response. By default, this file is used to render the React app to a string/stream that is sent as a response to the client. - The app/routes/ folder is where *route modules* go. Remix uses the files in this folder to create the URL routes for the app based on the naming of these files. - The app/styles/ folder is where CSS goes. Remix supports route-based stylesheets. Stylesheets that are named after routes will be used for those routes. Nested routes can add their own stylesheets to the page. Remix automatically prefetches, loads, and unloads stylesheets based on the current route. - The remix.config.js file is used to set various configuration options for Remix. > Any file ending with .client.* or .server.* is only available on the client or the server. Demos The default installation of Remix comes with demos that allow us to see some of Remix's defining characteristics in action. Forms and actions Head over to http://localhost:3000 in your browser. Click on the Actions link under the Demos In This App heading. This will give you a chance to try out Remix forms and their corresponding action methods. To view the code for this demo, take a look at the app/routes/demos/actions.tsx file. ` The action function above is a server-only function to handle data mutations. If a non-GET request is made to the page's route (POST, PUT, PATCH, DELETE), then the action function is called before the loader function. Actions are very similar to loaders. The only difference is when they are called. CSS and Nested routes Click on the Remix logo to go back to the welcome page. Now, click on Nested Routes, CSS loading/unloading to see how Remix allows certain CSS rules to only be included on specific routes and their children. To view the code for this demo, take a look at the files in theapp/routes/demos/about/ folder, as well as the app/styles/demos/about.css file for the route-based CSS. Linking to a nested page is as simple as: ` Linking back to a parent route from a nested route is as simple as: ` Routing and Error Boundaries Click on the Remix logo to go back to the welcome page. Now, click on URL Params and Error Boundaries to see how routing and error boundaries work in Remix. To view the code for this demo, take a look at theapp/routes/demos/params/$id.tsx file. Loader This route defines a *loader* function that is called on the server before providing data to the route. When a route needs to fetch data from the server, Remix uses the loader function to handle that responsibility. The loader function aims to simplify the task of loading data into components. Contrary to Next.js, API routes are not needed to fetch data for route components in Remix. Here is the loader function above the ParamDemo component. ` The ParamDemo component uses a useLoaderData hook to get the data from the loader function. In this case, that data is the id value of the URL parameter that is passed to the route. Error Boundary ` An ErrorBoundary component is rendered when an error occurs anywhere on the route. Error boundaries are helpful for uncaught exceptions that we don't expect to happen. Clicking on the *This one will throw an error* link will trigger the ErrorBoundary. Catch Boundary ` A CatchBoundary component is rendered when the loader throws a Response. The status code of the response can be checked from within the CatchBoundary by using the useCatch hook. Clicking on the *This will be a 404* and *And this will be 401 Unauthorized* links will trigger the CatchBoundary. Conclusion Remix is backed by some of the most talented engineers in the React community. Version 1.0 of this full stack React-based web framework was just released on November 22, 2021. It's now released under the MIT license and is open source, making it free to use. For more Remix tutorials, check out the following: - Developer blog - Jokes App...