Getting Started
Getting Started with Cloudillo Development
This guide will walk you through creating your first Cloudillo application.
Prerequisites
- Node.js 18+ and pnpm installed
- Basic knowledge of TypeScript/JavaScript
- Familiarity with React (optional, for UI apps)
Installation
For Standalone Apps
pnpm add @cloudillo/base @cloudillo/typesFor React Apps
pnpm add @cloudillo/base @cloudillo/types @cloudillo/reactFor Real-Time Database
pnpm add @cloudillo/rtdbFor Collaborative Editing
pnpm add @cloudillo/base yjs y-websocketYour First App: Hello Cloudillo
Let’s create a simple app that displays the current user’s profile.
Step 1: Initialize the App
Create src/index.ts:
import * as cloudillo from '@cloudillo/base'
async function main() {
// Initialize with your app name
const token = await cloudillo.init('hello-cloudillo')
console.log('Initialized successfully!')
console.log('Access Token:', token)
console.log('User ID:', cloudillo.idTag)
console.log('Tenant ID:', cloudillo.tnId)
console.log('Roles:', cloudillo.roles)
}
main().catch(console.error)Step 2: Fetch User Profile
import * as cloudillo from '@cloudillo/base'
async function main() {
await cloudillo.init('hello-cloudillo')
// Create an API client
const api = cloudillo.createApiClient()
// Fetch the current user's profile
const profile = await api.me.get()
console.log('Profile:', profile)
console.log('Name:', profile.name)
console.log('ID Tag:', profile.idTag)
console.log('Profile Picture:', profile.profilePic)
}
main().catch(console.error)Step 3: Create a Post
import * as cloudillo from '@cloudillo/base'
async function main() {
await cloudillo.init('hello-cloudillo')
const api = cloudillo.createApiClient()
// Create a new post
const newPost = await api.action.post({
type: 'POST',
content: {
text: 'Hello from my first Cloudillo app!',
title: 'My First Post'
}
})
console.log('Post created:', newPost)
}
main().catch(console.error)React Example
For React applications, use the provided hooks:
import React from 'react'
import { CloudilloProvider, useAuth, useApi } from '@cloudillo/react'
function App() {
return (
<CloudilloProvider appName="hello-cloudillo">
<Profile />
</CloudilloProvider>
)
}
function Profile() {
const auth = useAuth()
const api = useApi()
const [profile, setProfile] = React.useState(null)
React.useEffect(() => {
api.me.get().then(setProfile)
}, [api])
if (!profile) return <div>Loading...</div>
return (
<div>
<h1>Welcome, {profile.name}!</h1>
<p>ID: {auth.idTag}</p>
{profile.profilePic && (
<img src={profile.profilePic} alt="Profile" />
)}
</div>
)
}
export default AppReal-Time Database Example
Here’s how to use the real-time database:
import * as cloudillo from '@cloudillo/base'
import { RtdbClient } from '@cloudillo/rtdb'
async function main() {
const token = await cloudillo.init('rtdb-example')
// Create RTDB client
const rtdb = new RtdbClient({
fileId: 'my-database-file-id',
token,
url: 'wss://your-server.com/ws/rtdb'
})
// Get a collection reference
const todos = rtdb.collection('todos')
// Subscribe to real-time updates
todos.onSnapshot((snapshot) => {
console.log('Todos updated:', snapshot)
})
// Create a document
await todos.create({
title: 'Learn Cloudillo',
completed: false,
createdAt: Date.now()
})
// Query documents
const incompleteTodos = await todos
.where('completed', '==', false)
.orderBy('createdAt', 'desc')
.get()
console.log('Incomplete todos:', incompleteTodos)
}
main().catch(console.error)Collaborative Editing Example
Create a collaborative text editor:
import * as cloudillo from '@cloudillo/base'
import * as Y from 'yjs'
async function main() {
await cloudillo.init('collab-editor')
// Create a Yjs document
const yDoc = new Y.Doc()
// Open collaborative document
const { provider } = await cloudillo.openYDoc(yDoc, 'my-doc-id')
// Get shared text
const yText = yDoc.getText('content')
// Listen for changes
yText.observe(() => {
console.log('Text changed:', yText.toString())
})
// Insert text
yText.insert(0, 'Hello, collaborative world!')
// See awareness (other users' cursors/selections)
provider.awareness.on('change', () => {
const states = provider.awareness.getStates()
console.log('Connected users:', states.size)
})
}
main().catch(console.error)Microfrontend Integration
If you’re building an app to run inside the Cloudillo shell:
import * as cloudillo from '@cloudillo/base'
// The init() function automatically handles the shell protocol
async function main() {
const token = await cloudillo.init('my-microfrontend')
// Now you can use all Cloudillo features
const api = cloudillo.createApiClient()
// The shell provides:
// - cloudillo.idTag (user's identity)
// - cloudillo.tnId (tenant ID)
// - cloudillo.roles (user roles)
// - cloudillo.darkMode (theme preference)
// Your app logic here...
}
main().catch(console.error)Error Handling
All API calls can throw errors. Handle them appropriately:
import { FetchError } from '@cloudillo/base'
try {
const api = cloudillo.createApiClient()
const profile = await api.me.get()
} catch (error) {
if (error instanceof FetchError) {
console.error('API Error:', error.message)
console.error('Status:', error.status)
console.error('Code:', error.code) // e.g., 'E-AUTH-UNAUTH'
} else {
console.error('Unexpected error:', error)
}
}Next Steps
Now that you’ve created your first Cloudillo app, explore more features:
- Authentication - Learn about token-based authentication
- Client Libraries - Deep dive into available libraries
- REST API - Comprehensive API reference
- Actions - Implement social features
- RTDB - Build real-time apps
- CRDT - Collaborative editing patterns
- Microfrontends - Build shell-integrated apps
Common Patterns
Handling Dark Mode
import * as cloudillo from '@cloudillo/base'
await cloudillo.init('my-app')
// Check dark mode preference
if (cloudillo.darkMode) {
document.body.classList.add('dark-theme')
}Using Query Parameters
const api = cloudillo.createApiClient()
// List actions with filters
const posts = await api.action.get({
type: 'POST',
status: 'A', // Active
_limit: 20
})Uploading Files
const api = cloudillo.createApiClient()
// Create file metadata
const file = await api.file.post({
fileTp: 'BLOB',
contentType: 'image/png'
})
// Upload binary data
const formData = new FormData()
formData.append('file', imageBlob)
formData.append('fileId', file.fileId)
await api.file.upload.post(formData)Build and Deploy
Development
Most apps run as microfrontends inside the Cloudillo shell. Use your preferred build tool (Rollup, Webpack, Vite):
# Using Rollup (like the example apps)
pnpm build
# Using Vite
vite buildProduction
Deploy your built app to any static hosting:
# The built output goes to the shell's apps directory
cp -r dist /path/to/cloudillo/shell/public/apps/my-appTroubleshooting
“Failed to initialize”
Make sure you’re either:
- Running inside the Cloudillo shell (as a microfrontend), or
- Providing authentication manually for standalone apps
“CORS errors”
Ensure your Cloudillo server is configured to allow requests from your app’s origin.
“WebSocket connection failed”
Check that:
- The WebSocket URL is correct (wss:// for production)
- The server is running and accessible
- Your authentication token is valid
Example Apps
Check out the example apps in the Cloudillo repository:
- Quillo - Rich text editor with Quill
- Prello - Presentation tool
- Sheello - Spreadsheet application
- Formillo - Form builder
- Todollo - Task management
All use the same patterns described in this guide.