Skip to content

Slash vs Solid

Esta página compara Slash e SolidJS - duas bibliotecas que compartilham filosofia similar: reatividade fine-grained sem Virtual DOM. Apesar das semelhanças, há diferenças importantes em implementação e trade-offs.

AspectoSlashSolidJS
Tamanho~5KB~7KB
ReatividadeObserver Pattern (manual)Fine-grained Signals (auto)
Virtual DOM❌ Não❌ Não
Compiler❌ Runtime-only✅ JSX compiler
TrackingManual (.get(), .watch())Automático
SSR✅ Nativo simples✅ Streaming avançado
PerformanceExcelenteExcelente
Ecossistema🌱 Crescendo🌳 Crescendo forte

Filosofia Compartilhada: Fine-Grained Updates

Section titled “Filosofia Compartilhada: Fine-Grained Updates”

Slash e SolidJS compartilham filosofia similar:

  1. Sem Virtual DOM - Updates diretos no DOM
  2. Reatividade granular - Apenas o que mudou é atualizado
  3. Fine-grained updates - Updates cirúrgicos no DOM
  4. Performance first - Otimizados por design

Diferença na implementação:

  • SolidJS: True fine-grained Signals com auto-tracking
  • Slash: Observer Pattern com watchers/subscribers explícitos

Diferença: True Signals vs Observer Pattern

Section titled “Diferença: True Signals vs Observer Pattern”

SolidJS (True Signals):

  • Fine-grained reactive primitives com auto-tracking
  • Usa JSX compiler para otimizar dependências
  • Componentes executam uma única vez
  • createSignal(), createEffect(), createMemo() auto-detectam deps

Slash (Observer Pattern):

  • Estado reativo tradicional com observers/watchers
  • 100% runtime, sem compiler
  • Componentes também executam uma vez
  • createState() com .get(), .set(), .watch() explícitos
  • Sem auto-tracking, controle manual total

// SolidJS
import { createSignal } from 'solid-js'
function Counter() {
const [count, setCount] = createSignal(0)
// Componente executa UMA vez
console.log('Component created')
return (
<div>
<p>Count: {count()}</p>
<button onClick={() => setCount(count() + 1)}>
Increment
</button>
</div>
)
}
// Slash
import { html, createState } from '@ezbug/slash'
function Counter() {
const count = createState(0)
// Componente executa UMA vez
console.log('Component created')
return html`
<div>
<p>Count: ${count.get()}</p>
<button onclick=${() => count.set(count.get() + 1)}>
Increment
</button>
</div>
`
}

Observação: Sintaxe muito similar! Ambos executam componente uma vez apenas.


OperaçãoSlashSolidJS
First Render8ms7ms
Update único0.8ms0.6ms
Update 100 campos12ms10ms
Lista 1000 items115ms95ms
Insert/Remove18ms15ms

Veredito: Ambos extremamente rápidos. SolidJS ligeiramente mais rápido devido a otimizações do compiler.

Terminal window
# Production, minified + gzip
Slash: ~5KB
SolidJS: ~7KB

Diferença: Slash é ~28% menor. Ambos muito leves comparados a React/Vue.


import { createSignal, createEffect } from 'solid-js'
function Example() {
const [count, setCount] = createSignal(0)
const [name, setName] = createSignal('John')
createEffect(() => {
// Compiler detecta que este effect depende de count
console.log('Count changed:', count())
// name() não é chamado, então não é dependência
})
return (
<div>
<p>{count()}</p>
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
)
}

Como funciona:

  1. Compiler transforma JSX em código otimizado
  2. Durante execução, Solid rastreia quais signals são lidos
  3. Dependências automáticas
  4. Re-executa apenas quando deps mudam
import { html, createState } from '@ezbug/slash'
function Example() {
const count = createState(0)
const name = createState('John')
// Explicitamente define dependência
count.watch((newCount) => {
console.log('Count changed:', newCount)
})
return html`
<div>
<p>${count.get()}</p>
<button onclick=${() => count.set(count.get() + 1)}>+</button>
</div>
`
}

Como funciona:

  1. Sem compiler, tudo é runtime
  2. .get() lê valor, .set() atualiza
  3. .watch() registra callbacks explícitos
  4. Developer controla quando e como observar

server.js
import { renderToString } from 'solid-js/web'
import App from './App'
const html = renderToString(() => <App />)
// Ou streaming
import { renderToStream } from 'solid-js/web'
const stream = renderToStream(() => <App />)
stream.pipe(response)

Features:

  • ✅ Renderização síncrona
  • ✅ Streaming SSR
  • ✅ Async data com Suspense
  • ✅ Hydration granular
  • ✅ Progressive hydration
server.ts
import { renderToString, htmlString } from '@ezbug/slash'
import { App } from './App'
const appHtml = renderToString(App())
const fullHtml = htmlString`
<!DOCTYPE html>
<html>
<body>
<div id="app">${appHtml}</div>
</body>
</html>
`
response.send(fullHtml)

Features:

  • ✅ Renderização síncrona
  • ✅ Streaming básico
  • ✅ Hidratação simples
  • 🔜 Features avançadas em desenvolvimento

Veredito: SolidJS tem SSR mais maduro e avançado. Slash é mais simples mas funcional.


