Skip to content

Slash vs Solid

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

AspectoSlashSolidJS
ReatividadeObserver Pattern (re-render por componente)Fine-grained Signals (auto)
Virtual DOM❌ Não❌ Não
Compiler❌ Runtime-only✅ JSX compiler
TrackingPor componente (.get() no render; .watch() explícito)Automático
SSR✅ Nativo simples✅ Streaming avançado
Ecossistema🌱 Crescendo🌳 Crescendo forte

Slash e SolidJS compartilham filosofia similar:

  1. ✅ Sem Virtual DOM - Updates diretos no DOM
  2. ✅ Atualização direta do DOM - sem diffing de árvore virtual

Diferença na implementação:

  • SolidJS: True fine-grained Signals com auto-tracking (atualiza só o ponto afetado)
  • Slash: Observer Pattern com re-render por componente (atualiza o componente que leu o state)

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
  • Rastreia dependências em runtime; o compiler JSX apenas transforma o template
  • 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 re-executam quando um state lido muda (monte-os como <${Comp} />)
  • createState() com .get(), .set(), .watch() explícitos
  • Tracking por componente: as chamadas a get() durante a execução do componente definem suas dependências; .watch() é o controle manual

// 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 '@_bashell/slash'
// O state fica fora do componente: se fosse criado dentro, seria recriado a cada render
const count = createState(0)
function Counter() {
// Componente re-executa quando count muda
console.log('Component rendered')
return html`
<div>
<p>Count: ${count.get()}</p>
<button onClick=${() => count.set(count.get() + 1)}>
Increment
</button>
</div>
`
}

Observação: A sintaxe é parecida, mas o modelo de execução difere: no Solid o componente executa uma vez; no Slash ele re-executa quando um state que leu muda.


Esta página não traz tabelas de benchmark nem comparação de tamanho com o SolidJS: não há medições reproduzíveis no repositório para sustentá-las. Meça no seu caso de uso.

Para o Slash, o repositório mede o tamanho de um app mínimo (createState + html + render, minificado) com bun test scripts/bundle-size.test.ts no pacote core. Resultado medido na versão atual: ≈ 8,3 KB gzip. O número depende do que seu app importa.


import { createSignal, createEffect } from 'solid-js'
function Example() {
const [count, setCount] = createSignal(0)
const [name, setName] = createSignal('John')
createEffect(() => {
// O runtime detecta que este effect depende de count (leu 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 '@_bashell/slash'
const count = createState(0)
const name = createState('John')
// Observer explícito (criado uma vez, fora do componente)
count.watch((newCount) => {
console.log('Count changed:', newCount)
})
// Dependência implícita por componente: count.get() no render inscreve o componente
function Example() {
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. .get() durante a execução de um componente o inscreve no state; o componente re-executa quando o state muda
  4. .watch() registra callbacks explícitos fora do componente

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, serializeStateForScript } from '@_bashell/slash/ssr'
import { App } from './App'
// renderToString devolve { html, state }
const { html: appHtml, state } = renderToString(() => App())
// O documento é um template literal comum (htmlString com <!DOCTYPE> não funciona)
const fullHtml = `<!DOCTYPE html>
<html>
<body>
<div id="app">${appHtml}</div>
<script id="__SLASH_STATE__" type="application/json">${serializeStateForScript(state)}</script>
</body>
</html>`
response.send(fullHtml)

Features:

  • ✅ Renderização síncrona
  • ✅ Streaming básico
  • ✅ Hidratação simples (o cliente limpa o HTML do servidor e renderiza de novo)
  • 🔜 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. Atualizações Granulares

    • Reatividade fine-grained (atualiza só o ponto afetado)
    • Componentes que executam uma única vez
    • Apps com muitos updates pequenos
  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 Pequeno

    • Um app mínimo mede ≈ 8,3 KB gzip
    • Poucas dependências
    • 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 fora do componenteO corpo do componente re-executa; não há hook de montagem
onCleanup()Sem equivalente públicoGerencie timers/listeners você mesmo
// 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 '@_bashell/slash'
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
})
}
function TodoApp() {
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

Contras:

  • ❌ Necessita build step
  • ❌ Rastreamento implícito (menos explícito)
  • ❌ Curva de aprendizado de reactivity

Prós:

  • ✅ 100% runtime (sem build)
  • ✅ API explícita e previsível
  • ✅ Bundle pequeno (veja a medição em Benchmarks e tamanho)
  • ✅ Zero config
  • ✅ TypeScript first-class
  • ✅ API pequena e simples

Contras:

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

Slash e SolidJS não usam Virtual DOM. Os caminhos de atualização são diferentes:

React/Vue:
State change → Re-render → VDOM diff → Patch DOM
↑___________|
Solid: State change → Update DOM diretamente
Slash: State change → Re-executa o componente → Substitui seus nós (sem diff)

No Solid apenas o que mudou é atualizado. No Slash a unidade é o componente:

// Se apenas count muda:
<div>
<p>{count()}</p> ← Atualiza
<p>{name()}</p> ← NÃO atualiza
<p>Static text</p> ← NÃO atualiza
</div>

  • Quer reatividade fine-grained
  • 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
  • Quer uma biblioteca pequena (app mínimo: ≈ 8,3 KB gzip)
  • 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 escolhas modernas sem Virtual DOM; a escolha depende do modelo de reatividade e do ecossistema que você precisa.