Guia de Arquitetura Web Jaspr (v0.22.x)
Objetivo
Jaspr é um framework web Dart (versão atual: 0.22.x).
Ao contrário do Flutter Web (que desenha pixels via Canvas e produz SEO ruim), o Jaspr compila Dart para elementos HTML e CSS semânticos. Use Jaspr para sites, blogs, landing pages ou qualquer projeto que exija SEO adequado.
Instruções
1. Conceito Central: Experiência de Codificação Similar ao Flutter
O Jaspr espelha o modelo de componentes do Flutter. O método build retorna um único Component (equivalente a um Widget do Flutter).
| Conceito Flutter | Conceito Jaspr | Notas |
|---|---|---|
Widget | Component | Todo elemento de UI no Jaspr é um Component |
StatelessWidget | StatelessComponent | UI declarativa pura; recebe BuildContext context |
StatefulWidget | StatefulComponent | Gerencia ciclo de vida com setState, initState, createState() |
InheritedWidget | InheritedComponent | Propaga estado para baixo na árvore de componentes |
1.1 Elementos DOM
O Jaspr renderiza para o DOM, portanto use seus helpers de tags HTML (div, p, img, etc.) de jaspr/dom.dart.
import 'package:jaspr/jaspr.dart';
class ProfileCard extends StatelessComponent {
final String name;
const ProfileCard({required this.name, super.key});
@override
Component build(BuildContext context) {
return div(
classes: 'profile-card',
styles: Styles.box(width: 300.px, backgroundColor: Colors.white),
[
h2([.text(name)]), // 🌟 .text() shorthand disponível desde Dart 3.10 (Component.text)
p([
.text('Hello World!'),
]),
button(
onClick: () => print('Button successfully clicked!'),
[.text('Contact Me')]
)
]
);
}
}
2. Integração com Tailwind CSS (jaspr_tailwind)
O Jaspr fornece integração oficial com Tailwind CSS via jaspr_tailwind.
2.1 Instalação e Configuração
dev_dependencies:
jaspr_tailwind: ^0.1.0
Crie web/styles.tw.css com a sintaxe CSS-first do Tailwind v4:
/* web/styles.tw.css */
@import "tailwindcss";
2.2 Carregando CSS Compilado no Componente Raiz
No componente raiz, use Document para vincular a folha de estilo compilada e consuma as classes Tailwind através do parâmetro classes:
import 'package:jaspr/jaspr.dart';
class App extends StatelessComponent {
@override
Component build(BuildContext context) {
return Document(
head: [
// 🌟 jaspr_tailwind compila automaticamente styles.tw.css → styles.css
link(href: 'styles.css', rel: 'stylesheet'),
],
body: div(
// Use classes Tailwind diretamente; jaspr_tailwind auto-atualiza durante o desenvolvimento
classes: 'bg-gray-100 min-h-screen flex items-center justify-center',
[
h1(classes: 'text-4xl font-bold text-blue-600', [.text('Hello Tailwind!')]),
]
),
);
}
}
3. Roteamento (jaspr_router)
O roteamento do Jaspr espelha o go_router com uma API declarativa.
3.1 Instalação e Configuração
dependencies:
jaspr_router: ^0.2.0
import 'package:jaspr/jaspr.dart';
import 'package:jaspr_router/jaspr_router.dart';
class MyApp extends StatelessComponent {
@override
Component build(BuildContext context) {
return Router(
routes: [
Route(
path: '/',
builder: (context, state) => const HomePage(),
),
Route(
path: '/about',
builder: (context, state) => const AboutPage(),
),
],
);
}
}
4. SSR: Pré-carregamento Assíncrono de Dados no Backend
A principal vantagem do Jaspr sobre o Flutter Web é a renderização no lado do servidor (SSR). Com o Flutter Web, os dados são buscados em initState, causando um estado de carregamento no cliente. Com o SSR do Jaspr, os dados são buscados no servidor antes que o HTML seja enviado ao navegador.
4.1 AsyncStatelessComponent (Apenas Servidor)
Importe jaspr/server.dart para usar AsyncStatelessComponent, que permite um método build assíncrono.
import 'package:jaspr/server.dart'; // 🌟 Import apenas para servidor
class ArticlePage extends AsyncStatelessComponent {
final String articleId;
const ArticlePage(this.articleId);
@override
Future<Component> build(BuildContext context) async {
// Executa no lado do servidor; use await livremente para chamadas de banco de dados/API
final articleData = await Database.fetchArticle(articleId);
// O navegador recebe HTML totalmente renderizado para conteúdo instantâneo e amigável ao SEO
return div([
h1([.text(articleData.title)]),
p([.text(articleData.content)]),
]);
}
}
4.2 Pré-carregamento com Estado (PreloadStateMixin)
Quando o estado precisa ser preservado, misture PreloadStateMixin:
class MyState extends State<MyStatefulComponent> with PreloadStateMixin {
@override
Future<void> preloadState() async {
// Executa no lado do servidor antes do initState(); prepara o estado para hidratação no cliente
await loadInitialData();
}
// ...
}
5. Testes (jaspr_test)
jaspr_test cobre testes unitários de componente, resultados SSR e interações no navegador.
5.1 Configuração de Dependência
dart pub add jaspr_test --dev
Como jaspr_test re-exporta o nativo package:test, não é necessário importá-lo separadamente.
5.2 Três Principais Funções de Teste
Devido às complexidades do ambiente HTML/Web, o Jaspr fornece três funções de teste específicas para cada cenário:
testComponents (Teste de Componente em Ambiente Virtual)
Teste unitário da lógica do seu Componente em um ambiente simulado puro Dart e sem cabeçalho. Este é o método mais rápido. O uso é muito semelhante ao testWidgets do Flutter.
import 'package:jaspr_test/jaspr_test.dart';
void main() {
testComponents('Testa se clicar no botão incrementa o contador', (tester) async {
tester.pumpComponent(MyComponent());
expect(find.text('Count: 0'), findsOneComponent);
await tester.click(find.tag('button'));
expect(find.text('Count: 1'), findsOneComponent);
});
}
testServer (Teste de Renderização no Lado do Servidor)
Destinado a testar aplicações SSR. Ele inicia diretamente um Servidor HTTP local simulado. Você pode enviar Requisições e verificar as strings HTML ou propriedades de estado retornadas pelo Servidor.
import 'package:jaspr_test/jaspr_test.dart';
void main() {
testServer('Verifica HTML renderizado no servidor', (tester) async {
final response = await tester.request('/');
expect(response.document.body?.text, contains('Welcome to SSR'));
});
}
testClient (Testes de Hidratação e Sincronização de Estado no Navegador)
Executa em um ambiente de navegador sem cabeçalho, testando se o cliente assume corretamente via hidratação e lida com interações DOM após receber initialStateData do servidor.
Restrições
- Use
AsyncStatelessComponentapenas no lado do servidor (jaspr/server.dart). Nunca no código de UI do cliente. - Não aninhe
Widgetsdo Flutter dentro deComponentsdo Jaspr. - Escolha o testador de acordo com seu modo de renderização: SSR →
testServer, CSR →testComponents, navegador →testClient. Prefira correspondência de string DOM em vez de tipagem estrita.