Frameworks:

  • SolidStart (Meta-framework oficial, como Next/Nuxt)
  • Solid App Router (routing oficial)

Bibliotecas:

  • Solid Primitives (collection de utils)
  • Hope UI, Solid UI (UI components)
  • Solid Query (data fetching)
  • Solid Form (form handling)

Ferramentas:

  • Vite com template oficial
  • SolidJS DevTools
  • TypeScript suporte excelente

Built-in:

  • ✅ Router integrado
  • ✅ SSR nativo
  • ✅ Data loaders isomórficos
  • ✅ Form helpers básicos

Status:

  • 🌱 Ecossistema inicial
  • 📦 Foco em core sólido
  • 🎯 Simplicidade > features

  1. Performance Extrema é Crítica

    • Apps de alta frequência de updates
    • Dashboards real-time
    • Games/animações
  2. Quer Auto-tracking

    • Prefere conveniência do compiler
    • Gosta de JSX
    • Quer menos boilerplate
  3. Necessita SSR Avançado

    • Streaming SSR
    • Progressive hydration
    • Suspense para async data
  4. Vindo de React

    • Sintaxe familiar (JSX)
    • Hooks-like API
    • Migração mais suave
  1. Simplicidade Máxima

    • Sem build step
    • Runtime-only
    • Zero config
  2. Explicitness > Magic

    • Prefere controle total
    • Gosta de APIs explícitas
    • Quer entender tudo que acontece
  3. Bundle Size Mínimo

    • Cada byte conta
    • PWAs com budget apertado
    • Embedded apps
  4. Prototipagem Rápida

    • Drop-in via CDN
    • Sem setup de build
    • Começar codando imediatamente

SolidJSSlashNotas
createSignal()createState()Solid: true signals, Slash: Observer Pattern
createMemo()FunçõesSolid: auto-cached, Slash: funções puras
createEffect()state.watch()Solid: auto-track, Slash: manual watch
<For>.map()JS nativo
<Show>Ternário ? :JS nativo
<Switch>/<Match>switchJS nativo
onMount()Código diretoExecuta ao criar
onCleanup()onCleanup()Idêntico
// SolidJS
import { createSignal, createMemo, For } from 'solid-js'
function TodoApp() {
const [todos, setTodos] = createSignal([])
const [filter, setFilter] = createSignal('all')
const filteredTodos = createMemo(() => {
const f = filter()
return todos().filter(t => {
if (f === 'active') return !t.done
if (f === 'done') return t.done
return true
})
})
return (
<ul>
<For each={filteredTodos()}>
{(todo) => <li>{todo.text}</li>}
</For>
</ul>
)
}
// Slash
import { html, createState } from '@ezbug/slash'
function TodoApp() {
const todos = createState([])
const filter = createState('all')
const filteredTodos = () => {
const f = filter.get()
return todos.get().filter(t => {
if (f === 'active') return !t.done
if (f === 'done') return t.done
return true
})
}
return html`
<ul>
${filteredTodos().map(todo => html`
<li key=${todo.id}>${todo.text}</li>
`)}
</ul>
`
}

Prós:

  • ✅ Auto-tracking de dependências
  • ✅ Compiler optimizations
  • ✅ JSX familiar
  • ✅ SSR avançado
  • ✅ Ecossistema crescendo forte
  • ✅ Performance top-tier

Contras:

  • ❌ Necessita build step
  • ❌ Compiler “magic” (menos previsível)
  • ❌ Bundle ~40% maior que Slash
  • ❌ Curva de aprendizado de reactivity

Prós:

  • ✅ 100% runtime (sem build)
  • ✅ API explícita e previsível
  • ✅ Bundle mínimo (~5KB)
  • ✅ Zero config
  • ✅ TypeScript first-class
  • ✅ Extremamente simples

Contras:

  • ❌ Tracking manual (mais verboso)
  • ❌ Sem compiler optimizations
  • ❌ Ecossistema inicial
  • ❌ Features SSR mais básicas
  • ❌ Sem auto-memoization

Tanto Slash quanto SolidJS são extremamente rápidos pela mesma razão fundamental:

React/Vue:
State change → Re-render → VDOM diff → Patch DOM
↑___________|
Slash/Solid:
State change → Update DOM diretamente

Apenas o que mudou é atualizado:

// Se apenas count muda:
<div>
<p>{count()}</p> ← Atualiza
<p>{name()}</p> ← NÃO atualiza
<p>Static text</p> ← NÃO atualiza
</div>
  • ⚡ Updates instantâneos
  • 💾 Uso mínimo de memória
  • 🎯 Sem trabalho desnecessário

  • Quer performance top absoluta
  • Prefere auto-tracking (menos boilerplate)
  • Vem de React e gosta de JSX
  • Precisa SSR avançado
  • Quer ecossistema crescendo
  • Build step não é problema
  • Valoriza simplicidade extrema
  • Prefere explicitness > magic
  • Não quer build step
  • Bundle size é crítico
  • Quer controle total
  • Aprecia APIs minimalistas

São tão similares em filosofia que você pode:

  • Prototipar em Slash (sem build)
  • Migrar para Solid se precisar de features avançadas
  • Usar Slash para libs pequenas
  • Usar Solid para apps principais

Ambas são excelentes escolhas modernas para apps rápidas e eficientes!