lunx.docs
DocsFrameworksReact

React Adapter

First-class React 18 support with SWC-powered JSX compilation, React Fast Refresh HMR, automatic code splitting, and zero-config TypeScript.

React 18 · TypeScript · Fast Refresh
SWC JSX compiler

TypeScript and JSX compiled by SWC — 20× faster than Babel. No Babel config needed.

React Fast Refresh

Component-level HMR with state preserved. Powered by the official react-refresh runtime.

Auto code splitting

React.lazy() calls automatically create separate chunks loaded on demand.

Zero config TS

TypeScript works out of the box. No tsconfig plugins or extra dependencies.

RSC ready

Experimental React Server Components support via the 'react-rsc' preset.

Strict mode

React.StrictMode is enabled in development by default for early detection of side effects.

Setup

bash
npm create lunx-dev@latest my-react-app -- --framework react --ts
cd my-react-app && npm install && npm run dev
typescriptlunx.config.ts
import { defineConfig } from 'lunx'

export default defineConfig({
  framework: 'react',

  // React-specific options
  react: {
    // JSX runtime: 'automatic' (default) | 'classic'
    jsxRuntime: 'automatic',

    // Enable React Fast Refresh in dev (default: true)
    fastRefresh: true,

    // TypeScript-aware transforms
    typescript: {
      strictNullChecks: true,
    },
  },
})

Project structure

text
my-react-app/
├── src/
   ├── main.tsx           # ReactDOM.createRoot entry
   ├── App.tsx            # Root component
   ├── components/        # Shared UI components
   ├── pages/             # Route-level components
   ├── hooks/             # Custom hooks
   └── index.css          # Global styles
├── index.html
├── lunx.config.ts
└── tsconfig.json

Entry point

typescriptsrc/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>
)

TypeScript paths

jsontsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Using React Router v6

typescriptsrc/App.tsx
import { Routes, Route, Navigate } from 'react-router-dom'
import { Suspense, lazy } from 'react'
import { Layout } from '@/components/Layout'

// Code-split routes — each becomes a separate chunk
const HomePage    = lazy(() => import('@/pages/HomePage'))
const DashBoard   = lazy(() => import('@/pages/Dashboard'))
const ProfilePage = lazy(() => import('@/pages/Profile'))
const NotFound    = lazy(() => import('@/pages/NotFound'))

export default function App() {
  return (
    <Suspense fallback={<div className="p-8 text-center">Loading...</div>}>
      <Routes>
        <Route path="/" element={<Layout />}>
          <Route index       element={<HomePage />} />
          <Route path="dash" element={<DashBoard />} />
          <Route path="me"   element={<ProfilePage />} />
          <Route path="*"    element={<NotFound />} />
        </Route>
      </Routes>
    </Suspense>
  )
}

State management with Zustand

bash
npm install zustand
typescriptsrc/stores/useCounter.ts
import { create } from 'zustand'
import { persist } from 'zustand/middleware'

interface CounterState {
  count: number
  increment: () => void
  decrement: () => void
  reset:     () => void
}

export const useCounter = create<CounterState>()(
  persist(
    (set) => ({
      count:     0,
      increment: () => set(s => ({ count: s.count + 1 })),
      decrement: () => set(s => ({ count: s.count - 1 })),
      reset:     () => set({ count: 0 }),
    }),
    { name: 'counter-storage' }
  )
)

Data fetching with TanStack Query

bash
npm install @tanstack/react-query
typescriptsrc/main.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime:  1000 * 60,      // 1 minute
      gcTime:     1000 * 60 * 5,  // 5 minutes
      retry:      2,
    },
  },
})

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </QueryClientProvider>
  </React.StrictMode>
)
React DevTools
Install the React DevTools browser extension to inspect component trees, profile renders, and track state changes. With Fast Refresh enabled, component state is preserved between edits — you'll see updates instantly without losing your dev state.