Wayfinder Routes
Sembilan module yang di-import oleh published panel components tidak dikirim oleh package dan memang tidak akan pernah dikirim: Wayfinder menghasilkan module tersebut dari route table application Anda sendiri. Module inilah yang digunakan auth pages dan settings pages milik panel untuk melakukan POST ke Fortify serta ke settings controller milik application. Gunakan halaman ini ketika npm run build gagal pada @/routes/... atau @/actions/..., atau ketika Anda ingin mengetahui route dan controller apa saja yang wajib tersedia di application.
Satu command utama
php artisan wayfinder:generate --with-form
npm run build2
--with-form penting. Panel menggunakan .form() pada Inertia <Form> di sepuluh call site. Wayfinder yang dijalankan tanpa form helpers akan menghasilkan module yang tidak mengekspor method tersebut.
Daripada menebak apa yang kurang, tanyakan langsung pada package:
use PandaPanel\Support\Installer\FrontendRequirements;
FrontendRequirements::missingHostModules();
// ['@/routes/login', '@/routes/password', …]2
3
4
Sembilan module
Seluruh module berikut merupakan generated module. Menyimpan copy-nya di dalam package sama saja dengan mengirim snapshot route application milik orang lain.
| Specifier | Export yang digunakan panel | Dihasilkan dari | Method dan URI |
|---|---|---|---|
@/routes | logout | route logout | POST /logout |
@/routes/login | store | route login.store | POST /login |
@/routes/register | store | route register.store | POST /register |
@/routes/password | email, update | routes password.email, password.update | POST /forgot-password, POST /reset-password |
@/routes/two-factor | enable, disable | routes two-factor.enable, two-factor.disable | POST dan DELETE /user/two-factor-authentication |
@/routes/verification | send | route verification.send | POST /email/verification-notification |
@/actions/App/Http/Controllers/Settings/ProfileController | update, destroy | App\Http\Controllers\Settings\ProfileController | PATCH dan DELETE /settings/profile |
@/actions/App/Http/Controllers/Settings/SecurityController | update | App\Http\Controllers\Settings\SecurityController | PUT /settings/security |
@/actions/Laravel/Passkeys/Http/Controllers/PasskeyRegistrationController | destroy | Laravel\Passkeys\Http\Controllers\PasskeyRegistrationController | DELETE /passkeys |
Route module dinamai berdasarkan leading segment dari route name dan mengekspor bagian sisanya. Jadi password.email menjadi export email di @/routes/password. Controller module mencerminkan fully-qualified class name di bawah @/actions/. Method dan URI pada kolom terakhir mengikuti stand-in yang disimpan package di frontend/host/; stand-in tersebut menjadi specification mengenai surface yang harus tersedia agar panel dapat bekerja.
Fortify mendaftarkan enam route-based module. Dua controller App\Http\Controllers\Settings dan passkey controller biasanya berasal dari Laravel Vue starter kit.
File panel mana meng-import module apa
Sepuluh published file meng-import generated module. Semua ikut dikompilasi oleh build application walaupun panel tidak pernah merender screen tersebut, karena Inertia resolver melakukan glob terhadap resources/js/pages/**.
| File | Imports |
|---|---|
resources/js/pages/panel/auth/Login.vue | store dari @/routes/login |
resources/js/pages/panel/auth/Register.vue | store dari @/routes/register |
resources/js/pages/panel/auth/ForgotPassword.vue | email dari @/routes/password |
resources/js/pages/panel/auth/ResetPassword.vue | update dari @/routes/password |
resources/js/pages/panel/auth/VerifyEmail.vue | logout dari @/routes, send dari @/routes/verification |
resources/js/pages/panel/settings/Profile.vue | ProfileController, send dari @/routes/verification |
resources/js/pages/panel/settings/Security.vue | SecurityController |
resources/js/components/DeleteUser.vue | ProfileController |
resources/js/components/ManageTwoFactor.vue | enable, disable dari @/routes/two-factor |
resources/js/components/ManagePasskeys.vue | destroy dari passkey controller |
Tidak ada file di bawah resources/js/panel/** yang meng-import route module. Directory tersebut berisi layout, table, form, widget, dan action machinery — bagian yang harus tetap dapat dibuild tanpa mengetahui panel id/path pada build time.
Tiga bentuk pemanggilan yang digunakan panel
Wayfinder export memiliki capability lebih luas, tetapi panel hanya menggunakan tiga bentuk berikut. Inilah juga surface yang dimodelkan oleh frontend/host/routes/shape.ts.
.form() — di-bind ke Inertia <Form>
<script setup lang="ts">
import { Form } from '@inertiajs/vue3';
import { store } from '@/routes/login';
</script>
<template>
<Form v-slot="{ errors, processing }" v-bind="store.form()" :reset-on-success="['password']">
<input name="email" type="email" required />
<button type="submit" :disabled="processing">Log in</button>
</Form>
</template>2
3
4
5
6
7
8
9
10
11
v-bind menyebarkan action dan method ke form sehingga component tidak pernah hard-code URL. Bentuk yang sama digunakan seluruh auth page panel, kedua settings page, component two-factor, dan delete-account.
Controller module berupa object yang berisi definitions, sehingga call yang sama dilakukan melalui property:
<script setup lang="ts">
import { Form } from '@inertiajs/vue3';
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
</script>
<template>
<Form v-bind="ProfileController.update.form()">…</Form>
<Form v-bind="ProfileController.destroy.form()" reset-on-success>…</Form>
</template>2
3
4
5
6
7
8
9
.url(...) — string URL untuk router
import { router } from '@inertiajs/vue3';
import { destroy } from '@/actions/Laravel/Passkeys/Http/Controllers/PasskeyRegistrationController';
const handleDelete = (id: number, onError: () => void) => {
router.delete(destroy.url(id), {
preserveScroll: true,
onError,
});
};2
3
4
5
6
7
8
9
Ini satu-satunya tempat panel mengirim route parameter ke Wayfinder. ManagePasskeys.vue membutuhkan URL string karena delete dijalankan secara imperative dari confirmation handler, bukan melalui <Form>.
Bare invocation — href
<script setup lang="ts">
import { Link } from '@inertiajs/vue3';
import { logout } from '@/routes';
</script>
<template>
<Link :href="logout()" as="button">Log out</Link>
</template>2
3
4
5
6
7
8
VerifyEmail.vue menggunakannya. Guest yang sedang menunggu verification link tetap membutuhkan jalan untuk logout, dan logout tersebut adalah route application, bukan route khusus panel.
Contract export module
Stand-in di frontend/host/ adalah integration seam untuk type-check package sendiri, bukan sesuatu yang di-install application. Directory tersebut di-export-ignore, sehingga composer require tidak pernah membawanya ke host project. Meski demikian, file stand-in berguna sebagai contract karena mendeklarasikan surface yang benar-benar disentuh panel:
export interface RouteInvocation {
url: string;
method: 'get' | 'post' | 'put' | 'patch' | 'delete';
}
export interface RouteDefinition {
(...args: Array<string | number | undefined>): RouteInvocation;
url(...args: Array<string | number | undefined>): string;
form(...args: Array<string | number | undefined>): RouteInvocation;
}2
3
4
5
6
7
8
9
10
Real Wayfinder definition memiliki lebih banyak API — query builders, per-method variants, route-model-binding parameter objects. Stand-in hanya memodelkan surface yang benar-benar digunakan, karena menambahkan capability yang tidak pernah dipakai justru berarti menciptakan contract fiktif.
Area panel yang tidak menggunakan Wayfinder
Setiap URL di dalam panel berasal dari server. Framework tidak dapat menghasilkan route panel pada build time karena route name berbentuk panel.{id}.*, sedangkan id panel adalah runtime fact. Application dapat mendaftarkan tiga panel atau mengganti id tanpa rebuild frontend.
// PandaPanel\Core\Panel
$panel->getRouteNamePrefix(); // 'panel.admin.'
$panel->routeName('dashboard'); // 'panel.admin.dashboard'2
3
Server menyerialisasi URL final ke props:
'url' => route($panel->routeName('search'), absolute: false),Lalu component hanya membacanya:
| Sumber URL | Contoh |
|---|---|
| Shared props | panels[].url, search.url, tenancy.available[].url |
| Navigation metadata | setiap sidebar item's url, setiap user-menu item's url |
| Page props | action endpoints milik page, emailCodeUrls.enable |
panel.path | :action="`/${panel.path}/two-factor/verify`" di EmailCode.vue |
| Resource helpers, server-side | UserResource::url('edit', $record) |
Rule frontend adalah “tidak ada hardcoded panel URLs”. Setiap href berasal dari server atau Wayfinder, dan untuk URL internal panel selalu berasal dari server.
Wayfinder tetap dapat menghasilkan module untuk named routes milik panel ketika command dijalankan. Output-nya dapat muncul di resources/js/routes/panel/…. Package tidak meng-import module tersebut dan file generated itu bukan bagian publish map, sehingga panel:assets tidak pernah melaporkan atau overwrite output Wayfinder.
Pemeriksaan dan bentuk failure
use PandaPanel\Support\Installer\FrontendRequirements;
/** @return list<string> missing modules sebagai specifier `@/…` */
FrontendRequirements::missingHostModules();2
3
4
Sebuah specifier dianggap tersedia jika salah satu bentuk berikut ditemukan di bawah resources/js, sesuai urutan:
.ts .vue .d.ts /index.ts /index.vue /index.d.tsBare directory sengaja tidak dihitung. File::exists() bernilai true untuk directory sehingga bare check akan membuat @/routes dianggap terpenuhi hanya karena folder kosong tersedia.
php artisan panel:install menjalankan pemeriksaan yang sama dan menyebut module yang belum ada:
The published components import these modules, which belong to your application and are not
there yet:
@/routes
@/routes/login
@/routes/password
…
`@/routes/*` and `@/actions/*` are generated — run `php artisan wayfinder:generate`. The rest
come with a Laravel Vue starter kit.2
3
4
5
6
7
8
9
10
Daftar ditampilkan satu per satu, bukan hanya count, karena pola missing module menunjukkan akar masalah. Jika seluruh @/routes/* dan @/actions/* hilang, Wayfinder belum pernah dijalankan. Jika hanya beberapa component hilang, application kemungkinan bukan starter kit dan module tersebut perlu dibuat sendiri.
Jika pemeriksaan dilewati, build akan gagal dengan error module specifier yang benar tetapi kurang membantu:
Failed to resolve import "@/routes/login" from "resources/js/pages/panel/auth/Login.vue".Menjaga module tetap generated
Wayfinder adalah tool milik application dan dijalankan terhadap route application, sehingga package tidak pernah menjalankannya untuk Anda.
- Jika menggunakan Vite plugin — setup default Laravel Vue starter kit —
npm run devdannpm run builddapat regenerate module, sehingga route changes ikut diambil pada build berikutnya. - Tanpa plugin, jalankan
php artisan wayfinder:generate --with-formsetiap kali route name atau signature settings controller berubah.
Wayfinder berpatokan pada route name, sehingga route name sebaiknya dijaga stabil. URI aman untuk dipindahkan. Jika password.update di-rename, export module menghilang dan reset-password page milik panel berhenti build.
Notes
- Module dibutuhkan pada build time, bukan hanya runtime. Panel tanpa
login()memang tidak pernah merenderLogin.vue, tetapi Inertia resolver glob tetap mengompilasi file tersebut sehingga import harus dapat di-resolve. ProfileControllerharus memilikidestroy.DeleteUser.vuemenggunakanProfileController.destroy.form()dan component tersebut di-import secara unconditional oleh Profile page. Example application dapat hanya menampilkan server-sideupdate, tetapi starter kit nyata harus menyediakan delete route/controller method.SecurityControllerharus memilikiupdate. Panel memiliki security screen, tetapi write tetap dilakukan controller milik application agar password update memiliki satu implementation terlepas dari form mana yang mengirim request.- Panel POST ke endpoint Fortify asli, bukan duplikat route per panel. Menggandakan login POST berarti menggandakan rate limiting, two-factor, passkeys, dan session handling — concern yang tidak boleh memiliki behavior berbeda hanya karena entry point UI berbeda.
@/actions/Laravel/Passkeys/...hanya tersedia jika passkeys terpasang.ManagePasskeys.vuetidak merender UI jikacanManagePasskeysfalse, tetapi import bersifat static dan tetap harus resolve saat build.- Generated modules bukan published assets. File tersebut tidak masuk
PublishedAssets::map(), sehingga tidak muncul pada reportpanel:assets. Re-run Wayfinder adalah satu-satunya cara memperbaruinya. - Test menurunkan daftar contract dari imports.
FrontendContractTestmemindai published files untuk specifier@/…yang tidak dikirim package dan memastikan semuanya tercatat diFrontendRequirements. Import baru yang tidak masuk declaration list gagal di test package, bukan baru ditemukan pada build user.
See also
- Host modules, Published asset structure, Updating published assets
- Inertia pages, Vue component tree
- Frontend requirements, Laravel Vue starter kit setup, Common install problems
- Routing, Frontend assets
- URLs and routes, Panel URLs
- Fortify, Login, Profile, Security, Passkeys
panel:install- Troubleshooting: missing host modules, Vite