Files
web-log/container/site/content/posts/react-app-resurrection/index.md
T
2025-07-05 15:36:34 +00:00

239 lines
8.2 KiB
Markdown

+++
categories = ["software"]
tags = ["react","typescript","javascript"]
date = 2025-04-12T00:00:00-06:00
description = ""
draft = false
slug = "react-app-resurrection"
title = "⚛️ React App Resurrection"
author = "nicholas"
+++
[Project git repo](https://git.uuard.com/nicholas/storage-manager)
A few years ago the company I work for explored the idea of rewriting older **ASP.NET** and **Backbone.js** features in a more modern web framework. Between the two contenders, **React** and **Vue**, the development team was leaning toward Vue. Each developer went off and built a small feature or two using Vue to get a sense for it before we eventually committed to rewriting with it. I raised no objections to the decision because it did not matter to me, and I like Vue just fine.
Eventually, though, I wanted to try building something with React, so I contrived the simplest possible project that would force me to understand at the very least the fundamentals of React. This is why I created this in the first place.
The app is a simple CRUD app that manages *boxes*, which can contain *items*. I rewrite the app with TypeScript and clean it up a little bit.
## Technology Stack
I am using the **MERN** tech stack:
- **M**ongoDB (Database)
- **E**xpress.js (Backend framework)
- **R**eact (Frontend framework)
- **N**ode.js (Backend runtime)
There are a couple main goals I want to accomplish:
1. Get the app working
2. Upgrade to **Vite** from **Create React App**
3. Update Packages
4. Typescript rewrite, refactor using *better* practices
## 1. Get the App Working
The first thing I will do is get the **database** working. This is straightforward minus a small hiccup: my server runs on an *Intel Pentium Gold G5400*, and **MongoDB versions 5+ cannot run without the AVX instruction set extension**, which is regrettably absent in the spec sheet.
{{< image
src="images/pentium-gold-g5400-instruction-set-extensions.jpg"
caption="Pentium Gold G5400 Instruction Set Extensions - AVX missing" >}}
So I will use a very old version of mongodb (`mongo:4.4.6`) to get the app working.
Here is my `compose.yml` file. The container also includes Mongo Express which will allow me to manage my databases with a web interface rather than manage it through the command line. The environment variables are stored in `.env` file.
**compose.yml**
```yaml
services:
mongo:
container_name: mongo-db
image: mongo:4.4.6
networks:
- mongo-network
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
ports:
- 27017:27017
mongo-express:
container_name: mongo-express
image: mongo-express
networks:
- mongo-network
restart: always
ports:
- 8999:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: ${ME_CONFIG_MONGODB_ADMINUSERNAME}
ME_CONFIG_MONGODB_ADMINPASSWORD: ${ME_CONFIG_MONGODB_ADMINPASSWORD}
ME_CONFIG_MONGODB_URL: mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo:27017/
ME_CONFIG_BASICAUTH: false
networks:
mongo-network:
name: mongo-network
```
**.env**
```env
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=<password>
ME_CONFIG_MONGODB_ADMINUSERNAME=admin
ME_CONFIG_MONGODB_ADMINPASSWORD=<password>
```
`docker compose up -d`
This will start the Mongo DB and Mongo Express.
---
Next I need to edit the `server.js` connection string to match the credentials, port, and host:
```javascript
require('dotenv').config();
const DB_HOST = 'server';
const DB_PORT = 27017;
const DB_USERNAME =process.env.DB_USERNAME;
const DB_PASSWORD = process.env.DB_PASSWORD;
const connectionString = `mongodb://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}?authMechanism=DEFAULT`;
```
Once again, I am using a `.env` file to keep the username and password secret.
Now I start the **server** and the **client** with `npm run start`.
{{< image
src="images/server-db-connection-success.jpg"
caption="server connected to database" >}}
---
It could use some refinement, but it is working as expected.
{{< video
src="videos/testing-react-app-2x-speed.mp4"
width="100%" >}}
## 2. Upgrade React-Scripts → Vite
I will upgrade the app font end to use **Vite** build tools. The app was originally built with **Create React App**, but this was deprecated in favor of other tools such as Vite, Parcel, and RSBuildVite.
{{< image
src="images/create-react-app-deprecation.jpg"
caption="Create React App Deprecation blog post" >}}
First I scaffold a new Vite project: `npm create vite@latest` and select the following options:
- project Name: **client**
- framework: **React**
- variant: **Typescript**
{{< image
src="images/vite-scaffold-project.jpg"
caption="Scaffold Vite project" >}}
I do some work to hook everything up, then run the dev build.
`npm run dev`
{{< image
src="images/vite-run-dev.jpg"
caption="Vite run dev" >}}
It built the site in `121 ms`. Very nice.
## 3. Package Updates
There are a few outdated packages that I should update. I run `npm install <package>@latest`;
I verify that I do not have any remaining deprecated, old, bad packages:
- `npm audit`
- `npm outdated`
- `npm ls deprecated`
**server packages check**
{{< image
src="images/client-package-upgrades.jpg"
caption="Client packages check" >}}
**client packages check**
{{< image
src="images/server-package-upgrades.jpg"
caption="Server packages check" >}}
## 4. Javascript → Typescript Rewrite
The project was sort of a mess anyway, so I will rewrite it in Typescript as I clean it up. The logic and UI handling made the `app.js` component very fat indeed. I was handling all of the state there, prop-drilling all the way down. It worked, but it did not accord with best practices. Undoubtedly it still does not accord entirely with best practices, if this is even a meaningful concept, but surely I have improved it somewhat anyway. The point was to revive an old project, touch something with React again, and to write some TypeScript, for it is new to me. I liked it.
Anyway, there is nothing very interesting about the process of rewriting to TypeScript. The results are positive. Javascript with types, among other additional features. I extracted some components, restructured the directory, and ended up with a **front-end** directory like so:
### Client / Front-end
```
└── 📁src
└── 📁api
└── api.ts
└── apiResponse.types.ts
└── index.ts
└── 📁components
└── ColorSelector.jsx
└── GenericMenu.tsx
└── Modal.tsx
└── 📁features
└── 📁box
└── box.types.ts
└── 📁components
└── BoxCard.tsx
└── BoxFormModal.tsx
└── index.ts
└── 📁services
└── BoxService.tsx
└── 📁item
└── 📁components
└── ItemCard.tsx
└── ItemFormModal.tsx
└── index.ts
└── item.types.ts
└── 📁services
└── ItemService.tsx
└── 📁icons
└── Ellipsis.tsx
└── Garbage.tsx
└── Icon.tsx
└── index.ts
└── Move.tsx
└── Pencil.tsx
└── Plus.tsx
└── Search.tsx
└── .env
└── app.tsx
└── index.css
└── index.tsx
└── tsconfig.json
└── vite-env.d.ts
```
### Server / Back-end
This is a very simple flat directory containing the web API server.
```
└── 📁server
└── .env
└── .gitignore
└── package-lock.json
└── package.json
└── server.js
```
### Database
As I mention above, the MongoDB database is hosted in a Docker container.
```
└── 📁database
└── .env
└── .gitignore
└── compose.yml
```
## Results
It works. The app source is hosted on my [git repository](https://git.uuard.com/nicholas/storage-manager)
{{< video
src="videos/demo-react-app.mp4"
width="100%" >}}