End-to-End Guide To Remix, a Full Stack Web Framework | by Jennifer Fu | Mar, 2022

That helps you build faster and cleaner

Photo by Krys Amon on Unsplash

It includes esbuild, React Router, server-side rendering, production server, and backend optimization.

Remix is ​​a full-stack web framework that focuses on the user interface and works back through web fundamentals to deliver a fast, slick, and resilient user experience.

Since the formal release on October 2021, Remix has gained steam to be a widely adopted React framework.

Image by author

Remix comes with a number of advantages:

  • It compiles with esbuild, an extremely fast JavaScript/CSS bundler and minifier.
  • It uses progressive enhancement on the server side. Only necessary JavaScript, JSON, and CSS content are sent to the browser.
  • It performs dynamic server-side rendering.
  • It knows when to refetch mutated data, as Remix oversees the whole workflow.
  • It includes an end-to-end solution with React Router, server-side rendering, production server, and backend optimization.

Run the following command to install Remix:

% npx create-remix
npx: installed 210 in 10.198s
R E M I X - v1.2.3💿 Welcome to Remix! Let's get you set up with a new project.? Where would you like to create your app? remix-app
? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets. Remix App Server
? TypeScript or JavaScript? JavaScript
? Do you want me to run `npm install`? Yes

There are a few choices during the installation.

  • The Remix framework is installed in the folder, remix-app.
  • There are a number of servers to choose from. The choices are Remix App Server, Express Server, Architect (AWS Lambda), Fly.io, Netlify, Verceland Cloudflare Pages. We use the default,Remix App Serverwhich is a full-featured Node.js server based on Express.
  • There is also a choice between TypeScript and JavaScript. In this article, JavaScript is chosen.

After the installation, the folder, remix-applooks like this:

├── README.md
├── app
│ ├── entry.client.jsx
│ ├── entry.server.jsx
│ ├── root.jsx
│ └── routes
│ └── index.jsx
├── node_modules
├── package.json
├── package-lock.json
├── public
│ └── favicon.ico
├── .eslintrc.js
├── .gitignore
├── remix.config.js
└── jsconfig.json
  • app/entry.server.jsx: It is the first bit of JavaScript that will run when a request hits the server. Remix loads only the necessary data, but developers need to handle the response. This file is used to render the React app to a string/stream that is sent as a response to the client.
  • app/root.jsx: It is the root component for the application. It is equivalent to Create React App’s App.js. <LiveReload /> (line 27) is explicitly coded, which is recommended for development.
  • app/routes: It is the directory that hosts all routes.
  • app/routes/index.jsx: It is the indexed route that is invoked by default.
  • public: It is the directory that hosts static assets and the production build.
  • public/favicon.ico: It is the Remix icon displayed for the browser tab and bookmark.
  • remix.config.js: It is the Remix configuration file.
  • jsconfig.js: It is the JavaScript configuration file.

The app can be executed in the develop mode:

npm run dev

It can also be executed in the production mode:

npm run build
npm start
Image by author

Out of the box, we have React Router, server-side rendering, and production server.

The above official example has static links to external websites. Write app/routes/index.jsx to link to internal pages.

Line 9 is a link to the route, "/one".

Line 12 is a link to the route, "/two".

The page looks fine.

Image by author

But, clicking on either of the links shows a 404 error.

Image by author

Remix Router uses the file system to define page routes. There are two ways to handle this. The recommended way is to implement the missing page inside the route directory as an index file, ie app/routes/one/index.jsx:

Now the page works:

Image by author

The second way is to name the file as the route, ie, app/routes/two.jsx:

Here is the page:

Image by author

Remix Router supports React Router, including nested routes and dynamic parameters.

In Remix, most of the routes are composed of APIs and UI components. APIs interact with the backend, while UI components are displayed in the browser. Remix APIs simplify and optimize interactions with the backend, including how to get data into components and when to perform data mutations.

The loader function is a special API. It is exported to be called on the server before rendering. It typically fetches data from the backend.

Then, UI components render the page using the loaded data via the hook, useLoaderData.

We have written an article, Set Up and Use MySQL in Create React App Environment. Let’s see how easy it is to set up and use MySQL in the Remix environment.

Set up mysql (mysql2 works similarly), the JavaScript client for MySQL protocol:

npm i mysql

mysql becomes part of dependencies in package.json.

Modify app/routes/index.jsx to be the following:

Lines 4–9 define the user configuration.

Lines 11–13 create MySQL connection using the user configuration. Line 12 enables multiple statements, which are disabled by default to avoid possible SQL injection attacks.

Lines 15–25 define the loader function, which connects to the database to query the student table (line 16). If there is an error, the promise is resolved to null (line 19). Otherwise, the first row of the MySQL table is returned (line 22), assuming that there is at least one row.

Line 28 calls useLoaderData to retrieve the loaded data, which is rendered at line 33.

There is no need to restart the server. npm run dev is similar to nodemonwhich automatically monitors the code changes and rebuilds the changes.

However, there is an error on the browser console:

What a cryptic error message!

This error occurs when the server-side dependencies get bundled in the client scripts.

In order for Remix to run the app in both the server and browser environments, application modules and third-party dependencies you need to be careful about module side effects. The Remix compiler automatically removes server code from the browser bundles. In the above code, lines 11–13 create MySQL connection, which is the server code. The loader is gone but the mysql dependency stayed. The browser cannot handle the mysql module properly.

To fix this, remove the side effect by simply moving the code inside the loader function, along with the user configuration.

It works now.

Image by author

But, are we going to create a MySQL connection every time the loader function is called?

A better way is to create a MySQL connection inside app/entry.server.jsx (lines 30–32):

Then, app/routes/index.jsx simply imports the connection (line 2):

The <Form> component is a declarative way to perform data mutations: creating, updating, and deleting data. Remix’s Form is an enhanced HTML form component. Instead of using React event handlers, such as onClickthe route exports the action function that is called upon form submission. useState is not needed to maintain field values.

Similar to the loader function, there is the action function, which is invoked upon form submission. Similar to the hook, userLoaderDatathere is a hook for the action function, useActionDatawhich captures the returned data from the action function.

We use action and useActionData to build up our example with the ability of modifying the student’s grade.

Image by author

Here is the adapted app/routes/index.jsx:

Lines 17–33 define the action function, which reads the form submission data (lines 18–19) and connects to the database to update the student table (line 22). If there is an error, the promise is resolved to an error message (line 26). Otherwise, it returns a successful message (line 28).

Line 37 calls useActionData to retrieve the action result, which is rendered at line 50.

The Form component is added at lines 44–49.

Save the changes, and type 4 in the input field. Upon hitting enter, the value is sent to action to update the database. Remix detects data mutation and calls loader to retrieve the latest value to be displayed.

Image by author

If the input is invalid, the error message is displayed.

Image by author

The flow between Remix App Server and the backend is seamless. No boilerplate code is needed.

We have gone through how to use Remix. It has a lot of advantages, and the most noticeable one is speed — It is fast to load the page in the browser, and it is fast to develop the end-to-end application. Remix is ​​a full-stack Web framework that includes esbuild, React Router, server-side rendering, production server, and backend optimization.

We have written about these features in a number of articles. With Remix, they are all available, boilerplate-free.

Any disadvantages to Remix?

Yes, Remix is ​​still new. Error reporting needs improvement. For example, if we want a server on an occupied port, it does not report an error or suggest a different port. When it reports errors, some error messages are too cryptic.

Regardless, Remix has gained steam to be a widely adopted React framework.

Thanks for reading. I hope this was helpful.

Leave a Comment