Welcome to laroux! This guide will walk you through everything you need to know to build modern web applications with React Server Components and Deno.
Version: 3.0 Last Updated: 2025-11-01
- What is laroux?
- Prerequisites
- Installation
- Quick Start
- Project Templates
- Project Structure
- Development Workflow
- Building Components
- Server Actions
- Styling with Tailwind CSS
- Configuration
- Building for Production
- Deployment
- CLI Reference
- Troubleshooting
- Examples
laroux is a modern React Server Components framework built on Deno. It combines the power of:
- React Server Components (RSC) - Zero client-side JavaScript by default
- Deno Runtime - Secure, modern TypeScript runtime
- Tailwind CSS 4.0 - Utility-first styling
- Server Actions - Direct server interaction from client components
- Hot Module Replacement - Instant feedback during development
- Zero Configuration - Works out of the box, configure only when needed
- TypeScript First - Full TypeScript support with no setup
- Modern Tooling - Built on Deno's native bundler and runtime
- Developer Experience - Fast builds, instant HMR, helpful error messages
- Production Ready - Optimized builds with code splitting and minification
Before you begin, ensure you have:
-
Deno installed (v2.6 or later)
# Install Deno (if not already installed) curl -fsSL https://deno.land/install.sh | sh # Verify installation deno --version
-
eser cli installed
deno run -Ar jsr:@eser/cli install
-
Basic knowledge of:
- React and JSX
- TypeScript (optional but recommended)
- Command line basics
You'll need to clone the repository:
# Clone the repository
git clone https://github.com/eser/laroux.git
cd larouxComing Soon: Cloning templates via eser cli.
Start the development server:
cd my-app
deno task devYour app will be running at http://localhost:8000!
When you create a new laroux project, here's what you get:
my-app/
├── src/
│ ├── app/ # Your application components
│ │ └── app.tsx # Main app component
│ └── styles/ # CSS files
│ └── global.css # Global styles with Tailwind
├── public/ # Static assets
│ └── favicon.svg # App favicon
├── dist/ # Build output (generated)
├── package.json # Dependencies and scripts
├── deno.json # Deno configuration
├── tsconfig.json # TypeScript configuration
├── .gitignore # Git ignore rules
├── LICENSE # Project license
└── README.md # Project documentation
src/app/- Your React components (both server and client)src/styles/- CSS files, processed with Tailwind CSSpublic/- Static files (images, fonts, etc.) served directlydist/- Production build output (don't edit manually)
deno task dev # Start dev server (port 8000)
deno task dev --port 3000 # Custom port
deno task dev --open # Auto-open browser
deno task dev --no-hmr # Disable HMRThe dev server watches .tsx, .ts, .jsx, .js, and .css files for
changes and automatically rebuilds with HMR.
By default, all components in laroux are Server Components. They run only on the server and don't ship any JavaScript to the client.
// src/app/greeting.tsx
// This is a Server Component (no "use client" directive)
export default function Greeting() {
const serverTime = new Date().toISOString();
return (
<div>
<h1>Hello from the Server!</h1>
<p>Generated at: {serverTime}</p>
</div>
);
}Server Components can:
- Access databases directly
- Read files from the filesystem
- Use server-only libraries
- Keep sensitive data on the server
Server Components cannot:
- Use React hooks (useState, useEffect, etc.)
- Handle browser events (onClick, onChange, etc.)
- Access browser APIs
Add "use client" at the top of your file to create a Client Component:
// src/app/counter.tsx
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}Client Components can:
- Use React hooks
- Handle user interactions
- Access browser APIs
- Manage client-side state
Best Practice: Use Server Components by default, add "use client" only
when needed.
You can mix server and client components:
// src/app/app.tsx (Server Component)
import Counter from "./counter.tsx"; // Client Component
import Greeting from "./greeting.tsx"; // Server Component
export default function App() {
return (
<div>
<Greeting />
<Counter />
</div>
);
}Server Actions let you call server-side functions directly from client components.
// src/app/actions.ts
"use server";
export async function saveData(formData: FormData) {
const name = formData.get("name") as string;
// This runs on the server
await database.users.create({ name });
return { success: true };
}// src/app/form.tsx
"use client";
import { saveData } from "./actions.ts";
export default function Form() {
async function handleSubmit(formData: FormData) {
const result = await saveData(formData);
console.log(result); // { success: true }
}
return (
<form action={handleSubmit}>
<input name="name" required />
<button type="submit">Save</button>
</form>
);
}Server Actions are perfect for:
- Form submissions
- Database operations
- API calls
- File uploads
- Authentication
laroux includes Tailwind CSS 4.0 with zero configuration.
export default function Button() {
return (
<button className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
Click me
</button>
);
}Edit src/styles/global.css:
/* src/styles/global.css */
@import "tailwindcss";
/* Custom global styles */
body {
font-family: system-ui, sans-serif;
}Tailwind's dark mode works out of the box:
<div className="bg-white dark:bg-gray-900 text-black dark:text-white">
<h1>Supports dark mode!</h1>
</div>;Create a tailwind.config.js to customize:
export default {
theme: {
extend: {
colors: {
brand: "#1e40af",
},
},
},
};laroux works with zero configuration. Customize via laroux.config.ts:
import type { UserConfig } from "@eser/laroux-core/config/schema";
export default {
port: 3000,
server: { hmr: true, open: false },
build: { minify: true, sourcemap: true },
srcDir: "src",
distDir: "dist",
logLevel: "info", // trace | debug | info | warn | error
alias: { "@components": "./src/components" },
} satisfies UserConfig;CLI arguments override config: eser laroux dev --port 3001 --no-hmr
deno task build # Production build → dist/
deno task build --clean # Clean before build
deno task build --analyze # Bundle size analysis
deno task serve # Serve production build# Deno Deploy
deno deployDocker:
FROM denoland/deno:latest
WORKDIR /app
COPY . .
RUN deno task build
EXPOSE 8000
CMD ["deno", "task", "serve"]Run this commands with eser cli:
| Command | Options |
|---|---|
eser laroux init |
--template, --no-git, --no-install |
eser laroux dev |
--port, --no-hmr, --log-level, --open |
eser laroux build |
--out-dir, --clean, --no-minify, --analyze |
eser laroux serve |
--port, --dist-dir |
Run eser laroux --help for full details.
| Problem | Solution |
|---|---|
| Component not found | Ensure "use client" is first line; try --clean |
| Permission denied | Run with --allow-all or specific permissions |
| Port in use | Use --port 3001 |
| HMR not working | Hard refresh (Cmd+Shift+R), restart dev server |
| Cannot find module | Check import paths; run deno cache --reload |
| Hydration mismatch | Avoid Math.random()/Date.now() in render |
- GitHub - Source code and issues
- Deno
- React Server Components
- Tailwind CSS