Slash vs Solid
Slash vs SolidJS
Section titled “Slash vs SolidJS”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.
Resumo Rápido
Section titled “Resumo Rápido”| Aspecto | Slash | SolidJS |
|---|---|---|
| Reatividade | Observer Pattern (re-render por componente) | Fine-grained Signals (auto) |
| Virtual DOM | ❌ Não | ❌ Não |
| Compiler | ❌ Runtime-only | ✅ JSX compiler |
| Tracking | Por componente (.get() no render; .watch() explícito) | Automático |
| SSR | ✅ Nativo simples | ✅ Streaming avançado |
| Ecossistema | 🌱 Crescendo | 🌳 Crescendo forte |
Filosofia e Arquitetura
Section titled “Filosofia e Arquitetura”Filosofia Compartilhada
Section titled “Filosofia Compartilhada”Slash e SolidJS compartilham filosofia similar:
- ✅ Sem Virtual DOM - Updates diretos no DOM
- ✅ 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
Sintaxe e API
Section titled “Sintaxe e API”Componentes Básicos
Section titled “Componentes Básicos”// SolidJSimport { 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> )}// Slashimport { html, createState } from '@_bashell/slash'
// O state fica fora do componente: se fosse criado dentro, seria recriado a cada renderconst 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.
// SolidJSimport { createSignal, createMemo } from 'solid-js'
function Example() { const [count, setCount] = createSignal(0)
// Cached, só recalcula quando count muda const doubled = createMemo(() => { console.log('Computing doubled') return count() * 2 })
return <p>Doubled: {doubled()}</p>}// Slashimport { html, createState } from '@_bashell/slash'
const count = createState(0)
// Função pura, sem cache automáticoconst doubled = () => { console.log('Computing doubled') return count.get() * 2}
// Monte como <${Example} />: ler count.get() inscreve o componentefunction Example() { return html`<p>Doubled: ${doubled()}</p>`}Diferença: SolidJS createMemo() cacheia automaticamente. Slash usa funções puras (pode adicionar cache manual se necessário).
// SolidJSimport { createSignal, createEffect } from 'solid-js'
function Timer() { const [seconds, setSeconds] = createSignal(0)
// Effect auto-tracked createEffect(() => { console.log('Seconds:', seconds()) })
const interval = setInterval(() => { setSeconds(s => s + 1) }, 1000)
onCleanup(() => clearInterval(interval))
return <p>{seconds()}</p>}// Slashimport { html, createState } from '@_bashell/slash'
const seconds = createState(0)
// Watcher explícito (criado uma vez, fora do componente)seconds.watch((newVal) => { console.log('Seconds:', newVal)})
// Slash não tem onCleanup público: você controla início e fimconst interval = setInterval(() => { seconds.set(seconds.get() + 1)}, 1000)// clearInterval(interval) quando não precisar mais
function Timer() { return html`<p>${seconds.get()}</p>`}Diferença: SolidJS createEffect() auto-detecta deps. Slash watch() é explícito.
// SolidJSimport { createSignal, For } from 'solid-js'
function TodoList() { const [todos, setTodos] = createSignal([ { id: 1, text: 'Learn Solid' }, { id: 2, text: 'Build app' } ])
return ( <ul> <For each={todos()}> {(todo) => <li>{todo.text}</li>} </For> </ul> )}// Slashimport { html, createState } from '@_bashell/slash'
const todos = createState([ { id: 1, text: 'Learn Slash' }, { id: 2, text: 'Build app' }])
function TodoList() { return html` <ul> ${todos.get().map(todo => html` <li key=${todo.id}>${todo.text}</li> `)} </ul> `}Diferença: SolidJS tem componente <For> otimizado. Slash usa .map() nativo do JavaScript.
Performance
Section titled “Performance”Benchmarks e tamanho
Section titled “Benchmarks e tamanho”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.
Auto-tracking vs Manual Tracking
Section titled “Auto-tracking vs Manual Tracking”SolidJS: Auto-tracking (em runtime)
Section titled “SolidJS: Auto-tracking (em runtime)”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:
- Compiler transforma JSX em código otimizado
- Durante execução, Solid rastreia quais signals são lidos
- Dependências automáticas
- Re-executa apenas quando deps mudam
Slash: Manual Tracking (Explícito)
Section titled “Slash: Manual Tracking (Explícito)”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 componentefunction Example() { return html` <div> <p>${count.get()}</p> <button onClick=${() => count.set(count.get() + 1)}>+</button> </div> `}Como funciona:
- Sem compiler, tudo é runtime
.get()lê valor,.set()atualiza.get()durante a execução de um componente o inscreve no state; o componente re-executa quando o state muda.watch()registra callbacks explícitos fora do componente
SSR (Server-Side Rendering)
Section titled “SSR (Server-Side Rendering)”SolidJS: Streaming SSR Avançado
Section titled “SolidJS: Streaming SSR Avançado”import { renderToString } from 'solid-js/web'import App from './App'
const html = renderToString(() => <App />)
// Ou streamingimport { 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
Slash: SSR Simples e Direto
Section titled “Slash: SSR Simples e Direto”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.
Ecossistema
Section titled “Ecossistema”SolidJS
Section titled “SolidJS”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
Casos de Uso
Section titled “Casos de Uso”Quando Usar SolidJS
Section titled “Quando Usar SolidJS”-
Atualizações Granulares
- Reatividade fine-grained (atualiza só o ponto afetado)
- Componentes que executam uma única vez
- Apps com muitos updates pequenos
-
Quer Auto-tracking
- Prefere conveniência do compiler
- Gosta de JSX
- Quer menos boilerplate
-
Necessita SSR Avançado
- Streaming SSR
- Progressive hydration
- Suspense para async data
-
Vindo de React
- Sintaxe familiar (JSX)
- Hooks-like API
- Migração mais suave
Quando Usar Slash
Section titled “Quando Usar Slash”-
Simplicidade Máxima
- Sem build step
- Runtime-only
- Zero config
-
Explicitness > Magic
- Prefere controle total
- Gosta de APIs explícitas
- Quer entender tudo que acontece
-
Bundle Size Pequeno
- Um app mínimo mede ≈ 8,3 KB gzip
- Poucas dependências
- Embedded apps
-
Prototipagem Rápida
- Drop-in via CDN
- Sem setup de build
- Começar codando imediatamente
Migração entre Slash e SolidJS
Section titled “Migração entre Slash e SolidJS”Conceitos Equivalentes
Section titled “Conceitos Equivalentes”| SolidJS | Slash | Notas |
|---|---|---|
createSignal() | createState() | Solid: true signals, Slash: Observer Pattern |
createMemo() | Funções | Solid: 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> | switch | JS nativo |
onMount() | Código fora do componente | O corpo do componente re-executa; não há hook de montagem |
onCleanup() | Sem equivalente público | Gerencie timers/listeners você mesmo |
Exemplo de Migração
Section titled “Exemplo de Migração”// SolidJSimport { 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> )}// Slashimport { 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> `}Trade-offs Principais
Section titled “Trade-offs Principais”SolidJS
Section titled “SolidJS”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
Atualização sem Virtual DOM
Section titled “Atualização sem Virtual DOM”Slash e SolidJS não usam Virtual DOM. Os caminhos de atualização são diferentes:
Sem Virtual DOM Diff
Section titled “Sem Virtual DOM Diff”React/Vue:State change → Re-render → VDOM diff → Patch DOM ↑___________|
Solid: State change → Update DOM diretamenteSlash: State change → Re-executa o componente → Substitui seus nós (sem diff)Fine-Grained Reactivity (Solid)
Section titled “Fine-Grained Reactivity (Solid)”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>Conclusão
Section titled “Conclusão”Escolha SolidJS se:
Section titled “Escolha SolidJS se:”- 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
Escolha Slash se:
Section titled “Escolha Slash se:”- 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
Ou use ambos!
Section titled “Ou use ambos!”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.
Próximos Passos
Section titled “Próximos Passos”- Slash vs React - Comparação com React
- Slash vs Vue - Comparação com Vue
- API Reference - Documentação completa da API
- Exemplos Práticos - Apps completas