Konflik aset
php artisan panel:assets melaporkan file frontend yang telah dipublikasikan sebagai CONFLICT ketika file tersebut berubah baik di aplikasi Anda maupun di package. Tidak ada file yang ditulis ulang untuk kondisi ini, dan halaman ini menjelaskan cara menyelesaikannya. Gunakan panduan ini setelah menjalankan composer update chocoalano/panel, atau ketika sebuah upgrade tampaknya tidak membawa komponen yang Anda harapkan.
Mulai dari sini
php artisan panel:assets new ................................................................ 3
out of date ....................................................... 12
yours .............................................................. 2
CONFLICT ........................................................... 1
current .......................................................... 291
WARN 1 file(s) changed both here and upstream. Neither copy is safe to throw away, so
nothing was written. Diff each against the package copy under vendor/chocoalano/panel,
then re-run with --force once you have merged:
resources/js/panel/tables/DataTable.vue2
3
4
5
6
7
8
9
10
11
Selesaikan konfliknya:
diff resources/js/panel/tables/DataTable.vue \
vendor/chocoalano/panel/resources/js/panel/tables/DataTable.vue
# merge by hand into your copy, then:
php artisan panel:assets --force
npm run build2
3
4
5
6
Mengapa konflik bisa terjadi
Frontend panel dipublikasikan ke dalam aplikasi Anda, bukan diimpor langsung dari package. Ini memang disengaja — setiap component registry adalah allowlist import.meta.glob pada waktu build yang membaca tree milik aplikasi sendiri, sehingga komponen yang tidak pernah dilihat build tidak dapat di-resolve — tetapi pendekatan ini membawa konsekuensi yang sama seperti desain published asset lainnya: setelah sebuah file menjadi milik aplikasi Anda, update package tidak dapat memperbaruinya begitu saja.
vendor:publish tidak dapat menyelesaikan masalah ini karena hanya memiliki dua perilaku, dan keduanya tidak tepat untuk proses upgrade. Tanpa --force, semua file yang sudah ada akan dilewati sehingga tidak ada yang diperbarui. Dengan --force, semuanya akan ditimpa, termasuk file yang memang sengaja Anda ubah. Keduanya tidak dapat membedakan dua kondisi tersebut: "berbeda dari salinan package" sama-sama benar untuk file yang sudah tertinggal versinya maupun file yang sengaja diedit.
.panel-assets.json menyediakan nilai ketiga yang hilang — hash setiap file pada saat file tersebut dipublikasikan — sehingga perbandingan dua arah yang ambigu berubah menjadi perbandingan tiga arah yang tegas, menggunakan prinsip yang sama seperti git merge-base.
Tujuh status aset
PandaPanel\Support\Installer\AssetManifest mendefinisikan satu constant untuk setiap hasil. Label yang dicetak command ditunjukkan pada kolom ketiga.
| Constant | Value | Dicetak sebagai | Di disk | Di package | Ditulis oleh --update |
|---|---|---|---|---|---|
AssetManifest::NEW | new | new | tidak ada, atau belum pernah dipublikasikan | ada | ya |
AssetManifest::CURRENT | current | current | = manifest | = manifest | tidak |
AssetManifest::STALE | stale | out of date | = manifest | ≠ manifest | ya |
AssetManifest::MODIFIED | modified | yours | ≠ manifest | = manifest | hanya dengan --force |
AssetManifest::CONFLICT | conflict | CONFLICT | ≠ manifest | ≠ manifest | hanya dengan --force |
AssetManifest::DELETED | deleted | deleted by you | tidak ada | ada | tidak pernah |
AssetManifest::REMOVED_UPSTREAM | removed-upstream | no longer shipped | apa pun | tidak ada | tidak pernah |
Dua status dapat ditulis otomatis, dan pada kedua kondisi itu aplikasi Anda dapat dipastikan tidak memiliki perubahan khusus terhadap file tersebut: satu adalah file yang belum pernah dimiliki aplikasi, dan satu lagi adalah file yang belum pernah disentuh aplikasi.
Command
php artisan panel:assets # report only
php artisan panel:assets --update # write the new and out-of-date files
php artisan panel:assets --force # also overwrite yours and conflicted ones2
3
| Opsi | Efek |
|---|---|
| (tanpa opsi) | Menampilkan ringkasan, mencantumkan konflik berdasarkan path, dan tidak menulis apa pun |
--update | Menulis file berstatus new dan stale, lalu menulis ulang .panel-assets.json berdasarkan kondisi disk saat ini |
--force | Melakukan seluruh pekerjaan --update, ditambah menimpa file modified dan conflict |
--force hanya memperluas cakupan ke file yang Anda edit dan file yang konflik. File yang sengaja Anda hapus tetap terhapus, dan file yang sudah tidak dikirim package tidak akan dibuat kembali.
Command tetap keluar dengan kode 0 walaupun ada konflik. Konflik bukan berarti command gagal — command justru berjalan dengan benar dan menemukan sesuatu yang memang harus diperiksa manusia — dan menggagalkan deployment hanya karena ada file yang sengaja diedit juga bukan perilaku yang tepat.
Membaca manifest secara langsung
Semua yang dilakukan command tersedia melalui AssetManifest, sehingga konflik dapat diperiksa dari tinker atau diverifikasi dalam test.
use PandaPanel\Support\Installer\AssetManifest;
AssetManifest::path(); // '/var/www/app/.panel-assets.json'
AssetManifest::exists(); // bool2
3
4
| Method | Signature | Mengembalikan |
|---|---|---|
path | static path(): string | base_path('.panel-assets.json') |
exists | static exists(): bool | apakah file tersebut ada |
read | static read(): array | array<string, string> — path relatif aplikasi => hash |
write | static write(array $existing = []): void | merekam kondisi file yang sekarang ada di disk |
compare | static compare(?array $files = null): array | array<string, array{status: string, destination: string, source: string|null}> |
use PandaPanel\Support\Installer\AssetManifest;
$conflicts = array_keys(array_filter(
AssetManifest::compare(),
static fn (array $entry): bool => $entry['status'] === AssetManifest::CONFLICT,
));
// ['resources/js/panel/tables/DataTable.vue']2
3
4
5
6
7
8
compare() mengembalikan seluruh file yang dikirim package dengan key berupa destination relatif terhadap aplikasi, ditambah file yang tercatat di manifest tetapi sudah tidak dikirim package. Argumen opsional $files adalah map destination => source dan disediakan agar keempat state dapat diuji terhadap fixture sementara: repository ini sendiri merupakan aplikasi test-nya, sehingga jika memakai map asli, kondisi "di disk" dan "di package" tidak mungkin berbeda.
use Illuminate\Support\Facades\File;
use PandaPanel\Support\Installer\AssetManifest;
File::put('/tmp/pkg/Component.vue', 'version two');
File::put('/tmp/app/Component.vue', 'version one, with our change');
AssetManifest::compare(['/tmp/app/Component.vue' => '/tmp/pkg/Component.vue']);
// ['/tmp/app/Component.vue' => ['status' => 'conflict', …]]2
3
4
5
6
7
8
write() melakukan hash terhadap salinan milik aplikasi, bukan salinan package. Perbedaan ini adalah inti desainnya: file yang baru dipublikasikan lalu langsung diedit harus direkam sebagai file yang sudah diedit; jika hash package yang direkam, manifest akan mengklaim aplikasi memiliki salinan bersih yang sebenarnya tidak pernah dimiliki. Argumen $existing membawa hash lama untuk file yang tidak sedang ditulis pada proses ini.
Apa yang dianggap sebagai published file
Publish map dan laporan diff membaca daftar yang sama, sehingga keduanya tidak dapat keluar sinkron.
use PandaPanel\Support\Installer\PublishedAssets;
PublishedAssets::map();
// absolute package source => absolute application destination, per directory
PublishedAssets::files();
// absolute destination => absolute source, per file
PublishedAssets::relative('/var/www/app/resources/js/panel/tables/DataTable.vue');
// 'resources/js/panel/tables/DataTable.vue'2
3
4
5
6
7
8
9
10
| Destination | Source di package |
|---|---|
resources/js/panel (FrontendPaths::panel()) | 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 |
map() dibangun ulang pada setiap pemanggilan, bukan disimpan di constant, karena dua destination dapat dikonfigurasi melalui panda-panel.frontend.*. Membaca konfigurasi pada saat class didefinisikan akan membekukan nilai yang kebetulan aktif selama package discovery.
"No .panel-assets.json"
WARN No .panel-assets.json, so there is no record of what this application published.
Everything already identical to the package reads as current; anything else reads as new.
Run --update to write one.2
3
Kondisi ini terjadi pada aplikasi yang diinstal sebelum manifest tersedia, atau aplikasi yang tidak pernah melakukan commit terhadap file tersebut. Buat manifest lalu commit:
php artisan panel:assets --update
git add .panel-assets.json
git commit -m "Record the published panel frontend"2
3
Tanpa hash yang tercatat, compare() kembali ke perbandingan dua arah: file yang identik dengan package dianggap current, sedangkan yang lain dianggap new. Ini aman tetapi kurang presisi — edit milik Anda tidak dapat dibedakan dari salinan lama sampai manifest tersedia.
Menggabungkan konflik
Tidak ada resolusi otomatis dan memang tidak akan ada. Kedua salinan sama-sama dapat berisi pekerjaan yang perlu dipertahankan.
- Lakukan diff. Salinan package berada di
vendor/chocoalano/panel/dengan relative path yang sama. - Pahami tujuan edit Anda. Konflik biasanya masuk salah satu dari tiga kategori: perubahan styling yang perlu diterapkan ulang di atas file baru, bug fix yang sekarang sudah diperbaiki package, atau perubahan behavior yang seharusnya dipindahkan menjadi class
cssHooks()atau replacement component daripada mengedit file langsung. - Gabungkan perubahan ke salinan aplikasi, dengan mempertahankan perubahan Anda dan perubahan upstream.
- Jalankan
php artisan panel:assets --force— tetapi hanya setelah proses merge selesai.--forcemenimpa file aplikasi dengan milik package, jadi gunakan ketika merge sudah selesai dan Anda memang ingin salinan package menjadi baseline baru; jika tidak, biarkan file tetap seperti sekarang. - Jalankan
npm run build. Registry dievaluasi pada waktu build.
Three-way merge dengan git dapat digunakan jika file dicommit pada setiap proses publish:
git log --oneline -- resources/js/panel/tables/DataTable.vue
git diff HEAD~1 -- resources/js/panel/tables/DataTable.vue2
Catatan
- Hash menggunakan
xxh128atas content setelah\r\ndinormalisasi menjadi\n. Tanpa normalisasi ini, checkout Windows atau editor yang menulis CRLF akan membuat semua file terlihat telah diedit — dan laporan yang menyebut semuanya konflik adalah laporan yang akhirnya tidak akan dibaca siapa pun. - Commit
.panel-assets.json. File ini adalah catatan versi frontend yang pernah dipublikasikan aplikasi, mirip dengan caracomposer.lockmencatat dependency yang terinstal. Jika berada dibootstrap/cache, file akan diregenerasi dan menjadi tidak berguna; jika berada distorage, file biasanya terabaikan oleh git dan hilang pada deployment pertama. - Manifest yang tidak dapat diparse diperlakukan sebagai tidak ada, bukan sebagai fatal error. Dampak terburuknya adalah semua file terbaca sebagai
new, sama seperti aplikasi yang belum pernah melakukan publish. panel:assetsmenulis ulang manifest berdasarkan kondisi disk setelah penulisan, bukan berdasarkan apa yang direncanakan untuk ditulis. Jadi file yang gagal disalin tidak akan tercatat sebagaicurrent.--updatetidak menjalankannpm run build. Command akan mengingatkan ketika menulis sesuatu; source component yang sudah dipublikasikan belum masuk ke bundle sampai build dijalankan.- Baris
deleted by youtetap terhapus. Jika komponen memang sengaja Anda hapus, tidak ada command yang mengembalikannya — termasuk--force. no longer shippedhanya dilaporkan, tidak pernah dihapus. File yang tidak lagi dikirim package mungkin sudah diadopsi aplikasi dan menjadi bagian dari codebase Anda.- Aset plugin menggunakan command berbeda.
panel:publishmenangani aset plugin dan tidak pernah menimpa file yang sudah ada tanpa--force.