Performance

On this page 35

stx is built for speed and provides comprehensive performance optimization features. This page covers all performance capabilities and optimization strategies available in the stx ecosystem.

Markdown Parser Performance

The @stacksjs/ts-markdown package implements a high-performance markdown parser built specifically for Bun. The parser uses a flat token stream architecture inspired by markdown-it, combined with aggressive optimization techniques.

Benchmark Results

Performance comparison against popular markdown parsers:

Document Size@stacksjs/ts-markdownmarkdown-itSpeedup
Small (< 1KB)324B ops/sec112B ops/sec2.89x
Medium (~3KB)34.7B ops/sec17.7B ops/sec1.96x
Large (~50KB)1.81B ops/sec1.25B ops/sec1.45x

Architecture

The parser achieves this performance through several key design decisions:

  • Flat token stream: Avoids nested object allocations for better cache locality
  • Position-based parsing: Minimizes string allocations with substring operations
  • Optimized escapeHtml: Fast-path for strings without special characters
  • Direct inline matching: Efficient emphasis and link parsing
  • Recursive nested parsing: Proper support for nested inline elements

Usage

import { parseMarkdown } from '@stacksjs/ts-markdown'

const html = parseMarkdown('# Hello **world**')
// <h1 id="hello-world">Hello <strong>world</strong></h1>

The parser supports GitHub Flavored Markdown (GFM) including tables, task lists, and strikethrough text.

Runtime Performance

Fast Template Compilation

stx compiles templates to highly optimized JavaScript:

// Compile-time optimization
const template = compile(`
  @foreach(items as item)
    <div class="item">{{ item.name }}</div>
  @endforeach
`)

// Generates optimized code
function render(context) {
  let html = ''
  for (const item of context.items) {
    html += `<div class="item">${escape(item.name)}</div>`
  }
  return html
}

Efficient Rendering

// Streaming rendering for large datasets
import { renderStream } from '@stacksjs/core'

const stream = renderStream(template, {
  items: largeDataset,
  chunkSize: 100
})

// Progressive rendering
stream.on('chunk', (html) => {
  response.write(html)
})

Memory Management

// Automatic memory pooling
const pool = createTemplatePool({
  maxSize: 1000,
  ttl: 300000 // 5 minutes
})

// Efficient component recycling
const component = pool.get('Button')
component.render(props)
pool.release(component)

Build-time Optimization

Code Splitting

// Automatic route-based splitting
const routes = [
  {
    path: '/dashboard',
    component: () => import('./Dashboard.stx')
  },
  {
    path: '/profile',
    component: () => import('./Profile.stx')
  }
]

// Component-level splitting
const HeavyComponent = lazy(() => import('./HeavyComponent.stx'))

Tree Shaking

// Dead code elimination
import { render } from '@stacksjs/core' // Only imports what's used
import { component } from '@stacksjs/components' // Tree-shaken automatically

// Bundle analysis
bun run build:analyze

Asset Optimization

// Image optimization
const optimizedImage = `
  <img
    src="{{ image.src }}"
    srcset="{{ image.srcset }}"
    sizes="(max-width: 768px) 100vw, 50vw"
    loading="lazy"
    decoding="async"
  />
`

// CSS optimization
const styles = css`
  .button {
    /* Critical CSS inlined */
    display: inline-block;
    padding: 8px 16px;
  }
`

Caching Strategies

Template Caching

// In-memory template caching
const cache = createCache({
  strategy: 'lru',
  maxSize: 10000,
  ttl: 3600000 // 1 hour
})

// Redis-based distributed caching
const distributedCache = createRedisCache({
  host: 'redis.example.com',
  keyPrefix: 'stx:templates:'
})

Component Caching

// Memoized components
const MemoizedCard = memo(Card, {
  shouldUpdate: (prevProps, nextProps) => {
    return prevProps.data.id !== nextProps.data.id
  }
})

// Cache by props
@cache({
  key: (props) => `user-${props.userId}`,
  ttl: 300 // 5 minutes
})
function UserProfile({ userId }) {
  // Expensive computation
  const user = await fetchUserData(userId)
  return render(userTemplate, { user })
}

HTTP Caching

// Cache headers optimization
app.use(cacheHeaders({
  '/static': { maxAge: 31536000 }, // 1 year
  '/api': { maxAge: 300 }, // 5 minutes
  '/': { maxAge: 0, mustRevalidate: true }
}))

// CDN optimization
const cdnConfig = {
  enabled: true,
  provider: 'cloudflare',
  purgeOnDeploy: true,
  headers: {
    'Cache-Control': 'public, max-age=31536000',
    'CDN-Cache-Control': 'public, max-age=86400'
  }
}

Database Performance

Query Optimization

// Efficient data loading
const users = await db.users
  .select(['id', 'name', 'email']) // Only select needed fields
  .where('active', true)
  .limit(100)
  .offset(page * 100)

// N+1 query prevention
const usersWithPosts = await db.users
  .with('posts') // Eager loading
  .where('active', true)

