Migrating Remix web applications to Node 20 and React Router v7

As Upgrading from Remix to React Router states “React Router v7 is the next major version of Remix after v2”. React Router v7 now contains the functionality of @remix-run/node, @remix-run/cloudflare, etc.

To upgrade from Remix to React Router 7

Upgrade Node to version 20

React Router v7 requires Node.js version 20 or higher, so at the time of writing most users have to upgrade Node.js.

If you used Homebrew to install Node.js, execute the commands

brew update       # Update Homebrew
brew tap --repair # If brew notifies you about broken references
brew upgrade node # Update Node.js to the latest stable version

Create a new Remix site using the React Router framework

Follow the instructions at React Router Installation.

At the time of writing these are the recommended steps:

Create the base application

npx create-react-router@latest my-react-router-app
  • The process will create a folder matching the name of the application you specify, and will add that name to the package.json file as the “name” element.
  • The .git directory, and the .gitignore file will be placed in the application directory. As an application repository usually contains more than just the web application, like Terraform scripts, documentation, move the .gitignore file higher, remove the .git directory and recreate the repository with the git init command in the top level directory of your application.
  • Update the .gitignore file, and remove the leading slashes from all lines, as the node_modules, .react-router, and build directories are not in the root directory anymore.
.DS_Store
node_modules/

# React Router
.react-router/
build/

Install the Node.js packages

cd my-react-router-app
npm i

Run the application

npm run dev

Navigate to http://localhost:5173 to view it in the browser.

Copy and update the source code

  • Copy the app/models, app/routes/, app/styles directories into the app folder of the new base application structure.
  • Execute the codemod to update the package references
    npx codemod remix/2/react-router/upgrade

Make the application work

Separate files for server side and client side functions

To make the application work using the new framework and the Vite development tools, we have to make sure the client side files do not reference any modules that are not available in the browser. These include imports of our functions with database access.

The Remix compiler in the past could reference the server side and client side functions from common helper files. Vite needs separate files for the server side and client side.

If a client side file imports a function that contains references to functionality that is not available in the browser, like file system or database access the application compiles without error, the server starts without error, but we will find error messages in the console window of the browser.

Module “events” has been externalized for browser compatibility. Cannot access “events.EventEmitter” in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.

Uncaught ReferenceError: process is not defined
at node_modules/pg/lib/defaults.js

In this example our client side helper file only imported, but not called a function that accessed the PostgreSQL database.

Another example, when a function (logInfo) is imported from the server side file, but not used.

Solution: Delete the unused references

To import only a URL

RollupError]: “default” is not exported by ‘./index.css’ imported by “app/index.tsx”.

Style sheets are not compiled into the code, only the browser needs access to them to render the page. To reference style sheets, we only need to import the URL, so the compiler can make sure those are available and include them in the build. To import only the URL, add ?url to the end of the style sheet path.

import { LinksFunction } from "@remix-run/node";

-import styles from "./index.css";
+import styles from "./index.css?url";

Render UI only in the browser

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
or
React.jsx: type is invalid — expected a string (for built-in components) or a class/function (for composite components) but got: object.

Vite tries to render client side elements in the server. In the client side code render client side code only in the browser.

  // Check if the code is running in a browser
  const [isClient, setIsClient] = React.useState(false);
  React.useEffect(() => {
    setIsClient(true);
  }, []);
  
  # Render the UI
  return (
    <>
      {isClient ? (
        <Header/>
      ):null}

      {isClient ? (
        <div>
        ... The rest of the UI
        </div>
      ):null}

      {/* Display the Footer component */}
      {isClient ? (
        <Footer/>
      ):null}
      </>

  );

Custom image in the expandIcon

During the migration the compiler did not accept the Material UI icon library. You can use a custom PGN image for the expandIcon of the AccordionSummary:

<AccordionSummary
  expandIcon={<img src="/expand-more-down.png" />}
...

Error: Dev server origin not set

We can set up a new Remix web application based on the Getting Started guide at Remix Quick Start

We will encounter a few surprises during the setup:

We need to allow legacy dependencies during the command:
npm i -D @remix-run/dev vite --legacy-peer-deps

When we try to run the application, we get the error message:

Error: Dev server origin not set

To be able to run the application in the development server set the NODE_ENV variable to production. In the terminal execute

NODE_ENV=production

As a permanent fix, always run the application with these commands

NODE_ENV=production
npx remix-serve build/server/index.js

sh: remix: command not found

When I tried to refresh Node.js packages, I have received the following error message:

