fuex 0.2.0 copy "fuex: ^0.2.0" to clipboard
fuex: ^0.2.0 copied to clipboard

A Flutter meta-framework inspired by Next.js routing, React hooks, and GetX DI. Features folder-based routing, granular reactive state, context-less navigation, useQuery/useMutation, Super Schema vali [...]

Fuex 🚀 #

Flutter Framework — Yet simple Next.js in Flutter.

pub.dev License: MIT

Fuex eliminates Flutter boilerplate by combining:

  • 📁 Folder-based routing — Navigator 2.0 with auto-generated routes
  • Obx + Rx — GetX-style auto-tracking reactivity, zero StatefulWidget
  • 🌐 Context-less navigationFuex.push('/path')
  • 💉 Smart DI — Auto garbage collection on route pop
  • 🌍 Built-in Network — Dio-powered HTTP client out of the box
  • 🔄 React-style hooksuseQuery, useMutation, useState, useForm
  • 📱 Adaptive UI — Built-in responsive sizing (.w, .h, .sp) + AdaptiveLayout
  • 🔧 Powerful CLI — Scaffold pages, services, repos, CI/CD in one command
  • 🌿 Flavor/Env — Built-in .env.dev / .env.production management

Installation #

dependencies:
  fuex: ^0.1.0
import 'package:fuex/fuex.dart';

Install Fuex CLI #

Global install (from this repo):

dart pub global activate -s path fuex_cli

Verify:

fuex --help

If fuex is not found, add Dart pub-cache binaries to your PATH:

export PATH="$PATH:$HOME/.pub-cache/bin"

Generate new project:

[1] flutter create .
[2] fuex init --force

Quick Start #

void main() {
  // 1. Init global services
  Fuex.put(FuexNetwork(baseUrl: 'https://api.example.com'), permanent: true);

  // 2. Run app
  runApp(
    FuexApp(
      initialPath: '/',
      routes: [
        FuexRouteEntry(path: '/', builder: (_) => const HomePage(), binding: HomeBinding()),
        FuexRouteEntry(path: '/detail', builder: (_) => const DetailPage()),
        FuexRouteEntry(path: '/users/:id', builder: (_) => const UserPage()),
      ],
    ),
  );
}

Core API #

🧭 Context-Less Navigation #

Fuex.push('/dashboard');                    // push
Fuex.push('/detail', extra: product);       // with object
Fuex.replace('/home');                      // replace current
Fuex.offAll('/login');                      // clear stack
Fuex.pop();                                 // go back

final id   = Fuex.params['id'];            // /users/:id
final sort = Fuex.queryParams['sort'];     // ?sort=asc
final obj  = Fuex.extra as Product;        // extra object

👁️ Obx — Auto-Tracking Widget (GetX Style) #

No builders, no subscriptions. Just wrap with Obx() and read .value:

final count = 0.obs;
final users = <String>[].obs;

// Auto-rebuilds when count.value or users change
Obx(() => Text('Count: ${count.value}, Users: ${users.length}'))

⚡ Rx — Reactive Primitives #

final name  = Rx<String>('');     // or ''.obs
final items = RxList<String>();   // reactive list
final map   = RxMap<String, int>(); // reactive map

// Manual builder (alternative to Obx)
FuexBuilder<String>(rx: name, builder: (ctx, val) => Text(val))

// Multiple reactives
FuexMultiBuilder(listenables: [name, age], builder: (ctx) => Text('${name.value}'))

⚡ useState — Local Reactivity #

useState<int>(
  initial: 0,
  builder: (context, count) => Column(children: [
    Text('${count.value}'),
    ElevatedButton(onPressed: () => count.value++, child: const Text('+')),
  ]),
)

📦 useStorage — Persistent State #

useStorage<int>(
  storageKey: 'visit_count',
  initial: 0,
  builder: (context, visits) => Text('Visits: ${visits.value}'),
)

🌍 FuexNetwork — Built-in HTTP Client #

Pre-configured Dio wrapper with logging, timeout, and interceptor support:

