# Modern Web Development with Jaspr + Dart: A Complete Guide from Zero to Advanced

URL: https://hakangul.lovable.app/blog/jaspr-dart-modern-web-development-guide
Author: Hakan Gül — Team Lead Senior Test Automation Engineer
Published: 2026-09-03
Updated: 2026-09-03
Category: software-engineering
Tags: dart, jaspr, web-development, ssr, flutter

> Jaspr is a full-stack web framework written entirely in Dart that produces real HTML/DOM/CSS instead of drawing to a canvas like Flutter Web. This guide covers everything from installation to deployment, including the component system, routing, state management, SSR/SSG/client rendering modes, and testing.

## English

**TL;DR:** Jaspr is a full-stack web framework written entirely in Dart. Unlike Flutter Web, which paints pixels to a canvas, Jaspr produces real HTML, DOM, and CSS — making it SEO-friendly, fast to first paint, and fully compatible with the web ecosystem. It offers a Flutter-like component model (`StatelessComponent`, `StatefulComponent`, `InheritedComponent`) and three rendering modes (static/SSG, server/SSR, client/SPA). This guide walks through installation, the component system, routing, state management, rendering modes, styling, API integration, authentication, deployment, and testing.

## What is Jaspr and why does it exist?

**Jaspr** is a modern, full-stack web framework written entirely in Dart. It offers a component model that looks and feels very much like Flutter, but instead of drawing pixels to a canvas the way Flutter Web does, it produces **real HTML, DOM, and CSS**. The Dart code you write compiles down to standard web technologies the browser understands natively.

Jaspr answers three core questions:

- **Why?** To build a web framework that looks and feels like Flutter but renders normal HTML and CSS.
- **For whom?** Mostly Flutter developers who want to build any kind of website (especially those unsuitable for Flutter Web) in Dart.
- **What?** A full-stack web framework designed end to end, pushing Dart's limits on the web and the server.

Key features:

- **Familiar:** Flutter-like component model (`StatelessComponent`, `StatefulComponent`, `InheritedComponent`).
- **Powerful:** Server-side rendering (SSR) works out of the box.
- **Easy:** Automatically syncs component state between server and client (`@sync`).
- **Fast:** Optimized DOM updates only where needed.
- **Flexible:** Runs on the server, the client, or both.

Interesting proof point: both `dart.dev` and `docs.flutter.dev` are built with Jaspr — a strong indicator of how capable it is for content-heavy, text-driven sites.

## How does Jaspr relate to Dart and Flutter?

Jaspr is not an **alternative** to Flutter — it's a **complement**:

- **Dart** is the language; both Flutter and Jaspr are written in it.
- **Flutter** is a canvas-based UI toolkit for mobile/desktop/web. On the web it paints pixels with Skia/CanvasKit.
- **Jaspr** borrows Flutter's component model but its render layer is entirely web-native: HTML tags, the DOM tree, and CSS.

Flutter's own documentation states plainly: *"Flutter Web is for web apps, not web sites."* Text-heavy, flow-based, static content (like blog posts) benefits from the web's document-centric model. Jaspr fills exactly this gap.

## What problems does Jaspr solve?

- **SEO:** Flutter Web draws content inside a canvas, so search engines can't see it. Jaspr renders real HTML on the server, giving you SEO-friendly sites.
- **First load speed:** Flutter Web leaves the screen blank until a large JS bundle loads. Jaspr shows pre-rendered HTML instantly (very fast First Contentful Paint).
- **Web-standard compatibility:** Text selection, browser extensions, accessibility tools, and the existing CSS ecosystem all work naturally because Jaspr uses the real DOM.
- **Full-stack consistency:** You write frontend and backend in the same language (Dart) and share models, validation, and business logic between both sides.

## Which projects should use Jaspr?

| Project Type | Suitability | Recommended Mode |
|---|---|---|
| Blog, docs, landing page, portfolio | Excellent | static |
| Corporate site, SEO-critical pages | Excellent | static / server |
| Dynamic web app with login | Suitable | server |
| Dashboard, admin panel, SPA | Suitable | client |
| Heavy graphics/animation, game-like UI | Not suitable | Consider Flutter Web |
| Mobile app | Not suitable | Use Flutter |

## Jaspr vs Flutter Web: what's the difference?

| Feature | Jaspr | Flutter Web |
|---|---|---|
| Render target | Real HTML/DOM + CSS | Canvas (pixel drawing) |
| SEO | Excellent (pre-rendered HTML) | Poor |
| Layout | HTML elements + CSS (flexbox, grid) | Widgets (Row, Column, Stack) |
| Styling | CSS / Styles class / CSS frameworks | Widget params, theme |
| Prebuilt components | None (HTML tags exist) | Rich Material/Cupertino set |
| First load | Fast (small JS, pre-render) | Slow (large bundle) |
| Ideal use | Websites, content, SEO apps | App-like web interfaces |

