การใช้ Build Runner เพื่อ Generate Code ใน Flutter
ในบทความที่แล้ว เราได้เรียนรู้เกี่ยวกับการใช้ Freezed Package เพื่อลด Boilerplate Code ในการสร้าง Data Classes ใน Flutter ซึ่งเป็นประโยชน์อย่างมากในการพัฒนาแอปพลิเคชัน Flutter อย่างรวดเร็วและมีประสิทธิภาพ แต่ Freezed Package ไม่ได้ทำงานด้วยตัวมันเอง จำเป็นต้องมีเครื่องมือที่ช่วย "Generate" โค้ดที่ Freezed กำหนดไว้ นั่นก็คือ Build Runner นั่นเอง
บทความนี้จะพาคุณไปรู้จักกับ Build Runner เครื่องมือสำคัญสำหรับการ Generate Code อัตโนมัติใน Flutter และวิธีการใช้งานร่วมกับ Packages ต่างๆ เช่น Freezed, JsonSerializable และอื่นๆ เพื่อให้คุณสามารถเขียนโค้ดได้อย่างมีประสิทธิภาพและลดข้อผิดพลาดที่อาจเกิดขึ้นจากการเขียนโค้ดซ้ำๆ
Build Runner คืออะไร?
Build Runner คือเครื่องมือที่ช่วยให้คุณสามารถ Generate Code อัตโนมัติได้ใน Flutter โดยอาศัย Annotations และ Builders ที่กำหนดไว้ใน Packages ต่างๆ เช่น Freezed, JsonSerializable และอื่นๆ Build Runner จะทำการ Scan โค้ดของคุณ มองหา Annotations ที่เกี่ยวข้อง และใช้ Builders ที่สอดคล้องกันเพื่อ Generate โค้ดที่จำเป็น
พูดง่ายๆ คือ Build Runner เป็นเหมือน "ผู้ช่วย" ที่คอย Generate โค้ดที่น่าเบื่อและซ้ำซากให้เรา โดยที่เราแค่กำหนด Annotation ที่ถูกต้องเท่านั้น
ทำไมต้องใช้ Build Runner?
- ลด Boilerplate Code: ช่วยลดปริมาณโค้ดที่เราต้องเขียนเอง ทำให้โค้ดสะอาดและอ่านง่ายขึ้น
- ลดข้อผิดพลาด: ลดโอกาสในการเกิดข้อผิดพลาดจากการเขียนโค้ดซ้ำๆ
- เพิ่มประสิทธิภาพ: ช่วยให้เราพัฒนาแอปพลิเคชันได้เร็วขึ้น
- บำรุงรักษาง่าย: เมื่อมีการเปลี่ยนแปลง Data Model โค้ดที่ Generate จะถูก Update โดยอัตโนมัติ ทำให้การบำรุงรักษาง่ายขึ้น
การติดตั้ง Build Runner
ในการใช้งาน Build Runner คุณจะต้องติดตั้ง Package ที่เกี่ยวข้องลงใน pubspec.yaml ของโปรเจกต์ Flutter ของคุณ โดยปกติแล้วคุณจะต้องติดตั้ง build_runner และ build_verify (optional แต่แนะนำ) เป็น dev_dependencies
dev_dependencies:
build_runner: ^2.4.8
build_verify: ^3.1.0 # Optional, but recommended
หลังจากแก้ไข pubspec.yaml แล้ว ให้ทำการ flutter pub get เพื่อติดตั้ง Packages ที่จำเป็น
การใช้งาน Build Runner
Build Runner มี Command Line Interface (CLI) ที่ใช้สำหรับ Generate Code โดยมีคำสั่งหลักๆ ดังนี้:
flutter pub run build_runner build: Generate Code เพียงครั้งเดียวflutter pub run build_runner watch: Generate Code อัตโนมัติเมื่อมีการเปลี่ยนแปลงไฟล์flutter pub run build_runner serve: Generate Code อัตโนมัติและให้บริการผ่าน Web Server (เหมาะสำหรับ Web Development)flutter pub run build_runner test: Generate Code สำหรับการ Testflutter pub run build_runner clean: ลบไฟล์ที่ Generate ทั้งหมด
โดยทั่วไปแล้ว คำสั่ง flutter pub run build_runner watch เป็นคำสั่งที่นิยมใช้มากที่สุด เพราะจะช่วยให้เราสามารถ Generate Code อัตโนมัติเมื่อมีการเปลี่ยนแปลงไฟล์ ทำให้เราไม่ต้อง Run คำสั่ง Build Runner ซ้ำๆ
ตัวอย่างการใช้งาน Build Runner ร่วมกับ Freezed
สมมติว่าเรามี Data Class ที่ชื่อ User ซึ่งใช้ Freezed Package ในการ Generate Code:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
@freezed
class User with _$User {
const factory User({
required String id,
required String name,
required String email,
}) = _User;
}
เพื่อให้ Build Runner สามารถ Generate Code สำหรับ User ได้ เราจะต้อง Run คำสั่ง flutter pub run build_runner build หรือ flutter pub run build_runner watch ใน Terminal
หลังจาก Run คำสั่งแล้ว Build Runner จะทำการ Generate ไฟล์ user.freezed.dart ซึ่งมี Code ที่ Freezed กำหนดไว้ เช่น Constructor, copyWith, toJson, fromJson
ตัวอย่างการใช้งาน Build Runner ร่วมกับ JsonSerializable
JsonSerializable เป็น Package ที่ช่วยให้เราสามารถ Serialize และ Deserialize JSON ได้อย่างง่ายดาย โดย Build Runner จะช่วย Generate Code ที่จำเป็นในการแปลง Data Class ของเราไปเป็น JSON และจาก JSON กลับมาเป็น Data Class
ในการใช้งาน JsonSerializable เราจะต้องติดตั้ง Package ที่เกี่ยวข้อง:
dependencies:
json_annotation: ^4.8.1
dev_dependencies:
build_runner: ^2.4.8
json_serializable: ^6.7.1
จากนั้นเราสามารถสร้าง Data Class ที่มี Annotation @JsonSerializable():
import 'package:json_annotation/json_annotation.dart';
part 'person.g.dart';
@JsonSerializable()
class Person {
final String firstName;
final String lastName;
final int age;
Person({required this.firstName, required this.lastName, required this.age});
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
Map<String, dynamic> toJson() => _$PersonToJson(this);
}
และ Run คำสั่ง flutter pub run build_runner build หรือ flutter pub run build_runner watch เพื่อ Generate ไฟล์ person.g.dart ซึ่งมี Code ที่จำเป็นในการ Serialize และ Deserialize JSON
ข้อผิดพลาดที่พบบ่อยและการแก้ไข
- Missing
partdirective: หากคุณลืมใส่partdirective ในไฟล์ Data Class ของคุณ Build Runner จะไม่สามารถ Generate Code ได้ ตรวจสอบให้แน่ใจว่าคุณได้ใส่part 'your_file_name.g.dart';หรือpart 'your_file_name.freezed.dart';ในไฟล์ Data Class ของคุณแล้ว - Conflicting Outputs: หากคุณมีหลาย Packages ที่พยายาม Generate ไฟล์ที่มีชื่อเดียวกัน Build Runner อาจจะเกิดข้อผิดพลาดได้ คุณสามารถแก้ไขได้โดยการกำหนด
build.yamlเพื่อกำหนด Output Path ที่แตกต่างกันสำหรับแต่ละ Package - Outdated Dependencies: หาก Dependencies ของคุณล้าสมัย Build Runner อาจจะไม่ทำงานอย่างถูกต้อง ตรวจสอบให้แน่ใจว่าคุณได้ Update Dependencies ของคุณเป็นเวอร์ชันล่าสุดแล้ว
- Build Cache: บางครั้ง Build Cache อาจจะทำให้เกิดปัญหาได้ คุณสามารถ Clear Build Cache ได้โดยการ Run คำสั่ง
flutter clean
การใช้ build.yaml เพื่อกำหนดค่า Build Runner
build.yaml เป็นไฟล์ที่ใช้สำหรับกำหนดค่า Build Runner เช่น กำหนด Output Path, Filter ไฟล์ที่ต้องการ Generate Code และอื่นๆ ไฟล์นี้จะช่วยให้เราสามารถควบคุมการทำงานของ Build Runner ได้อย่างละเอียด
ตัวอย่างการใช้งาน build.yaml:
targets:
$default:
sources:
- lib/**
- web/**
exclude:
- lib/**.g.dart
- lib/**.freezed.dart
builders:
json_serializable:
options:
# Options configure how source code is generated for every
# `@JsonSerializable`-annotated class.
field_rename: snake
explicit_to_json: true
ในตัวอย่างนี้ เรากำหนดให้ Build Runner Scan ไฟล์ทั้งหมดใน lib และ web Directory แต่ยกเว้นไฟล์ที่ลงท้ายด้วย .g.dart และ .freezed.dart นอกจากนี้เรายังกำหนด Options สำหรับ json_serializable Builder ให้ทำการ Rename Field เป็น Snake Case และ Generate toJson Method อย่างชัดเจน
สรุป
Build Runner เป็นเครื่องมือที่สำคัญสำหรับการ Generate Code อัตโนมัติใน Flutter ซึ่งช่วยให้เราสามารถลด Boilerplate Code, ลดข้อผิดพลาด และเพิ่มประสิทธิภาพในการพัฒนาแอปพลิเคชัน การใช้งาน Build Runner ร่วมกับ Packages ต่างๆ เช่น Freezed และ JsonSerializable จะช่วยให้เราสามารถเขียนโค้ดได้อย่างมีประสิทธิภาพและบำรุงรักษาง่ายขึ้น
ในบทความถัดไป เราจะมาเรียนรู้เกี่ยวกับการสร้าง Custom Painter ใน Flutter เพื่อสร้าง UI ที่มีความซับซ้อนและสวยงาม