sh: remix: command not found

The steps described at ERESOLVE could not resolve While resolving: remix-utils@8.1.0 cleared the cache and reinstalled all package versions to satisfy the package dependency requirements.

ETIMEDOUT: connection timed out, read [plugin browser-route-module]

When NPM, the Node Package Manager finds dependency version conflicts, we can help it to solve those by executing the steps described at ERESOLVE could not resolve While resolving: remix-utils@8.1.0

After the package reinstallation, when I tried to run my application, I have received the error message:

ETIMEDOUT: connection timed out, read [plugin browser-route-module]

I had to reboot my computer to be able to run the application again. Most likely that closed running processes and cleared memory caches of old packages.

ERESOLVE could not resolve While resolving: remix-utils@8.1.0

NPM, the Node Package Manager for Node.js applications and web sites, always tries to find the latest versions of all packages your application can use. If some packages require different versions of the same dependency, an error is displayed, for example:

ERESOLVE could not resolve While resolving: remix-utils@8.1.0

To resolve the conflict we will try to help NPM to start with a fresh environment. Open a terminal in the root directory of your application and execute these commands:

  • Delete the node_modules directory and the package-lock.json file:
    rm -rf node_modules package-lock.json
  • Clear the NPM cache:
    npm cache clean --force
    • On some macOS systems you don’t have enough permissions to access the .npm directory, so execute the command:
      sudo chown -R 504:20 "/Users/YOUR_USER_NAME/.npm"
  • Reinstall all NPM packages allowing older versions to satisfy all package dependency requirements:
    npm install --legacy-peer-deps

After the package reinstallation, when I tried to run my web application, I have received the error message:

ETIMEDOUT: connection timed out, read [plugin browser-route-module]

I have restarted my computer to stop all processes and clear memory caches. See ETIMEDOUT: connection timed out, read [plugin browser-route-module]

Using the Visual Studio Code Debug Console

When we activate the Debug feature of Visual Studio Code, the Terminal displays the console output.

To find the correct location of data among the objects and variables, we can use the Debug Console.

Start the application in debug mode

  • Set up your application in the debug configuration file
  • Set a breakpoint in your code by clicking the margin. When you add or remove a breakpoint, you always have to stop and start the debug session for the debugger to notice the change.
  • Start the application with the debugger

Explore the object and variable values in the Debug Console

  • Select the Debug Console at the bottom of the screen
  • Type the name of the object to see its value
  • Expand the elements to see their structure
  • Use dot notation to display the value of elements. Use the same in your code to access the value runtime.

TypeError: (0 , _styledEngine.internal_processStyles) is not a function

Node.js packages are constantly updated, and the developers usually test those against the latest versions of other packages. When our application uses older packages, a single package update can cause errors and the application will stop with an error, like

TypeError: (0 , _styledEngine.internal_processStyles) is not a function

Usually a global update of all Node.js packages can bring those to the latest allowed version and solve the incompatibility error.

  • Open a terminal in the application root directory
  • Execute
    npm update

Electric Car Owner’s Thoughts

Electric cars are awesome. We still have an older gasoline car for road trips, the EV is for a long daily commute to save money on gasoline, and maintenance. To protect the environment, we have selected 100% renewable energy source at our local electric company, and the plan which is available for EV owners (and electric heat pump air conditioner users) to purchase electricity at discounted rate outside of prime usage hours.

Range

As it is better for the battery to operate it between 10% and 80%, the everyday usable range of an electric car is around 70% of the advertised one. With a 290 mile advertised range car, you can reasonably expect a 200 mile range, which will bring down the battery to 10% without any safety margin.

If you charge the car to 100% before a long trip, the maximum range is still around 260 miles, as you don’t want to deplete the battery below 10%. This calculation does not even account for any extra miles in case the planned charging station is occupied or does not work. For peace of mind, even with 100% charge, I would plan to charge the car every 200 miles to make sure no tow truck is necessary to continue the trip. If the battery is dead, you need to have the car towed to the nearest charging station, as currently, there are no mobile charging trucks on the road.

You also need to know, that fast charging considerably slows down above 80% battery charge level to protect the battery from overheating, so on the road, do not expect to have enough time to charge above 80%. This will only give you a maximum 200 mile, and a 140-160 mile safe range for your second leg of the day. So electric cars are great for commute, and driving around town, but not yet practical for longer trips.

Charging

Home charger

Plan in advance

