Chuyển đến nội dung chính

Bài đăng

go_router: Điều hướng Flutter lấy URL làm trung tâm

go_router: Điều hướng Flutter lấy URL làm trung tâm go_router đáng chú ý vì nó giải quyết routing khai báo, deep link, redirect và ShellRoute. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu final router = GoRouter ( redirect : (context, state) => isSignedIn || state.uri.path == '/login' ? null : '/login' , routes : [ GoRoute (path : '/' , builder : (_, __) => const HomePage ()), GoRoute (path : '/orders/:id' , builder : (_, state) => OrderPage (id : state.pathParameters[ 'id' ] ! )), ], ); Checklist trước khi s...
Các bài đăng gần đây

FVM: ghim Flutter version theo từng repository

FVM: ghim Flutter version theo từng repository fvm đáng chú ý vì nó giải quyết file version, parity với CI, onboarding team và nhịp migration. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu fvm use stable fvm flutter pub get fvm flutter test fvm flutter build apk -- release Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về background. Kiểm tra Android, iOS, web hoặc desktop đúng platform mà app hỗ trợ. Ghi lại owner, upgrade cadence và kế hoạch rollback trong repo. Pitfall hay gặp Ghim version cả ở CI và docs; setting ...

Freezed: model bất biến và union an toàn hơn

Freezed: model bất biến và union an toàn hơn freezed đáng chú ý vì nó giải quyết data class bất biến, JSON union, copyWith và state UI exhaustive. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu @freezed sealed class LoadState < T > with _$LoadState < T > { const factory LoadState . idle () = Idle < T >; const factory LoadState . loading () = Loading < T >; const factory LoadState . data ( T value) = Data < T >; const factory LoadState . failure ( Object error) = Failure < T >; } Checklist trước khi ship Đọc README và changelog của package đúng versi...

go_router: URL-first navigation for Flutter