// Register globally (once in main.dart or GlobalBindings)
Fuex.put(FuexNetwork(baseUrl: 'https://api.example.com'), permanent: true);

// Use anywhere
final net = Fuex.find<FuexNetwork>();
final res = await net.get('/users');
await net.post('/login', data: {'email': '...'});
await net.put('/users/1', data: {...});
await net.delete('/users/1');

🔄 useQuery — Async Data Fetching #

useQuery<List<Article>>(
  queryKey: 'articles',
  fetcher: () => repo.fetchArticles(),
  builder: (context, state, refetch) {
    if (state.isLoading) return const CircularProgressIndicator();
    if (state.hasError) return Text('Error: ${state.error}');
    return ListView(children: state.data!.map((a) => Text(a.title)).toList());
  },
)

// Cache management
invalidateQuery('articles');  // clear one
clearQueryCache();            // clear all

🔀 useMutation — POST / PUT / DELETE #

useMutation<void, LoginRequest>(
  mutationFn: (req) => authService.login(req),
  builder: (context, mutation) => ElevatedButton(
    onPressed: mutation.isLoading ? null : () => mutation.mutate(loginReq,
      onSuccess: (_) => Fuex.replace('/dashboard'),
    ),
    child: mutation.isLoading ? const CircularProgressIndicator() : const Text('Login'),
  ),
)

📋 useForm + FuexSchema — Form Validation #

class LoginRequest extends FuexSchema {
  final String email, password;
  const LoginRequest({required this.email, required this.password});

  @override
  ValidationResult validate() {
    final errors = <String, String>{};
    FieldValidator('email', email).required().isEmail().validate()
        ?.let((e) => errors['email'] = e);
    FieldValidator('password', password).required().minLength(8).validate()
        ?.let((e) => errors['password'] = e);
    return errors.isEmpty ? ValidationResult.valid() : ValidationResult.invalid(errors);
  }

  @override
  Map<String, dynamic> toJson() => {'email': email, 'password': password};
}
Rule Usage
required() Must not be null/empty
isEmail() Valid email format
minLength(n) / maxLength(n) String length
isNumeric() Must parse as number
matches(regex) Must match RegExp
min(n) / max(n) Numeric bounds

💉 Dependency Injection + Smart GC #

// Register (auto-disposed when route pops)
Fuex.put(MyController());

// Register permanently (survives navigation)
Fuex.put(AuthService(), permanent: true);

// Retrieve
final ctrl = Fuex.find<MyController>();
final safe = Fuex.tryFind<MyController>(); // null-safe

// Manual cleanup
Fuex.delete<MyController>();  // delete one
Fuex.clearAll();              // wipe everything (e.g. on logout)

// Auto-dispose interface
class MyController implements FuexDisposable {
  @override void onDispose() { /* cleanup */ }
}

🔗 Bindings — Per-Route DI #

class HomeBinding implements FuexBinding {
  @override
  void dependencies() {
    Fuex.put(HomeController());
    Fuex.put(NewsRepository());
  }
}

// Auto-injected when route opens, auto-disposed when route pops
FuexRouteEntry(path: '/', builder: (_) => const HomePage(), binding: HomeBinding())

🛡️ Route Guards #

class AuthMiddleware extends FuexAuthGuard {
  const AuthMiddleware();
  @override
  bool get isAuthenticated => Fuex.isRegistered<String>(tag: 'token');
  @override
  String get loginPath => '/login';
}

📱 Adaptive & Responsive Design #

Built-in screen scaling — no ScreenUtil needed:

Container(width: 100.w, height: 50.h)           // adaptive sizing
Text('Hi', style: TextStyle(fontSize: 16.sp))    // scaled font
EdgeInsets.all(5.sw)                              // 5% of screen width

// Device-aware layout
AdaptiveLayout(
  mobile:  MobileView(),     // default
  tablet:  TabletView(),     // ≥ 600px
  desktop: DesktopView(),    // ≥ 1024px
  tv:      TvView(),         // ≥ 1440px
)

🌿 Environment / Flavor #

await FuexEnv.init(flavor: Flavor.dev);       // or Flavor.production

