duxt 0.2.6 copy "duxt: ^0.2.6" to clipboard
duxt: ^0.2.6 copied to clipboard

A meta-framework for Jaspr with module-based architecture, file-based routing, layouts, and scaffold generators.

Duxt #

Pub Version License: MIT Dart

The meta-framework for Jaspr — Build full-stack Dart web apps with module-based architecture, file-based routing, and powerful scaffolding.


✨ Features #

Feature Description
📁 Module-Based Architecture Organize code by feature with pages, components, models & APIs
🛣️ File-Based Routing Pages auto-generate routes — no manual configuration
🌐 Simple API Client Static Api class with auth, headers & error handling
SPA State Management DuxtState mixin handles loading, error & data states
🔧 Scaffold Generator Full CRUD generation with a single command
🎨 Tailwind CSS First-class Tailwind integration out of the box
🔒 Middleware Route guards for authentication & authorization
📝 Content Support Markdown content with frontmatter for docs sites

🚀 Quick Start #

Installation #

dart pub global activate duxt

Create Your First App #

duxt create my-app
cd my-app
dart pub get
duxt dev

Your app is running at http://localhost:8080 🎉


📂 Project Structure #

my-app/
├── lib/
│   ├── posts/                    # Feature module
│   │   ├── pages/
│   │   │   ├── index.dart        # → /posts
│   │   │   ├── [id].dart         # → /posts/:id
│   │   │   └── [id]/
│   │   │       └── edit.dart     # → /posts/:id/edit
│   │   ├── components/
│   │   │   └── post_card.dart
│   │   ├── model.dart
│   │   └── api.dart
│   ├── shared/
│   │   ├── layouts/
│   │   │   └── default.dart
│   │   ├── components/
│   │   └── middleware/
│   ├── app.dart
│   └── main.dart
├── web/
│   └── index.html
└── .duxt/                        # Generated files
    └── routes.g.dart

🖥️ CLI Commands #

Command Description
duxt create <name> Create a new project
duxt dev [--port] Start dev server with hot reload
duxt build Build for production
duxt start [--port] Run production server
duxt g <type> <name> Generate files
duxt scaffold <name> Generate full CRUD module

⚙️ Generators #

Generate Files #

# Module (creates pages/, components/, model.dart, api.dart)
duxt g module posts

# Page (with dynamic params)
duxt g page posts/[id]

# Component (with props)
duxt g component posts/card title:String author:String

# Model (with fields)
duxt g model post title:String content:String createdAt:DateTime

# API
duxt g api posts

# Layout
duxt g layout dashboard

Type shortcuts: p=page, c=component, m=model, a=api, l=layout

Scaffold (Full CRUD) #

duxt scaffold posts title:String content:String author:String

Generates:

  • Model with JSON serialization
  • API class with CRUD methods
  • List page with pagination
  • Detail page
  • Create/Edit forms

🌐 API Client #

Configuration #

import 'package:duxt/duxt.dart';

// Set base URL
Api.configure(baseUrl: 'https://api.example.com');

// Set auth token
Api.setAuth('your-jwt-token');

// Add custom headers
Api.configure(
  baseUrl: 'https://api.example.com',
  headers: {'X-Custom-Header': 'value'},
);

Making Requests #

// GET
final posts = await Api.get('/posts');
final post = await Api.get('/posts/1');

// POST
final newPost = await Api.post('/posts', body: {
  'title': 'Hello World',
  'content': 'My first post',
});

// PUT
await Api.put('/posts/1', body: {'title': 'Updated'});

// PATCH
await Api.patch('/posts/1', body: {'title': 'Patched'});

// DELETE
await Api.delete('/posts/1');

Module API Pattern #

// lib/posts/api.dart
class PostsApi {
  static Future<List<Post>> getAll() async {
    final data = await Api.get('/posts');
    return Post.fromList(data);
  }

  static Future<Post> getOne(String id) async {
    final data = await Api.get('/posts/$id');
    return Post.fromJson(data);
  }

  static Future<Post> create(Post post) async {
    final data = await Api.post('/posts', body: post.toJson());
    return Post.fromJson(data);
  }

  static Future<Post> update(String id, Post post) async {
    final data = await Api.put('/posts/$id', body: post.toJson());
    return Post.fromJson(data);
  }

  static Future<void> delete(String id) async {
    await Api.delete('/posts/$id');
  }
}

🔄 State Management (SPA) #

DuxtState #

Handle async data loading with automatic state management:

class PostsPage extends StatefulComponent {
  @override
  State createState() => _PostsState();
}

class _PostsState extends DuxtState<PostsPage, List<Post>> {
  @override
  Future<List<Post>> load() => PostsApi.getAll();

  @override
  Component buildLoading() => DSpinner();

