Installation
Install the core packages:
npm install @pyreon/core @pyreon/reactivity @pyreon/runtime-dom @pyreon/vite-pluginbun add @pyreon/core @pyreon/reactivity @pyreon/runtime-dom @pyreon/vite-pluginpnpm add @pyreon/core @pyreon/reactivity @pyreon/runtime-dom @pyreon/vite-pluginyarn add @pyreon/core @pyreon/reactivity @pyreon/runtime-dom @pyreon/vite-pluginVite Setup
Add the Pyreon plugin to your Vite config. The plugin is a default export — convention is to name the import pyreon:
import { defineConfig } from 'vite'
import pyreon from '@pyreon/vite-plugin'
export default defineConfig({
plugins: [pyreon()],
})Your First Component
import { signal, computed } from '@pyreon/reactivity'
import { Show } from '@pyreon/core'
import { mount } from '@pyreon/runtime-dom'
const count = signal(0)
function App() {
const doubled = computed(() => count() * 2)
return (
<div>
<h1>Hello Pyreon!</h1>
<button onClick={() => count.update((n) => n + 1)}>
Clicks: {count()}
</button>
<p>Doubled: {doubled()}</p>
<Show when={() => count() > 0}>
<p>You've started clicking!</p>
</Show>
</div>
)
}
mount(<App />, document.getElementById('app')!)HTML Entry Point
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pyreon App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>Adding SSR
For server-side rendering, install the server runtime:
npm install @pyreon/runtime-serverbun add @pyreon/runtime-serverpnpm add @pyreon/runtime-serveryarn add @pyreon/runtime-serverimport { renderToString } from '@pyreon/runtime-server'
import App from './App'
export async function render() {
return await renderToString(<App />)
}For streaming SSR with Suspense support:
import { renderToStream } from '@pyreon/runtime-server'
import App from './App'
export function render(res: WritableStream) {
return renderToStream(<App />, res)
}Adding Routing
npm install @pyreon/routerbun add @pyreon/routerpnpm add @pyreon/routeryarn add @pyreon/routerimport { createRouter } from '@pyreon/router'
export const router = createRouter({
routes: [
{ path: '/', component: () => import('./pages/Home') },
{ path: '/about', component: () => import('./pages/About') },
{ path: '/users/:id', component: () => import('./pages/User') },
],
})import { RouterProvider, RouterView, RouterLink } from '@pyreon/router'
import { router } from './router'
export default function App() {
return (
<RouterProvider router={router}>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>
<RouterView />
</RouterProvider>
)
}Using a Compatibility Layer
If you're coming from React, you can use familiar hooks:
npm install @pyreon/react-compatbun add @pyreon/react-compatpnpm add @pyreon/react-compatyarn add @pyreon/react-compatimport { useState, useEffect, memo } from '@pyreon/react-compat'
const Counter = memo(() => {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = `Count: ${count}`
}, [count])
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>
})What's Next?
Learn about Reactivity — the signal engine at the core
Explore the Component Model — component functions, lifecycle, control flow
Set up Routing — type-safe nested routes
Add State Management — Pinia-inspired stores
Style with Styler — CSS-in-JS for signals