> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Wayfinder 介绍

> 解析从 Ziggy 演进、在 Inertia 启动套件中被采用的 Laravel Wayfinder。从 Laravel 后端与 TypeScript 前端类型安全对接的机制、与 Ziggy 的差异、安装与基本用法,到在 next 分支中演进的下一代能力都做详细介绍。

## 什么是 Wayfinder

**Laravel Wayfinder** 是一个零摩擦地把 Laravel 后端和 TypeScript 前端桥接起来的包。它会根据控制器和路由自动生成完全类型化的 TypeScript 函数,让你在前端可以像调用普通函数一样直接调用 Laravel 的端点。

URL 硬编码、路由参数手动维护、后端变化人工同步——这些统统不需要了。

<Info>
  Wayfinder 目前是 Beta 版(当前 v0.1.x)。在 v1.0.0 发布前 API 可能会变化。所有重要变更都会记录在 [CHANGELOG](https://github.com/laravel/wayfinder/blob/main/CHANGELOG.md) 中。
</Info>

***

## Ziggy 与 Wayfinder 的差异

### 什么是 Ziggy

[Ziggy](https://github.com/tighten/ziggy) 是长期以来在 Laravel 生态里广泛使用的路由 helper。它把 Laravel 的路由定义暴露给 JavaScript 端,让你可以用 `route('posts.show', { id: 1 })` 这样的形式生成 URL。

### 为什么被 Wayfinder 取代

Ziggy 用字符串来表达路由名和参数,与 TypeScript 的契合度有限。路由名的拼写错误或参数名错误只能在运行时才暴露。

Wayfinder 是 TypeScript first 的设计,会把控制器方法生成为**可导入的函数**。

| 对比项     | Ziggy                            | Wayfinder                              |
| ------- | -------------------------------- | -------------------------------------- |
| 引用路由的方式 | `route('posts.show', { id: 1 })` | `import { show } from "@/actions/..."` |
| 类型安全    | 类型定义有限                           | 完整的 TypeScript 类型                      |
| IDE 支持  | 补全能力弱                            | 补全和类型检查完全可用                            |
| 树摇      | 所有路由都会打进 bundle                  | 只把用到的路由打进 bundle                       |
| 生成时机    | 运行时注入                            | 构建时静态生成                                |

在基于 Inertia 的 Laravel 启动套件(React / Vue / Svelte)中,Wayfinder 已被默认采用。

***

## 安装

### 1. 用 Composer 安装服务端包

```bash theme={null}
composer require laravel/wayfinder
```

### 2. 用 NPM 安装 Vite 插件

```bash theme={null}
npm i -D @laravel/vite-plugin-wayfinder
```

### 3. 在 `vite.config.js` 中加入插件

```ts theme={null}
import { wayfinder } from "@laravel/vite-plugin-wayfinder";
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";

export default defineConfig({
    plugins: [
        laravel({
            input: ["resources/js/app.ts"],
            refresh: true,
        }),
        wayfinder(),
    ],
});
```

加上 Vite 插件后,开发服务器运行时,只要 PHP 文件或路由文件发生变化,TypeScript 文件就会被自动重新生成。

***

## 生成 TypeScript 定义文件

用 `wayfinder:generate` 命令生成 TypeScript 文件。

```bash theme={null}
php artisan wayfinder:generate
```

默认会在 `resources/js` 下生成 3 个目录。

```
resources/js/
├── actions/         # 控制器 action 的函数
│   └── App/Http/Controllers/
│       └── PostController.ts
├── routes/          # 命名路由的函数
│   └── post.ts
└── wayfinder/       # 类型定义文件
    └── types.ts
```

<Tip>
  生成的文件会在每次构建时完全重生成,建议把它们加入 `.gitignore`。可以把 `wayfinder`、`actions`、`routes` 3 个目录一次性排除掉。
</Tip>

想改输出位置时用 `--path` 参数。

```bash theme={null}
php artisan wayfinder:generate --path=resources/js/api
```

也可以只生成 action 或只生成路由。

```bash theme={null}
php artisan wayfinder:generate --skip-actions  # 只生成路由
php artisan wayfinder:generate --skip-routes   # 只生成 action
```

***

## 基本用法

### 导入并使用 action

生成 `PostController` 的 `show` 方法对应 URL 的示例。

```ts theme={null}
import { show } from "@/actions/App/Http/Controllers/PostController";

show(1);
// { url: "/posts/1", method: "get" }
```

只需要 URL 时用 `.url()`。

```ts theme={null}
show.url(1); // "/posts/1"
```

也可以指定具体的 HTTP 方法。

```ts theme={null}
show.head(1); // { url: "/posts/1", method: "head" }
```

### 参数传递方式

Wayfinder 的函数支持多种形态的参数。

```ts theme={null}
import { update } from "@/actions/App/Http/Controllers/PostController";

// 单个参数
show(1);
show({ id: 1 });

// 多个参数
update([1, 2]);
update({ post: 1, author: 2 });
update({ post: { id: 1 }, author: { id: 2 } });
```

路由上指定了键绑定(`/posts/{post:slug}`)时,可以直接传对应的值。

```ts theme={null}
// 当路由是 /posts/{post:slug} 时
show("my-new-post");
show({ slug: "my-new-post" });
```

### 一次性导入整个控制器

也可以直接把整个控制器导入,然后调用其方法。

```ts theme={null}
import PostController from "@/actions/App/Http/Controllers/PostController";

PostController.show(1);
PostController.index();
```

<Warning>
  整个控制器导入时不会享受到树摇,所有 action 都会被打进 bundle。想让最终 bundle 更小,建议逐个导入。
</Warning>

### 单一 action 控制器

单一 action 控制器(Invokable Controller)对应的导入函数可以直接调用。

```ts theme={null}
import StorePostController from "@/actions/App/Http/Controllers/StorePostController";

StorePostController(); // { url: "/posts", method: "post" }
```

### 导入命名路由

按路由名访问时使用 `routes/` 下的文件。

```ts theme={null}
import { show } from "@/routes/post";

// 路由名是 `post.show` 时
show(1); // { url: "/posts/1", method: "get" }
```

### 查询参数

所有 Wayfinder 函数都能通过 `query` 选项加查询参数。

```ts theme={null}
import { show } from "@/actions/App/Http/Controllers/PostController";

show(1, { query: { page: 1, sort_by: "name" } });
// { url: "/posts/1?page=1&sort_by=name", method: "get" }
```

要和当前 URL 的查询参数合并时用 `mergeQuery`。

```ts theme={null}
// 当前 URL:/posts/1?page=1&sort_by=category&q=shirt

show.url(1, { mergeQuery: { page: 2, sort_by: "name" } });
// "/posts/1?page=2&sort_by=name&q=shirt"

// 要删除某个参数,传 null
show.url(1, { mergeQuery: { sort_by: null } });
// "/posts/1?page=1&q=shirt"
```

### 表单变体

想在传统 HTML 表单中使用时,加上 `--with-form` 参数生成,然后用 `.form` 变体。

```bash theme={null}
php artisan wayfinder:generate --with-form
```

```tsx theme={null}
import { store, update } from "@/actions/App/Http/Controllers/PostController";

// React 示例
const Page = () => (
    <form {...store.form()}>
        {/* <form action="/posts" method="post"> */}
    </form>
);

const EditPage = () => (
    <form {...update.form(1)}>
        {/* <form action="/posts/1?_method=PATCH" method="post"> */}
    </form>
);
```

***

## Inertia 与 Wayfinder 的搭配

把 Inertia 的 form helper 与 Wayfinder 组合起来,就可以在不写任何 URL 字符串的情况下完成表单提交。

```ts theme={null}
import { useForm } from "@inertiajs/react";
import { store } from "@/actions/App/Http/Controllers/PostController";

const form = useForm({ name: "My Post" });

form.submit(store()); // 提交到 POST /posts
```

`Link` 组件里也可以这样用。

```tsx theme={null}
import { Link } from "@inertiajs/react";
import { show } from "@/actions/App/Http/Controllers/PostController";

const Nav = () => (
    <Link href={show(1)}>查看文章</Link>
);
```

***

## 在启动套件中的采用

用 `laravel new` 创建新项目并选择 React / Vue / Svelte 时,Wayfinder 会作为自动配置好的组件被引入。启动套件里包含:

* Composer 包 `laravel/wayfinder`
* NPM 包 `@laravel/vite-plugin-wayfinder`
* `vite.config.js` 里已加入插件配置
* 生成目录已经加入 `.gitignore`

在已有项目中按上面的步骤手动引入同样可行。

***

## 处理和保留字冲突的方法名

对 `delete`、`import` 这类和 JavaScript 保留字重名的控制器方法,会加上 `Method` 后缀。

```ts theme={null}
// 控制器里有 delete 方法时
import { deleteMethod } from "@/actions/App/Http/Controllers/PostController";

deleteMethod(1); // { url: "/posts/1", method: "delete" }
```

***

## 当前状态(v0.1.x)

当前稳定版位于 `v0.1.x` 分支。截至 2026 年 3 月的最新版本是 **v0.1.15**。

### v0.1.x 系列主要更新记录

| 版本      | 主要内容                              |
| ------- | --------------------------------- |
| v0.1.15 | 支持 Laravel 13,修复 Blade 视图崩溃       |
| v0.1.13 | 改进查询参数在 TypeScript strict 模式下的兼容性 |
| v0.1.7  | 支持从前端指定 URL 默认参数                  |
| v0.1.6  | 引入 Vite 插件                        |
| v0.1.5  | 支持 PHP 8.2,兼容缓存过的路由               |
| v0.1.0  | 初次发布                              |

***

## next 分支中开发中的下一代能力

`next` 分支正在开发相较 v0.1.x 大幅扩展的下一版。

<Warning>
  `next` 分支可以通过 `dev-next` 约束安装,但 API 可能大幅变化,不建议在生产环境使用。
</Warning>

```bash theme={null}
composer require laravel/wayfinder:dev-next
```

### 生成的 TypeScript 范围大幅扩展

v0.1.x 只针对路由和控制器 action,而下一版会把下面的东西都作为 TypeScript 生成。

```mermaid theme={null}
graph TD
    A["Laravel 应用"] --> B["wayfinder:generate"]
    B --> C["Routes & Actions<br>路由 URL 函数"]
    B --> D["Form Requests<br>校验类型"]
    B --> E["Eloquent Models<br>模型接口"]
    B --> F["PHP Enums<br>TypeScript 常量"]
    B --> G["Inertia Page Props<br>页面 props 类型"]
    B --> H["Broadcast Channels<br>频道类型"]
    B --> I["Broadcast Events<br>事件 payload 类型"]
    B --> J["Environment Variables<br>import.meta.env 类型"]
```

### Form Request 的 TypeScript 类型生成

```php theme={null}
class StorePostRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'title'   => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
            'tags'    => ['nullable', 'array'],
            'tags.*'  => ['string'],
        ];
    }
}
```

从上面的 Form Request 会生成:

```ts theme={null}
export type Request = {
    title: string;
    content: string;
    tags?: string[] | null;
};
```

### Eloquent 模型的类型生成

```php theme={null}
class User extends Model
{
    protected $casts = [
        'email_verified_at' => 'datetime',
        'is_admin' => 'boolean',
    ];

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}
```

上面的模型会在 `types.d.ts` 里生成类型:

```ts theme={null}
export namespace App.Models {
    export type User = {
        id: number;
        name: string;
        email: string;
        email_verified_at: string | null;
        is_admin: boolean;
        posts: App.Models.Post[];
    };
}
```

### PHP Enum 转 TypeScript

```php theme={null}
enum PostStatus: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}
```

类型和常量都会生成:

```ts theme={null}
// 类型定义(types.d.ts)
export namespace App.Enums {
    export type PostStatus = "draft" | "published" | "archived";
}

// 常量(App/Enums/PostStatus.ts)
export const Draft = "draft";
export const Published = "published";
export const Archived = "archived";

export const PostStatus = { Draft, Published, Archived } as const;
```

### 输出目录变化

v0.1.x 中会分成 `actions/`、`routes/`、`wayfinder/` 3 个目录,而下一版把它们汇集到 `resources/js/wayfinder` 下。

```
resources/js/wayfinder/
├── App/Http/Controllers/
│   └── PostController.ts    # action 函数(actions/ 被废弃)
├── routes/
│   └── post.ts              # 命名路由(不变)
├── broadcast-channels.ts    # 广播频道
├── broadcast-events.ts      # 广播事件
└── types.d.ts               # 全部类型定义(从 types.ts 改名)
```

### 从 v0.1.x 到 next 的主要变化

* 导入路径从 `@/actions/...` 变成 `@/wayfinder/...`
* 废弃 `--skip-actions`、`--skip-routes`、`--with-form` 参数,统一改到配置文件
* `types.ts` 改名为 `types.d.ts`

***

## 总结

Laravel Wayfinder 把 Ziggy 提供的“在 JavaScript 里引用 Laravel 路由”的能力用 TypeScript first 的方式重新设计。通过导入并调用生成的函数,类型安全、IDE 支持和树摇都得到了显著改善。

即便是当前的 v0.1.x,对路由和控制器 action 的类型安全引用也已经足够好用,并且在基于 Inertia 的 Laravel 启动套件中已成为标配。`next` 分支正在开发的下一版会把 Form Request、Eloquent 模型、Enum、Inertia 页面 props 也一起生成为 TypeScript,朝着更全面的类型安全基座演进。

<Card title="Laravel Wayfinder GitHub" icon="github" href="https://github.com/laravel/wayfinder">
  源代码、CHANGELOG、Issue 请查看这里。
</Card>

<Card title="Vite Plugin Wayfinder" icon="bolt" href="https://github.com/laravel/vite-plugin-wayfinder">
  Vite 插件的配置项详情请查看这里。
</Card>


## Related topics

- [Blaze 包介绍](/zh/blog/blaze-introduction.md)
- [Laravel Pennant 实战用例](/zh/blog/laravel-pennant.md)
- [Laravel Telescope 实战技巧](/zh/blog/telescope-introduction.md)
- [用 Pest PHP 开始 Laravel 测试](/zh/blog/pest-introduction.md)
- [Laravel Bluesky](/zh/packages/laravel-bluesky/index.md)