  @override
  Component buildError(Object error) => DAlert(
    title: 'Error',
    description: error.toString(),
    color: DAlertColor.error,
  );

  @override
  Component buildData(List<Post> posts) => div([
    for (final post in posts)
      PostCard(post: post),
  ]);
}

DuxtMultiState #

Load multiple data sources in parallel:

class _DashboardState extends DuxtMultiState<DashboardPage> {
  @override
  Map<String, Future<dynamic>> get loaders => {
    'posts': PostsApi.getAll(),
    'users': UsersApi.getAll(),
    'stats': StatsApi.get(),
  };

  @override
  Component buildData(Map<String, dynamic> data) {
    final posts = data['posts'] as List<Post>;
    final users = data['users'] as List<User>;
    final stats = data['stats'] as Stats;

    return Dashboard(posts: posts, users: users, stats: stats);
  }
}

🔒 Middleware #

Create Middleware #

// lib/shared/middleware/auth_middleware.dart
class AuthMiddleware extends DuxtMiddleware {
  @override
  Future<MiddlewareResult> handle(RouteState route) async {
    final token = await TokenStorage.getToken();

    if (token == null) {
      return MiddlewareResult.redirect('/login');
    }

    return MiddlewareResult.next();
  }
}

Apply to Pages #

class SecurePage extends DuxtPage {
  @override
  List<DuxtMiddleware> get middleware => [AuthMiddleware()];

  @override
  Component build(BuildContext context) => div([
    text('Protected content'),
  ]);
}

📐 Layouts #

Create a Layout #

// lib/shared/layouts/dashboard_layout.dart
class DashboardLayout extends DuxtLayout {
  @override
  Component build(BuildContext context, Component child) => div(
    classes: 'flex min-h-screen',
    [
      Sidebar(),
      main(classes: 'flex-1 p-6', [child]),
    ],
  );
}

Apply to Pages #

class DashboardPage extends DuxtPage {
  @override
  Type get layout => DashboardLayout;

  @override
  Component build(BuildContext context) => div([
    text('Dashboard content'),
  ]);
}

🛠️ Server API (Backend) #

Create API Routes #

// lib/api/server.dart
import 'package:duxt/server.dart';

void main() {
  final server = DuxtServer();

  // Middleware
  server.use(corsMiddleware());
  server.use(loggerMiddleware());
  server.use(jsonBodyParser());

  // Routes
  server.get('/posts', (req, res) async {
    final posts = await db.posts.findAll();
    return res.json(posts);
  });

  server.post('/posts', (req, res) async {
    final body = req.body;
    final post = await db.posts.create(body);
    return res.json(post, status: 201);
  });

  server.get('/posts/:id', (req, res) async {
    final id = req.params['id'];
    final post = await db.posts.findById(id);
    if (post == null) return res.notFound();
    return res.json(post);
  });

  server.listen(port: 3000);
}

📝 Content & Documentation #

Build documentation sites with markdown:

// Load markdown content
final content = await ContentLoader.load('docs/getting-started.md');

// Access frontmatter
print(content.frontmatter['title']);
print(content.frontmatter['description']);

// Render HTML
print(content.html);

// Get table of contents
print(content.toc);

🎨 Using with Duxt UI #

Duxt works seamlessly with Duxt UI for beautiful, pre-built components:

dependencies:
  duxt: ^0.2.2
  duxt_ui: ^0.2.0
import 'package:duxt/duxt.dart';
import 'package:duxt_ui/duxt_ui.dart';

class HomePage extends DuxtPage {
  @override
  Component build(BuildContext context) => DContainer([
    DPageHero(
      title: 'Welcome to Duxt',
      description: 'Build beautiful Dart web apps',
    ),
    DButton(
      label: 'Get Started',
      color: DButtonColor.primary,
      onClick: () => Router.of(context).push('/docs'),
    ),
  ]);
}

📦 Requirements #

  • Dart SDK ^3.0.0
  • Jaspr ^0.22.1

📚 Documentation #

Visit duxt.dev for full documentation.


🤝 Contributing #

Contributions are welcome! Please read our Contributing Guide first.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing)
  5. Open a Pull Request

📄 License #

MIT License - see LICENSE for details.


Built by the duxt.dev team

3
likes
0
points
616
downloads

Publisher

verified publisherbase.al

Weekly Downloads

A meta-framework for Jaspr with module-based architecture, file-based routing, layouts, and scaffold generators.

Homepage
Repository (GitHub)
View/report issues

Topics

#web #framework #jaspr #routing #scaffolding

License

unknown (license)

Dependencies

ansicolor, args, http, jaspr, jaspr_content, jaspr_router, markdown, path, shelf, shelf_proxy, shelf_static, watcher, yaml

More

Packages that depend on duxt