Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laroute Laravel Package

lord/laroute

LaRoute exposes your Laravel named routes to JavaScript, letting you generate URLs client-side with a route() helper that mirrors Laravel's API. It supports route parameters, filtering, and easy integration so frontend code stays in sync with backend routes.

View on GitHub
Deep Wiki
Context7

Getting Started

Laroute takes your named Laravel routes and compiles them into a plain-JS file so the browser can build URLs with the same names the backend uses.

Install and wire up (4 steps):

composer require lord/laroute
// config/app.php — only needed on Laravel < 5.5; newer versions auto-discover
Lord\Laroute\LarouteServiceProvider::class,
# 1. publish the config so you can control output location / filtering
php artisan vendor:publish --provider="Lord\Laroute\LarouteServiceProvider"

# 2. generate the JS file (defaults to public/js/laroute.js)
php artisan laroute:generate
{{-- 3. load it before your app JS --}}
<script src="{{ asset('js/laroute.js') }}"></script>
<script>
  // 4. generate a URL by route name, params keyed by placeholder name
  fetch(laroute.route('users.show', { user: 42 }))
</script>

Where to look first, in this order:

  1. The generated public/js/laroute.js — open it. It's a small IIFE containing a route map (name → URI pattern + domain). Everything the frontend can do is visible in that file.
  2. config/laroute.php — output path/filename, the JS namespace (laroute by default), absolute-vs-relative URL behaviour, and route filtering.
  3. vendor/lord/laroute/src — the package is a few hundred lines; the generator class is the authoritative answer for any "why did this route come out like that" question.

First realistic use case: a Blade page with a small amount of AJAX. Instead of hardcoding /users/42/edit in JS (which breaks the moment you add a prefix or rename a segment), call laroute.route('users.edit', { user: 42 }). Same string you'd write in route() server-side.

Implementation Patterns

Layout-level include, app-level usage. Load the generated file once in your main layout, then use it anywhere:

// vanilla / axios
axios.get(laroute.route('api.posts.index'));
axios.delete(laroute.route('api.posts.destroy', { post: id }));

// Vue/React components — just a global, no import needed
methods: {
  url(id) { return laroute.route('orders.show', { order: id }); }
}

Named routes only. This is the pattern that matters: treat laroute as a hard argument for naming every route the frontend touches. Route::get(...)->name('reports.export') becomes a contract; anonymous routes are invisible to JS.

Extra params become a query string. Useful for the common "same page, different filters" case:

laroute.route('products.index', { page: 2, sort: 'price' })
// -> /products?page=2&sort=price

Named placeholders that exist in the URI are substituted; anything left over is appended as a query string. This means one route can cover pagination, sorting and filtering without separate endpoints.

Generate in the deploy pipeline, not by hand. The generated file is a build artifact derived from your route table:

php artisan route:cache
php artisan laroute:generate   # after route cache, before/with your asset build
npm run production             # Mix/Vite versions asset() so the file is cache-busted

If your frontend build hashes or versions assets, make sure the laroute file goes through the same pipeline — otherwise browsers keep a stale route map after a deploy and you get 404s that only affect returning visitors.

Filter what you expose. The published config lets you restrict which routes get emitted. Expose the frontend's API surface only; there's no reason to ship admin/webhook/health-check route names to every visitor.

Server-to-client handoff. For the "I already know the URL on the server" case, prefer Blade's route() and pass the string in via a data attribute or a window.__CONFIG__ = @json([...]) blob. Use laroute.route() for URLs only known at runtime. Mixing the two is fine and is the normal arrangement.

CI guard. Because the file is generated, a renamed route can silently break JS. A cheap test: assert that every route name your JS references appears in the generated output, or snapshot the generated file and diff it on PRs so route renames surface as reviewable changes.

Gotchas and Tips

  • It's a static snapshot. Nothing updates until you re-run php artisan laroute:generate. In local dev this means every Route::...->name(...) addition needs a regenerate; add it to a file watcher or a composer script or you will lose an hour to a phantom 404. If you skip the build step in CI, the file is whatever was committed last.
  • Unnamed routes don't exist. laroute.route('foo') on a route without ->name() fails at runtime with no compile-time signal. This is the single most common source of "it works in Blade but not in JS".
  • No model binding. You pass the raw scalar. { user: user.id }, not the object. Passing an object stringifies to [object Object] and you get a 404 with a URL that looks almost right.
  • Optional URI params (/foo/{bar?}) are the sharp edge. Test them explicitly — omitting an optional param can leave a dangling separator or an empty segment depending on the pattern. If you rely on them heavily, prefer separate named routes.
  • Absolute vs relative matters behind proxies. If the generated URLs are absolute and APP_URL doesn't match the public host, you get cross-origin or wrong-host links. Force relative in the config where possible, or pass the third argument to laroute.route(name, params, false) for a relative URL.
  • Bundler integration is not ESM. The output is an IIFE that assigns a global. With Webpack/Vite, either load it as a plain <script> before your bundle, or shim it — don't expect import laroute from './laroute' to give you anything useful. The global name is configurable, so set it to something namespaced if you're on a page with other globals.
  • Read-only filesystems will bite you. The command writes into public/, which fails on read-only containers/Vapor-style deploys. Generate at build time and ship the artifact; never generate at request time.
  • Controller-action URLs (laroute.action(...)) are brittle. They hardcode controller class names into JS; a namespace refactor breaks the frontend with no PHP-level error. Stick to named routes.
  • Debugging checklist: open the generated file and search for the route name. Not there → it's unnamed, filtered, or you didn't regenerate. There but the URL is wrong → check placeholder names match exactly (they're case-sensitive keys) and whether extra params became a query string. Wrong host → absolute/proxy config.
  • Version risk. Last tagged release is early 2023, so on Laravel 11/12 verify config publishing and provider discovery still behave before adopting. The package is small enough to fork or vendor if a framework change breaks it — and if you're starting fresh on a modern stack, Ziggy covers the same ground with active maintenance and a bundler-friendly module. Laroute is still a perfectly good fit for a legacy app or a Blade-plus-jQuery frontend where a single global script is exactly what you want.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource