Mỗi lần muốn tách một phần dùng chung thành Laravel package, mình thường mất một đoạn khá chán để dựng lại composer.json, service provider, Testbench và workflow test. Laravel Installer 5.31.0 thêm lệnh laravel package để gom phần khởi động đó vào một câu lệnh. Nghe tiện, nhưng mình vẫn muốn chạy thật trước khi bảo anh em dùng.

Mình cài đúng laravel/installer 5.31.0 trên Windows, PHP 8.4.23, tạo một package tạm có config, route, view, migration và command rồi chạy Pest. Kết quả cuối là 6 test qua với 7 assertion; giữa đường có một lỗi autoload nhỏ khá đáng nhớ.

Lệnh mới thực sự làm những gì?

Theo Laravel News và mã nguồn installer, lệnh mới clone package-skeleton chính thức, xóa lịch sử Git của skeleton, cài dependency không chạy script rồi gọi configure.php. Tức là đây không phải generator tự ghép vài chuỗi PHP; nó dùng một bộ khung có test, Workbench và CI tương đối đầy đủ.

composer global require laravel/installer:^5.31
laravel package my-package

Máy cần PHP từ 8.2 trở lên. Packagist ghi bản 5.31.0 hỗ trợ các nhánh Illuminate 10, 11, 12 và 13. Anh em đang giữ installer global cũ nên kiểm tra bằng laravel --version trước; nếu chưa có subcommand package thì đừng ngồi đoán vì sao lệnh không tồn tại.

Tủ module minh họa các thành phần trong một package Laravel
Ảnh minh họa biên tập: skeleton cho sẵn nhiều ngăn, nhưng chỉ nên giữ những phần package thực sự cần.

Mình đã dựng package thử ra sao?

Mình tạo một thư mục tạm, cài riêng installer 5.31.0 để không đụng cấu hình global. Phần help trả về đầy đủ các cờ --config, --routes, --views, --translations, --migrations, --assets, --commands, --facade--boost-skill.

laravel package nghiane-lab-package \
  --config --routes --views --migrations --commands \
  --author-name="Nghia" \
  --author-email="lab@example.com" \
  --package-name="nghiane/lab-package" \
  --package-name-human="Nghiane Lab Package" \
  --package-description="Temporary package scaffold test" \
  --vendor-namespace="NghiaNe" \
  --class-name="NghianeLabPackage" \
  --no-interaction

Chỗ dễ sai đầu tiên là --package-name. Mình nhập nghiane-lab-package và configurator từ chối ngay vì Composer yêu cầu dạng vendor/package. Đổi thành nghiane/lab-package thì quá trình cấu hình chạy xong và trả một summary dạng JSON, khá hữu ích khi lệnh được gọi bởi agent hoặc script CI.

NhómFile chính được sinhVai trò
Coresrc/NghianeLabPackage.php, service providerĐiểm vào của package
Cấu hìnhconfig/lab-package.phpCho ứng dụng publish và tùy chỉnh
HTTP/UIroutes/lab-package.php, Blade viewRoute và giao diện mẫu
Dữ liệuMigration placeholderKhung thay đổi database
CLINghianeLabPackageCommand.phpCommand mẫu của package
TestPest, Testbench, Arch testChạy package ngoài app thật

Cú vấp autoload sau khi đổi namespace

Ngay sau khi configurator báo thành công, mình chạy vendor/bin/pest --compact. Pest báo không tìm thấy NghiaNe\NghianeLabPackage\Tests\TestCase. Lý do là dependency đã được cài khi skeleton còn dùng namespace mẫu; configurator đổi namespace trong composer.json và source nhưng autoload hiện tại chưa được tạo lại trong lab thủ công của mình.

composer dump-autoload
php vendor/bin/pest --compact

Sau khi dump autoload, kết quả là 6 test pass, 7 assertion, 279 ms. Lệnh scaffold chuẩn vốn chạy cấu hình sau bước cài dependency; dù vậy, nếu anh em sửa metadata hoặc namespace thủ công rồi test báo thiếu class, hãy kiểm tra autoload trước khi đổ lỗi cho Pest.

Quy trình đóng gói phần mềm bên cạnh màn hình test tự động
Ảnh minh họa biên tập: scaffold chỉ đáng tin sau khi autoload và bộ test chạy lại trên metadata mới.

Cờ nào nên bật, cờ nào chưa cần?

Đừng bật mọi thứ chỉ vì lệnh cho phép. Package chỉ cung cấp service hoặc helper thì core class, provider và test có thể đã đủ. Package cần route web mới thêm route và view; có dữ liệu riêng mới thêm migration. Một facade nhìn gọn lúc gọi nhưng cũng thêm API phải bảo trì, nên mình chỉ bật khi nó thực sự làm cách dùng package rõ hơn.

  • --config: hợp với package có giá trị mặc định cần publish.
  • --commands: dùng khi package có tác vụ vận hành hoặc generator riêng.
  • --boost-skill: dành cho package muốn cung cấp ngữ cảnh cho Laravel Boost; không dùng Boost thì bỏ.
  • --assets--translations: chỉ thêm khi package thật sự có tài nguyên frontend hoặc nội dung đa ngôn ngữ.

Bộ khung còn kèm GitHub Actions, Dependabot, issue template, security policy và changelog workflow. Đây là điểm mình thích hơn một generator tối giản: package mở nguồn thường chết ở khâu release và test nhiều phiên bản chứ không phải ở file service provider đầu tiên.

Dùng trong automation có ổn không?

Bản 5.31.0 dùng laravel/agent-detector. Khi nhận ra đang chạy dưới coding agent, lệnh tắt tương tác và xuất JSON gồm trạng thái, tên, thư mục cùng log khi thất bại. Các cờ metadata giúp chạy hoàn toàn non-interactive, tránh agent bị đứng ở câu hỏi tên tác giả giữa chừng.

Tuy nhiên, automation vẫn cần Git, Composer và mạng để clone skeleton/cài dependency. Đừng cho job quyền ghi bừa vào repository chính. Mình sẽ tạo trong thư mục tạm, chạy test, xem diff rồi mới chuyển phần cần thiết vào source. Cách này giống lúc mình thử CPX 2.0: tiện đến đâu cũng phải giữ ranh giới giữa công cụ tải về và code đang chạy production.

Nếu package có broadcasting hoặc WebSocket, phần test khung chỉ là bước đầu. Bài bảng tỷ số với Laravel Reverb là ví dụ cho phần tích hợp ứng dụng mà skeleton không thể tự kiểm tra thay mình.

Một checklist ngắn trước khi publish package

  1. Đổi toàn bộ placeholder, mô tả và namespace; chạy composer dump-autoload.
  2. Viết lại test mẫu thành hành vi package thực sự cung cấp.
  3. Chạy Pest trên các phiên bản PHP/Laravel cần hỗ trợ.
  4. Kiểm tra file nào cần publish, file nào nên load trực tiếp.
  5. Xem lại license, security policy và workflow release trước khi đẩy GitHub.

Kết luận

laravel package không viết package thay mình, nhưng nó loại được phần dựng giàn giáo lặp đi lặp lại và cho một điểm bắt đầu có test, CI, Workbench. Trên máy mình, bộ khung cấu hình đúng những phần đã chọn và test qua sau khi làm mới autoload. Với package nhỏ dùng nội bộ, lệnh này tiết kiệm kha khá thời gian; với package public, phần khó vẫn là thiết kế API và giữ tương thích lâu dài.