Build Frontend
Component Vue milik PandaBear dipublish ke resources/js application lalu dibuild oleh Vite milik application itu sendiri, masuk ke bundle application tersebut. Tidak ada compiled asset yang dikirim dari vendor/chocoalano/panel. Karena itu deploy tanpa proses build berarti server menjalankan backend baru dengan frontend lama. Gunakan halaman ini saat menulis build step, ketika component hanya menampilkan fallback di production, atau ketika bundle frontend tidak sesuai dengan metadata yang dikirim server.
Contoh minimal yang berfungsi
npm ci
php artisan wayfinder:generate
npm run build2
3
Untuk application yang source Panel-nya tidak berubah, tiga langkah tersebut sudah cukup. Bagian berikut menjelaskan dependency setiap langkah dan beberapa kondisi ketika build dapat sukses tetapi hasilnya tetap salah.
Mengapa build step diperlukan
Frontend PandaBear dipublish ke application, bukan di-import langsung dari vendor:
php artisan vendor:publish --tag=panda-panel-assets| Source package | Destination 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 |
Setelah dipublish, file tersebut menjadi bagian dari application: tersimpan di repository application, ikut dibuild, dan dapat diedit. Model ini memungkinkan component registry bekerja sebagai build-time allowlist melalui import.meta.glob terhadap tree application sendiri:
const modules = import.meta.glob<{ default: Component }>(
'../../pages/Panels/**/Widgets/*.vue',
);2
3
Server hanya mengirim component name sebagai string. Frontend hanya dapat me-resolve nama tersebut melalui map hasil build. Component yang tidak ikut di-compile tidak dapat dipanggil walaupun request/server mengirim nama itu. Ini adalah security property sekaligus alasan build tidak optional:
Menambahkan custom widget, field, column, atau shell component di sisi PHP tidak menghasilkan apa pun sampai bundle frontend dibuild ulang.
Requirement
package.json milik package merupakan single source of truth untuk version range frontend. panel:install membaca file yang sama sehingga installer dan component tidak dapat memiliki daftar dependency yang berbeda. Matrix lengkap tersedia di compatibility matrix.
| Didukung | |
|---|---|
| Node | 20.19+, 22, 24 |
| Vite | 7.x |
| Vue | 3.5+ |
| Tailwind | 4.1+ |
| TypeScript | 5.7+ |
@inertiajs/vue3 | 3.x |
reka-ui | 2.x |
Tailwind 3 tidak dapat mengompilasi resources/css/panda-panel.css, karena stylesheet tersebut menggunakan fitur Tailwind 4 seperti @theme, @custom-variant, dan @source.
Import yang digunakan component
use PandaPanel\Support\Installer\FrontendRequirements;
FrontendRequirements::npmPackages(); // list<string> 'name@range'
FrontendRequirements::missingNpmPackages(); // package yang belum dideklarasikan application2
3
4
| Method | Signature | Menjawab |
|---|---|---|
npmPackages | static npmPackages(): list<string> | seluruh npm dependency yang di-import component dalam format name@range |
missingNpmPackages | static missingNpmPackages(): list<string> | dependency dari daftar tersebut yang belum dideklarasikan application |
missingHostModules | static missingHostModules(): list<string> | host-seam module yang tidak ditemukan, dalam bentuk @/… |
hasVite | static hasVite(): bool | apakah vite.config.ts atau vite.config.js tersedia |
missingInertia | static missingInertia(): list<string> | root view dan Inertia middleware yang belum tersedia |
layoutOverrides | static layoutOverrides(): list<array{file: string, line: int, code: string}> | entry file yang mengoverride layout Page secara paksa |
npmPackages() membaca langsung block dependencies dari package.json milik PandaBear, bukan menyimpan salinan daftar dependency di PHP. Ini mencegah installer menjadi stale ketika component baru meng-import package baru.
missingNpmPackages() membaca package.json milik application, bukan node_modules, karena yang penting adalah dependency tersebut dideklarasikan oleh project. Transitive dependency yang kebetulan tersedia hari ini dapat hilang ketika dependency lain di-upgrade.
Sebelum build pertama jalankan:
php artisan panel:installCommand tersebut melakukan publish/scaffolding dan melaporkan dependency serta host module yang belum tersedia.
Host module yang tidak dikirim package
Published component meng-import @/routes/*, @/actions/*, dan beberapa component/composable starter kit.
Ada dua kategori:
- Generated module —
@/routes/*dan@/actions/*dihasilkan Wayfinder dari route table application. Package tidak boleh mengirim salinan karena setiap application memiliki route berbeda. - Starter-kit/application module — seperti
@/components/UserMenuContent.vue,@/composables/useTwoFactorAuth, dan@/types/ui. Module ini memang milik application karena di sanalah project menentukan account menu, 2FA flow, dan desain aplikasinya sendiri.
Generate Wayfinder sebelum build:
php artisan wayfinder:generateLakukan setelah setiap perubahan route. Resource baru dapat mengubah route table; generated module yang stale menghasilkan TypeScript error saat build, yang jauh lebih baik dibanding link rusak di runtime.
FrontendRequirements::missingHostModules() adalah daftar authoritative yang digunakan panel:install. Repository PandaBear memiliki stand-in untuk development package di frontend/host/.
Jebakan layout override
Setiap Panel Page mendeklarasikan layout sendiri:
defineOptions({ layout: PanelLayout });Karena itu resources/js/app.ts tidak perlu memasang layout Panel secara manual.
Kesalahan umum adalah application memaksa semua Page memakai AppLayout:
page.default.layout = AppLayout; // salah — mengganti Panel shell
page.default.layout ??= AppLayout; // benar — hanya fallback jika Page tidak punya layout2
Assignment tanpa kondisi membuat Panel Page tetap 200 tetapi tampil di shell application, sehingga sidebar/navigation Panel hilang tanpa error server. panel:install memeriksa resources/js/app.ts, app.js, ssr.ts, dan ssr.js, lalu melaporkan file serta line jika menemukan override seperti ini. Bentuk ||=, ??=, atau assignment yang sudah memiliki fallback dianggap aman.
Perubahan yang mewajibkan rebuild
Build yang sukses belum tentu current. Perubahan berikut membutuhkan rebuild:
| Perubahan | Alasan |
|---|---|
menjalankan php artisan panel:icons | registry icon adalah TypeScript yang di-compile ke bundle |
| menambah custom widget / field / column / page component | registry component menggunakan build-time glob |
| perubahan route | Wayfinder module ikut di-compile |
php artisan panel:assets --update | command menulis source component baru ke application |
Environment variable VITE_* juga merupakan build input. Contohnya perubahan VITE_REVERB_HOST membutuhkan npm run build, bukan hanya restart server.
Menjaga published component tetap terbaru
php artisan panel:assets # lihat apa yang ketinggalan, diedit, atau conflict
php artisan panel:assets --update # tulis hanya file yang belum pernah Anda modifikasi
php artisan panel:assets --force # termasuk overwrite file yang diedit application
npm run build2
3
4
| Status | Kondisi di disk | Kondisi di package | --update |
|---|---|---|---|
new | belum ada, atau belum pernah dicatat | ada | ditulis |
out of date | belum diedit application | package berubah | ditulis |
yours | application berubah | package tidak berubah | dibiarkan |
CONFLICT | application berubah | package juga berubah | tidak ditulis |
deleted by you | file tidak ada, pernah dipublish | masih ada | dibiarkan |
no longer shipped | pernah dicatat | package sudah tidak mengirimnya | dibiarkan |
current | sama | sama | — |
Command selalu exit 0. Conflict bukan kegagalan command; justru command berhasil menemukan kondisi yang membutuhkan keputusan manusia. Menggagalkan deploy hanya karena application sengaja mengedit file published akan menjadi behavior yang salah.
Commit .panel-assets.json. File tersebut adalah catatan source asset yang pernah dipublish, analog dengan composer.lock untuk dependency yang ter-install.
Vite config milik package bukan Vite config application
vite.config.ts di repository PandaBear membuild frontend/entry.ts ke build/frontend dalam mode unminified. Output itu tidak dikirim ke consumer. Tujuannya hanya sebagai compile check:
Apakah seluruh source frontend package dapat resolve dan compile bersama-sama?
Application tetap memiliki Vite build sendiri.
Entry point tambahan milik Panel
Panel dapat menambahkan Vite entrypoint yang hanya digunakan pada Page Panel tersebut:
use PandaPanel\Core\Panel;
Panel::make('admin')
->assets('resources/css/admin.css', 'resources/js/admin.ts');2
3
4
| Method | Signature |
|---|---|
assets | assets(string ...$entrypoints): self |
getAssets | getAssets(): list<string> |
Yang dideklarasikan adalah source path, bukan built file. Path tersebut juga harus terdaftar pada input array di Vite config application. Jika tidak, Vite manifest tidak memiliki asset tersebut dan Page akan gagal dengan manifest error. Failure tersebut memang benar karena Panel mendeklarasikan asset yang tidak pernah dibuild.
Daftar asset bersifat akumulatif sehingga plugin dapat menambahkan stylesheet tanpa mengganti asset milik Panel.
SSR
PandaBear tidak menyediakan SSR entrypoint dan component-nya tidak didesain terhadap satu entry SSR khusus. resources/js/ssr.ts hanya diperiksa installer untuk kasus layout override. Application yang menggunakan inertia:start-ssr harus menangani SSR Panel Page sendiri.
Hal yang perlu diperhatikan
- Deploy tanpa
npm run buildmenjalankan bundle lama terhadap metadata server baru. Gejala umum adalah renderer tidak mengenali type/shape baru yang dikirim PHP. - Gunakan
npm ci, bukannpm install, pada deploy.npm cimengikutipackage-lock.jsonsecara deterministik. - Aliased glob dapat gagal pada dev server. Registry bawaan menggunakan relative glob agar bekerja konsisten; menyalin pola lalu menggantinya menjadi
@/dapat bekerja saat production build tetapi fallback di development. vendor:publishtanpa--forcemelewati file yang sudah ada. Pada starter kit ini biasanya benar karena component milik application harus menang. Untuk update terkontrol gunakanpanel:assets.- Component di
pages/Panels/yang tidak dicommit tidak ikut build release. Glob membaca working tree saat build. - Tailwind membutuhkan literal class yang terlihat saat scanning. Jangan membangun class penting dengan interpolasi runtime jika Tailwind tidak dapat menemukannya saat build.