@ossy/app
v1.40.0
Published
Server-side rendering runtime and build tooling for Ossy apps.
Downloads
12,382
Readme
@ossy/app
Server-side rendering runtime and build tooling for Ossy apps.
For custom setups (Next.js, Vite, etc.), use @ossy/connected-components directly.
Setup
Add @ossy/app, react, react-dom, and @ossy/connected-components (plus its peer deps) to your package.json, then run app build.
{
"scripts": {
"build": "app build",
"start": "node build/server.js"
}
}Pages
Create *.page.jsx files in src/. Each file becomes a route.
// src/home.page.jsx
export const metadata = {
id: 'home',
title: 'Home',
path: '/',
}
export default function Home({ url }) {
return (
<body>
<h1>Welcome</h1>
<p>Current URL: {url}</p>
</body>
)
}File → route mapping: home.page.jsx → /, about.page.jsx → /about. The metadata export controls the route id, path, and page title. For multi-language paths:
export const metadata = {
id: 'about',
path: { en: '/about', sv: '/om' },
}What the framework provides: The build wraps every page automatically with <html>, <head> (including the page title and injected styles), and <App> (providers for theme, router, SDK). Your page component only needs to return the <body> element and its content.
Props: The full app config is passed as props to the page component — url, theme, isAuthenticated, pages, workspaceId, apiUrl, etc. You can also access config via useApp() / useRouter() hooks from @ossy/connected-components and @ossy/router-react.
Build output: Each page produces two self-contained bundles (React included):
build/ssr/<id>.mjs— used by the server for SSR on each requestbuild/public/static/<id>.js— loaded by the browser for hydration
Config
Add src/config.js to set workspace, theme, and API options:
import { CloudLight } from '@ossy/themes'
export default {
workspaceId: 'your-workspace-id',
theme: CloudLight,
apiUrl: 'https://api.ossy.se/api/v0',
}Config is loaded at build time and merged with request-time settings (e.g. user theme preference from cookies).
API routes
Create *.api.js files in src/. Each file exports a metadata object and a default handler function.
// src/health.api.js
export const metadata = {
id: 'health',
path: '/api/health',
}
export default function handle(req, res) {
res.json({ status: 'ok' })
}The handler receives the raw Express req and res. API routes are matched before page rendering. The router supports dynamic segments (e.g. path: '/api/users/:id').
Build output: build/.ossy/api.generated.json — a registry of [{ id, path, module }] entries. Handlers are lazy-imported on first request.
Background tasks (*.task.js)
For background job processors, create *.task.js files in src/. Each file exports a metadata object with a type field and a default handler function.
// src/send-email.task.js
export const metadata = {
type: 'send-email',
}
export default async function handle({ sdk, job }) {
// process the job
}The worker polls the job queue every 3 seconds and lazy-imports the handler module the first time a job of that type arrives.
Build output: build/.ossy/tasks.generated.json — a registry of [{ type, module }] entries. Run the worker with node build/worker.js. Requires OSSY_WORKSPACE_ID, OSSY_API_URL, and OSSY_API_TOKEN environment variables.
Components (*.component.jsx)
Register injectable UI via *.component.jsx in src/ or feature packages. Components are bundled separately and resolved into slots at runtime.
Shell chrome — the app assigns placement in *.layout.jsx:
export const slots = {
'shell:header': 'app-header',
'shell:sidebar': 'app-sidebar',
}Resource / input UI — feature packages use metadata.id as the slot key:
export const metadata = { id: 'resource:booking/service/form' }
export default function ServiceForm() { … }See docs/component-primitive.md and design-system/docs/SLOTS.md.
Port configuration
The server listens on port 3000 by default.
PORT=4000 node build/server.js
node build/server.js --port 4000
node build/server.js -p 4000