Notably, Jaspr deliberately does **not** copy Flutter's `Row`, `Column`, `Stack` layout primitives. Instead you use standard HTML elements like `div` with CSS. The goal is to avoid hiding the web platform's strengths and keep developers close to web-native technologies.

## How do you install Jaspr and create a project?

**Requirements:** Dart SDK 3.10+ (recommended for dot-shorthand syntax and current Jaspr), a text editor (VS Code + Jaspr Extension recommended), and terminal access. Flutter SDK is only needed for Flutter embedding or plugins.

Install the CLI (the current, recommended AOT-compiled approach):

```bash
# Current (recommended, faster AOT executable):
dart install jaspr_cli

# Legacy (still works):
dart pub global activate jaspr_cli
```

Create and run a project:

```bash
jaspr create my_website
cd my_website
jaspr serve   # dev server at http://localhost:8080 with hot reload
```

Project templates map to rendering modes:

| Template | Mode | When? |
|---|---|---|
| Static Site | static | General purpose (recommended start): blog, docs |
| Server Rendered Site | server | Backend integration, auth, frequently changing content |
| Single Page Application | client | App-like sites: dashboards, admin panels |
| Embedded Flutter Site | static + Flutter | Sites with embedded Flutter widgets |
| Custom Backend Site | server + shelf | Full-stack projects where you write your own API |

## How does the component system work?

Every piece of UI in Jaspr is a **Component**. There are three types: `StatelessComponent`, `StatefulComponent`, and `InheritedComponent` — structurally almost identical to Flutter's widgets.

A stateless component:

```dart
import 'package:jaspr/jaspr.dart';

class HelloComponent extends StatelessComponent {
  const HelloComponent({super.key});

  @override
  Component build(BuildContext context) {
    return p([.text('Hello World')]);
  }
}
```

A stateful component with `setState`:

```dart
class Counter extends StatefulComponent {
  const Counter({super.key});

  @override
  State<Counter> createState() => CounterState();
}

class CounterState extends State<Counter> {
  int count = 0;

  @override
  Component build(BuildContext context) {
    return div([
      p([.text('Counter: $count')]),
      button(
        onClick: () => setState(() => count++),
        [.text('Increment')],
      ),
    ]);
  }
}
```

Every common HTML tag is available as a component function. Rules of thumb: put the children list last (`div(id: 'main', [.text('Hello')])`), and always wrap plain text with `.text('...')` — `div(['Hello'])` will not compile.

Common shared parameters on every HTML component: `id`, `classes`, `styles`, `attributes`, `events`, and `key`.

## How does routing work in Jaspr?

Routing uses the `jaspr_router` package, whose API closely resembles Flutter's `go_router`:

```dart
Router(routes: [
  Route(path: '/', builder: (context, state) => Home()),
  Route(path: '/about', builder: (context, state) => About()),
  Route(path: '/users/:userId',
    builder: (context, state) => UserScreen(id: state.params['userId']!)),
])
```

You choose between two routing strategies:

- **Multi-page (server):** Real page loads; navigation via `Link` / `<a>`. Best for traditional sites, blogs, corporate sites.
- **Single-page (client):** Entirely client-side; navigation via `context.push(...)`. Best for app-like sites and dashboards.

Use `ShellRoute` for a shared layout (like a nav bar), `Route.lazy` with deferred imports for code splitting, and `errorBuilder` for a custom 404 page. Guard protected routes with `redirect`:

```dart
Router(
  redirect: (context, state) {
    if (!AuthState.of(context).isSignedIn) return '/signin';
    return null;
  },
  routes: [ /* ... */ ],
)
```

## How do you manage state in Jaspr?

Jaspr's state model is the same as Flutter's: the component tree, `setState()`-triggered rebuilds, and `InheritedComponent`s carrying data down the tree. The difference is that the render target is the DOM — when `setState` is called, Jaspr only updates the affected DOM nodes.

For local state, use `StatefulComponent` + `setState`. For global state, the recommended approach is `jaspr_riverpod`:

```dart
final counterProvider = StateProvider<int>((ref) => 0);

class CounterPage extends StatelessComponent {
  const CounterPage({super.key});

  @override
  Component build(BuildContext context) {
    final count = context.watch(counterProvider);
    return div([
      p([.text('Counter: $count')]),
      button(
        onClick: () => context.read(counterProvider.notifier).state++,
        [.text('Increment')],
      ),
    ]);
  }
}
```

### Server-to-client state sync

In static/server mode the page is rendered on the server then hydrated on the client. The `@sync` annotation serializes a `State` field during server pre-render and restores it on the client during `initState()`. The `@client` component's constructor parameters are also automatically serialized from server to client — the most practical way to pass data. Supported parameter types are `bool`, `int`, `double`, `String` and their `List`/`Map`s; use `@encoder`/`@decoder` for custom types.

## What are the three rendering modes: SSR, SSG, and client?