go_router: URL-first navigation for Flutter go_router is useful because it focuses on declarative routing, deep links, redirects, and ShellRoute. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point final router = GoRouter ( redirect : (context, state) => isSignedIn || state.uri.path == '/login' ? null : '/login' , routes : [ GoRoute (path : '/' , builder : (_, __) => const HomePage ()), GoRoute (path : '/orders/:id' , builder : (_, state) => OrderPage (id : state.pathParameters[ 'id' ] ! )),...

FVM: pin Flutter versions per repository

FVM: pin Flutter versions per repository fvm is useful because it focuses on version files, CI parity, team onboarding, and migration cadence. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point fvm use stable fvm flutter pub get fvm flutter test fvm flutter build apk -- release Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, and app background/foreground behavior. Verify every platform your product supports, not only the developer machine. Record ownership, upgrade cadence, and rollback notes in the repository. ...

Freezed: safer immutable models and unions

Freezed: safer immutable models and unions freezed is useful because it focuses on immutable data classes, JSON unions, copyWith, and exhaustive UI states. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point @freezed sealed class LoadState < T > with _$LoadState < T > { const factory LoadState . idle () = Idle < T >; const factory LoadState . loading () = Loading < T >; const factory LoadState . data ( T value) = Data < T >; const factory LoadState . failure ( Object error) = Failure < T >; } Production checklist Read the RE...

ForUI: component headless dễ tiếp cận cho Flutter

ForUI: component headless dễ tiếp cận cho Flutter forui đáng chú ý vì nó giải quyết control có thể ghép, theme, keyboard behavior và accessibility. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu FButton ( onPress : submit, child : const Text ( 'Save' ), ); FPopoverMenu ( control : FButton (onPress : openMenu, child : const Text ( 'More' )), menu : [ FPopoverMenuItem (onPress : archive, child : const Text ( 'Archive' )), ], ); Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi ...

Forui: hệ thống UI Flutter có chủ kiến

Forui đặt cược khác “Material ở khắp nơi”: cấu trúc chặt, default mạnh và theme được thiết kế như một hệ thống. Khi nào nên đánh giá Sản phẩm muốn một look nhất quán mobile/desktop. Bạn chán override internal component Material. Accessibility là yêu cầu launch, không phải backlog. Cạm bẫy Adopt hệ thống UI đầy đủ là migration. Pilot một luồng (settings + form) trước khi rewrite cả app. So Forui với package material_ui độc lập nếu team vẫn muốn Material của Google làm nền. Bài viết gốc đăng tại FlutterCook . Bản trên đó là bản được cập nhật mới nhất.

flutter_secure_storage: secret nằm sau keychain của platform

flutter_secure_storage: secret nằm sau keychain của platform flutter_secure_storage đáng chú ý vì nó giải quyết Keychain, Keystore, encrypted shared preferences và migration. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu const storage = FlutterSecureStorage (); await storage. write (key : 'refresh_token' , value : refreshToken); final token = await storage. read (key : 'refresh_token' ); await storage. delete (key : 'refresh_token' ); Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về back...

ForUI: accessible headless components for Flutter

ForUI: accessible headless components for Flutter forui is useful because it focuses on composable controls, theming, keyboard behavior, and accessibility. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point FButton ( onPress : submit, child : const Text ( 'Save' ), ); FPopoverMenu ( control : FButton (onPress : openMenu, child : const Text ( 'More' )), menu : [ FPopoverMenuItem (onPress : archive, child : const Text ( 'Archive' )), ], ); Production checklist Read the README and changelog for the exact version you pin. Add one test...

Forui: an opinionated Flutter UI system

Forui takes a different bet than “Material everywhere”: strict structure, strong defaults, and a theme system designed as a system. When to evaluate it Product wants one coherent look across mobile/desktop. You are tired of overriding Material component internals. Accessibility is a launch requirement, not a backlog item. Pitfalls Adopting a full UI system is a migration. Pilot one flow (settings + forms) before a full rewrite. Compare Forui with material_ui standalone packages if your team still wants Google Material as the base. Originally published on FlutterCook . Read the latest version there — that copy is the one kept up to date.

flutter_secure_storage: secrets behind platform keychains

flutter_secure_storage: secrets behind platform keychains flutter_secure_storage is useful because it focuses on Keychain, Keystore, encrypted shared preferences, and migration. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point const storage = FlutterSecureStorage (); await storage. write (key : 'refresh_token' , value : refreshToken); final token = await storage. read (key : 'refresh_token' ); await storage. delete (key : 'refresh_token' ); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, ...

flutter_rust_bridge: Rust có kiểu mà không phải tự viết FFI glue

flutter_rust_bridge: Rust có kiểu mà không phải tự viết FFI glue flutter_rust_bridge đáng chú ý vì nó giải quyết code generation, Rust async, stream, error boundary và native build. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu #[flutter_rust_bridge :: frb] pub async fn hash_file (path : String ) -> anyhow :: Result < String > { Ok (sha256 :: digest (std :: fs :: read (path) ? )) } final digest = await api. hashFile (path : filePath); Checklist trước khi ship Đọc README và changelog của package đúng version đang pin. Viết một test cho lifecycle, lỗi và hành vi khi app về background. Kiểm...

flutter_hooks: tái sử dụng behavior có state bằng hook nhỏ

flutter_hooks: tái sử dụng behavior có state bằng hook nhỏ flutter_hooks đáng chú ý vì nó giải quyết lifecycle hook, ownership controller, effect và UI logic ghép được. Bài này trình bày cách đặt package vào đúng boundary của một ứng dụng Flutter production thay vì chỉ copy một snippet vào màn hình. Package này sở hữu phần nào? Giữ API của package ở một adapter hoặc feature boundary có tên rõ ràng. Đưa lifecycle, lỗi và trạng thái loading vào contract mà UI có thể kiểm thử. Chỉ expose capability cần thiết; đừng để toàn app phụ thuộc vào chi tiết triển khai. Snippet bắt đầu class SearchField extends HookWidget { const SearchField ({ super .key}); @override Widget build ( BuildContext context) { final controller = useTextEditingController (); final focusNode = useFocusNode (); useEffect (() { focusNode. requestFocus (); return null ; }, const []); return TextField (controller : controller, focusNode : focusNode); ...

Flutter Deer: dự án luyện tập dáng production

Không phải repo học tập nào cũng sống lâu. Deer vẫn hữu ích vì cho thấy khung app hoàn chỉnh : flavor, component dùng chung, integration test và domain shop nhàm chán một cách có chủ đích. Nên copy Folder theo feature thay vì mega-folder chỉ theo layer khi scale. Thư viện widget dùng chung kèm token/mockup trong repo. Integration test là một phần của “done”. Nên cập nhật Ý kiến state management đã dịch chuyển (Riverpod/bloc…). Giữ cấu trúc Deer, làm mới tầng state theo team bạn. Cạm bẫy Đừng paste UI mà không trích design token. Template thối khi hardcode API host. Bài viết gốc đăng tại FlutterCook . Bản trên đó là bản được cập nhật mới nhất.

flutter_rust_bridge: typed Rust without hand-written FFI glue

flutter_rust_bridge: typed Rust without hand-written FFI glue flutter_rust_bridge is useful because it focuses on code generation, async Rust, streams, error boundaries, and native builds. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point #[flutter_rust_bridge :: frb] pub async fn hash_file (path : String ) -> anyhow :: Result < String > { Ok (sha256 :: digest (std :: fs :: read (path) ? )) } final digest = await api. hashFile (path : filePath); Production checklist Read the README and changelog for the exact version you pin. Add one test for lifecycle, failure, ...

flutter_hooks: reusable stateful behavior as tiny hooks

flutter_hooks: reusable stateful behavior as tiny hooks flutter_hooks is useful because it focuses on hook lifecycle, controller ownership, effects, and composable UI logic. The important engineering move is to place the package behind a clear boundary, so your Flutter UI depends on a stable capability rather than a vendor-shaped API. What the library should own Keep package calls inside a named adapter or feature boundary. Make lifecycle, errors, and loading state part of a testable contract. Expose only the capability the app needs; hide implementation details from the whole tree. A focused starting point class SearchField extends HookWidget { const SearchField ({ super .key}); @override Widget build ( BuildContext context) { final controller = useTextEditingController (); final focusNode = useFocusNode (); useEffect (() { focusNode. requestFocus (); return null ; }, const []); return TextField (controller : co...

Flutter Deer: a production-shaped practice project

Not every learning repo ages well. Deer remains useful because it shows a complete app skeleton : flavors, common components, integration tests, and a shop domain that is boring on purpose. What to copy Feature folders over layer-only mega-folders at scale. Shared widgets library with design tokens/mockups in-repo. Integration tests as part of “done.” What to update State management opinions have moved (Riverpod/bloc/etc.). Keep Deer’s structure , refresh the state layer for your team. Pitfalls Do not paste UI without extracting design tokens. Templates rot when they hardcode API hosts. Originally published on FlutterCook . Read the latest version there — that copy is the one kept up to date.