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 zustandtypescriptsrc/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-querytypescriptsrc/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.