Publish Tags
PandaBear menyediakan empat vendor:publish tag utama dan satu umbrella tag.
Melalui tag tersebut package dapat menyalin ke application:
- config;
- Vue/frontend assets;
- migrations;
- generator stubs.
Gunakan publish tag ketika hanya membutuhkan bagian tertentu secara manual.
php artisan panel:install menjalankan publish yang sama dalam urutan yang benar dan mengerjakan langkah instalasi lainnya.
Contoh Minimal
composer require chocoalano/panel
php artisan vendor:publish --tag=panda-panel-config
php artisan vendor:publish --tag=panda-panel-assets
npm install && npm run build2
3
4
Tag pertama menulis:
config/panda-panel.phpPanel harus terdaftar di config tersebut sebelum URL-nya tersedia.
Tag kedua menulis Vue components ke resources/js, sehingga build-time component registry dapat melihat component tersebut.
Itulah minimum publish yang dibutuhkan agar sebuah Panel dapat boot.
Daftar Tag
Service provider:
// PandaPanel\PandaPanelServiceProvider::registerPublishing()
$this->publishes([
$this->packagePath('config/panda-panel.php') => config_path('panda-panel.php'),
], ['panda-panel', 'panda-panel-config']);
$this->publishes([
$this->packagePath('database/migrations') => database_path('migrations'),
], ['panda-panel', 'panda-panel-migrations']);
$this->publishes([
$this->packagePath('stubs/panel') => base_path('stubs/panel'),
], 'panda-panel-stubs');
$this->publishes(PublishedAssets::map(), ['panda-panel', 'panda-panel-assets']);2
3
4
5
6
7
8
9
10
11
12
13
14
15
| Tag | Yang Dipublish | Destination | Termasuk panda-panel |
|---|---|---|---|
panda-panel-config | config/panda-panel.php | config/panda-panel.php | ya |
panda-panel-assets | tujuh frontend source group | resources/js/**, resources/css/panda-panel.css | ya |
panda-panel-migrations | package migrations | database/migrations | ya |
panda-panel-stubs | generator stubs | stubs/panel | tidak |
panda-panel | config + migrations + assets | destination masing-masing | umbrella |
registerPublishing() hanya berjalan ketika:
$this->app->runningInConsole()karena vendor:publish memang merupakan console concern.
Konsekuensinya, test yang hanya boot application melalui HTTP lalu memeriksa ServiceProvider::publishableGroups() tidak melihat registration publish tersebut.
panda-panel-config
php artisan vendor:publish --tag=panda-panel-configMenulis satu file:
config/panda-panel.phpService provider sudah memanggil mergeConfigFrom() saat register, sehingga default value tersedia bahkan sebelum config dipublish.
Alasan utama mempublish config adalah agar application dapat memiliki dan mengedit setting, terutama daftar Panel:
// config/panda-panel.php
'panels' => [
App\Panels\Admin\AdminPanelProvider::class,
],2
3
4
5
Panel didaftarkan, bukan didiscover.
Provider yang tidak ada di list tidak memiliki route.
panel:install menambahkan provider secara otomatis.
make:panel hanya mencetak line yang perlu ditambahkan.
Semua key dijelaskan di Configuration Reference.
panda-panel-assets
php artisan vendor:publish --tag=panda-panel-assetsPublish map berasal dari:
PandaPanel\Support\Installer\PublishedAssets::map()Source of truth yang sama dipakai oleh:
- service provider
publishes(); panel:assets.
Dengan demikian directory yang ditambahkan package di release baru tidak dapat dipublish tanpa ikut diperiksa oleh asset upgrade command.
| Package Source | Application Destination |
|---|---|
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 |
API:
use PandaPanel\Support\Installer\PublishedAssets;
PublishedAssets::map();
// array<string, string>
// absolute source => absolute destination
PublishedAssets::files();
// array<string, string>
// destination => source, satu entry per file
PublishedAssets::relative('/app/resources/js/panel/palette.ts');
// 'resources/js/panel/palette.ts'2
3
4
5
6
7
8
9
10
11
12
Configurable Frontend Path
Destination resources/js/panel dapat diubah:
// config/panda-panel.php
'frontend' => [
'panel_path' => 'js/panel',
'pages_path' => 'js/pages/Panels',
],2
3
4
5
6
Urutan yang benar:
1. publish config
2. ubah frontend.panel_path
3. publish assets2
3
Jika assets dipublish terlebih dahulu, component sudah ditempatkan di default path dan memindahkannya menjadi pekerjaan manual.
pages_path bukan publish destination.
Package tidak menaruh generated custom Page/Widget di sana pada install. Generator menulis ke location tersebut ketika Anda menjalankan generator.
Frontend dipublish karena component registries menggunakan import.meta.glob terhadap source tree application. Component yang tidak dilihat build tidak dapat di-resolve.
Published assets menjadi milik application:
- masuk repository application;
- dapat diedit;
- ikut build application.
Publishing tidak melakukan build.
Setelah publish:
npm run buildpanda-panel-migrations
php artisan vendor:publish --tag=panda-panel-migrations
php artisan migrate2
Package menyediakan empat migration:
| File | Fungsi |
|---|---|
2026_08_14_130919_create_notifications_table.php | Membuat Laravel notifications table untuk Notification Centre |
2026_08_14_143501_add_email_two_factor_to_users_table.php | Menambahkan two_factor_email_confirmed_at ke users |
2026_08_15_120000_create_panel_integrations_table.php | Membuat panel_integrations |
2026_08_15_140000_add_history_and_signing_to_panel_integrations.php | Menambahkan delivery history dan signing secret |
Migration tersebut sudah dijalankan dari package karena default:
'load_migrations' => true,dan package memanggil loadMigrationsFrom().
Publishing migration adalah tentang ownership, bukan syarat agar table tersedia.
Jika application ingin menyimpan migration di database/migrations, publish lalu ubah:
// config/panda-panel.php
'load_migrations' => false,2
3
Filename dipertahankan.
Package menggunakan plain publishes(), bukan publishesMigrations(), sehingga Laravel tidak memberi timestamp baru pada published copy.
Ini penting bagi:
PandaPanel\Support\PackageSchema::isOwned()yang menggunakan migration ownership untuk menentukan apakah rollback boleh menghapus schema tertentu.
Setiap up() defensif: jika table/column sudah tersedia, migration tidak menulis duplicate schema.
panda-panel-stubs
php artisan vendor:publish --tag=panda-panel-stubsMenyalin semua generator template ke:
stubs/panelStub yang tersedia:
| Stub | Digunakan oleh |
|---|---|
panel-provider.stub | make:panel |
resource.stub, resource-table.stub, resource-form.stub, resource-page.stub | make:panel-resource |
page.stub, page-component.stub | make:panel-page |
widget-stats.stub, widget-table.stub, widget-chart.stub, widget-custom.stub | make:panel-widget |
widget-component.stub | make:panel-widget --type=custom |
relation-manager.stub, relation-page.stub | make:panel-relation-manager |
Resolver:
protected function stubPath(string $name): string
{
$published = base_path("stubs/panel/{$name}.stub");
if (File::exists($published)) {
return $published;
}
return dirname(__DIR__, 3)."/stubs/panel/{$name}.stub";
}2
3
4
5
6
7
8
9
10
Application stub memiliki prioritas.
Anda tidak wajib mempublish seluruh stub agar generator bekerja. Package stub selalu menjadi fallback.
Bahkan jika hanya satu stub yang Anda customize, stub lainnya tetap dibaca dari package.
Placeholder menggunakan bentuk:
{{ token }}dan diisi oleh writeStub() menggunakan str_replace().
Token yang digunakan oleh shipped stubs:
base
bulkActions
class
component
filters
imports
label
modelBasename
pageClass
pageEntries
panel
path
pivotForm
plural
recordActions
relationship
resource
softDeletes2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Generator hanya dapat mengganti token yang memang dikirim generator tersebut. Menambahkan placeholder baru ke custom stub tanpa generator menyediakan value tidak akan otomatis bekerja.
Mengapa Stubs Tidak Termasuk Umbrella Tag
panda-panel-stubs sengaja tidak masuk:
panda-panelStub hanya perlu dimiliki application jika Anda ingin mengubah hasil scaffold.
Jika semua project otomatis mempublish stubs, release PandaBear berikutnya tidak lagi dapat memperbaiki generated code karena application copy selalu memiliki prioritas.
Umbrella Tag panda-panel
php artisan vendor:publish --tag=panda-panelMempublish sekaligus:
config
migrations
assets2
3
Convenient untuk scripted install yang memang ingin application memiliki migration.
Untuk use case biasa, individual tags lebih aman agar migration tidak dipublish tanpa sengaja.
Option Milik Laravel vendor:publish
Option berikut milik Laravel, bukan PandaBear:
| Option | Efek |
|---|---|
--tag=* | Publish satu atau beberapa tag. |
--force | Menimpa existing files. |
--existing | Hanya publish file yang sudah ada, menimpa existing copy. |
--provider= | Publish semua yang diregistrasikan provider tersebut. |
--all | Publish semua provider assets tanpa interactive picker. |
Contoh:
php artisan vendor:publish --tag=panda-panel-config --tag=panda-panel-assets
php artisan vendor:publish --tag=panda-panel-assets --force
php artisan vendor:publish --provider="PandaPanel\PandaPanelServiceProvider"2
3
--provider mempublish union dari semua asset yang diregistrasikan provider, termasuk panda-panel-stubs.
Gunakan hanya jika memang ingin semuanya.
Tanpa --force, existing file dilaporkan SKIPPED dan tidak diubah.
Pada Laravel Vue starter kit, banyak file resources/js/components/* sudah ada sehingga application copy tetap menang.
Apa yang Dipublish panel:install
php artisan panel:install
php artisan panel:install --force2
Installer memanggil vendor:publish maksimal tiga kali, dalam urutan:
panda-panel-config;panda-panel-assets;panda-panel-migrationshanya jika user mengonfirmasi; default no.
Di antara assets dan migrations, installer menulis:
AssetManifest::write(AssetManifest::read());untuk membuat .panel-assets.json.
--force pada installer diteruskan ke setiap vendor:publish.
Publish Ulang Saat Upgrade
Untuk upgrade, vendor:publish --tag=panda-panel-assets bukan tool yang tepat.
Tanpa --force:
existing file tidak diupdateDengan --force:
custom edit application ikut ditimpaGunakan baseline .panel-assets.json melalui:
php artisan panel:assets
php artisan panel:assets --update
php artisan panel:assets --force2
3
Status dasar:
| Disk | Package | Status | --update |
|---|---|---|---|
| unchanged | unchanged | current | tidak ditulis |
| unchanged | changed | out of date | ditulis |
| changed | unchanged | yours | dibiarkan |
| changed | changed | CONFLICT | tidak ditulis otomatis |
Rule praktis:
vendor:publish --tag=panda-panel-assetsuntuk initial install.panel:assetsuntuk upgrade setelahnya.
Plugin Assets Bukan Publish Tag
Plugin files dipublish melalui:
php artisan panel:publish
php artisan panel:publish billing
php artisan panel:publish billing --force2
3
Bukan vendor:publish tag.
Alasannya publish map berada pada plugin instance dan baru diketahui setelah Panels diboot.
PublishPanelAssetsCommand membaca:
publishes(): arraydengan map absolute source => absolute destination.
Existing destination dilewati kecuali --force.
API di Balik Publish System
use PandaPanel\Support\FrontendPaths;
use PandaPanel\Support\Installer\AssetManifest;
use PandaPanel\Support\Installer\PublishedAssets;
PublishedAssets::map();
PublishedAssets::files();
PublishedAssets::relative(
base_path('resources/js/panel/palette.ts')
);
// 'resources/js/panel/palette.ts'
FrontendPaths::panel('icons/registry.ts');
// /app/resources/js/panel/icons/registry.ts
FrontendPaths::pages('Admin/Pages/Reports.vue');
// /app/resources/js/pages/Panels/Admin/Pages/Reports.vue
AssetManifest::path();
// /app/.panel-assets.json
AssetManifest::exists();
AssetManifest::read();
AssetManifest::compare();
AssetManifest::write(
AssetManifest::read()
);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Methods:
| Method | Signature / Return |
|---|---|
PublishedAssets::map | static map(): array — absolute source => destination |
PublishedAssets::files | static files(): array — destination => source per file |
PublishedAssets::relative | path relatif terhadap base_path() |
FrontendPaths::panel | absolute path berdasarkan frontend.panel_path, default js/panel |
FrontendPaths::pages | absolute path berdasarkan frontend.pages_path, default js/pages/Panels |
AssetManifest::path | base_path('.panel-assets.json') |
AssetManifest::exists | apakah manifest tersedia |
AssetManifest::read | destination relatif => hash |
AssetManifest::write | rehash file yang tersedia di disk |
AssetManifest::compare | status comparison per shipped file |
Status AssetManifest:
| Constant | Value | Arti |
|---|---|---|
NEW | new | belum ada baseline dan berbeda dari package current |
CURRENT | current | tidak berubah di kedua sisi |
STALE | stale | application untouched, upstream berubah |
MODIFIED | modified | application berubah, upstream sama |
CONFLICT | conflict | application dan upstream sama-sama berubah |
DELETED | deleted | pernah dipublish lalu dihapus application |
REMOVED_UPSTREAM | removed-upstream | pernah dipublish, package tidak lagi mengirim |
Hash menggunakan xxh128, dengan CRLF dinormalisasi ke LF agar Windows checkout tidak terlihat mengubah semua file.
Yang Tidak Pernah Dipublish
| Package Content | Alasan |
|---|---|
frontend/host/** | Hanya stand-in untuk module yang harus disediakan application. |
frontend/entry.ts, vite.config.ts, tsconfig.json, eslint.config.js | Build/toolchain milik package sendiri. |
src/** | Framework diimport melalui Composer, bukan dicopy. |
| Blade views | Inertia root view adalah file milik application. |
Hal yang Perlu Diperhatikan
- Stubs tidak termasuk umbrella tag.
vendor:publishtidak menulis.panel-assets.json. Initial baseline dibuat olehpanel:installatau dengan memanggilAssetManifest::write()sendiri.- Commit
.panel-assets.json. --forcepada assets tag dapat menimpa application-owned component/type files. Untuk upgrade gunakanpanel:assets --update.- Jika migration dipublish, ubah
load_migrationsmenjadi false untuk menyatakan ownership dengan jelas. frontend.panel_pathdibaca ketika map dibuat. Ubah config sebelum assets dipublish.- Publish tidak melakukan frontend build. Jalankan
npm run build.