final apiUrl = FuexEnv.get('API_URL');
final isDebug = FuexEnv.isDev;                // true / false

🏛️ FuexLayout — Persistent Shells #

FuexRouteEntry(
  path: '/dashboard',
  builder: (_) => const DashboardPage(),
  layout: FuexLayout.wrap(bottomNavigationBar: const MyBottomNav()),
)

CLI Tool (fuex_cli) #

Scaffold Commands #

# Scaffold a page (page.dart + controller.dart + binding.dart)
fuex page dashboard

# Scaffold with multi-device views (mobile + tablet + optional desktop/tv)
fuex view dashboard --desktop --tv

# Scaffold a repository (pre-wired to FuexNetwork)
fuex repo user

# Scaffold a global service
fuex service auth

# Scaffold a reusable widget
fuex widget primary_button

# Scaffold a JSON schema blueprint
fuex schema product

# Scaffold environment files (.env.dev, .env.production, .env.example)
fuex env

# Scaffold CI/CD (GitHub Actions, GitLab CI, Fastlane, Google Drive upload)
fuex ci

Code Generation #

# Auto-generate routes & models from folder structure
fuex generate

# Watch for changes and auto-generate
fuex watch

# Full dev server with flavor support
fuex dev --flavor dev --device chrome

# Open DevTools & Network Monitor in browser
fuex dev --devtools
fuex watch --devtools

lib/
├── app/                         # Route pages (folder-based)
│   ├── dashboard/
│   │   ├── page.dart            # → /dashboard
│   │   ├── controller.dart      # Business logic
│   │   ├── binding.dart         # DI registration
│   │   ├── mobile_view.dart     # Phone layout
│   │   └── tablet_view.dart     # Tablet layout
│   ├── users/[id]/
│   │   └── page.dart            # → /users/:id
│   └── (auth)/
│       └── login/page.dart      # → /login (route group)
├── core/
│   ├── services/                # Global services
│   └── widgets/                 # Reusable components
├── data/
│   ├── repositories/            # Data access (uses FuexNetwork)
│   └── schemas/                 # JSON schema → Dart model
├── main.dart
├── .env.dev
└── .env.production

Example App #

See example/ for a complete Space News Reader app demonstrating:

  • FuexNetwork → fetch from SpaceFlightNews API
  • FuexBinding → auto-inject controller per route
  • Obx() → auto-tracking bookmark badge & toggle
  • useQuery → data fetching with loading/error/cache
  • useState → local counter
  • useStorage → persistent notes per article
  • AdaptiveLayout → list on phone, grid on tablet/desktop
  • .sp / .w → responsive sizing
  • Fuex.push/pop → context-less navigation

Roadmap #

  • ✅ Core: Rx<T>, RxList, RxMap, FuexStore
  • ✅ Hooks: useState, useStorage, useQuery, useMutation, useForm, useInfiniteQuery
  • ✅ Router: Navigator 2.0, path/query params, route groups, catch-all
  • ✅ Navigation: context-less Fuex.push/replace/offAll/pop
  • ✅ DI: Fuex.put/find/delete/clearAll + auto GC + bindings
  • ✅ Schema: FuexSchema, FieldValidator, ValidationResult
  • ✅ Widgets: FuexApp, Obx, FuexBuilder, FuexMultiBuilder, FuexLayout
  • ✅ Network: Built-in FuexNetwork (Dio)
  • ✅ Responsive: AdaptiveLayout, .w, .h, .sp, .sw, .sh
  • ✅ Env: FuexEnv flavor management
  • ✅ CLI: fuex page/view/repo/service/widget/schema/env/ci/generate/watch/dev
  • ❌ Internationalization (i18n) support
  • ❌ Built-in analytics integration

License #

MIT © Fuex Contributors

2
likes
140
points
110
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter meta-framework inspired by Next.js routing, React hooks, and GetX DI. Features folder-based routing, granular reactive state, context-less navigation, useQuery/useMutation, Super Schema validation, and auto garbage collection.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

dio, flutter, shared_preferences

More

Packages that depend on fuex