Advanced Topics
This chapter covers Lyt.js advanced features and best practices to help you build high-performance, maintainable applications.
Performance Optimization
1. Component Optimization
Using v-memo to Cache Components
The v-memo directive caches component render results, skipping re-renders when dependencies haven't changed.
import { defineComponent, ref } from '@lytjs/core'
const ExpensiveComponent = defineComponent({
props: { item: Object },
template: `
<div v-memo="[item.id]">
<!-- Complex rendering logic -->
{{ heavyComputation(item) }}
</div>
`,
methods: {
heavyComputation(item) {
// Expensive computation
let result = 0
for (let i = 0; i < 1000000; i++) {
result += i
}
return result
}
}
})Using v-if and v-show Appropriately
- v-if: Suitable for infrequently changing conditions; destroys/recreates the component
- v-show: Suitable for frequently changing conditions; only toggles the display property
// Infrequently changing condition
<div v-if="user.isAdmin">Admin Panel</div>
// Frequently changing condition
<div v-show="isVisible">Popup</div>Using key to Optimize List Rendering
Using unique key values in v-for helps Lyt.js update the DOM more efficiently.
// Recommended
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
// Not recommended
<ul>
<li v-for="(item, index) in items" :key="index">
{{ item.name }}
</li>
</ul>2. Reactivity Optimization
Avoiding Unnecessary Reactivity
For data that doesn't need to be reactive, use shallowRef or markRaw to improve performance.
import { shallowRef, markRaw } from '@lytjs/reactivity'
// Shallow reactive (only top-level properties are reactive)
const shallowData = shallowRef({ deep: { nested: 'data' } })
// Non-reactive
const rawData = markRaw({ complex: 'object' })Using computed to Cache Computation Results
import { computed } from '@lytjs/core'
const expensiveValue = computed(() => {
// Complex computation, automatically cached
return heavyComputation()
})Using watch Appropriately
- Use
immediate: falseto avoid initial execution - Use
deep: falseto avoid deep watching - Use
flush: 'post'to avoid multiple triggers
watch(
() => state.user,
(newUser) => {
// Handle user change
},
{ deep: false, flush: 'post' }
)3. Rendering Optimization
Virtual Scrolling
For long lists, virtual scrolling can significantly improve performance.
import { defineComponent, ref, computed } from '@lytjs/core'
const VirtualList = defineComponent({
props: { items: Array, itemHeight: Number },
setup(props) {
const containerRef = ref(null)
const visibleCount = ref(20)
const scrollTop = ref(0)
const visibleItems = computed(() => {
const start = Math.floor(scrollTop.value / props.itemHeight)
const end = start + visibleCount.value
return props.items.slice(start, end)
})
const offsetY = computed(() => {
const start = Math.floor(scrollTop.value / props.itemHeight)
return start * props.itemHeight
})
return { containerRef, scrollTop, visibleItems, offsetY }
},
template: `
<div
ref="containerRef"
style="height: 400px; overflow-y: auto"
@scroll="scrollTop = $event.target.scrollTop"
>
<div :style="{ height: items.length * itemHeight + 'px', position: 'relative' }">
<div :style="{ transform: 'translateY(' + offsetY + 'px)', position: 'absolute', width: '100%' }">
<div
v-for="item in visibleItems"
:key="item.id"
:style="{ height: itemHeight + 'px' }"
>
{{ item.name }}
</div>
</div>
</div>
</div>
`
})Batch Updates
Use nextTick or $patch for batch updates.
import { nextTick } from '@lytjs/core'
async function updateData() {
// Multiple state updates
state.loading = true
state.count = 0
state.items = []
// Wait for DOM update to complete
await nextTick()
// Continue processing
state.loading = false
}4. Resource Optimization
Code Splitting
Use dynamic imports for code splitting.
// Route lazy loading
const About = () => import('./views/About.vue')
// Component lazy loading
const HeavyComponent = defineAsyncComponent(() => import('./HeavyComponent.vue'))Image Optimization
- Use appropriate image formats (WebP, AVIF)
- Implement lazy loading for images
- Use responsive images
const LazyImage = defineComponent({
props: { src: String, alt: String },
setup(props) {
const isLoaded = ref(false)
const handleLoad = () => {
isLoaded.value = true
}
return { isLoaded, handleLoad }
},
template: `
<div class="lazy-image-container">
<img
v-if="isLoaded"
:src="src"
:alt="alt"
@load="handleLoad"
/>
<div v-else class="placeholder"></div>
</div>
`
})Custom Renderers
1. Creating a Custom Renderer
Lyt.js supports creating custom renderers for different platforms.
import { createRenderer } from '@lytjs/renderer'
const customRenderer = createRenderer({
// Create element
createElement(tag) {
console.log('Creating element:', tag)
return { tag }
},
// Insert element
insert(el, parent, anchor) {
console.log('Inserting element:', el.tag, 'into', parent.tag)
},
// Remove element
remove(el) {
console.log('Removing element:', el.tag)
},
// Set element property
setElementProp(el, key, value) {
console.log('Setting property:', key, '=', value)
},
// Add event listener
addEventListener(el, event, handler) {
console.log('Adding event listener:', event)
}
})
// Use custom renderer
const app = customRenderer.createApp({
template: '<div @click="onClick">Hello</div>',
methods: {
onClick() {
console.log('Clicked')
}
}
})
// Mount to custom container
app.mount({ tag: 'root' })2. Platform-Specific Renderers
Lyt.js includes built-in renderers for multiple platforms:
DOM Renderer
import { createApp } from '@lytjs/core'
const app = createApp({
template: '<div>Hello DOM</div>'
})
app.mount('#app')Server-Side Rendering (SSR)
import { renderToString } from '@lytjs/renderer/ssr'
const app = createApp({
template: '<div>Hello SSR</div>'
})
const html = await renderToString(app)
console.log(html) // <div>Hello SSR</div>Mini-App Renderer
import { createApp } from '@lytjs/renderer/miniapp'
const app = createApp({
template: '<view>Hello Miniapp</view>'
})
app.mount()Native Renderer
import { createApp } from '@lytjs/renderer/native'
const app = createApp({
template: '<View>Hello Native</View>'
})
app.mount()3. Custom Renderer Best Practices
- Platform adaptation: Adjust rendering logic based on target platform characteristics
- Performance optimization: Optimize for specific platforms
- Feature extension: Add platform-specific features
- Error handling: Handle platform-specific errors
Compilation Optimization
1. Template Compilation
The Lyt.js compiler optimizes templates:
- Static analysis: Identifies and optimizes static content
- Tree shaking: Removes unused code
- Inlining: Inlines simple computations
- Caching: Caches compilation results
2. Vapor Mode
Vapor Mode is a more efficient rendering mode, suitable for simple components.
import { defineComponent } from '@lytjs/core'
const VaporComponent = defineComponent({
// Enable Vapor Mode
vapor: true,
props: { message: String },
template: `
<div class="container">
<h1>{{ message }}</h1>
<p>Welcome to Lyt.js</p>
</div>
`
})3. WebAssembly Compilation
Lyt.js supports compiling templates to WebAssembly for improved rendering performance.
// Compilation configuration
const compilerOptions = {
target: 'wasm',
optimize: true
}
// Compile template
const wasmCode = compileTemplate('<div>{{ message }}</div>', compilerOptions)Memory Management
1. Avoiding Memory Leaks
- Clean up timers: Clear timers when components unmount
- Remove event listeners: Remove event listeners when components unmount
- Cancel subscriptions: Cancel state subscriptions when components unmount
- Clean up references: Avoid circular references
import { defineComponent, onMounted, onUnmounted } from '@lytjs/core'
const TimerComponent = defineComponent({
setup() {
let timer = null
onMounted(() => {
timer = setInterval(() => {
console.log('Tick')
}, 1000)
})
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
return {}
},
template: '<div>Timer Component</div>'
})2. Memory Monitoring
Use Lyt.js DevTools for memory monitoring:
- Component memory usage: View memory consumption per component
- Memory leak detection: Detect potential memory leaks
- Performance analysis: Analyze rendering performance
3. Garbage Collection
- Reduce object creation: Avoid creating new objects in render functions
- Use object pools: Reuse objects to reduce GC pressure
- Release promptly: Set unused objects to null promptly
// Avoid creating new objects in rendering
// Bad practice
const BadComponent = defineComponent({
template: `
<div :style="{ color: 'red', fontSize: '16px' }"></div>
`
})
// Good practice
const GoodComponent = defineComponent({
setup() {
const styles = { color: 'red', fontSize: '16px' }
return { styles }
},
template: `
<div :style="styles"></div>
`
})Server-Side Rendering (SSR)
1. Basic Usage
import { createApp } from '@lytjs/core'
import { renderToString } from '@lytjs/renderer/ssr'
const app = createApp({
template: '<div>Hello SSR</div>'
})
// Render to string
const html = await renderToString(app)
console.log(html) // <div>Hello SSR</div>2. Data Prefetching
import { defineComponent, ref, onServerPrefetch } from '@lytjs/core'
const DataComponent = defineComponent({
setup() {
const data = ref(null)
// Server-side data prefetch
onServerPrefetch(async () => {
const response = await fetch('https://api.example.com/data')
data.value = await response.json()
})
return { data }
},
template: `
<div>
<div v-if="data">
{{ data.message }}
</div>
<div v-else>Loading...</div>
</div>
`
})3. Client-Side Hydration
// Server-side
const html = await renderToString(app)
// Client-side
import { createApp } from '@lytjs/core'
const app = createApp({
template: '<div>Hello SSR</div>'
})
// Hydrate into already-rendered DOM
app.mount('#app', true) // Second parameter true means hydrateAdvanced Component Patterns
1. Higher-Order Components (HOC)
function withErrorBoundary(Component) {
return defineComponent({
setup(props, { slots }) {
return () => {
try {
return h(Component, props, slots)
} catch (error) {
return h('div', { class: 'error' }, 'An error occurred')
}
}
}
})
}
// Usage
const SafeComponent = withErrorBoundary(MyComponent)2. Render Props
const List = defineComponent({
props: { items: Array, renderItem: Function },
template: `
<ul>
<li v-for="item in items" :key="item.id">
{{ renderItem(item) }}
</li>
</ul>
`
})
// Usage
<List
:items="todos"
:renderItem="(item) => h('div', [
h('input', { type: 'checkbox', checked: item.done }),
h('span', item.text)
])"
/>3. Functional Components
const FunctionalComponent = defineComponent({
functional: true,
props: { message: String },
render(h, { props }) {
return h('div', props.message)
}
})4. Async Components
import { defineAsyncComponent } from '@lytjs/core'
const AsyncComponent = defineAsyncComponent({
loader: () => import('./HeavyComponent.vue'),
loadingComponent: LoadingComponent,
errorComponent: ErrorComponent,
delay: 200,
timeout: 3000
})Internationalization (i18n)
1. Basic Implementation
import { createApp, ref, computed } from '@lytjs/core'
const messages = {
en: {
hello: 'Hello',
welcome: 'Welcome to Lyt.js'
},
zh: {
hello: '你好',
welcome: '欢迎使用 Lyt.js'
}
}
const i18n = {
locale: ref('en'),
t(key) {
return messages[this.locale.value][key]
}
}
const app = createApp({
setup() {
const changeLocale = () => {
i18n.locale.value = i18n.locale.value === 'en' ? 'zh' : 'en'
}
return { i18n, changeLocale }
},
template: `
<div>
<h1>{{ i18n.t('hello') }}</h1>
<p>{{ i18n.t('welcome') }}</p>
<button @click="changeLocale">Switch Language</button>
</div>
`
})
app.mount('#app')2. Plugin Integration
// i18n plugin
const i18nPlugin = {
install(app, options) {
const i18n = {
locale: ref(options.defaultLocale || 'en'),
messages: options.messages || {},
t(key) {
return this.messages[this.locale.value][key] || key
}
}
app.provide('i18n', i18n)
app.config.globalProperties.$i18n = i18n
}
}
// Use plugin
app.use(i18nPlugin, {
defaultLocale: 'en',
messages: {
en: { hello: 'Hello' },
zh: { hello: '你好' }
}
})Testing Strategies
1. Unit Testing
import { mount } from '@lytjs/test-utils'
import Counter from './Counter.vue'
describe('Counter', () => {
test('renders initial count', () => {
const wrapper = mount(Counter)
expect(wrapper.text()).toContain('Count: 0')
})
test('increments count when button is clicked', async () => {
const wrapper = mount(Counter)
await wrapper.find('button').trigger('click')
expect(wrapper.text()).toContain('Count: 1')
})
})2. End-to-End Testing
import { test, expect } from '@playwright/test'
test('counter increments', async ({ page }) => {
await page.goto('http://localhost:3000')
await page.click('button')
await expect(page.locator('div')).toContainText('Count: 1')
})3. Performance Testing
import { performance } from 'perf_hooks'
function measureRender() {
const start = performance.now()
// Render component
const end = performance.now()
console.log(`Render time: ${end - start}ms`)
}Deployment Optimization
1. Build Optimization
# Production build
npm run build
# Analyze build output
npm run build -- --analyze2. Static Asset Optimization
- Compression: Compress CSS, JavaScript, HTML
- Caching: Set appropriate caching strategies
- CDN: Use CDN to accelerate static assets
- Gzip/Brotli: Enable compression
3. Server Configuration
- HTTP/2: Enable HTTP/2
- HTTPS: Use HTTPS
- Caching: Set appropriate cache headers
- Compression: Enable server-side compression
Summary
Lyt.js provides rich advanced features and optimization strategies to help you build high-performance, maintainable applications:
- Performance optimization: Component optimization, reactivity optimization, rendering optimization, resource optimization
- Custom renderers: Multi-platform rendering support
- Compilation optimization: Template compilation, Vapor Mode, WebAssembly compilation
- Memory management: Avoiding memory leaks, memory monitoring, garbage collection
- Server-side rendering: SSR, data prefetching, client-side hydration
- Advanced component patterns: HOC, Render Props, functional components, async components
- Internationalization: Multi-language support
- Testing strategies: Unit testing, end-to-end testing, performance testing
- Deployment optimization: Build optimization, static asset optimization, server configuration
By mastering these advanced topics, you can fully leverage Lyt.js's potential to build more professional and efficient frontend applications.