Overview
Let’s talk about React.js!
Of course, Python will always be my native tongue, and it’s the best, no doubt! But if I had to pick a second place, it would be JavaScript and TypeScript. Among the frontend frameworks for JS and TS, one of the most well-known is React.js.
This time, I'll walk you through:
- Using
yarn
, - Setting up
react
, - Introducing
vite-tsconfig-paths
to enable writingsrc/
as@/
, - Preparing basic layers for pages, components, and utils,
- Incorporating
react-router-dom
to make it a SPA, - Deploying it to GitHub Pages,
up to the stage just before adding your own unique touch.
Points to Note
- Project name: my-react
- In this article, the project name (= GitHub repository name) is
my-react
. Feel free to replace this with any name you prefer.
- In this article, the project name (= GitHub repository name) is
- For GitHub Pages, we won’t use a custom domain; instead, we’ll keep it simple with
https://foo.github.io/my-react/
.
...Honestly, I don’t think there are many programming enthusiasts among the dear readers of Midori HP!
Using yarn
Get node
and yarn
ready. Use version 1 of yarn
.
node --version
# --> v20.11.0
yarn --version
# --> 1.22.22
Setting up react
yarn create vite my-react -- --template react-swc-ts
# Created with React + TypeScript + SWC
cd my-react
yarn install
# yarn.lock
yarn list react
# --> └─ react@18.3.1
# NOTE: Warnings may appear, but that’s due to yarn list lacking exact match search.
yarn dev --host
# Yep, it opens.
yarn build
# Great, the dist folder is created.
yarn preview --host
# Nice, the content in dist opens.
# *.tsbuildinfo is a build cache, so exclude it from version control.
Deploying to GitHub Pages
Personally, I like to set up the deployment environment right at the start. After all, the deployment environment is the goal, so it makes sense to establish it early on.
First, set the base URL in vite.config.ts
like this:
// Add this in vite.config.ts...
export default defineConfig({
base: '/my-react/', // <-- This part
})
Here's a sample yaml for deploying to GitHub Pages. Pushing this to GitHub will create a gh-pages
branch. Then, go to Settings > Pages and publish that branch.
# .github/workflows/deploy-react-application.yml
name: Deploy React Application
on:
workflow_dispatch:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
# The one that’s easy to forget.
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: yarn install
- name: Build
run: yarn build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Default build output for React is dist.
publish_dir: ./dist
Introducing vite-tsconfig-paths
Writing imports like ../../../components/Button
is too much of a hassle, so let’s make it possible to write @/components/Button
instead.
yarn add -D vite-tsconfig-paths
# Installed vite-tsconfig-paths
Referencing the official README, add the following to vite.config.ts
:
// vite.config.ts
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
base: '/my-react/',
plugins: [react(), tsconfigPaths()],
})
It’s not very clear in the official README, but you’ll also need to edit tsconfig.json
like this:
// tsconfig.json
{
"compilerOptions": {
// ... omitted for brevity ...
// Configuration for vite-tsconfig-paths to map @ to src/.
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"]
}
Note that in recent setups, tsconfig
might be split into multiple files. If your tsconfig.json
looks like this:
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
The baseUrl
and paths
configuration should go in tsconfig.app.json
, not tsconfig.json
. As a rule of thumb, make changes in the file that already contains include
.
// tsconfig.app.json
{
"compilerOptions": {
// ... omitted for brevity ...
// Configuration for vite-tsconfig-paths to map @ to src/.
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"]
}
Creating layers for pages, components, and utils
Starting with an empty React setup can leave you wondering where to go next. Let’s establish a foundation.
# Create folders.
mkdir -p src/{pages,components,utils}
# Create src/components/Button.tsx
echo 'type ButtonProps = {
label: string
onClick: () => void
}
function Button({ label, onClick }: ButtonProps) {
return <button onClick={onClick}>{label}</button>
}
export default Button' > src/components/Button.tsx
# Create src/utils/formatDate.ts
echo 'function formatDate(date: Date): string {
return date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})
}
export default formatDate' > src/utils/formatDate.ts
# Create src/pages/HomePage.tsx
echo 'import Button from "@/components/Button"
import formatDate from "@/utils/formatDate"
import { useEffect, useState } from "react"
function HomePage() {
const [formattedDate, setFormattedDate] = useState<string>('')
useEffect(() => {
const currentDate = new Date()
const dateStr = formatDate(currentDate)
setFormattedDate(dateStr)
}, [])
const handleClick = () => {
alert("Button clicked!")
}
return (
<div>
<h1>Welcome to the Home Page - {formattedDate}</h1>
<Button label="Click Me" onClick={handleClick} />
</div>
)
}
export default HomePage' > src/pages/HomePage.tsx
# Create src/pages/NotFoundPage.tsx
echo 'function NotFoundPage() {
return (
<div>
<h1>Not Found</h1>
</div>
)
}
export default NotFoundPage' > src/pages/NotFoundPage.tsx
Now the files are set up, but HomePage.tsx
isn’t in use yet. We’ll handle that in the next step.
Using react-router-dom to utilize pages
Install the package and edit main.tsx
and App.tsx
.
yarn add react-router-dom
echo 'import App from "@/App"
import "@/index.css"
import React from "react"
import ReactDOM from "react-dom/client"
import { BrowserRouter } from "react-router-dom"
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<BrowserRouter basename="/my-react">
<App />
</BrowserRouter>
</React.StrictMode>
)' > src/main.tsx
echo 'import "@/App.css"
import HomePage from "@/pages/HomePage"
import NotFoundPage from "@/pages/NotFoundPage"
import { Route, Routes } from "react-router-dom"
function App() {
return (
<Routes>
<Route path="/" element={<HomePage />} />
{/* All other paths lead to 404 */}
<Route path="*" element={<NotFoundPage />} />
</Routes>
)
}
export default App
' > src/App.tsx
And that's it!
Wrapping Up
Pushing this setup to GitHub Pages should make it work like this:
From here, you can add more screens by expanding the pages, add more UI components by growing the components, or centralize logic by expanding utils! Having a foundation like this makes the process so much easier.
I started with React.js thinking it might be a good fit for the front end of Midori HP. Vue.js was also an option, but since Vue 3 seems to have taken on some characteristics of React.js, I figured, “Hmm, maybe React.js is the better choice?”