vite-plugin-ferry
v1.9.2
Published
Ferries Laravel types to your TypeScript frontend
Readme
vite-plugin-ferry
Type-safe Inertia apps end to end: TypeScript for routes, enums, resources, page props, and form types, generated straight from your Laravel backend.
Ferry reads your Laravel app and generates TypeScript for the surface your Inertia frontend touches: named routes, PHP enums, JsonResource shapes, per-page Inertia props, and FormRequest data. Your frontend is typed from the backend that owns the data, so a change to a resource or a rule shows up as a type error where the frontend uses it. Nothing lands in your project tree: runtime code ships as Vite virtual modules, types as one generated ambient .d.ts, and everything regenerates on every run.
Install
npm install vite-plugin-ferry typescript@^5 --save-devQuick start
Add the plugin to vite.config.ts:
import { defineConfig } from 'vite';
import ferry from 'vite-plugin-ferry';
export default defineConfig({
plugins: [ferry()],
});That's it. No tsconfig changes, no generated files to gitignore. See Getting started for how generation runs and how the types load.
Ferry generates six virtual modules you import from directly:
import { OrderStatus } from '@ferry/enums'; // enum classes
import type { PostResource } from '@ferry/resources'; // resource shapes
import type { UsersShowProps } from '@ferry/pages'; // per-page Inertia props
import type { StoreUserRequest } from '@ferry/forms'; // form data shapes
// @ferry/route and @ferry/enum back route() and the Enum base classThe typed surface, in one page component:
import type { UsersShowProps } from '@ferry/pages';
import type { StoreUserRequest } from '@ferry/forms';
const page = usePage<UsersShowProps>();
page.props.user; // UserResource
const href = route('users.show', { user: 1 }); // usable as a string AND as Inertia's { url, method }
route.is('users.*'); // current-route check: name, wildcard, or an array of either
const form = useForm<StoreUserRequest>({ name: '', role: 'admin' });
form.data.role; // 'admin' | 'editor' | 'viewer'
form.errors['profile.bio']; // error keys derived from the shapeWhat it generates
- Routes (
@ferry/route): a typedroute()helper that resolves named routes to their URL and method client-side, with zero route table shipped to the browser. - Enums (
@ferry/enum,@ferry/enums): PHP enums become real JS classes withis/from/fromOrFail/values/keys/cases/options, plus a<Enum>Valuebacking-value union for serialized data. - Resources (
@ferry/resources,@ferry/pagination): precise types for yourJsonResourceclasses from statictoArray()analysis plus real column and cast metadata, degrading gracefully instead of breaking your build.Resource::collection()over a paginator types as the real{ data, links, meta }envelope. - Page props (
@ferry/pages): the props each Inertia page receives, typed throughusePage<T>(), with shared props typed through Inertia's own augmentation. - Form types (
@ferry/forms): the data shape of yourFormRequestclasses, typed throughuseForm<T>()withform.errorskeys derived for free. - Environment variables (
import.meta.env): everyVITE_-prefixed env var typed asstring, merged into Vite's ownImportMetaEnv— keys only, no values, no import.
Any field ferry can't resolve statically degrades instead of breaking the build, and you can pin it precisely with a @ferry docblock tag.
Documentation
- Getting started: requirements, plugin setup, how generation and type loading work.
- Routes, Enums, Resources, Page props, Form types, Environment variables: the full reference for each generated surface.
- Ferry pins: the
@ferrydocblock tag for overriding a generated type. - Configuration: the
cwd,strict, andverbosityoptions.
Contributing
Issues and pull requests are welcome. Run the test suite with npm test.
License
See LICENSE for details.
