Struktur Asset yang Dipublish
Frontend Vue milik panel disalin ke dalam application Anda melalui vendor:publish, bukan di-import langsung dari package. Halaman ini menjadi peta untuk memahami apa yang disalin ke mana: directory mana yang ditulis, isi masing-masing directory, dua path mana yang dapat dikonfigurasi, serta file mana yang tetap disimpan hanya di dalam package. Gunakan halaman ini setelah instalasi, sebelum memindahkan sesuatu di bawah resources/js, atau ketika Anda perlu memastikan apakah file yang sedang dilihat adalah milik application atau milik package.
Contoh minimal yang berfungsi
php artisan panel:install
npm install && npm run build2
panel:install mem-publish tag config terlebih dahulu, kemudian tag assets, lalu mencatat file yang ditulis ke .panel-assets.json. Setelah itu:
ls resources/js
# components composables lib pages panel types2
Semua yang ada pada daftar tersebut, kecuali pages/Panels, adalah file yang dikirim oleh package. Setelah dipublish, semuanya menjadi bagian dari application Anda: masuk repository Anda, ikut build Anda, dan dapat Anda edit.
Peta publish
PandaPanel\Support\Installer\PublishedAssets::map() adalah satu-satunya sumber kebenaran untuk peta publish. Service provider memberikannya ke publishes(), dan panel:assets membandingkan file terhadap peta yang sama, sehingga tidak ada salinan konfigurasi kedua yang berpotensi berbeda.
| Sumber di package | Tujuan di application |
|---|---|
resources/js/panel | FrontendPaths::panel() — default resources/js/panel |
resources/js/components | resources/js/components |
resources/js/composables | resources/js/composables |
resources/js/lib | resources/js/lib |
resources/js/pages | resources/js/pages |
resources/js/types | resources/js/types |
resources/css/panda-panel.css | resources/css/panda-panel.css |
use PandaPanel\Support\Installer\PublishedAssets;
PublishedAssets::map();
// array<string, string> — absolute source => absolute destination
PublishedAssets::files();
// array<string, string> — absolute destination => absolute source, satu entry per file
PublishedAssets::relative('/app/resources/js/panel/layouts/PanelLayout.vue');
// 'resources/js/panel/layouts/PanelLayout.vue'2
3
4
5
6
7
8
9
10
| Method | Signature | Mengembalikan |
|---|---|---|
map | static map(): array | source => destination, termasuk directory |
files | static files(): array | destination => source, sudah di-expand menjadi file individual |
relative | static relative(string $path): string | path setelah base_path() dihilangkan, untuk report |
files() meng-expand directory karena pertanyaan “apakah asset ini sudah up to date?” harus dijawab pada level file. Sebuah directory yang mendapatkan satu component baru sementara component lain di dalamnya diedit tidak bisa disebut sekadar berubah atau tidak berubah sebagai satu kesatuan.
Publish tags
php artisan vendor:publish --tag=panda-panel-config
php artisan vendor:publish --tag=panda-panel-assets
php artisan vendor:publish --tag=panda-panel-migrations
php artisan vendor:publish --tag=panda-panel-stubs
php artisan vendor:publish --tag=panda-panel2
3
4
5
| Tag | Yang dipublish |
|---|---|
panda-panel-config | config/panda-panel.php |
panda-panel-assets | seluruh isi peta publish di atas |
panda-panel-migrations | table notifications, column two-factor email, dan table integrations |
panda-panel-stubs | generator stubs ke stubs/panel |
panda-panel | config, migrations, dan assets sekaligus |
panda-panel-stubs sengaja tidak dimasukkan ke umbrella tag. Stub hanya berguna bagi project yang memang ingin mengedit output yang dihasilkan generator.
Isi setiap directory
resources/js/panel/
Frontend inti framework: layouts, shell components, renderer untuk tables, forms, infolists, widgets, dan actions, composables yang membaca shared props, enam component registry, serta TypeScript mirror untuk setiap bentuk data yang diserialisasi. Tidak ada file di sini yang di-resolve sebagai Inertia page — semuanya di-import berdasarkan nama, bukan dicari dari string nama page component.
Lihat Vue Component Tree untuk rincian setiap file.
resources/js/pages/
Ada dua jenis isi, dan pemisahan ini penting:
| Path | Peran |
|---|---|
pages/panel/** | screen milik framework — Dashboard.vue, Page.vue, resources/{Index,Create,Edit,View,ManageRelated,Integrations}.vue, auth/*, settings/* |
pages/Panels/** | panel components milik application Anda — custom pages, columns, fields, widgets, hooks, shell replacements |
Keduanya berada di bawah pages/ karena Inertia me-resolve nama component terhadap resources/js/pages, dan setiap screen panel adalah Inertia response. pages/Panels juga menjadi root untuk setiap import.meta.glob yang digunakan component registry.
Package mem-publish pages/panel/** dan tidak membuat apa pun di bawah pages/Panels. Directory pages/Panels ditulis oleh generator ketika Anda mulai membuat custom component.
resources/js/components/, composables/, lib/, types/
File dengan struktur seperti Laravel Vue starter kit yang di-import langsung oleh components milik panel:
| Path | Isi |
|---|---|
components/*.vue | AppShell, AppContent, NavUser, InputError, ManagePasskeys, ManageTwoFactor, dan beberapa lainnya |
components/ui/** | primitive shadcn yang dipakai renderer — button, table, dialog, sidebar, select, sonner, dan lainnya |
composables/useAppearance.ts | toggle light/dark yang digunakan Panel Header |
lib/utils.ts, lib/flashToast.ts | helper cn() dan bridge flash toast |
types/auth.ts, types/global.d.ts | shared types yang digunakan components |
Directory inilah yang paling mungkin bentrok dengan file bawaan Laravel Vue starter kit yang sudah ada. vendor:publish tidak pernah overwrite file yang sudah ada kecuali Anda memberikan --force, sehingga pada application berbasis starter kit, file yang bentrok akan dilewati dan versi milik application tetap digunakan — biasanya memang itu yang diinginkan.
resources/css/panda-panel.css
Stylesheet Tailwind v4: mapping theme, palette light dan dark, serta sejumlah kecil component class yang dibutuhkan panel. Lihat Tailwind Theme.
Tujuan dua path yang dapat dikonfigurasi
use PandaPanel\Support\FrontendPaths;
FrontendPaths::panel(); // /app/resources/js/panel
FrontendPaths::panel('icons/registry.ts');
// /app/resources/js/panel/icons/registry.ts
FrontendPaths::pages(); // /app/resources/js/pages/Panels
FrontendPaths::pages('Admin/Widgets/SystemInfo.vue');
// /app/resources/js/pages/Panels/Admin/Widgets/SystemInfo.vue2
3
4
5
6
7
8
9
| Method | Signature | Config key | Default |
|---|---|---|---|
panel | static panel(string $path = ''): string | panda-panel.frontend.panel_path | js/panel |
pages | static pages(string $path = ''): string | panda-panel.frontend.pages_path | js/pages/Panels |
Keduanya di-resolve melalui resource_path(), sehingga value konfigurasi bersifat relatif terhadap resources/:
// config/panda-panel.php
'frontend' => [
'panel_path' => 'js/panel',
'pages_path' => 'js/pages/Panels',
],2
3
4
5
Semua bagian framework yang perlu mengetahui salah satu path tersebut membacanya dari sini — peta publish, generator, dan panel:icons. Path yang bisa ditulis berbeda pada tiga tempat cepat atau lambat akan tidak konsisten.
pages_path adalah yang paling berpengaruh. Path ini juga menjadi root dari pola import.meta.glob di component registry, dan pola tersebut merupakan string literal di file hasil publish. Mengubah config hanya memindahkan lokasi tempat generator menulis file; perubahan itu tidak otomatis mengubah glob. Lihat Component Registries.
File yang tidak dipublish package
| Path di package | Mengapa tetap berada di package |
|---|---|
frontend/host/** | stand-in untuk module yang disediakan application Anda — lihat Host Modules |
frontend/entry.ts | glob entry untuk compile check milik package sendiri |
vite.config.ts | build config milik package, bukan milik application |
tsconfig.json, eslint.config.js | toolchain milik package sendiri |
resources/views/** | root view Inertia merupakan file milik application |
Build Vite package menghasilkan build/frontend, dan tidak ada satu pun isinya yang menjadi deliverable. Build tersebut hanya menjawab satu pertanyaan yang tidak dapat dijawab type checking: apakah semua file ini benar-benar dapat di-resolve dan dikompilasi bersama.
Mencatat asset yang sudah dipublish
panel:install menulis .panel-assets.json di root application setelah proses publish, lalu panel:assets membacanya:
php artisan panel:assets # hanya report
php artisan panel:assets --update # menulis file yang aman untuk diperbarui
php artisan panel:assets --force # juga overwrite file yang sudah diedit application2
3
use PandaPanel\Support\Installer\AssetManifest;
AssetManifest::path(); // /app/.panel-assets.json
AssetManifest::exists(); // bool
AssetManifest::read(); // array<string, string> relative destination => hash
AssetManifest::compare(); // array<string, array{status, destination, source}>
AssetManifest::write(AssetManifest::read());2
3
4
5
6
7
File tersebut menyimpan hash setiap file pada saat file dipublish. Nilai inilah common ancestor yang hilang pada perbandingan dua arah biasa. Commit file ini ke repository: ia merekam keputusan project, sama seperti composer.lock. Updating Published Assets menjelaskan setiap status dan bagaimana --update bekerja.
Gotchas
vendor:publishmelewati file yang sudah ada. Tanpa--force, tidak ada file existing yang disentuh. Inilah alasan instalasi kedua biasanya hampir tidak menulis apa pun. Untuk upgrade gunakanpanel:assets, bukanvendor:publish --force, karenavendor:publishtidak dapat membedakan file yang sengaja diedit dari file yang sekadar tertinggal versinya.- Tag assets menulis ke
resources/js/componentsdanresources/js/types. Pada application yang sudah memiliki file starter kit,--forcedi sini dapat benar-benar merusak hasil customisasi. Lebih aman gunakanpanel:assets --update, yang hanya menulis file yang dapat dibuktikan belum pernah Anda ubah. pages_pathdan registry glob adalah dua perubahan terpisah. Memindahkan salah satunya tanpa yang lain membuat semua custom component gagal di-resolve secara silent; petunjuknya hanya console warning yang muncul pada development.- Published component menjadi milik Anda.
composer updatetidak dapat memperbaruinya. Ini adalah konsekuensi dari allowlistimport.meta.glob, danpanel:assetsdisediakan untuk mengelola konsekuensi tersebut. panel:installaman dijalankan ulang. Command akan publish, mencatat manifest, membuat scaffold, mengecek frontend, lalu mencetak apa yang masih perlu diselesaikan satu kali di bagian akhir. Hanya--forceyang melakukan overwrite.- Tidak ada apa pun di bawah
frontend/hostyang masuk ke application Anda. Directory tersebut hanya dipakai agar type-check dan build package ini sendiri dapat berjalan. Application Anda menyediakan module aslinya.