Error build Vite
Frontend panel dipublish ke aplikasi Anda dan dibangun oleh Vite milik aplikasi bersama entrypoint lainnya. Tidak ada compiled asset yang dikirim dari vendor/chocoalano/panel, sehingga setiap layar panel bergantung pada build yang berhasil me-resolve ratusan file Vue dan TypeScript terhadap module yang sebagian sengaja tidak dibawa package. Ketika gagal, masalah biasanya muncul saat npm run build sebagai error module specifier—error yang benar tetapi sering tidak langsung menunjukkan akar masalah. Gunakan halaman ini ketika build gagal, build berhasil tetapi panel tetap salah, atau halaman gagal dengan manifest error.
Tanyakan terlebih dahulu apa yang hilang kepada package
Sebelum membaca Rollup stack trace, jalankan pemeriksaan yang menjelaskan penyebab dalam kalimat yang lebih mudah dipahami:
php artisan panel:install --no-panel --no-user --no-interactionCommand ini tidak mempublish ulang file yang sudah tersedia, lalu menampilkan numbered list mengenai hal-hal yang tidak dapat dilakukan package untuk aplikasi Anda: npm dependency yang hilang beserta command npm install, host module yang belum tersedia, vite.config yang tidak ada, root view atau middleware Inertia yang belum tersedia, serta resources/js/app.ts yang menimpa layout yang sudah dideklarasikan setiap panel page. Setelah itu:
npm ci
php artisan wayfinder:generate
npm run build2
3
Itulah seluruh proses build untuk aplikasi yang source panel-nya tidak berubah.
Pemeriksaan satu per satu
PandaPanel\Support\Installer\FrontendRequirements adalah class yang dipakai installer dan seluruh method-nya public, sehingga dapat dipanggil dari tinker, test, maupun deployment script.
| Method | Signature | Menjawab |
|---|---|---|
npmPackages | static npmPackages(): list<string> | seluruh dependency yang diimport komponen dalam bentuk name@range |
missingNpmPackages | static missingNpmPackages(): list<string> | subset yang belum dideklarasikan package.json aplikasi |
missingHostModules | static missingHostModules(): list<string> | module pada host seam yang tidak ditemukan di disk, sebagai specifier @/… |
hasVite | static hasVite(): bool | apakah vite.config.ts atau vite.config.js tersedia |
missingInertia | static missingInertia(): list<string> | root view dan middleware Inertia yang hilang, dalam bentuk penjelasan |
layoutOverrides | static layoutOverrides(): list<array{file: string, line: int, code: string}> | entry file yang menimpa layout yang sudah dideklarasikan page |
use PandaPanel\Support\Installer\FrontendRequirements;
FrontendRequirements::missingNpmPackages();
// ['@lucide/vue@^1.31.0', 'reka-ui@^2.0.0', …]
FrontendRequirements::missingHostModules();
// ['@/routes/two-factor', '@/components/UserMenuContent', …]
FrontendRequirements::hasVite(); // false — nothing will build
FrontendRequirements::missingInertia(); // ['Inertia\'s middleware (php artisan inertia:middleware)']
FrontendRequirements::layoutOverrides(); // [['file' => 'resources/js/app.ts', 'line' => 4, 'code' => '…']]2
3
4
5
6
7
8
9
10
11
npmPackages() dibaca langsung dari package.json milik package, bukan ditulis ulang di PHP, sehingga list tersebut tidak mudah stale ketika komponen mulai mengimport dependency baru. missingNpmPackages() membaca package.json aplikasi, bukan node_modules: yang penting adalah project mendeklarasikan dependency tersebut, karena transitive copy yang tersedia sekarang dapat hilang ketika dependency lain diupgrade.
Failure 1: build tidak dapat me-resolve @/…
Komponen hasil publish mengimport module yang sengaja tidak dibawa package, dan ada dua kelompok. @/routes/* serta @/actions/* digenerate Wayfinder dari route table aplikasi—membawa copy dari package justru berarti mengirim snapshot route milik aplikasi lain. Sisanya adalah component yang biasanya tersedia pada Laravel Vue starter kit dan menjadi tempat aplikasi memasang account link serta flow two-factor sendiri. List lengkapnya adalah FrontendRequirements::HOST_MODULES:
@/routes @/components/Heading
@/routes/login @/components/UserInfo
@/routes/register @/components/UserMenuContent
@/routes/password @/components/PasskeyItem
@/routes/two-factor @/components/PasskeyRegister
@/routes/verification @/components/TwoFactorRecoveryCodes
@/types @/components/TwoFactorSetupModal
@/types/ui @/composables/useTwoFactorAuth
@/actions/App/Http/Controllers/Settings/ProfileController
@/actions/App/Http/Controllers/Settings/SecurityController
@/actions/Laravel/Passkeys/Http/Controllers/PasskeyRegistrationController2
3
4
5
6
7
8
9
10
11
Perhatikan bentuk daftar yang hilang, bukan jumlahnya. Jika seluruh @/routes/* dan @/actions/* hilang, Wayfinder belum dijalankan:
php artisan wayfinder:generateJalankan sebelum build dan selalu setelah route berubah—resource baru mengubah route table, dan generated module yang stale menghasilkan TypeScript error pada build time alih-alih broken link saat runtime, yang merupakan failure mode lebih baik. Jika hanya beberapa component yang hilang, kemungkinan aplikasi bukan starter kit dan file tersebut harus disediakan oleh aplikasi; working stand-in untuk masing-masing tersedia di frontend/host/ pada repository ini.
Module dicari sebagai .ts, .vue, .d.ts, /index.ts, /index.vue, atau /index.d.ts. Bare directory tidak dihitung—pernah ada bug yang membuat @/types dianggap tersedia hanya karena folder yang dipublish package sudah ada, walaupun module yang sebenarnya diimport tidak ada di dalamnya.
Failure 2: npm dependency belum tersedia
Komponen mengimport seluruh package dari block dependencies repository ini. Range yang digunakan:
| Package | Range | Package | Range |
|---|---|---|---|
@inertiajs/vue3 | ^3.0.0 | reka-ui | ^2.0.0 |
@internationalized/date | ^3.12.0 | tailwind-merge | ^3.0.0 |
@laravel/echo-vue | ^2.4.0 | tailwindcss | ^4.1.0 |
@laravel/passkeys | ^0.4.0 | tw-animate-css | ^1.2.0 |
@lucide/vue | ^1.31.0 | vue | ^3.5.0 |
@tailwindcss/vite | ^4.1.0 | vue-input-otp | ^0.4.0 |
@tanstack/vue-table | ^9.0.0 | vue-sonner | ^2.0.0 |
@vueuse/core | ^14.0.0 | class-variance-authority | ^0.7.0 |
clsx | ^2.1.0 |
Node harus >=20.19. Tailwind 3 tidak dapat mengompilasi resources/css/panda-panel.css: stylesheet tersebut ditulis untuk Tailwind 4 dan menggunakan @import 'tailwindcss', @theme inline, @custom-variant, serta @source, yang tidak dibaca Tailwind 3—lihat masalah Tailwind 4.
Failure 3: Vite manifest error saat request
Ada dua exception berbeda dengan dua penyebab berbeda.
| Exception | Message | Penyebab |
|---|---|---|
Illuminate\Foundation\ViteManifestNotFoundException | Vite manifest not found at: …/public/build/manifest.json | build belum dijalankan pada release ini, atau dev server tidak berjalan |
Illuminate\Foundation\ViteException | Unable to locate file in Vite manifest: {file}. | path diberikan ke @vite tetapi build tidak pernah menghasilkan file tersebut |
Exception kedua dapat disebabkan konfigurasi panel dan biasanya memiliki dua bentuk.
Entrypoint panel tidak ada di vite.config.ts. Panel::assets() menambahkan Vite entrypoint yang hanya dimuat pada halaman panel tersebut:
use PandaPanel\Core\Panel;
Panel::make('admin')->assets('resources/css/panels/admin.css');2
3
| Method | Signature |
|---|---|
assets | assets(string ...$entrypoints): self |
getAssets | getAssets(): list<string> |
Entrypoint adalah path, bukan built file, sehingga path yang sama harus tercantum pada array input milik vite.config.ts. Dibutuhkan dua konfigurasi secara sengaja: asset yang dideklarasikan tetapi tidak dibangun adalah kesalahan dan manifest error adalah failure mode yang tepat, bukan sesuatu yang harus disembunyikan. List entrypoint bersifat akumulatif, sehingga pemanggilan assets() berikutnya—termasuk dari plugin—menambah list, bukan menggantikannya. List tersebut juga tidak dikirim ke frontend; browser menerima tag hasil build, bukan metadata entrypoint.
Page component tidak pernah dilihat build. Root view Laravel Vue starter kit memberikan current page component ke @vite:
@vite([
'resources/css/app.css',
'resources/js/app.ts',
"resources/js/pages/{$page['component']}.vue",
...(panel()?->getAssets() ?? []),
])2
3
4
5
6
Akibatnya panel page dengan $component yang menunjuk file tidak tersedia menghasilkan manifest error, bukan blank screen. Penyebab umum: scaffold make:panel-page --component tetapi file Vue kemudian diganti nama, atau custom page PHP menggunakan protected static string $component = 'Panels/Admin/Pages/Settings'; tanpa file resources/js/pages/Panels/Admin/Pages/Settings.vue. Page yang tidak mendeklarasikan component menggunakan generic renderer (panel/Page) dan tidak membutuhkan file Vue khusus.
Failure 4: build berhasil tetapi tampilan panel salah
Empat kondisi berikut dapat lolos compile tetapi tetap bukan hasil yang Anda inginkan.
Semua layar panel dirender di dalam shell aplikasi. Panel page sudah mendeklarasikan layout sendiri—defineOptions({ layout: PanelLayout })—sehingga tidak perlu wiring tambahan di app.ts. Kesalahan yang masih mungkin terjadi adalah aplikasi menimpa pilihan tersebut:
page.default.layout = AppLayout; // replaces the panel shell
page.default.layout ??= AppLayout; // correct2
Assignment tanpa fallback membuat seluruh panel tampil di sidebar aplikasi, sementara navigation panel hilang, tetap dengan HTTP 200 dan tanpa log. layoutOverrides() membaca resources/js/app.ts, app.js, ssr.ts, dan ssr.js, lalu melaporkan file, line, dan code. Operator ||=, ??=, maupun assignment yang RHS-nya sudah memiliki fallback (page.default.layout || AppLayout) diterima.
Custom widget, field, column, atau shell component menampilkan fallback. Seluruh registry adalah import.meta.glob terhadap tree milik aplikasi—sebuah build-time allowlist yang sekaligus menjadi security property dan alasan build wajib dilakukan:
const modules = import.meta.glob<{ default: Component }>(
'../../pages/Panels/**/Widgets/*.vue',
);2
3
| Registry | Glob |
|---|---|
panel/widgets/registry.ts | pages/Panels/**/Widgets/*.vue |
panel/forms/registry.ts | pages/Panels/**/{Fields,Schemas,Entries,Modals}/*.vue |
panel/tables/registry.ts | custom columns |
panel/tables/registryEmptyStates.ts | custom empty states |
panel/hooks/registry.ts | render-hook components |
panel/shell/registry.ts | shell replacements |
Nama yang tidak resolve menghasilkan satu warning di development dan menyebut directory tempat component harus berada: [panel] The widget component [x] is not in the build-time registry, so a fallback is drawn instead. Tiga penyebab terlihat identik di layar dan semuanya dijelaskan warning tersebut: typo, file berada di luar glob directory, atau build belum dijalankan ulang.
Icon tidak tampil sama sekali. resources/js/panel/icons/registry.ts digenerate oleh php artisan panel:icons dan merupakan closed map. Nama yang tidak dikenal resolve menjadi null dan tidak ada icon yang digambar. Lucide menyediakan 1768 icon, tetapi bundle hanya perlu membawa icon yang benar-benar dideklarasikan panel. Di development registry memperingatkan satu kali per nama dan menyebut command perbaikannya; di production icon hanya tidak tampil karena ini masalah build, bukan runtime.
php artisan panel:icons # rewrite the registry from the icons the PHP declares
php artisan panel:icons --check # fail instead of writing, for CI
npm run build2
3
Generator memindai source untuk ->icon('…'), $navigationIcon = '…', icon: '…', 'icon' => '…', Icon::make('…'), serta body method yang secara literal bernama icon(). Nama yang tidak dimiliki Lucide dilaporkan sebagai Not a Lucide icon: … dan command keluar non-zero. Perhatikan stub make:panel-page mendeklarasikan 'file-text', yang belum berada di shipped registry; page hasil scaffold tidak memiliki navigation icon sampai panel:icons dan build dijalankan.
Bundle lebih lama daripada metadata server. Deployment yang melewati npm run build melayani frontend lama terhadap prop server baru, dan kegagalannya terlihat sebagai renderer yang belum mengenali shape baru. Lima perubahan berikut membutuhkan rebuild:
| Perubahan | Alasan |
|---|---|
php artisan panel:icons | registry berupa TypeScript yang dikompilasi ke bundle |
| custom widget / field / column / page component baru | registry menggunakan build-time glob |
| perubahan route | module Wayfinder dikompilasi ke bundle |
php artisan panel:assets --update | command menulis component source dan menampilkan Wrote N file(s). Run \npm run build`.` |
environment variable VITE_* | value diinline pada build time sehingga perubahan membutuhkan rebuild, bukan restart |
Failure 5: bekerja saat production build tetapi gagal di dev server
import.meta.glob dengan aliased pattern dapat resolve menjadi kosong pada npm run dev—Object.assign({})—sementara production build me-resolve dengan benar. Karena itu setiap registry package menggunakan relative pattern. Custom registry yang menyalin pola tersebut tetapi menggantinya dengan @/ dapat menampilkan fallback saat development dan justru bekerja setelah build, sebuah failure mode yang membingungkan.
Asimetri yang sama berlaku pada key: format glob key Vite mengikuti pattern yang digunakan dan dapat berbeda antara dev server serta production build. Registry menurunkan nama dari real path (path.indexOf('/pages/')) alih-alih menyusun key sendiri. Registry yang merekonstruksi key secara manual dapat gagal secara diam-diam dan membuat component tidak pernah resolve.
Perilaku development-only yang memang diharapkan dan semuanya dijaga import.meta.env.DEV: warning icon, enam warning registry, dan warning Echo ketika panel mengaktifkan broadcasting tanpa broadcaster yang dikonfigurasi.
Failure 6: vue-tsc gagal di file yang tidak ditulis aplikasi
Panel membaca shared Inertia props melalui panel/types/shared.ts, yang tidak membutuhkan module augmentation. Package sengaja tidak membawa declare module '@inertiajs/core' untuk name, auth, atau sidebarOpen; ketiganya milik aplikasi. Augmentation package yang tidak ter-load pernah membuat page.props menjadi {} dan menghasilkan error di published file yang tidak pernah disentuh developer aplikasi. FrontendContractTest memastikan tidak ada file di resources/js/panel yang membaca usePage().props.<shared key> secara langsung. Ikuti aturan yang sama pada custom component di pages/Panels/.
Failure 7: memindahkan frontend path
Dua destination dapat dikonfigurasi:
// config/panda-panel.php
'frontend' => [
'panel_path' => 'js/panel',
'pages_path' => 'js/pages/Panels',
],2
3
4
5
Keduanya relatif terhadap resources/. PandaPanel\Support\FrontendPaths::panel() dan ::pages() membacanya, sementara PublishedAssets::map() melakukan publish ke lokasi tersebut. Yang tidak dapat dipindahkan oleh config adalah glob: glob merupakan literal string di TypeScript hasil publish, ditulis relatif terhadap resources/js/panel/{registry} dan menunjuk ke ../../pages/Panels/**. Mengubah panel_path mengubah kedalaman directory, sedangkan mengubah pages_path mengubah target. Pada kedua kasus, glob di file hasil publish juga harus diedit agar sesuai; jika tidak, seluruh custom component resolve menjadi kosong.
pages_path memiliki constraint tambahan yang berasal dari luar package ini: @inertiajs/vite hanya melakukan glob terhadap resources/js/pages/**, sehingga page component di luar tree tersebut tidak dapat di-resolve Inertia berapa pun konfigurasi build-nya.
Menjaga published component tetap terbaru
Build hanya mengompilasi apa yang ada di disk, sementara isi disk adalah copy dari saat asset terakhir dipublish:
php artisan panel:assets # report only
php artisan panel:assets --update # write the files that are safe to write
php artisan panel:assets --force # also overwrite files this application edited
npm run build2
3
4
| Dilaporkan sebagai | Di disk | Di package | --update |
|---|---|---|---|
new | tidak ada | ada | ditulis |
out of date | tidak berubah | berubah | ditulis |
yours | berubah | tidak berubah | dibiarkan |
CONFLICT | berubah | berubah | tidak pernah ditulis |
deleted by you | tidak ada | ada, sebelumnya pernah dipublish | dibiarkan |
no longer shipped | ada | tidak ada | dibiarkan |
current | tidak berubah | tidak berubah | — |
Perbandingan tiga arah berasal dari .panel-assets.json, yang ditulis pada AssetManifest::path()—base_path('.panel-assets.json'). Commit file tersebut: ia merekam versi frontend yang pernah dipublish aplikasi, sama seperti composer.lock merekam versi dependency yang terpasang. Tanpa manifest, upgrade tidak dapat membedakan edit milik aplikasi dari copy lama yang sudah stale. Hash dihitung setelah line ending dinormalisasi, sehingga checkout CRLF tidak membuat seluruh file dianggap conflict. Command selalu exit 0; conflict berarti perlu diperiksa manusia, bukan alasan otomatis untuk menggagalkan deployment.
vite.config.ts milik package bukan milik aplikasi
Repository ini membangun frontend/entry.ts—generated glob atas seluruh tree—ke build/frontend tanpa minify, dan output tersebut tidak digunakan oleh aplikasi. Tujuannya hanya sebagai compile check untuk menjawab pertanyaan yang tidak dijawab type-checking: apakah seluruh file benar-benar dapat di-resolve dan dikompilasi bersama? Plugin hostSeam() mengimplementasikan resolusi dua tahap @/x yang sama seperti paths pada tsconfig.json, sehingga bundler dan type-checker tidak berbeda pendapat. Konfigurasi tersebut tidak berlaku untuk aplikasi, karena aplikasi memiliki build Vite sendiri.
Hal yang perlu diperhatikan
- Gunakan
npm ci, bukannpm install, saat deployment.cimemasang persis dependency yang ditentukanpackage-lock.json. vendor:publishtanpa--forcemelewati file yang sudah ada, sehingga pada aplikasi starter kit component milik aplikasi tetap menang. Biasanya itu perilaku yang benar, danpanel:assetstersedia untuk kasus ketika Anda memang perlu melakukan upgrade source hasil publish.- Component di
pages/Panels/yang tidak pernah dicommit tidak ikut build. Glob membaca working tree pada build time, sehingga kondisi seperti ini dapat bekerja lokal tetapi gagal di CI. - Tailwind memindai source dan tidak dapat melihat class yang dibangun melalui interpolasi. Column span, badge color, dan grid column seluruhnya dipetakan melalui literal record di component panel. Class dari
cssHooks()adalah string di PHP provider dan secara default tidak berada di source yang discan Tailwind—tambahkan provider ke content glob atau gunakan class yang muncul di source lain. - Tidak ada SSR entry. Panel tidak mengirim SSR entry dan component tidak ditulis khusus untuk SSR;
ssr.tshanya dibaca untuk pemeriksaan layout. php artisan panel:cachebukan frontend cache. Command tersebut meng-cache nama class, bukan component. Resource yang hilang setelah build lebih mungkin disebabkan panel manifest stale—di development boot check menulis[panel] The cached panel manifest is out of date, dan solusinyaphp artisan panel:clear.
Lihat juga
- Frontend build, production checklist
- Frontend requirements, compatibility matrix
- Struktur published asset, memperbarui asset
- Host module, Wayfinder
- Component registry, frontend assets
panel:install,panel:assets,panel:icons- Masalah Tailwind 4, konflik asset, host module yang hilang, icon yang hilang
- Root view Inertia