Welcome to Voltz! This guide will help you set up your development environment and build your first desktop application.
Before you begin, ensure you have the following installed:
- Node.js 18+ (Download)
- npm or yarn package manager
- Git for version control
- Visual Studio Code (recommended) with TypeScript support
git clone https://github.com/voltz-team/voltz.git
cd voltznpm installThis will install all required dependencies including:
- Electron 35+
- React 19+
- TypeScript 5+
- TailwindCSS 4
- Vite for fast development
npm run devThe application will launch with:
- Hot Module Replacement (HMR) for instant updates
- Main and renderer process development servers
voltz/
├── src/
│ ├── main/ # Electron main process (Node.js)
│ │ ├── core/ # Core framework classes
│ │ ├── decorators/ # TypeScript decorators
│ │ ├── modules/ # Controllers and services
│ │ └── utils/ # Utility functions
│ ├── preload/ # Secure bridge between main and renderer
│ └── renderer/ # React frontend (Chromium)
│ ├── components/ # Reusable UI components
│ └── pages/ # Application pages
├── build/ # Build configuration and assets
└── resources/ # Application icons and resources
- Create a new service in
src/main/modules/services/:
// src/main/modules/services/user.service.ts
import { IpcService } from '../../decorators/service-decorator'
import { LifecycleAware, LifecycleService } from '../../decorators/lifecycle-decorator'
@IpcService()
@LifecycleService()
export class UserService implements LifecycleAware {
private users: string[] = []
onInit(): void {
console.log('UserService initialized')
this.users = ['Alice', 'Bob', 'Charlie']
}
getAllUsers(): string[] {
return this.users
}
addUser(name: string): void {
this.users.push(name)
}
onDestroy(): void {
console.log('UserService destroyed')
}
}- Create a controller to handle IPC communication:
// src/main/modules/controllers/user.controller.ts
import { IpcHandle, IpcController } from '../../decorators/ipc-decorator'
import { LifecycleAware, LifecycleService } from '../../decorators/lifecycle-decorator'
import { UserService } from '../services/user.service'
@IpcController(['UserService'])
@LifecycleService()
export class UserController implements LifecycleAware {
constructor(private readonly userService: UserService) {}
onInit(): void {
console.log('UserController initialized')
}
@IpcHandle('user:getAll')
async getUsers(): Promise<string[]> {
return this.userService.getAllUsers()
}
@IpcHandle('user:add')
async addUser(event: any, name: string): Promise<void> {
this.userService.addUser(name)
}
}- Add type definitions for your IPC channels in
src/preload/index.d.ts:
interface ElectronAPI {
// ...existing methods
getUserList: () => Promise<string[]>
addUser: (name: string) => Promise<void>
}- Implement the IPC methods in
src/preload/index.ts:
// Add to the existing contextBridge.exposeInMainWorld call
{
// ...existing methods
getUserList: () => ipcRenderer.invoke('user:getAll'),
addUser: (name: string) => ipcRenderer.invoke('user:add', name)
}- Use the IPC methods in your React components:
// src/renderer/src/components/user-list.tsx
import { useState, useEffect } from 'react'
import { Button } from './ui/button'
export function UserList() {
const [users, setUsers] = useState<string[]>([])
const [newUser, setNewUser] = useState('')
useEffect(() => {
loadUsers()
}, [])
const loadUsers = async () => {
const userList = await window.electron.getUserList()
setUsers(userList)
}
const handleAddUser = async () => {
if (newUser.trim()) {
await window.electron.addUser(newUser)
setNewUser('')
loadUsers() // Refresh the list
}
}
return (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Users</h3>
<ul className="space-y-2">
{users.map((user, index) => (
<li key={index} className="p-2 bg-muted rounded">
{user}
</li>
))}
</ul>
<div className="flex gap-2">
<input
type="text"
value={newUser}
onChange={(e) => setNewUser(e.target.value)}
placeholder="Enter user name"
className="flex-1 p-2 border rounded"
/>
<Button onClick={handleAddUser}>Add User</Button>
</div>
</div>
)
}| Command | Description |
|---|---|
npm run dev |
Start development with hot reload |
npm run build |
Build for production |
npm run build:win |
Build for Windows |
npm run build:mac |
Build for macOS |
npm run build:linux |
Build for Linux |
npm run lint |
Run ESLint |
npm run typecheck |
Run TypeScript checking |
Voltz supports hot reload for both:
- Renderer process: React components update instantly
- Main process: Electron restarts automatically on changes
- Renderer Process: Use Chrome DevTools (F12)
- Main Process: Use VS Code debugger or
console.log() - Preload Scripts: Logs appear in both main and renderer consoles
# Windows
npm run build:win
# macOS
npm run build:mac
# Linux
npm run build:linuxThe built application will be in the dist/ directory.
Now that you have a basic understanding, explore these advanced topics:
- Architecture Overview - Deep dive into Voltz's architecture
- Service System - Advanced service patterns and dependency injection
- IPC Communication - Type-safe inter-process communication
- Decorator System - Using TypeScript decorators effectively
- Configuration Guide - Customizing your application
If you see "port already in use" errors, either:
- Kill existing processes:
npx kill-port 5173 - Change ports in
electron.vite.config.mjs
- Run
npm run typecheckto see detailed type errors - Ensure all dependencies are properly installed
- Check that decorator support is enabled
- Clear cache:
rm -rf node_modules package-lock.json && npm install - Ensure all required build tools are installed
- Check platform-specific requirements for your target OS
- 📖 Documentation
- 🐛 Issues
- 💬 Discussions
Note: This documentation was auto-generated, some sections may require manual adjustments or further customization. If you find something that needs fixing, feel free to open an issue right away!