TL;DR With a Package
https://github.com/halivert/laravel-js-routes
We generally use JavaScript for the front-end in our applications, if we also use Laravel we notice that it includes a very useful wrapper called Laravel Mix, that can preprocess our JS files.
There's a problem when we want to get some Laravel route in any JS module. A naive approach is to export all our routes into a JSON and then use a function that has a similar behavior but in JS.
Code
That's why I crafted a Laravel command (usable with php artisan
) composed by this code:
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Route;
class CreateJSRoutesCommand extends Command
{
public function handle()
{
/*
* When we call the command, this method executes
* first.
*/
}
public function createFile($fileName, $contents)
{
/*
* This method creates a file with name equals to
* $fileName and content equals to $contents, it also
* asks if you want to overwrite the file in case
* another with same name exists.
*/
}
private function includeRoute($value, $routeName)
{
/*
* This function determines if a route must be included
* or not in our JSON, by default excludes telescope
* routes.
*/
}
public function getJSPath($path)
{
/*
* This returns the route where our new file with JSON
* and function must be written.
*/
}
}
The handle
function does most of the work, first we get Laravel routes, filter it and keep its URI.
$routes = collect(
Route::getRoutes()->getRoutesByName()
)->filter(function ($route, $key) {
return $this->includeRoute($route, $key);
})->map(function ($route) {
return [
'uri' => $route->uri
];
});
The content of our file will be composed of the JSON and function route
so we start adding the var name and the content.
$jsonFlags = JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE;
$content = 'const routes = ';
$content .= json_encode($routes, $jsonFlags);
$content .= ";\n\n";
Then we build the route
function (it's on a separate file)
$content .= file_get_contents(
__DIR__ . '/../assets/js/routeFunction.js'
);
// assets/js/routeFunction.js
// This function receives as a route name and an array of
// parameters
const route = (routeName, params = []) => {
// It searches in the stored routes one that match with the
// given name and if it doesn't exists throws an error
const _route = routes[routeName];
if (_route == null) throw "Requested route doesn't exist";
let uri = _route.uri;
// If an URI is found, replace the parameters with a RegEx
// (I don't know how I did it) and throws another error if
// there are missing parameters.
// Remaining parameters will be ignored.
const matches = uri.match(/{[\w]+}/g) || [];
const requiredParametersCount = matches.length;
if (params instanceof Array) {
if (params.length < requiredParametersCount) throw "Missing parameters";
for (let i = 0; i < requiredParametersCount; i++)
uri = uri.replace(/{[\w]+}/, params.shift());
for (let i = 0; i < params.length; i++)
uri += (i ? "&" : "?") + params[i] + "=" + params[i];
} else if (params instanceof Object) {
let extraParams = matches.reduce((ac, match) => {
let key = match.substring(1, match.length - 1);
if (params.hasOwnProperty(key)) {
uri = uri.replace(new RegExp(match, "g"), params[key]);
delete ac[key];
}
return ac;
}, params);
Object.keys(extraParams).forEach((key, i) => {
uri += (i ? "&" : "?") + key + "=" + extraParams[key];
});
}
if (uri.includes("}")) throw "Missing parameters";
return "/" + uri;
};
export { route };
Finally we create the file.
$fileName = $this->option('name') ?? config('app.jsroutes.name');
if ($this->createFile($fileName, $content)) {
$this->info("$fileName created");
}
Installation
composer require halivert/laravel-js-routes
Before use
If we already add the command to Laravel, then we execute it with
php artisan route:tojs
Then we add the file to our webpack.mix.js
file, so it can be processed.
mix.js("resources/js/routes", "public/js");
And after a yarn prod
or npm prod
we can use our routes
function when we want to call a route by its name in a JS file.
import { route } from "./routes.js";
Use
Use examples:
axios
.get(route("routeName", [param1, param2]))
.then(response => {
console.log(response.data);
});
I would love to read your comments
Happy coding! 👋
Top comments (6)
Hopefully topic and this tutorial was grate for me, thanks a lot :)
Thank you 😌
I was struggling with other similar product but when i get this my headache gone.
hoe can i use halivert/laravel-js-routes in larave version 7.x.x
Thanks for your comments, I appreciate them 😌🙏🏽
Also the package now depends on laravel/framework: 6, 7 or 8
Good one. Does this generate a full URL or relative URL?
Thank you
The route generated is relative, for now