lunx.docs
DocsTutorialsYour First Project

Your First Project

Build a complete React application with Lunx from scratch. This tutorial covers project creation, routing, API integration, and deploying a production build.

What you'll build

By the end of this tutorial you'll have a fully working React + TypeScript app with:

  • Client-side routing via React Router v6
  • A data-fetching hook that calls a public REST API
  • Tailwind CSS styling with dark mode support
  • A production build with SRI hashes and SBOM
01
Create the project

Use the Lunx CLI to scaffold a React + TypeScript project with Tailwind CSS.

bash
npm create lunx-dev@latest lunx-demo -- --framework react --ts --tailwind
cd lunx-demo && npm install
02
Install React Router

Add client-side routing. Lunx handles the SPA fallback automatically — no extra config needed.

bash
npm install react-router-dom
03
Set up routes in main.tsx

Wrap your app in BrowserRouter and define your top-level routes.

typescript
// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
)
04
Build the App component with routes

Define page routes and a shared navigation header.

typescript
// src/App.tsx
import { Routes, Route, Link } from 'react-router-dom'
import { HomePage } from '@/pages/HomePage'
import { UsersPage } from '@/pages/UsersPage'

export default function App() {
  return (
    <div className="min-h-screen bg-gray-950 text-gray-100">
      <nav className="border-b border-gray-800 px-6 py-4 flex gap-6">
        <Link to="/" className="font-semibold text-white">Home</Link>
        <Link to="/users" className="text-gray-400 hover:text-white transition">Users</Link>
      </nav>
      <main className="p-6">
        <Routes>
          <Route path="/"       element={<HomePage />} />
          <Route path="/users"  element={<UsersPage />} />
        </Routes>
      </main>
    </div>
  )
}
05
Create a data-fetching page

Fetch data from the public JSONPlaceholder API and display it with loading and error states.

typescript
// src/pages/UsersPage.tsx
import { useEffect, useState } from 'react'

type User = { id: number; name: string; email: string; company: { name: string } }

export function UsersPage() {
  const [users, setUsers] = useState<User[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then(r => r.json())
      .then(data => { setUsers(data); setLoading(false) })
      .catch(e => { setError(e.message); setLoading(false) })
  }, [])

  if (loading) return <p className="text-gray-400">Loading users...</p>
  if (error)   return <p className="text-red-400">Error: {error}</p>

  return (
    <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
      {users.map(u => (
        <div key={u.id} className="p-4 rounded-xl border border-gray-800 bg-gray-900 hover:border-blue-500/40 transition-all">
          <div className="font-semibold text-white">{u.name}</div>
          <div className="text-sm text-gray-400 mt-1">{u.email}</div>
          <div className="text-xs text-gray-600 mt-2">{u.company.name}</div>
        </div>
      ))}
    </div>
  )
}
06
Run and verify with HMR

Start the dev server. Edit any component — changes appear in the browser in ~18ms without losing application state.

bash
npm run dev
# ⚡ lunx v1.0.0  adapter: react  port: 5173
# ✓ ready in 36ms
07
Build for production

Run the production build. Lunx automatically scans for secrets, checks CVEs, generates an SBOM, and injects SRI hashes before writing output.

bash
npm run build

🔍 Security scan  0 issues
📦 dist/
  assets/main-4a2c1.js     112 kB  gzip: 35 kB
  assets/style-8d3f2.css    14 kB  gzip:  4 kB
  index.html                 1.1 kB
  bom.json                   8.4 kB
 built in 612ms

Project structure after tutorial

text
lunx-demo/
├── src/
   ├── pages/
      ├── HomePage.tsx
      └── UsersPage.tsx
   ├── components/
      └── UserCard.tsx
   ├── hooks/
      └── useUsers.ts
   ├── App.tsx
   ├── main.tsx
   └── index.css
├── dist/                   production output
   ├── assets/
   ├── bom.json            CycloneDX SBOM
   └── index.html          SRI hashes injected
├── lunx.config.ts
└── package.json
You're ready to ship!
Deploy the dist/ folder to any static host — Vercel, Netlify, Cloudflare Pages, AWS S3, or GitHub Pages. No server required for a standard SPA.