| | static | server | client |
|---|---|---|---|
| HTML/CSS generation | Yes | Yes | No |
| Pre-rendering | At build time | On every request | None |
| Client interactivity | Yes | Yes | Yes |
| Requires server | No | Yes | No |
| Deploy to static hosting | Yes | No | Yes |
| Custom backend | No | Yes | No |

- **SSR (server):** Renders full HTML on the server for each request, then hydrates. Right for login-specific content and frequently changing data.
- **SSG (static):** `jaspr build` renders all routes at build time into static `.html` files. No server needed.
- **Client:** Everything runs in the browser. Good for dashboards where SEO is irrelevant.

**Targeted hydration** is a key optimization: only `@client`-annotated components are hydrated, so push `@client` as far down the tree as possible (e.g., a single "Like" button rather than the whole page).

Scope matters: server-scope components can use `dart:io` but not `dart:js_interop`/`package:web`; client-scope is the reverse. Use `package:universal_web` to work in both, and `jaspr_lints`' `unsafe_imports` rule to catch mistakes early.

## How do you style Jaspr apps?

Jaspr is deliberately flexible: it offers a type-safe CSS-in-Dart system, external stylesheets, and CSS frameworks together.

The recommended approach is component-scoped `@css` styling:

```dart
class App extends StatelessComponent {
  const App({super.key});

  @override
  Component build(BuildContext context) {
    return div(classes: 'main', [
      p([.text('Hello World')]),
    ]);
  }

  @css
  static List<StyleRule> get styles => [
    css('.main', [
      css('&').styles(width: 100.px, padding: Padding.all(10.rem)),
      css('p').styles(color: Colors.blue),
    ]),
  ];
}
```

Instead of Flutter's `Row`/`Column`, you use CSS flexbox and grid. Responsive design uses `css.media(...)`. Tailwind (`jaspr_tailwind`), Bulma, and Sass (`sass_builder`) all integrate — Jaspr sites are ordinary websites, so almost anything in the CSS ecosystem works.

## How do you integrate APIs and a backend?

On the client, use `package:http` (fetch-based in the browser). The three-state pattern (loading / error / data) shows up on every data-loading screen — make it a habit.

On the server (static/server mode), `AsyncBuilder` and `AsyncStatelessComponent` let you `await` in the build method (server-only), and `PreloadStateMixin` loads async data before `initState()`. Combine `@sync` + `PreloadStateMixin` for the typical blog scenario: load on the server, filter on the client.

For a custom backend, `serveApp(handler)` turns Jaspr's server side into a single shelf handler, letting you combine it with **shelf**, **Serverpod**, or **dart_frog**. Server-side context APIs include `context.url`, `context.headers`, `context.cookies`, `context.setHeader`, `context.setCookie`, and `context.setStatusCode`.

## How do you handle authentication?

There's no built-in auth module; you combine Jaspr's building blocks (cookies, redirects, server context) with standard web patterns. This architecture requires **server mode**. The classic secure approach uses a session cookie:

1. The user submits login → the server verifies credentials.
2. The server writes an `HttpOnly` cookie with the session ID.
3. On each subsequent request the server reads the cookie during SSR.
4. Protected pages are guarded with the Router `redirect`.

Security essentials: never store passwords in plain text (hash with `bcrypt`/`argon2`); set cookies `HttpOnly` + `Secure` + `SameSite`; always verify auth on the server — client checks are only for UX.

## How do you deploy a Jaspr app?

`jaspr build` writes output to `build/jaspr`. Static/client output is fully static files (deploy to any static host); server output is an `app` executable plus a `web/` asset folder.

- **Static hosting:** Firebase Hosting, GitHub Pages (via GitHub Actions). Mind the base URL when the repo isn't `<user>.github.io`.
- **Server mode:** Docker (Cloud Run, fly.io, DigitalOcean, AWS) using the official Dockerfile that builds with `dart:stable` and runs from `scratch`.
- **Environment variables:** Read on the server with `Platform.environment`; never put secrets in client code — everything compiled to the client is publicly visible.

## How do you test Jaspr apps?

The `jaspr_test` package sits on top of `package:test` with an API similar to `flutter_test`. Three test functions cover the full stack:

| Function | Environment | Use |
|---|---|---|
| `testComponents` | Simulated | Component unit tests |
| `testClient` | Headless browser | DOM interactions |
| `testServer` | Virtual HTTP server | SSR request/response tests |

A component test example:

```dart
import 'package:jaspr_test/jaspr_test.dart';
import '../lib/components/counter.dart';

void main() {
  group('Counter component', () {
    testComponents('increments', (tester) async {
      tester.pumpComponent(Counter());
      expect(find.text('Counter: 0'), findsOneComponent);
      await tester.click(find.tag('button'));
      expect(find.text('Counter: 1'), findsOneComponent);
    });
  });
}
```

Test strategy: pure logic (validators, services, models) with `package:test`; components with `testComponents`; SSR behavior with `testServer`; critical flows with `testClient`.

## FAQ

### Is Jaspr a replacement for Flutter?

