vexana_jaspr

Pub CI License: MIT

vexana_jaspr brings the full power of Vexana to the Jaspr web framework.

It allows you to share identical INetworkModel classes between your Flutter apps and Jaspr web apps while providing web-native storage caching and reactive offline UI components.


Features

  • Built on vexana_core: Share the exact same INetworkModel classes across Flutter mobile apps, Jaspr web apps, and backend services.
  • Web LocalStorage Cache: Built-in JasprLocalStorageFileManager backed by window.localStorage with duration-based cache expiration (falls back gracefully to in-memory storage during SSR or VM tests).
  • Jaspr No-Network Handler: JasprNoNetwork implements INoNetworkHandler to intercept requests made without an active internet connection.
  • Reactive Offline Component: Drop-in JasprNoNetworkComponent component rendering an interactive banner with a "Retry" button when connectivity drops.
  • Navigator Connectivity Check: JasprNetworkCheck checks connection state via window.navigator.onLine.

Installation

Add vexana_jaspr to your Jaspr project's pubspec.yaml:

dependencies:
  jaspr: ^0.23.5
  vexana_jaspr: ^0.1.0

Quick Start

1. Define a Shared Model

import 'package:vexana_jaspr/vexana_jaspr.dart';

final class Post extends INetworkModel<Post> {
  Post({this.id, this.title, this.body});

  final int? id;
  final String? title;
  final String? body;

  @override
  Post fromJson(Map<String, dynamic> json) => Post(
        id: json['id'] as int?,
        title: json['title'] as String?,
        body: json['body'] as String?,
      );

  @override
  Map<String, dynamic>? toJson() => {'id': id, 'title': title, 'body': body};
}

2. Configure NetworkManager with Web Cache & NoNetwork

import 'package:vexana_jaspr/vexana_jaspr.dart';

final networkManager = NetworkManager<EmptyModel>(
  isEnableLogger: true,
  options: BaseOptions(
    baseUrl: 'https://jsonplaceholder.typicode.com',
    connectTimeout: const Duration(seconds: 10),
  ),
  // Caches responses in browser window.localStorage
  fileManager: JasprLocalStorageFileManager(),
);

3. Display Offline Banner in your Jaspr Component Tree

JasprNoNetwork only acts when the browser is offline (navigator.onLine) and the request was sent with isErrorDialog: true. onNetworkLoss receives retry and dismiss; the failed request waits until one of them is called. Retries are capped by maxRetryCount.

import 'package:jaspr/dom.dart';
import 'package:jaspr/jaspr.dart';
import 'package:vexana_jaspr/vexana_jaspr.dart';

class App extends StatefulComponent {
  const App({super.key});

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  late final NetworkManager<EmptyModel> _manager;
  JasprRetryCallback? _pendingRetry;

  @override
  void initState() {
    super.initState();
    _manager = NetworkManager<EmptyModel>(
      options: BaseOptions(baseUrl: 'https://jsonplaceholder.typicode.com'),
      noNetwork: JasprNoNetwork(
        onNetworkLoss: (retry, dismiss) {
          setState(() => _pendingRetry = retry);
        },
      ),
    );
  }

  void _retry() {
    final retry = _pendingRetry;
    setState(() => _pendingRetry = null);
    retry?.call();
  }

  @override
  Component build(BuildContext context) {
    return div([
      if (_pendingRetry != null) JasprNoNetworkComponent(onRetry: _retry),
      h1([Component.text('Welcome to My Jaspr App')]),
    ]);
  }
}

Requests opt in per call:

await _manager.send<Post, List<Post>>(
  '/posts',
  parseModel: Post(),
  method: RequestType.GET,
  isErrorDialog: true,
);

Complete Example

Check out the full working Jaspr web application in the example directory:

cd packages/vexana_jaspr/example
jaspr serve

  • vexana_core: Pure Dart core engine (zero Flutter SDK dependencies).
  • vexana: Flutter package with mobile disk cache and Flutter widgets.

License

This package is licensed under the MIT License - see the LICENSE file.

Libraries

vexana_jaspr
Jaspr web networking package for Vexana.