A Javascript route() helper for Laravel
laravel javascript routes commands
Note: this is an updated version of a post originally published on GitHub.
Using named routes in Laravel makes it easy to change URLs as an app matures during development. But there’s no built-in way to access routes by name from your front-end JS code. The solution I’ve come up with is to:
-
Create a new
artisan route:json
command to export all named routes as JSON -
Create a simple JS
route()
function to access and fill in URLs with parameters in my front-end code
Installation
Install RouteJson.php
Create a file named app/Console/Commands/RouteJson.php
in
your app. Copy the following code into that file:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Route;
class RouteJson extends Command
{/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'route:json';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Export named routes as JSON';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{$routes = $this->generateRoutes();
$this->writeJson($routes);
return;
}
public function generateRoutes()
{$routes = [];
foreach (Route::getRoutes()->getRoutes() as $route) {
if (is_null($route->getName())) {
continue;
}if (isset($routes[$route->getName()])) {
$this->comment(
'Overwriting duplicate named route: ' . $route->getName()
;
)
}$routes[$route->getName()] = '/' . $route->uri();
}return $routes;
}
protected function writeJson($routes)
{$filename = 'resources/assets/js/routes.json';
if (!($handle = fopen($filename, 'w'))) {
$this->error("Cannot open file: $filename");
return;
}
// Write $somecontent to our opened file.
if (fwrite($handle, json_encode($routes)) === false) {
$this->error("Cannot write to file: $filename");
return;
}
$this->info("Wrote routes to: $filename");
fclose($handle);
} }
Edit Kernel.php
Edit the app/Console/Kernel.php
file to make sure that
Commands\RouteJson::class
is included in the
$commands
array. For example, the
$commands
in my Kernel.php
looks like this:
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Commands\RouteJson::class
; ]
Install the JS route()
helper
Create a file named resources/assets/js/route.js
. Copy
the following code into that file:
import routes from './routes.json';
/**
* Resolve a named route into a valid URI
* @param {string} routeName name of route
* @param {Object} [replacements={}] Object whose keys are parameter names, and whose values are the values to replace those parameters with.
* @return {string} A filled, resolved URI
*/
export default function (routeName, replacements = {}) {
var uri = routes[routeName];
if (!uri) {
throw new Error(`Cannot find route: ${routeName}`);
}
Object.keys(replacements).forEach(
=>
(key) = uri.replace(new RegExp('{' + key + '\\??}'), replacements[key])),
(uri ;
)
// remove any leftover optional parameters (inc leading slash)
= uri.replace(/{[^/]+\?}/, '');
uri
if (uri.match(/{.*}/)) {
throw new Error(`Route contains unfilled parameters: ${routeName} ${uri}`);
}
return uri;
}
Usage
Issue the command php artisan route:json
to export your
routes to the file resources/assets/js/routes.json
. Then,
in your Javascript code, you can
import route from './route.js'
and use the
route()
helper very similarly to the PHP version in
Laravel:
import route from './route.js'; // or '../route.js', '../../route.js', etc
console.log(route('user.note.store', { user: 123 })); // -> /user/123/note
Optional route parameters that aren’t passed in the paramerter object will be discarded, but mandatory route parameters that aren’t passed in will trigger an error.
It’s not perfect, but it’s worked pretty well for me. Maybe it will work for you.
Update
After I wrote this, TightenCo published a related package called Ziggy. Initially, Ziggy could only send the routes to the browser on every page load, but recent versions appear to be able to also output a file, which can be bundled and cached as part of your build process, similar to how this works.