239 lines
8.2 KiB
Markdown
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%" >}} |