When we had to wait three weeks for the charger installation, we had to find a way to charge the car. As there are no Level 2 public chargers in walking distance, we need to use the EVgo fast chargers during this period. The daytime fast charging cost is $0.66/kWh, plus a $0.99 transaction fee which is comparable to $6.00/gallon gasoline price. At the time of writing, in our area we can buy gasoline at around $4.05/gallon, so this can only be temporary. At home we can expect $0.26/kWh during night time charging, which will be comparable to $2.40/gallon gasoline.

If you are really sure you want to buy an electric car, it is a good idea to at least have the electrical connection installed, so you only need to install the charger when you buy the car. We have received a free Level 2 changer in the mail two weeks after the car purchase from the car manufacturer.

As the Level 2 changers only need 240V, it is enough to install only two hot and one ground lines and a three prong 6-50 50A outlet. There is no real need for the neutral line and the 14-50 four prong outlet.

CHECK THE REQUIREMENTS OF THE CHARGER, THE PLUG TYPE, AND CONSULT WITH AN HONEST ELECTRICIAN TO CONFIRM THIS.
Many electricians charge for the fourth (neutral) wire installation, and never connect it to anything.

If the charger is not hot wired, and comes with an already installed plug, it only takes a few minutes to mount it on the wall under the already installed 240V 50A outlet, anyone with a power drill can do that. Make sure the outlet is compatible with the plug of the charger. In the worst case, an electrician can replace the plug at the end of the charger’s power cable if a new changer comes with a different plug.

Installation cost

As the electric panel of our building is at the opposite end, it will cost us $3,200 to bring the electricity to our parking spot from 130 feet away, and install the charger. For very short distances, the installation cost is around $250 – $500. When you buy the car, calculate with the charger installation cost. Preferably get an estimate from a few electricians to see if it is even possible to install the home changer, and how much it will cost.

Charging schedule

Most likely your can is smart enough to wait for the best time to start charging. In our area between 9:00 pm and 4:00 pm the next day is the least expensive to use electricity at $0.26/kWh. I have programmed my car to start charging during these hours to save as much as possible.

Charging at public Level 2 changers

Some businesses, like Wholefoods, have free Level 2 charging spots around the store. You can get approximately 30 miles of charge in an hour, if you are one of the lucky ones to find an available charger. This is obviously not sufficient on longer road trips, but helps to put some free electric charge into your battery while shopping for groceries.

Charging on the go

For longer road trips check the location and the number of working fast chargers along your route.

Things to consider
Available changers

Expect occupied and broken chargers.

If the app you use, shows a few available chargers at a location, it can be occupied in the next minute, just before you arrive there, or it is not working, that is why it is always available. When you encounter a broken charger, please call the customer service number posted on the charger and report it, as most people think someone else already did that. You will be surprised how many times you are the first one to report a non-working charger.

Charging times

Real charging times can be more than twice as long as advertised.

Our car is capable of 150kW fast charging between 10-80%. Even on 350kW EVgo CCS fast chargers at 65-70ºF (18-21ºC) comfortable air temperature, it only charges at the maximum of 60-70kW rate. We have not yet tried to charge above 80%, that will be even slower to protect the battery. As you can expect more than twice the charging time of the advertised one, it may adds considerable time to your trip.

Driving

One pedal driving

To fully take advantage of the regenerative breaking, enable one pedal driving. When you lift your foot off the accelerator, the car starts to slow down, many cars even stop, while recharging the battery. On a steep enough downhill road you can recover most of the extra energy you used to climb up. We usually regain 4-5 miles on a longer downhill slope. In city traffic you don’t have to worry about stop and go traffic anymore, you regain most of the extra energy spent during acceleration. Of course nothing has 100% efficiency, so you never gain all spent energy back.

Watch your speed

Stay within the speed limits.

At highway speeds most of the energy is spent on countering wind resistance. As we remember from our physics studies, there is an exponential relation between speed and wind resistance. When you double the speed, the wind resistance and energy usage quadruples. If you feel you are scraping the bottom of the battery to get home, it is not the time for speeding, stay within the speed limits.

HOV lane access

In our state, zero emission car owners can request a decal from the DMV once the permanent license plate arrives. It allows the car to use the high occupancy vehicle, HOV lanes (carpool lanes) even with one person in it. During rush hours this can save considerable time.

Free parking

Some cities allow zero emission vehicles with the HOV decal attached, to park for free at parking meters.

Convenience

As mornings can be chilly or hot, our car can automatically start the climate system based on a schedule. We programmed it to heat or cool the car to 72ºF (22ºC) every weekday a few minutes before the driver leaves the house.