Decorator-Free API
Use Gluonic without TypeScript decorators - perfect for build tool compatibility or personal preference.
Why Decorator-Free?
Reasons to avoid decorators:
- Build tool issues (Vite, Webpack configuration complexity)
- Team preference (some developers dislike decorators)
- Legacy TypeScript (pre-5.0)
- JavaScript projects (decorators are TypeScript-only)
Gluonic supports both! Choose what works for you.
Imperative Model Registration
With Decorators (Standard)
import { Model, ClientModel, Property, ManyToOne, LazyReference } from '@gluonic/client'
@ClientModel('user')
export class User extends Model {
@Property() id: string = ''
@Property() email: string = ''
@Property() name: string = ''
}Without Decorators (Alternative)
import { Model, registerModel } from '@gluonic/client'
export class User extends Model {
id: string = ''
email: string = ''
name: string = ''
}
// Register manually
registerModel(User, {
type: 'user',
properties: {
id: { type: 'primitive' },
email: { type: 'primitive' },
name: { type: 'primitive' }
}
})Relationships Without Decorators
import { Model, registerModel, LazyReference } from '@gluonic/client'
export class Post extends Model {
id = ''
title = ''
authorId = ''
author?: User
}
registerModel(Post, {
type: 'post',
properties: {
id: { type: 'primitive' },
title: { type: 'primitive' },
authorId: { type: 'primitive' },
author: {
type: 'object',
relationshipType: 'm2o',
relatedType: 'user',
fk: 'authorId',
inverse: 'posts'
}
}
})Builder Pattern API
Fluent API for model definition:
import { defineModel } from '@gluonic/client/builder'
export const User = defineModel('user')
.property('id', 'string')
.property('email', 'string')
.property('name', 'string', { optional: true })
.property('createdAt', 'number', { server: true })
.hasMany('posts', 'Post', { inverse: 'author' })
.computed('displayName', function() {
return this.name || this.email.split('@')[0]
})
.build()Benefits:
- Fluent API (reads like English)
- Type-safe
- No decorators needed
- Works in pure JavaScript
Functional API
Pure functions (no classes):
import { createModel } from '@gluonic/client/functional'
export const User = createModel({
type: 'user',
fields: {
id: 'string',
email: 'string',
name: 'string'
},
relationships: {
posts: { type: 'hasMany', model: 'Post' }
},
computed: {
displayName: (user) => user.name || user.email.split('@')[0]
}
})
// Usage in components (same!)
const user = useModel('user', userId)
console.log(user.displayName)TypeScript Support
All approaches are fully type-safe:
// Decorator approach
const user = useModel<User>('user', 'u1')
user.email // string ✓
// Imperative approach
const user = useModel<User>('user', 'u1')
user.email // string ✓
// Builder approach
const user = useModel<typeof User>('user', 'u1')
user.email // string ✓
// Functional approach
const user = useModel<typeof User>('user', 'u1')
user.email // string ✓Choosing an Approach
| Approach | Pros | Cons | Best For |
|---|---|---|---|
| Decorators | Clean syntax, standard TS | Build config needed | Modern TS projects |
| Imperative | No decorators, flexible | More verbose | Build tool issues |
| Builder | Fluent API, readable | New pattern to learn | Preference |
| Functional | No classes, pure | Different paradigm | Functional fans |
Migration Between Approaches
From Decorators to Imperative
# Auto-convert with CLI
npx gluonic convert --from=decorators --to=imperative --dir=./modelsFrom Imperative to Builders
npx gluonic convert --from=imperative --to=builder --dir=./modelsConfiguration
Tell Gluonic which approach you’re using:
const { store } = SyncClient({
modelStyle: 'decorators', // or 'imperative', 'builder', 'functional'
// ... other config
})Next Steps
- Defining Models - Decorator approach (standard)
- Code Generation - Generate models automatically
- Builder Pattern - Fluent API details
Last updated on