No. Jaspr complements Flutter. Flutter is a canvas-based toolkit ideal for app-like interfaces and mobile; Jaspr renders real HTML/CSS and is ideal for websites, content, and SEO-critical apps. Both are written in Dart, and Jaspr borrows Flutter's component model.

### Do I need to know Flutter to learn Jaspr?

It's strongly recommended but not strictly required. If you know Flutter's `StatelessWidget`, `StatefulWidget`, `setState`, and widget-tree concepts, Jaspr's learning curve is very shallow because the component model is nearly identical. You do need Dart fundamentals and basic HTML/CSS knowledge.

### Which rendering mode should I choose?

Use **static** for content-driven sites (blog, docs, landing, portfolio); **server** for dynamic, personalized apps with login; and **client** for app-like dashboards and admin panels where SEO is irrelevant. Template choice doesn't lock you in — you can change the mode later via `jaspr.mode` in `pubspec.yaml`.

### Does Jaspr have a prebuilt component library like Material?

No. There is no styled component library equivalent to Material/Cupertino. You build the UI with CSS yourself, using the type-safe `Styles` class, `@css` scoped styling, or CSS frameworks like Tailwind, Bulma, and Sass.

### Why doesn't Jaspr have Row and Column widgets?

By design. Jaspr deliberately avoids copying Flutter's layout primitives so it doesn't hide the web platform's strengths. You use standard HTML elements like `div` with CSS flexbox and grid instead, keeping you close to web-native technologies.

### How does Jaspr sync state between server and client?

Through the `@sync` annotation (serializes a `State` field from server to client during pre-render, applied once in `initState`) and `@client` component constructor parameters (automatically serialized). The sync is one-way (server → client) and only on the first render. To send data from client to server, use a normal API.

### Can I use existing JavaScript libraries with Jaspr?

Yes. Since Jaspr compiles to JavaScript, you can use JS interop via `package:universal_web/js_interop.dart` with `@JS()` annotations and extension types. For standard web APIs, prefer `package:web`/`package:universal_web`; reserve raw `js_interop` for external JS libraries and advanced scenarios.

---

*This guide is based on the official Jaspr documentation (docs.jaspr.site, v0.23.x).*

## Türkçe

**Özet:** Jaspr, tamamen Dart ile yazılmış full-stack bir web framework'üdür. Flutter Web gibi canvas'a piksel çizmek yerine **gerçek HTML, DOM ve CSS** üretir — bu da onu SEO dostu, ilk boyamada hızlı ve web ekosistemiyle tam uyumlu kılar. Flutter'a benzer bir component modeli (`StatelessComponent`, `StatefulComponent`, `InheritedComponent`) ve üç rendering modu (static/SSG, server/SSR, client/SPA) sunar. Bu rehber kurulumdan başlayıp component sistemi, routing, state yönetimi, rendering modları, stil, API entegrasyonu, kimlik doğrulama, deployment ve test konularını kapsar.

## Jaspr nedir ve neden var?

**Jaspr**, tamamen Dart ile yazılmış modern, full-stack bir web framework'üdür. Flutter'a görünüş ve his olarak çok benzeyen bir component modeli sunar; ancak Flutter Web'in aksine canvas'a piksel çizmek yerine **gerçek HTML, DOM ve CSS** üretir. Yazdığınız Dart kodu, tarayıcının doğal olarak anladığı standart web teknolojilerine dönüşür.

Jaspr üç temel soruya şöyle cevap verir:

- **Neden?** Flutter gibi görünen ve hissettiren, fakat normal HTML ve CSS render eden bir web framework'ü oluşturmak için.
- **Kimin için?** Dart ile her tür web sitesi (özellikle Flutter Web'e uygun olmayanlar) geliştirmek isteyen, ağırlıklı olarak Flutter geliştiricileri için.
- **Ne?** Dart'ın web ve sunucudaki sınırlarını zorlayan, baştan sona düşünülmüş bir full-stack web framework'ü.

Öne çıkan özellikler:

- **Tanıdık:** Flutter widget'larına benzer component modeli (`StatelessComponent`, `StatefulComponent`, `InheritedComponent`).
- **Güçlü:** Server-side rendering (SSR) kutudan çıkar çıkmaz hazır.
- **Kolay:** Sunucu ve istemci arasında component state'ini otomatik senkronize eder (`@sync`).
- **Hızlı:** Sadece gereken yerlerde optimize DOM güncellemeleri yapar.
- **Esnek:** Sunucuda, istemcide veya her ikisinde birden çalışabilir.

İlginç bir kanıt: `dart.dev` ve `docs.flutter.dev` sitelerinin ikisi de Jaspr ile geliştirilmiştir. Bu, Jaspr'ın metin ağırlıklı, içerik odaklı sitelerde ne kadar yetkin olduğunun iyi bir göstergesidir.

## Jaspr'ın Dart ve Flutter ile ilişkisi nedir?

Jaspr, Flutter'ın **alternatifi** değil, **tamamlayıcısıdır**:

- **Dart** dildir; hem Flutter hem Jaspr bu dille yazılır.
- **Flutter**, mobil/masaüstü/web için canvas tabanlı bir UI toolkit'idir. Web'de Skia/CanvasKit ile piksel çizer.
- **Jaspr**, Flutter'ın component modelini ödünç alır ama render katmanı tamamen web'e özgüdür: HTML etiketleri, DOM ağacı ve CSS.

Flutter ekibi kendi dokümantasyonunda açıkça belirtir: *"Flutter Web, web siteleri değil web uygulamaları içindir."* Metin ağırlıklı, akış tabanlı, statik içerikler (blog yazıları gibi) web'in doküman merkezli modelinden faydalanır. Jaspr tam olarak bu boşluğu doldurur.

## Jaspr hangi problemleri çözer?

- **SEO problemi:** Flutter Web, içeriği canvas içine çizdiği için arama motorları içeriği göremez. Jaspr, sunucuda gerçek HTML ürettiği için SEO dostu siteler sağlar.
- **İlk yükleme hızı:** Flutter Web'de büyük bir JavaScript bundle'ı yüklenmeden ekran boş kalır. Jaspr'da pre-render edilmiş HTML anında görüntülenir (çok hızlı First Contentful Paint).
- **Web standartlarıyla uyum:** Metin seçimi, tarayıcı eklentileri, erişilebilirlik araçları ve mevcut CSS ekosistemi gerçek DOM kullanıldığı için doğal olarak çalışır.
- **Full-stack tutarlılık:** Frontend ve backend'i aynı dilde (Dart) yazarsınız; modelleri, validasyon kodunu ve iş mantığını iki taraf arasında paylaşabilirsiniz.

## Hangi projelerde Jaspr tercih edilmeli?

| Proje Tipi | Uygunluk | Önerilen Mod |
|---|---|---|
| Blog, dokümantasyon, tanıtım, portföy | Çok uygun | static |
| Kurumsal site, SEO kritik sayfalar | Çok uygun | static / server |
| Kullanıcı girişli dinamik web uygulaması | Uygun | server |
| Dashboard, admin paneli, SPA | Uygun | client |
| Ağır grafik/animasyon, oyun benzeri UI | Uygun değil | Flutter Web düşün |
| Mobil uygulama | Uygun değil | Flutter kullan |

## Jaspr ile Flutter Web arasındaki fark nedir?

| Özellik | Jaspr | Flutter Web |
|---|---|---|
| Render hedefi | Gerçek HTML/DOM + CSS | Canvas (piksel çizimi) |
| SEO | Mükemmel (pre-render edilmiş HTML) | Zayıf |
| Layout | HTML elementleri + CSS (flexbox, grid) | Widget'lar (Row, Column, Stack) |
| Stil | CSS / Styles sınıfı / CSS framework'leri | Widget parametreleri, tema |
| Hazır component | Yok (HTML etiketleri var) | Zengin Material/Cupertino seti |
| İlk yükleme | Hızlı (küçük JS, pre-render) | Yavaş (büyük bundle) |
| İdeal kullanım | Web siteleri, içerik, SEO'lu uygulamalar | Uygulama benzeri web arayüzleri |

Dikkat çekici olarak Jaspr, Flutter'ın `Row`, `Column`, `Stack` gibi layout primitive'lerini bilerek **kopyalamaz**. Bunun yerine `div` gibi standart HTML elementlerini CSS ile kullanırsınız. Amaç, web platformunun kendi güçlü yanlarını gizlememek ve geliştiriciyi web'e özgü teknolojilere yakın tutmaktır.

## Jaspr nasıl kurulur ve proje nasıl oluşturulur?

**Gereksinimler:** Dart SDK 3.10+ (dot-shorthand yazımı ve güncel Jaspr için önerilir), bir metin editörü (VS Code + Jaspr Extension önerilir) ve terminal erişimi. Flutter SDK yalnızca Flutter embedding veya plugin'leri kullanacaksanız gerekir.

CLI kurulumu (güncel, önerilen AOT derlenmiş yöntem):

```bash
# Güncel (önerilen, daha hızlı AOT executable):
dart install jaspr_cli

# Eski (hâlâ çalışır):
dart pub global activate jaspr_cli
```

Proje oluşturma ve çalıştırma:

```bash
jaspr create my_website
cd my_website
jaspr serve   # http://localhost:8080 adresinde hot reload'lu geliştirme sunucusu
```

Proje şablonları rendering modlarına karşılık gelir:

| Şablon | Mod | Ne zaman? |
|---|---|---|
| Static Site | static | Genel amaçlı (önerilen başlangıç): blog, dokümantasyon |
| Server Rendered Site | server | Backend entegrasyonu, auth, sık değişen içerik |
| Single Page Application | client | Uygulama benzeri siteler: dashboard, admin paneli |
| Embedded Flutter Site | static + Flutter | Flutter widget'ları gömülü siteler |
| Custom Backend Site | server + shelf | Kendi API'nizi yazacağınız full-stack projeler |

## Component sistemi nasıl çalışır?

Jaspr'da UI'ın her parçası bir **Component**'tir. Üç tip vardır: `StatelessComponent`, `StatefulComponent` ve `InheritedComponent` — yapısal olarak Flutter'ın widget'larıyla neredeyse birebir aynıdır.

Durumsuz bir component:

```dart
import 'package:jaspr/jaspr.dart';

class SelamComponent extends StatelessComponent {
  const SelamComponent({super.key});

  @override
  Component build(BuildContext context) {
    return p([.text('Merhaba Dünya')]);
  }
}
```

`setState` ile durumlu bir component:

```dart
class Sayac extends StatefulComponent {
  const Sayac({super.key});

  @override
  State<Sayac> createState() => SayacState();
}

class SayacState extends State<Sayac> {
  int sayi = 0;

  @override
  Component build(BuildContext context) {
    return div([
      p([.text('Sayaç: $sayi')]),
      button(
        onClick: () => setState(() => sayi++),
        [.text('Artır')],
      ),
    ]);
  }
}
```

Her yaygın HTML etiketi bir component fonksiyonu olarak hazır gelir. Temel kurallar: çocuk listesini en sona koyun (`div(id: 'main', [.text('Merhaba')])`) ve düz metni her zaman `.text('...')` ile sarın — `div(['Merhaba'])` derlenmez.

Her HTML component'inin aldığı ortak parametreler: `id`, `classes`, `styles`, `attributes`, `events` ve `key`.

## Jaspr'da routing nasıl çalışır?

Routing için `jaspr_router` paketi kullanılır; API'si Flutter'daki `go_router`'a çok benzer:

```dart
Router(routes: [
  Route(path: '/', builder: (context, state) => Home()),
  Route(path: '/about', builder: (context, state) => About()),
  Route(path: '/users/:userId',
    builder: (context, state) => UserScreen(id: state.params['userId']!)),
])
```

İki routing stratejisinden birini seçersiniz:

- **Multi-page (sunucu):** Gerçek sayfa yüklemesi; navigasyon `Link` / `<a>` ile. Geleneksel siteler, bloglar, kurumsal siteler için idealdir.
- **Single-page (istemci):** Tamamen istemcide; navigasyon `context.push(...)` ile. Uygulama benzeri siteler ve dashboard'lar için idealdir.

Ortak yerleşim (navigasyon çubuğu gibi) için `ShellRoute`, kod bölme için deferred import'lu `Route.lazy`, özel 404 sayfası için `errorBuilder` kullanın. Korumalı sayfaları `redirect` ile koruyun:

```dart
Router(
  redirect: (context, state) {
    if (!AuthState.of(context).isSignedIn) return '/giris';
    return null;
  },
  routes: [ /* ... */ ],
)
```

## Jaspr'da state nasıl yönetilir?

Jaspr'ın state modeli Flutter ile aynıdır: component ağacı, `setState()` ile tetiklenen yeniden build'ler ve veriyi ağaçta aşağı taşıyan `InheritedComponent`'ler. Fark, render hedefinin DOM olmasıdır — `setState` çağrıldığında Jaspr yalnızca değişen DOM düğümlerini günceller.

Yerel durum için `StatefulComponent` + `setState` yeterlidir. Global state için önerilen yaklaşım `jaspr_riverpod`'dir:

```dart
final sayacProvider = StateProvider<int>((ref) => 0);

class SayacSayfasi extends StatelessComponent {
  const SayacSayfasi({super.key});

  @override
  Component build(BuildContext context) {
    final sayi = context.watch(sayacProvider);
    return div([
      p([.text('Sayaç: $sayi')]),
      button(
        onClick: () => context.read(sayacProvider.notifier).state++,
        [.text('Artır')],
      ),
    ]);
  }
}
```

### Sunucu → istemci state senkronizasyonu

Static/server modunda sayfa sunucuda render edilir, ardından istemcide hydrate edilir. `@sync` anotasyonu bir `State` alanını sunucu pre-render sırasında serialize eder ve istemcide `initState()` sırasında geri yükler. `@client` component'inin constructor parametreleri de sunucudan istemciye otomatik serialize edilir — veri aktarmanın en pratik yoludur. Desteklenen parametre tipleri `bool`, `int`, `double`, `String` ve bunların `List`/`Map`'leridir; özel tipler için `@encoder`/`@decoder` kullanın.

## Üç rendering modu (SSR, SSG, client) nedir?

| | static | server | client |
|---|---|---|---|
| HTML/CSS üretimi | Evet | Evet | Hayır |
| Pre-rendering | Build zamanında | Her istekte | Yok |
| İstemci etkileşimi | Evet | Evet | Evet |
| Sunucu gerektirir | Hayır | Evet | Hayır |
| Statik hosting'e deploy | Evet | Hayır | Evet |
| Özel backend | Hayır | Evet | Hayır |

- **SSR (server):** Her istek için sunucuda tam HTML üretir, sonra hydrate eder. Girişe özel içerik ve sık değişen veriler için doğru seçimdir.
- **SSG (static):** `jaspr build` tüm route'ları build zamanında statik `.html` dosyalarına render eder. Sunucu gerekmez.
- **Client:** Her şey tarayıcıda çalışır. SEO'nun gereksiz olduğu dashboard'lar için uygundur.

**Hedefli hydration** önemli bir optimizasyondur: yalnızca `@client` işaretli component'ler hydrate edilir, bu yüzden `@client`'i ağaçta mümkün olduğunca aşağı taşıyın (örn. tüm sayfa yerine tek bir "Beğen" butonu).

Scope önemlidir: sunucu scope'undaki component'ler `dart:io` kullanabilir ama `dart:js_interop`/`package:web` kullanamaz; istemci scope'unda tam tersidir. İki ortamda da çalışmak için `package:universal_web`, hataları erken yakalamak için `jaspr_lints`'in `unsafe_imports` kuralını kullanın.

## Jaspr uygulamaları nasıl stillendirilir?

Jaspr stil konusunda kasıtlı olarak esnektir: tip-güvenli CSS-in-Dart sistemi, harici stil dosyaları ve CSS framework'leri birlikte kullanılabilir.

Önerilen yaklaşım component seviyesinde `@css` stilidir:

```dart
class App extends StatelessComponent {
  const App({super.key});

  @override
  Component build(BuildContext context) {
    return div(classes: 'main', [
      p([.text('Merhaba Dünya')]),
    ]);
  }

  @css
  static List<StyleRule> get styles => [
    css('.main', [
      css('&').styles(width: 100.px, padding: Padding.all(10.rem)),
      css('p').styles(color: Colors.blue),
    ]),
  ];
}
```

Flutter'daki `Row`/`Column` yerine CSS flexbox ve grid kullanırsınız. Responsive tasarım `css.media(...)` ile yapılır. Tailwind (`jaspr_tailwind`), Bulma ve Sass (`sass_builder`) entegre olur — Jaspr siteleri sıradan web siteleridir, dolayısıyla CSS ekosistemindeki neredeyse her şeyi kullanabilirsiniz.

## API ve backend entegrasyonu nasıl yapılır?

İstemcide `package:http` (tarayıcıda fetch tabanlı) kullanılır. Üç durum deseni (loading / error / data) her veri yükleme ekranında karşınıza çıkar; bunu alışkanlık haline getirin.

Sunucuda (static/server modu) `AsyncBuilder` ve `AsyncStatelessComponent` build metodunda `await` kullanmanızı sağlar (yalnızca sunucu), `PreloadStateMixin` ise `initState()` öncesi asenkron veri yükler. Tipik blog senaryosu için `@sync` + `PreloadStateMixin` birleştirin: sunucuda yükleyin, istemcide filtreleyin.

Özel backend için `serveApp(handler)`, Jaspr'ın sunucu tarafını tek bir shelf handler'a dönüştürür; böylece **shelf**, **Serverpod** veya **dart_frog** ile birleştirebilirsiniz. Sunucu tarafı context API'leri: `context.url`, `context.headers`, `context.cookies`, `context.setHeader`, `context.setCookie` ve `context.setStatusCode`.

## Kimlik doğrulama nasıl yapılır?

Hazır bir auth modülü yoktur; Jaspr'ın yapı taşlarını (cookie'ler, redirect'ler, sunucu context'i) standart web kalıplarıyla birleştirirsiniz. Bu mimari **server modu** gerektirir. Klasik ve güvenli yaklaşım oturum çerezi (session cookie) kullanmaktır:

1. Kullanıcı login formunu gönderir → sunucu kimliği doğrular.
2. Sunucu, `HttpOnly` bir cookie ile oturum kimliği yazar.
3. Sonraki her istekte sunucu, SSR sırasında cookie'yi okur.
4. Korumalı sayfalar Router `redirect`'i ile korunur.

Güvenlik esasları: şifreleri asla düz metin saklamayın (`bcrypt`/`argon2` ile hash'leyin); cookie'leri `HttpOnly` + `Secure` + `SameSite` ile ayarlayın; auth'u her zaman sunucuda doğrulayın — istemci kontrolleri yalnızca kullanıcı deneyimi içindir.

## Jaspr uygulaması nasıl deploy edilir?

`jaspr build` çıktıyı `build/jaspr` klasörüne yazar. Static/client çıktısı tamamen statik dosyalardır (herhangi bir statik hosting'e yüklenir); server çıktısı bir `app` çalıştırılabilir dosyası artı bir `web/` asset klasörüdür.

- **Statik hosting:** Firebase Hosting, GitHub Pages (GitHub Actions ile). Repo `<kullanici>.github.io` değilse base URL'e dikkat edin.
- **Server modu:** Docker (Cloud Run, fly.io, DigitalOcean, AWS) — resmi Dockerfile `dart:stable` ile build alıp `scratch`'ten çalıştırır.
- **Environment variables:** Sunucuda `Platform.environment` ile okuyun; gizli anahtarları asla istemci koduna koymayın — istemciye derlenen her şey herkes tarafından görülebilir.

## Jaspr uygulamaları nasıl test edilir?

`jaspr_test` paketi `package:test` üzerine kuruludur ve API'si `flutter_test`'e benzer. Üç test fonksiyonu tüm yığını kapsar:

| Fonksiyon | Ortam | Kullanım |
|---|---|---|
| `testComponents` | Simüle edilmiş | Component birim testleri |
| `testClient` | Headless tarayıcı | DOM etkileşimleri |
| `testServer` | Sanal HTTP sunucusu | SSR istek/yanıt testleri |

Bir component testi örneği:

```dart
import 'package:jaspr_test/jaspr_test.dart';
import '../lib/components/sayac.dart';

void main() {
  group('Sayac component testi', () {
    testComponents('sayac artirilabilmeli', (tester) async {
      tester.pumpComponent(Sayac());
      expect(find.text('Sayaç: 0'), findsOneComponent);
      await tester.click(find.tag('button'));
      expect(find.text('Sayaç: 1'), findsOneComponent);
    });
  });
}
```

Test stratejisi: saf mantık (validators, servisler, modeller) `package:test` ile; component'ler `testComponents` ile; SSR davranışı `testServer` ile; kritik akışlar `testClient` ile.

## SSS

### Jaspr, Flutter'ın yerini mi alıyor?

Hayır. Jaspr, Flutter'ı tamamlar. Flutter, uygulama benzeri arayüzler ve mobil için ideal olan canvas tabanlı bir toolkit'tir; Jaspr gerçek HTML/CSS render eder ve web siteleri, içerik ve SEO kritik uygulamalar için idealdir. İkisi de Dart ile yazılır ve Jaspr, Flutter'ın component modelini ödünç alır.

### Jaspr öğrenmek için Flutter bilmem gerekir mi?

Şiddetle önerilir ama kesinlikle zorunlu değildir. Flutter'ın `StatelessWidget`, `StatefulWidget`, `setState` ve widget ağacı kavramlarını biliyorsanız Jaspr'ın öğrenme eğrisi çok sığdır çünkü component modeli neredeyse birebir aynıdır. Dart temellerini ve temel HTML/CSS bilgisini bilmeniz gerekir.

### Hangi rendering modunu seçmeliyim?

İçerik odaklı siteler için (blog, dokümantasyon, tanıtım, portföy) **static**; girişli, kişiselleştirilmiş dinamik uygulamalar için **server**; SEO'nun gereksiz olduğu uygulama benzeri dashboard ve admin panelleri için **client** kullanın. Şablon seçimi sizi kilitlemez — modu sonradan `pubspec.yaml`'daki `jaspr.mode` ile değiştirebilirsiniz.

### Jaspr'ın Material gibi hazır bir component kütüphanesi var mı?

Hayır. Material/Cupertino karşılığı stillendirilmiş bir component kütüphanesi yoktur. UI'ı CSS ile kendiniz kurarsınız; tip-güvenli `Styles` sınıfı, `@css` scoped stil veya Tailwind, Bulma, Sass gibi CSS framework'leri kullanabilirsiniz.

### Jaspr'da neden Row ve Column widget'ları yok?

Tasarım tercihidir. Jaspr, web platformunun güçlü yanlarını gizlememek için Flutter'ın layout primitive'lerini bilerek kopyalamaz. Bunun yerine `div` gibi standart HTML elementlerini CSS flexbox ve grid ile kullanırsınız, bu da sizi web'e özgü teknolojilere yakın tutar.

### Jaspr sunucu ve istemci arasında state'i nasıl senkronize eder?

`@sync` anotasyonu (bir `State` alanını pre-render sırasında sunucudan istemciye serialize eder, `initState`'te bir kez uygulanır) ve `@client` component constructor parametreleri (otomatik serialize edilir) aracılığıyla. Senkronizasyon tek yönlüdür (sunucu → istemci) ve yalnızca ilk render'da yapılır. İstemciden sunucuya veri göndermek için normal bir API kullanın.

### Jaspr ile mevcut JavaScript kütüphanelerini kullanabilir miyim?

Evet. Jaspr JavaScript'e derlendiği için `package:universal_web/js_interop.dart` üzerinden `@JS()` anotasyonları ve extension type'larla JS interop yapabilirsiniz. Standart web API'leri için `package:web`/`package:universal_web`'i tercih edin; ham `js_interop`'u yalnızca harici JS kütüphaneleri ve ileri senaryolar için ayırın.

---

*Bu rehber, resmi Jaspr dokümantasyonu (docs.jaspr.site, v0.23.x) temel alınarak hazırlanmıştır.*
