Starting a new React project with support for TypeScript, Serverless, and Routing

Follow these steps to start and deploy a new React project right from your localhost with support for TypeScript, serverless, and routing using Vite and Vercel CLI. If you wish to jump start your project without going through these steps, simply clone this repo: https://github.com/smohadjer/boilerplate-react-serverless-vite

mkdir my-project
cd my-project
npm create vite@latest -- --template react-ts .
npm install
npm run dev

Now your react project with TypeScript support is available at: http://localhost:5173/

Adding serverless support

We use Vercel's free serverless platform for running our application. If you don't have Vercel CLI, install it first:

npm i -g vercel

Create an api folder in root and add a test.js file with following content:

// api/test.js
import fs from 'fs';
import path from 'path';

export default async (req, res) => {
  const jsonPath = path.join(process.cwd(), 'data', 'data.json');
  const jsonFile = fs.readFileSync(jsonPath, 'utf8');
  const json = JSON.parse(jsonFile);
  res.setHeader('Content-Type', 'application/json');
  return res.json(json);
}

Now create a data folder in root and put a data.json with following content in it:

 [
    {
        "id": 1,
        "name": "Apple"
    },
    {
        "id": 2,
        "name": "Banana"
    },
    {
        "id": 3,
        "name": "Kiwi"
    }
]

Now create Home.tsx file in 'src' folder and paste the following inside:

import { useState, useEffect } from "react";

interface Item {
    id: string;
    name: string;
}

export function Home() {
    const [data, setData] = useState([]);

    useEffect(() => {
        fetch('/api/json-server')
        .then(res => res.json())
        .then(json => {
            setData(json);
        });
    }, []);

    return (
        <ul>
        {
            data.map((item: Item) => {
                return <li key={item.id}>Item {item.id} {item.name}</li>
            })
        }
        </ul>
    )
}

Now open src/App.tsx, remove all content and paste the following instead:

import { Home } from './Home';

export default () => {
    return (
        <Home />
    )
}

Now in terminal run vercel dev and answer questions asked in cli. Then open http://localhost:3000 and you have to be able to see a list of fruits rendered in your browser. To deploy live run:

vercel --prod

Adding Routing

If you wish to add routing to your project, follow the next steps:

  • run npm i react-router-dom
  • open src/main.tsx and replace its content with the following:
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from "react-router-dom";
import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
     <BrowserRouter>
        <App />
     </BrowserRouter>
  </React.StrictMode>,
)
  • create src/About.tsx with following content:
export function About() {
    return (
        <h1>About</h1>
    )
}
  • replace content of src/App.tsx with the following:
import { Routes, Route } from "react-router-dom";
import { Home } from "./Home";
import { About } from "./About";

export default function App() {
    return (
        <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
        </Routes>
    );
}
  • add a link to about page on the home page by adding the following two changes in src/Home.tsx:
...
// import Link 
import { Link } from 'react-router-dom';
...

    return (
        <>
            ...    
            {/* using Link component for navigation */}
            <p><Link to="/about">About</Link></p>
        </>
    )

Now if run vercel dev and go to http://localhost:3000 you will see the homepage and if you click the About link you will go to about page without a page reload from the server.

If you deploy to Vercel you may notice that reloading any page except the index.html will throw a 404 error. To fix this problem we should redirect all page requests to index.html so that react router can then take over the routing task. We do this by adding a rewrite rule for each request to vercel.json in root of the project:

{
    "rewrites": [
        { "source": "/about", "destination": "/" }
        { "source": "/about:path", "destination": "/" }
    ]
}