Slash vs React
Slash vs React
Section titled “Slash vs React”Esta página compara Slash e React em termos de arquitetura, performance, DX (Developer Experience) e casos de uso. Ambas são excelentes bibliotecas, mas com filosofias e trade-offs diferentes.
Resumo Rápido
Section titled “Resumo Rápido”| Aspecto | Slash | React |
|---|---|---|
| Virtual DOM | ❌ Não | ✅ Sim |
| Reatividade | Observer Pattern (re-render por componente que lê o state) | Re-render component tree |
| SSR | ✅ renderToString/renderToStream no pacote | ✅ react-dom/server (frameworks adicionam roteamento e data loading) |
| Ecossistema | 🌱 Crescendo | 🌳 Maduro e extenso |
| Curva de Aprendizado | Baixa | Média |
| Tooling | TypeScript nativo | Excelente (DevTools, etc) |
Arquitetura Fundamental
Section titled “Arquitetura Fundamental”React: Virtual DOM e Reconciliação
Section titled “React: Virtual DOM e Reconciliação”React usa um Virtual DOM para comparar estados e fazer updates eficientes:
// Reactimport { useState } from 'react'
function Counter() { const [count, setCount] = useState(0)
// Todo o componente re-renderiza quando count muda console.log('Component rendered')
return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}> Increment </button> </div> )}Como funciona:
- State muda via
setCount() - React agenda re-render do componente
- Componente executa novamente (função é chamada)
- React compara Virtual DOM antigo vs novo
- Aplica apenas as diferenças no DOM real
Slash: Observer Pattern (Sem VDOM)
Section titled “Slash: Observer Pattern (Sem VDOM)”Slash usa um sistema de estado reativo baseado em Observer Pattern: um componente que lê state.get() re-executa quando o state muda e seus nós são substituídos, sem diff de Virtual DOM:
// Slashimport { html, createState } from '@_bashell/slash'
// O state fica fora do componente: se fosse criado dentro, seria recriado a cada renderconst count = createState(0)
// Monte como <${Counter} />function Counter() { // Componente re-executa quando count muda (porque leu count.get()) console.log('Component rendered')
return html` <div> <p>Count: ${count.get()}</p> <button onClick=${() => count.set(count.get() + 1)}> Increment </button> </div> `}Como funciona:
- State muda via
count.set() - O componente que leu
count.get()executa de novo - Os nós anteriores do componente são substituídos pelos novos
- Sem diff de Virtual DOM
- A granularidade é o componente: divida a interface em componentes pequenos para re-renderizar só o necessário
Performance
Section titled “Performance”Benchmarks e tamanho
Section titled “Benchmarks e tamanho”Esta página não traz benchmarks nem comparação de tamanho com o React: 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: ≈ 8,3 KB gzip. O número depende do que seu app importa.
Developer Experience
Section titled “Developer Experience”Sintaxe e API
Section titled “Sintaxe e API”// Reactimport { useState } from 'react'
function Greeting({ name }) { const [count, setCount] = useState(0)
return ( <div> <h1>Hello {name}</h1> <p>Clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click </button> </div> )}// Slashimport { html, createState } from '@_bashell/slash'
// Slash não tem estado local por instância: o state vive fora do componente// (dentro dele seria recriado a cada render). Monte como <${Greeting} name="..." />const count = createState(0)
function Greeting({ name }) { return html` <div> <h1>Hello ${name}</h1> <p>Clicked ${count.get()} times</p> <button onClick=${() => count.set(count.get() + 1)}> Click </button> </div> `}// Reactimport { useState, useEffect } from 'react'
function Timer() { const [seconds, setSeconds] = useState(0)
useEffect(() => { const interval = setInterval(() => { setSeconds(s => s + 1) }, 1000)
return () => clearInterval(interval) }, [])
return <p>Seconds: {seconds}</p>}// Slashimport { html, createState } from '@_bashell/slash'
const seconds = createState(0)
// Slash não tem useEffect nem onCleanup: o efeito vive fora do componente// e 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: ${seconds.get()}</p>`}// Reactimport { useState } from 'react'
function LoginForm() { const [email, setEmail] = useState('') const [password, setPassword] = useState('')
const handleSubmit = (e) => { e.preventDefault() console.log({ email, password }) }
return ( <form onSubmit={handleSubmit}> <input value={email} onChange={(e) => setEmail(e.target.value)} /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> <button type="submit">Login</button> </form> )}// Slashimport { html, createState } from '@_bashell/slash'
const form = createState({ email: '', password: '' })
// Os campos não leem o state no render, então não são recriados a cada teclafunction LoginForm() { const handleSubmit = (e: Event) => { e.preventDefault() console.log(form.get()) }
return html` <form onSubmit=${handleSubmit}> <input onInput=${(e: Event) => form.set({ ...form.get(), email: (e.target as HTMLInputElement).value })} /> <input type="password" onInput=${(e: Event) => form.set({ ...form.get(), password: (e.target as HTMLInputElement).value })} /> <button type="submit">Login</button> </form> `}Observações:
- React tem mais boilerplate (
useState,useEffect, etc) - Slash é mais direto, mas não tem estado local nem hooks de efeito: o state fica fora do componente e efeitos/cleanup são por sua conta
- Ambos têm boa DX, mas Slash é mais minimalista
Ecossistema
Section titled “Ecossistema”Vantagens:
- ✅ Ecossistema gigantesco
- ✅ Frameworks (Next.js, Remix, Gatsby)
- ✅ UI libraries (MUI, Chakra, Ant Design)
- ✅ DevTools excelentes
- ✅ Comunidade massiva
- ✅ Recursos de aprendizado abundantes
Exemplos:
# Frameworksnpx create-next-appnpx create-remix
# UI Librariesnpm install @mui/materialnpm install chakra-ui
# State Managementnpm install zustandnpm install jotainpm install reduxVantagens:
- ✅ Sem dependências externas
- ✅ TypeScript first-class
- ✅ SSR nativo
- ✅ Router integrado
- ✅ Data loading isomórfico
Status Atual:
- 🌱 Ecossistema em crescimento
- 📦 Foco em simplicidade e zero config
- 🎯 Ideal para apps pequenos/médios
Casos de Uso
Section titled “Casos de Uso”Quando Usar React
Section titled “Quando Usar React”-
Aplicações Empresariais Grandes
- Múltiplos times
- Necessidade de UI libraries maduras
- Ecosistema extenso importante
-
Necessidade de Frameworks Específicos
- Next.js para SSR/SSG avançado
- Remix para data loading
- Gatsby para sites estáticos
-
Contratação e Onboarding
- Pool de desenvolvedores React é enorme
- Curva de aprendizado conhecida
- Material de treinamento abundante
-
Mobile (React Native)
- Código compartilhado web/mobile
- Ecosistema maduro
Quando Usar Slash
Section titled “Quando Usar Slash”-
Controle sobre o DOM
- Atualizações diretas, sem Virtual DOM
- Integração com código DOM existente
- Aplicações com poucas dependências
-
Bundle Size Limitado
- Um app mínimo mede ≈ 8,3 KB gzip (veja a seção Performance)
- Quando cada dependência conta
- Embedded apps
-
Simplicidade e Rapidez de Desenvolvimento
- Protótipos rápidos
- MVPs
- Apps pequenas/médias
-
SSR Simples Sem Frameworks
- Blog estático com interatividade
- Landing pages dinâmicas
- Sites de documentação
-
Aprendizado de Fundamentos
- Entender reatividade
- Aprender DOM manipulation
- Projetos educacionais
Migração
Section titled “Migração”De React para Slash
Section titled “De React para Slash”O que é similar:
- Componentes funcionais
- Props e children
- Event handlers
- Conditional rendering
O que muda:
useState→createStateuseEffect→state.watch()(criado fora do componente; não háonCleanuppúblico)useMemo→ Não necessário (pode usar funções puras)- JSX →
htmltemplate tag (ou hyperscript)
Exemplo de migração:
// Reactfunction TodoItem({ todo, onToggle }) { const [isEditing, setIsEditing] = useState(false)
return ( <li> {isEditing ? ( <input defaultValue={todo.text} /> ) : ( <span onClick={() => onToggle(todo.id)}> {todo.text} </span> )} <button onClick={() => setIsEditing(!isEditing)}> Edit </button> </li> )}// Slashimport { html, createState } from '@_bashell/slash'
// Sem estado local por instância: guarde qual item está em edição fora do componenteconst editingId = createState<number | null>(null)
function TodoItem({ todo, onToggle }) { const isEditing = editingId.get() === todo.id
return html` <li> ${isEditing ? html` <input value=${todo.text} /> ` : html` <span onClick=${() => onToggle(todo.id)}> ${todo.text} </span> `} <button onClick=${() => editingId.set(isEditing ? null : todo.id)}> Edit </button> </li> `}Trade-offs Principais
Section titled “Trade-offs Principais”Prós:
- ✅ Ecossistema maduro e extenso
- ✅ Ferramentas de desenvolvimento excelentes
- ✅ Grande comunidade e recursos
- ✅ Padrões estabelecidos
- ✅ React Native para mobile
Contras:
- ❌ Mais dependências (
reactereact-dom) - ❌ Mais boilerplate (hooks, etc)
- ❌ Re-renders podem ser confusos
- ❌ SSR com roteamento e data loading costuma exigir um framework
Prós:
- ✅ Bundle pequeno (app mínimo medido em ≈ 8,3 KB gzip, veja a seção Performance)
- ✅ API minimalista e direta
- ✅ SSR nativo
- ✅ TypeScript first-class
- ✅ Sem dependências
Contras:
- ❌ Ecossistema menor
- ❌ Comunidade pequena
- ❌ Menos recursos de aprendizado
- ❌ Sem mobile (por enquanto)
- ❌ Ferramentas de dev em desenvolvimento
Conclusão
Section titled “Conclusão”Escolha React se:
- Precisa de ecossistema maduro
- Trabalha em time grande
- Necessita de UI libraries prontas
- Quer React Native
- Valoriza estabilidade e padrões
Escolha Slash se:
- Quer uma biblioteca pequena e sem dependências
- Bundle size é limitação (app mínimo: ≈ 8,3 KB gzip)
- Prefere simplicidade
- Gosta de controle direto
- App pequena/média
- Quer aprender conceitos fundamentais
Ambas são excelentes. A escolha depende do contexto do projeto e preferências da equipe.
Próximos Passos
Section titled “Próximos Passos”- Slash vs Vue - Comparação com Vue
- Slash vs Solid - Comparação com SolidJS
- Guia de Migração - Migrando de outras bibliotecas