Libraries API
The libs API provides access to the third-party libraries that Epos uses internally. This allows you to use the same library versions without bundling them yourself.
Available Libraries
All libraries are accessible through the epos.libs object:
epos.libs: {
mobx: typeof mobx
mobxReactLite: typeof mobxReactLite
react: typeof react
reactDom: typeof reactDom
reactDomClient: typeof reactDomClient
reactJsxRuntime: typeof reactJsxRuntime
yjs: typeof yjs
}epos.libs.react
Access to the React library.
epos.libs.react: typeof ReactExample
const { useState, useEffect, useMemo } = epos.libs.react
const MyComponent = () => {
const [count, setCount] = useState(0)
useEffect(() => {
console.log('Count changed:', count)
}, [count])
const doubled = useMemo(() => count * 2, [count])
return (
<div>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}epos.libs.reactDom
Access to the ReactDOM library.
epos.libs.reactDom: typeof ReactDOMExample
const { createPortal } = epos.libs.reactDom
const Modal = ({ children }) => {
return createPortal(
<div className="modal">{children}</div>,
document.body
)
}epos.libs.reactDomClient
Access to the ReactDOM client library for rendering.
epos.libs.reactDomClient: typeof ReactDOMClientExample
const { createRoot } = epos.libs.reactDomClient
// Manual rendering (usually epos.render() does this)
const container = document.getElementById('root')
const root = createRoot(container)
root.render(<App />)epos.libs.reactJsxRuntime
Access to the React JSX runtime.
epos.libs.reactJsxRuntime: typeof ReactJsxRuntimeExample
const { jsx, jsxs, Fragment } = epos.libs.reactJsxRuntime
// Manual JSX creation
const element = jsx('div', {
className: 'container',
children: 'Hello World',
})epos.libs.mobx
Access to the MobX library for state management.
epos.libs.mobx: typeof MobXExample
const { makeObservable, observable, action, computed } = epos.libs.mobx
class TodoStore {
todos = []
constructor() {
makeObservable(this, {
todos: observable,
addTodo: action,
completedCount: computed,
})
}
addTodo(text) {
this.todos.push({ text, done: false })
}
get completedCount() {
return this.todos.filter(todo => todo.done).length
}
}
const store = new TodoStore()epos.libs.mobxReactLite
Access to the MobX React integration library.
epos.libs.mobxReactLite: typeof MobXReactLiteExample
const { observer } = epos.libs.mobxReactLite
// Manually create observer (epos.component() does this)
const Counter = observer(() => {
const state = epos.state.create({ count: 0 })
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => state.count++}>+</button>
</div>
)
})epos.libs.yjs
Access to the Yjs library for CRDT-based data synchronization.
epos.libs.yjs: typeof YjsExample
const { Doc, Map, Array } = epos.libs.yjs
// Create a Yjs document
const doc = new Doc()
const ymap = doc.getMap('data')
ymap.set('name', 'John')
ymap.set('age', 30)
// Listen for changes
ymap.observe(event => {
console.log('Map changed:', event)
})
// Create shared array
const yarray = doc.getArray('items')
yarray.push(['item1', 'item2'])Why Use Built-in Libraries?
1. Smaller Bundle Size
Using epos.libs instead of importing libraries directly means you don't need to bundle them, resulting in smaller extension sizes.
// ❌ Increases bundle size
import React from 'react'
import { observable } from 'mobx'
// ✅ Uses built-in libraries (no bundling needed)
const React = epos.libs.react
const { observable } = epos.libs.mobx2. Version Consistency
Using the same library versions as Epos ensures compatibility and prevents conflicts.
3. Instant Availability
Libraries are immediately available without installation or build steps.
Usage Patterns
React Hooks
const { useState, useEffect, useCallback, useMemo, useRef } = epos.libs.react
const MyComponent = epos.component(() => {
const [count, setCount] = useState(0)
const [text, setText] = useState('')
const inputRef = useRef(null)
const increment = useCallback(() => {
setCount(c => c + 1)
}, [])
const doubled = useMemo(() => count * 2, [count])
useEffect(() => {
console.log('Component mounted')
return () => console.log('Component unmounted')
}, [])
return (
<div>
<p>Count: {count} (Doubled: {doubled})</p>
<button onClick={increment}>+</button>
<input
ref={inputRef}
value={text}
onChange={e => setText(e.target.value)}
/>
</div>
)
})MobX Observable Class
const { makeObservable, observable, action, computed, reaction } = epos.libs.mobx
class Store {
count = 0
items = []
constructor() {
makeObservable(this, {
count: observable,
items: observable,
increment: action,
addItem: action,
total: computed,
isEmpty: computed,
})
// React to changes
reaction(
() => this.count,
count => console.log('Count changed to:', count),
)
}
increment() {
this.count++
}
addItem(item) {
this.items.push(item)
}
get total() {
return this.items.reduce((sum, item) => sum + item.price, 0)
}
get isEmpty() {
return this.items.length === 0
}
}Yjs Document Sync
const { Doc, Map, Array, applyUpdate, encodeStateAsUpdate } = epos.libs.yjs
// Create document
const doc = new Doc()
const data = doc.getMap('shared-data')
// Sync with other peers
doc.on('update', update => {
// Send update to other peers
epos.bus.send('yjs:update', Array.from(update))
})
// Receive updates from other peers
epos.bus.on('yjs:update', (update: number[]) => {
applyUpdate(doc, new Uint8Array(update))
})
// Modify shared data
data.set('user', { name: 'John', status: 'online' })React Portal
const { createPortal } = epos.libs.reactDom
const Modal = epos.component(({ isOpen, onClose, children }) => {
if (!isOpen) return null
return createPortal(
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
{children}
<button onClick={onClose}>Close</button>
</div>
</div>,
document.body
)
})Advanced MobX Patterns
const { makeObservable, observable, action, computed, reaction, autorun, when, runInAction } = epos.libs.mobx
class AsyncStore {
data = null
loading = false
error = null
constructor() {
makeObservable(this, {
data: observable,
loading: observable,
error: observable,
fetchData: action,
hasData: computed,
})
// Auto-run on changes
autorun(() => {
if (this.hasData) {
console.log('Data available:', this.data)
}
})
// Wait for condition
when(
() => this.hasData,
() => console.log('Data loaded!'),
)
}
async fetchData() {
this.loading = true
this.error = null
try {
const response = await fetch('https://api.example.com/data')
const data = await response.json()
runInAction(() => {
this.data = data
this.loading = false
})
} catch (error) {
runInAction(() => {
this.error = error.message
this.loading = false
})
}
}
get hasData() {
return this.data !== null
}
}TypeScript Support
All libraries have full TypeScript support:
import type { FC, ReactNode } from 'react'
import type { IObservableArray } from 'mobx'
import type { Doc, Map as YMap } from 'yjs'
const MyComponent: FC<{ children: ReactNode }> = ({ children }) => {
return <div>{children}</div>
}
const observable: IObservableArray<string> = epos.libs.mobx.observable.array([])
const doc: Doc = new epos.libs.yjs.Doc()
const ymap: YMap<any> = doc.getMap('data')TIP
Using epos.libs instead of installing packages separately keeps your extension lightweight and ensures compatibility with Epos's internal systems.
INFO
The libraries are already loaded and available globally. You don't need to import or install them.