Connection Pooling

// Database connection pool
const pool = createPool({
  host: 'localhost',
  database: 'stx_app',
  user: 'stx_user',
  password: process.env.DB_PASSWORD,
  min: 2,
  max: 10,
  idleTimeoutMillis: 30000
})

Frontend Performance

Client-side Optimization

// Preload critical resources
preload('/api/user', { as: 'fetch' })
preload('/fonts/inter.woff2', { as: 'font', type: 'font/woff2' })

// Intersection Observer for lazy loading
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadComponent(entry.target)
      observer.unobserve(entry.target)
    }
  })
})

Bundle Optimization

// Webpack bundle optimization
export default {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        },
        common: {
          name: 'common',
          minChunks: 2,
          chunks: 'all'
        }
      }
    }
  }
}

Performance Monitoring

Core Web Vitals

// Track performance metrics
import { performanceMonitor } from '@stacksjs/monitoring'

performanceMonitor.track({
  // Largest Contentful Paint
  onLCP: (metric) => {
    analytics.track('LCP', { value: metric.value })
  },

  // First Input Delay
  onFID: (metric) => {
    analytics.track('FID', { value: metric.value })
  },

  // Cumulative Layout Shift
  onCLS: (metric) => {
    analytics.track('CLS', { value: metric.value })
  }
})

Custom Performance Metrics

// Custom timing measurements
const renderTimer = performance.mark('render-start')
await renderComponent()
performance.mark('render-end')
performance.measure('component-render', 'render-start', 'render-end')

// Memory usage tracking
const memoryUsage = performance.memory
analytics.track('memory-usage', {
  used: memoryUsage.usedJSHeapSize,
  total: memoryUsage.totalJSHeapSize
})

Performance Testing

Load Testing

// Artillery load testing
export default {
  config: {
    target: 'http://localhost:3000',
    phases: [
      { duration: 60, arrivalRate: 10 },
      { duration: 120, arrivalRate: 50 },
      { duration: 60, arrivalRate: 100 }
    ]
  },
  scenarios: [
    {
      name: 'Homepage load test',
      requests: [
        { get: { url: '/' } },
        { get: { url: '/api/users' } }
      ]
    }
  ]
}

Benchmarking

// Performance benchmarks
import { benchmark } from '@stacksjs/testing'

benchmark('template rendering', async () => {
  const html = render(complexTemplate, largeDataset)
  return html
}, {
  iterations: 1000,
  warmup: 100
})

benchmark('component mounting', async () => {
  const component = new Component(props)
  await component.mount()
  component.unmount()
}, {
  iterations: 500
})

Advanced Optimization

Service Workers

For a server-rendered STX app, configure the app offline worker rather than adding a second worker that caches API answers without accounting for the signed-in user:

import type { StxOptions } from '@stacksjs/stx'

export default {
  offline: {
    enabled: true,
    pages: ['/m', '/m/calendar'],
    apiPrefix: '/api/',
    networkTimeoutMs: 1500,
    precacheTimeoutMs: 10000,
    fallback: '/m',
  },
} satisfies StxOptions

The server integration must serve generateOfflineWorker(config.offline, buildId) at OFFLINE_WORKER_PATH (/_stx/sw.js) with scope /; rendered pages register it automatically when offline.enabled is true. Use the same offline configuration and build identifier when rendering pages and serving the worker.

Installation fetches each listed page and its router fragment, then the linked stylesheets and scripts. At most two background downloads run at once, leaving connection capacity for navigation. Each background request has a precacheTimeoutMs budget covering its response body as well as its headers; a stalled download is aborted and does not prevent the remaining files from being attempted. Failed files can still be requested normally by the page. This budget does not cancel foreground navigation or API reads.

networkTimeoutMs controls when a foreground read falls back to an available cached copy. Pages are kept per build, and API answers per bearer token. Requests and API responses marked no-store are not retained. Only declare staticPages for account-independent HTML shells. On sign-out, call the offline composable's clearOfflineData() to remove retained account data.

Edge Computing

// Edge function optimization
export default {
  runtime: 'edge',
  regions: ['iad1', 'sfo1'],
  cache: {
    maxAge: 3600,
    staleWhileRevalidate: 86400
  }
}

// Geographic content delivery
const userLocation = request.geo.country
const localizedContent = await getLocalizedContent(userLocation)

Best Practices

Code Optimization

// Efficient loops
// Slow
for (let i = 0; i < items.length; i++) {
  processItem(items[i])
}

// Fast
const length = items.length
for (let i = 0; i < length; i++) {
  processItem(items[i])
}

// Even faster for simple operations
items.forEach(processItem)

Memory Optimization

// Object pooling
const objectPool = {
  objects: [],
  get() {
    return this.objects.pop() || {}
  },
  release(obj) {
    // Clear object properties
    Object.keys(obj).forEach(key => delete obj[key])
    this.objects.push(obj)
  }
}